clutter: Move X11 input to src/backends/x11
The end goal is to have all clutter backend code in src/backends. Input is the larger chunk of it, which is now part of our specific MutterClutterBackendX11, this extends to device manager, input devices, tools and keymap. This was supposed to be nice and incremental, but there's no sane way to cut this through. As a result of the refactor, a number of private Clutter functions are now exported for external backends to be possible. https://gitlab.gnome.org/GNOME/mutter/merge_requests/672
This commit is contained in:

committed by
Jonas Ådahl

parent
fa4580de53
commit
ad72fa46b0
@ -45,6 +45,8 @@
|
||||
#include "backends/meta-idle-monitor-private.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "backends/x11/meta-clutter-backend-x11.h"
|
||||
#include "backends/x11/meta-event-x11.h"
|
||||
#include "backends/x11/meta-stage-x11.h"
|
||||
#include "backends/x11/meta-renderer-x11.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
@ -382,7 +384,7 @@ handle_host_xevent (MetaBackend *backend,
|
||||
if (!bypass_clutter)
|
||||
{
|
||||
handle_input_event (x11, event);
|
||||
clutter_x11_handle_event (event);
|
||||
meta_x11_handle_event (event);
|
||||
}
|
||||
|
||||
XFreeEventData (priv->xdisplay, &event->xcookie);
|
||||
@ -807,7 +809,7 @@ Window
|
||||
meta_backend_x11_get_xwindow (MetaBackendX11 *x11)
|
||||
{
|
||||
ClutterActor *stage = meta_backend_get_stage (META_BACKEND (x11));
|
||||
return clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
|
||||
return meta_x11_get_stage_window (CLUTTER_STAGE (stage));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -29,7 +29,10 @@
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-renderer.h"
|
||||
#include "backends/x11/meta-clutter-backend-x11.h"
|
||||
#include "backends/x11/meta-device-manager-x11.h"
|
||||
#include "backends/x11/meta-keymap-x11.h"
|
||||
#include "backends/x11/meta-stage-x11-nested.h"
|
||||
#include "backends/x11/meta-xkb-a11y-x11.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "core/bell.h"
|
||||
@ -38,6 +41,8 @@
|
||||
struct _MetaClutterBackendX11
|
||||
{
|
||||
ClutterBackendX11 parent;
|
||||
MetaKeymapX11 *keymap;
|
||||
MetaDeviceManagerX11 *device_manager;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaClutterBackendX11, meta_clutter_backend_x11,
|
||||
@ -64,7 +69,7 @@ meta_clutter_backend_x11_create_stage (ClutterBackend *backend,
|
||||
if (meta_is_wayland_compositor ())
|
||||
stage_type = META_TYPE_STAGE_X11_NESTED;
|
||||
else
|
||||
stage_type = CLUTTER_TYPE_STAGE_X11;
|
||||
stage_type = META_TYPE_STAGE_X11;
|
||||
|
||||
stage = g_object_new (stage_type,
|
||||
"backend", backend,
|
||||
@ -81,6 +86,116 @@ meta_clutter_backend_x11_bell_notify (ClutterBackend *backend)
|
||||
meta_bell_notify (display, NULL);
|
||||
}
|
||||
|
||||
static ClutterDeviceManager *
|
||||
meta_clutter_backend_x11_get_device_manager (ClutterBackend *backend)
|
||||
{
|
||||
MetaClutterBackendX11 *backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
return CLUTTER_DEVICE_MANAGER (backend_x11->device_manager);
|
||||
}
|
||||
|
||||
static PangoDirection
|
||||
meta_clutter_backend_x11_get_keymap_direction (ClutterBackend *backend)
|
||||
{
|
||||
ClutterKeymap *keymap = clutter_backend_get_keymap (backend);
|
||||
|
||||
if (G_UNLIKELY (keymap == NULL))
|
||||
return PANGO_DIRECTION_NEUTRAL;
|
||||
|
||||
return meta_keymap_x11_get_direction (META_KEYMAP_X11 (keymap));
|
||||
}
|
||||
|
||||
static ClutterKeymap *
|
||||
meta_clutter_backend_x11_get_keymap (ClutterBackend *backend)
|
||||
{
|
||||
MetaClutterBackendX11 *backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
return CLUTTER_KEYMAP (backend_x11->keymap);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_clutter_backend_x11_translate_event (ClutterBackend *backend,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
MetaClutterBackendX11 *backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
|
||||
MetaDeviceManagerX11 *device_manager_x11;
|
||||
MetaStageX11 *stage_x11;
|
||||
ClutterBackendClass *clutter_backend_class;
|
||||
|
||||
clutter_backend_class =
|
||||
CLUTTER_BACKEND_CLASS (meta_clutter_backend_x11_parent_class);
|
||||
if (clutter_backend_class->translate_event (backend, native, event))
|
||||
return TRUE;
|
||||
|
||||
if (meta_keymap_x11_handle_event (backend_x11->keymap, native))
|
||||
return TRUE;
|
||||
|
||||
stage_x11 = META_STAGE_X11 (clutter_backend_get_stage_window (backend));
|
||||
if (meta_stage_x11_translate_event (stage_x11, native, event))
|
||||
return TRUE;
|
||||
|
||||
device_manager_x11 = META_DEVICE_MANAGER_X11 (backend_x11->device_manager);
|
||||
if (meta_device_manager_x11_translate_event (device_manager_x11,
|
||||
native, event))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_keymap_state_change (MetaKeymapX11 *keymap_x11,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterDeviceManager *device_manager = CLUTTER_DEVICE_MANAGER (data);
|
||||
ClutterKbdA11ySettings kbd_a11y_settings;
|
||||
|
||||
/* On keymaps state change, just reapply the current settings, it'll
|
||||
* take care of enabling/disabling mousekeys based on NumLock state.
|
||||
*/
|
||||
clutter_device_manager_get_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
|
||||
meta_device_manager_x11_apply_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_clutter_backend_x11_init_events (ClutterBackend *backend)
|
||||
{
|
||||
MetaClutterBackendX11 *backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
|
||||
int event_base, first_event, first_error;
|
||||
|
||||
if (XQueryExtension (clutter_x11_get_default_display (),
|
||||
"XInputExtension",
|
||||
&event_base,
|
||||
&first_event,
|
||||
&first_error))
|
||||
{
|
||||
int major = 2;
|
||||
int minor = 3;
|
||||
|
||||
if (XIQueryVersion (clutter_x11_get_default_display (),
|
||||
&major, &minor) != BadRequest)
|
||||
{
|
||||
g_debug ("Creating XI2 device manager");
|
||||
backend_x11->device_manager =
|
||||
g_object_new (META_TYPE_DEVICE_MANAGER_X11,
|
||||
"backend", backend_x11,
|
||||
"opcode", event_base,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!backend_x11->device_manager)
|
||||
g_error ("No XInput 2.3 support");
|
||||
|
||||
backend_x11->keymap = g_object_new (META_TYPE_KEYMAP_X11,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
g_signal_connect (backend_x11->keymap,
|
||||
"state-changed",
|
||||
G_CALLBACK (on_keymap_state_change),
|
||||
backend_x11->device_manager);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_clutter_backend_x11_init (MetaClutterBackendX11 *clutter_backend_x11)
|
||||
{
|
||||
@ -94,4 +209,9 @@ meta_clutter_backend_x11_class_init (MetaClutterBackendX11Class *klass)
|
||||
clutter_backend_class->get_renderer = meta_clutter_backend_x11_get_renderer;
|
||||
clutter_backend_class->create_stage = meta_clutter_backend_x11_create_stage;
|
||||
clutter_backend_class->bell_notify = meta_clutter_backend_x11_bell_notify;
|
||||
clutter_backend_class->get_device_manager = meta_clutter_backend_x11_get_device_manager;
|
||||
clutter_backend_class->get_keymap_direction = meta_clutter_backend_x11_get_keymap_direction;
|
||||
clutter_backend_class->get_keymap = meta_clutter_backend_x11_get_keymap;
|
||||
clutter_backend_class->translate_event = meta_clutter_backend_x11_translate_event;
|
||||
clutter_backend_class->init_events = meta_clutter_backend_x11_init_events;
|
||||
}
|
||||
|
2195
src/backends/x11/meta-device-manager-x11.c
Normal file
2195
src/backends/x11/meta-device-manager-x11.c
Normal file
File diff suppressed because it is too large
Load Diff
60
src/backends/x11/meta-device-manager-x11.h
Normal file
60
src/backends/x11/meta-device-manager-x11.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright © 2011 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef META_DEVICE_MANAGER_X11_H
|
||||
#define META_DEVICE_MANAGER_X11_H
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
#include <libwacom/libwacom.h>
|
||||
#endif
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_DEVICE_MANAGER_X11 (meta_device_manager_x11_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaDeviceManagerX11, meta_device_manager_x11,
|
||||
META, DEVICE_MANAGER_X11, ClutterDeviceManager)
|
||||
|
||||
struct _MetaDeviceManagerX11
|
||||
{
|
||||
ClutterDeviceManager parent_instance;
|
||||
|
||||
GHashTable *devices_by_id;
|
||||
GHashTable *tools_by_serial;
|
||||
|
||||
GSList *all_devices;
|
||||
|
||||
GList *master_devices;
|
||||
GList *slave_devices;
|
||||
|
||||
int opcode;
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
WacomDeviceDatabase *wacom_db;
|
||||
#endif
|
||||
};
|
||||
|
||||
gboolean meta_device_manager_x11_translate_event (MetaDeviceManagerX11 *manager_xi2,
|
||||
XEvent *xevent,
|
||||
ClutterEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_DEVICE_MANAGER_X11_H */
|
173
src/backends/x11/meta-event-x11.c
Normal file
173
src/backends/x11/meta-event-x11.c
Normal file
@ -0,0 +1,173 @@
|
||||
/* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
|
||||
* Copyright (C) 2009, 2010 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authored by:
|
||||
* Matthew Allum <mallum@openedhand.com>
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "backends/x11/meta-event-x11.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
|
||||
MetaEventX11 *
|
||||
meta_event_x11_new (void)
|
||||
{
|
||||
return g_slice_new0 (MetaEventX11);
|
||||
}
|
||||
|
||||
MetaEventX11 *
|
||||
meta_event_x11_copy (MetaEventX11 *event_x11)
|
||||
{
|
||||
if (event_x11 != NULL)
|
||||
return g_slice_dup (MetaEventX11, event_x11);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_event_x11_free (MetaEventX11 *event_x11)
|
||||
{
|
||||
if (event_x11 != NULL)
|
||||
g_slice_free (MetaEventX11, event_x11);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_x11_handle_event:
|
||||
* @xevent: pointer to XEvent structure
|
||||
*
|
||||
* This function processes a single X event; it can be used to hook
|
||||
* into external X11 event processing (for example, a GDK filter
|
||||
* function).
|
||||
*
|
||||
* Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE
|
||||
* indicates that Clutter has internally handled the event and the
|
||||
* caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE
|
||||
* indicates that Clutter is either not interested in the event,
|
||||
* or has used the event to update internal state without taking
|
||||
* any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not
|
||||
* occur.
|
||||
*
|
||||
* Since: 0.8
|
||||
*/
|
||||
ClutterX11FilterReturn
|
||||
meta_x11_handle_event (XEvent *xevent)
|
||||
{
|
||||
ClutterX11FilterReturn result;
|
||||
ClutterBackend *backend;
|
||||
ClutterEvent *event;
|
||||
gint spin = 1;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
Display *xdisplay;
|
||||
gboolean allocated_event;
|
||||
|
||||
/* The return values here are someone approximate; we return
|
||||
* META_X11_FILTER_REMOVE if a clutter event is
|
||||
* generated for the event. This mostly, but not entirely,
|
||||
* corresponds to whether other event processing should be
|
||||
* excluded. As long as the stage window is not shared with another
|
||||
* toolkit it should be safe, and never return
|
||||
* %META_X11_FILTER_REMOVE when more processing is needed.
|
||||
*/
|
||||
|
||||
result = CLUTTER_X11_FILTER_CONTINUE;
|
||||
|
||||
_clutter_threads_acquire_lock ();
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
|
||||
event = clutter_event_new (CLUTTER_NOTHING);
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
xdisplay = backend_x11->xdpy;
|
||||
|
||||
allocated_event = XGetEventData (xdisplay, &xevent->xcookie);
|
||||
|
||||
if (_clutter_backend_translate_event (backend, xevent, event))
|
||||
{
|
||||
_clutter_event_push (event, FALSE);
|
||||
|
||||
result = CLUTTER_X11_FILTER_REMOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_event_free (event);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Motion events can generate synthetic enter and leave events, so if we
|
||||
* are processing a motion event, we need to spin the event loop at least
|
||||
* two extra times to pump the enter/leave events through (otherwise they
|
||||
* just get pushed down the queue and never processed).
|
||||
*/
|
||||
if (event->type == CLUTTER_MOTION)
|
||||
spin += 2;
|
||||
|
||||
while (spin > 0 && (event = clutter_event_get ()))
|
||||
{
|
||||
/* forward the event into clutter for emission etc. */
|
||||
_clutter_stage_queue_event (event->any.stage, event, FALSE);
|
||||
--spin;
|
||||
}
|
||||
|
||||
out:
|
||||
if (allocated_event)
|
||||
XFreeEventData (xdisplay, &xevent->xcookie);
|
||||
|
||||
_clutter_threads_release_lock ();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Time
|
||||
meta_x11_get_current_event_time (void)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
|
||||
return CLUTTER_BACKEND_X11 (backend)->last_event_time;
|
||||
}
|
||||
|
||||
gint
|
||||
meta_x11_event_get_key_group (const ClutterEvent *event)
|
||||
{
|
||||
MetaEventX11 *event_x11;
|
||||
|
||||
g_return_val_if_fail (event != NULL, 0);
|
||||
g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS ||
|
||||
event->type == CLUTTER_KEY_RELEASE, 0);
|
||||
|
||||
event_x11 = _clutter_event_get_platform_data (event);
|
||||
if (event_x11 == NULL)
|
||||
return 0;
|
||||
|
||||
return event_x11->key_group;
|
||||
}
|
||||
|
||||
guint
|
||||
meta_x11_event_sequence_get_touch_detail (const ClutterEventSequence *sequence)
|
||||
{
|
||||
g_return_val_if_fail (sequence != NULL, 0);
|
||||
|
||||
return GPOINTER_TO_UINT (sequence);
|
||||
}
|
55
src/backends/x11/meta-event-x11.h
Normal file
55
src/backends/x11/meta-event-x11.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
|
||||
* Copyright (C) 2009, 2010 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authored by:
|
||||
* Matthew Allum <mallum@openedhand.com>
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef META_EVENT_X11_H
|
||||
#define META_EVENT_X11_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
|
||||
typedef struct _MetaEventX11 MetaEventX11;
|
||||
|
||||
struct _MetaEventX11
|
||||
{
|
||||
/* additional fields for Key events */
|
||||
gint key_group;
|
||||
|
||||
guint key_is_modifier : 1;
|
||||
guint num_lock_set : 1;
|
||||
guint caps_lock_set : 1;
|
||||
};
|
||||
|
||||
MetaEventX11 * meta_event_x11_new (void);
|
||||
MetaEventX11 * meta_event_x11_copy (MetaEventX11 *event_x11);
|
||||
void meta_event_x11_free (MetaEventX11 *event_x11);
|
||||
|
||||
Time meta_x11_get_current_event_time (void);
|
||||
|
||||
gint meta_x11_event_get_key_group (const ClutterEvent *event);
|
||||
|
||||
guint meta_x11_event_sequence_get_touch_detail (const ClutterEventSequence *sequence);
|
||||
|
||||
ClutterX11FilterReturn meta_x11_handle_event (XEvent *xevent);
|
||||
|
||||
#endif /* META_EVENT_X11_H */
|
45
src/backends/x11/meta-input-device-tool-x11.c
Normal file
45
src/backends/x11/meta-input-device-tool-x11.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright © 2016 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-input-device-tool-x11.h"
|
||||
|
||||
G_DEFINE_TYPE (MetaInputDeviceToolX11, meta_input_device_tool_x11,
|
||||
CLUTTER_TYPE_INPUT_DEVICE_TOOL)
|
||||
|
||||
static void
|
||||
meta_input_device_tool_x11_class_init (MetaInputDeviceToolX11Class *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_device_tool_x11_init (MetaInputDeviceToolX11 *tool)
|
||||
{
|
||||
}
|
||||
|
||||
ClutterInputDeviceTool *
|
||||
meta_input_device_tool_x11_new (guint serial,
|
||||
ClutterInputDeviceToolType type)
|
||||
{
|
||||
return g_object_new (META_TYPE_INPUT_DEVICE_TOOL_X11,
|
||||
"type", type,
|
||||
"serial", serial,
|
||||
NULL);
|
||||
}
|
51
src/backends/x11/meta-input-device-tool-x11.h
Normal file
51
src/backends/x11/meta-input-device-tool-x11.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright © 2016 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef META_INPUT_DEVICE_TOOL_X11_H
|
||||
#define META_INPUT_DEVICE_TOOL_X11_H
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
#define META_TYPE_INPUT_DEVICE_TOOL_X11 (meta_input_device_tool_x11_get_type ())
|
||||
|
||||
#define META_INPUT_DEVICE_TOOL_X11(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), META_TYPE_INPUT_DEVICE_TOOL_X11, MetaInputDeviceToolX11))
|
||||
#define META_IS_INPUT_DEVICE_TOOL_X11(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), META_TYPE_INPUT_DEVICE_TOOL_X11))
|
||||
#define META_INPUT_DEVICE_TOOL_X11_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), META_TYPE_INPUT_DEVICE_TOOL_X11, MetaInputDeviceToolX11Class))
|
||||
#define META_IS_INPUT_DEVICE_TOOL_X11_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), META_TYPE_INPUT_DEVICE_TOOL_X1))
|
||||
#define META_INPUT_DEVICE_TOOL_X11_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), META_TYPE_INPUT_DEVICE_TOOL_X11, MetaInputDeviceToolX11Class))
|
||||
|
||||
typedef struct _MetaInputDeviceToolX11 MetaInputDeviceToolX11;
|
||||
typedef struct _MetaInputDeviceToolX11Class MetaInputDeviceToolX11Class;
|
||||
|
||||
struct _MetaInputDeviceToolX11
|
||||
{
|
||||
ClutterInputDeviceTool parent_instance;
|
||||
};
|
||||
|
||||
struct _MetaInputDeviceToolX11Class
|
||||
{
|
||||
ClutterInputDeviceToolClass parent_class;
|
||||
};
|
||||
|
||||
GType meta_input_device_tool_x11_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterInputDeviceTool * meta_input_device_tool_x11_new (guint serial,
|
||||
ClutterInputDeviceToolType type);
|
||||
|
||||
#endif /* META_INPUT_DEVICE_TOOL_X11_H */
|
422
src/backends/x11/meta-input-device-x11.c
Normal file
422
src/backends/x11/meta-input-device-x11.c
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright © 2011 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "backends/x11/meta-input-device-x11.h"
|
||||
|
||||
struct _MetaInputDeviceX11
|
||||
{
|
||||
ClutterInputDevice device;
|
||||
|
||||
gint device_id;
|
||||
ClutterInputDeviceTool *current_tool;
|
||||
|
||||
guint inhibit_pointer_query_timer;
|
||||
gboolean query_status;
|
||||
float current_x;
|
||||
float current_y;
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
WacomDevice *wacom_device;
|
||||
GArray *group_modes;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct _MetaInputDeviceX11Class
|
||||
{
|
||||
ClutterInputDeviceClass device_class;
|
||||
};
|
||||
|
||||
#define N_BUTTONS 5
|
||||
|
||||
G_DEFINE_TYPE (MetaInputDeviceX11,
|
||||
meta_input_device_x11,
|
||||
CLUTTER_TYPE_INPUT_DEVICE)
|
||||
|
||||
static void
|
||||
meta_input_device_x11_constructed (GObject *object)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (object);
|
||||
|
||||
g_object_get (object, "id", &device_xi2->device_id, NULL);
|
||||
|
||||
if (G_OBJECT_CLASS (meta_input_device_x11_parent_class)->constructed)
|
||||
G_OBJECT_CLASS (meta_input_device_x11_parent_class)->constructed (object);
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
if (clutter_input_device_get_device_type (CLUTTER_INPUT_DEVICE (object)) == CLUTTER_PAD_DEVICE)
|
||||
{
|
||||
device_xi2->group_modes = g_array_new (FALSE, TRUE, sizeof (guint));
|
||||
g_array_set_size (device_xi2->group_modes,
|
||||
clutter_input_device_get_n_mode_groups (CLUTTER_INPUT_DEVICE (object)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_input_device_x11_keycode_to_evdev (ClutterInputDevice *device,
|
||||
guint hardware_keycode,
|
||||
guint *evdev_keycode)
|
||||
{
|
||||
/* When using evdev under X11 the hardware keycodes are the evdev
|
||||
keycodes plus 8. I haven't been able to find any documentation to
|
||||
know what the +8 is for. FIXME: This should probably verify that
|
||||
X server is using evdev. */
|
||||
*evdev_keycode = hardware_keycode - 8;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_input_device_x11_is_grouped (ClutterInputDevice *device,
|
||||
ClutterInputDevice *other_device)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_device_x11_finalize (GObject *object)
|
||||
{
|
||||
#ifdef HAVE_LIBWACOM
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (object);
|
||||
|
||||
if (device_xi2->wacom_device)
|
||||
libwacom_destroy (device_xi2->wacom_device);
|
||||
|
||||
if (device_xi2->group_modes)
|
||||
g_array_unref (device_xi2->group_modes);
|
||||
|
||||
if (device_xi2->inhibit_pointer_query_timer)
|
||||
g_source_remove (device_xi2->inhibit_pointer_query_timer);
|
||||
#endif
|
||||
|
||||
G_OBJECT_CLASS (meta_input_device_x11_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gint
|
||||
meta_input_device_x11_get_group_n_modes (ClutterInputDevice *device,
|
||||
gint group)
|
||||
{
|
||||
#ifdef HAVE_LIBWACOM
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
|
||||
if (device_xi2->wacom_device)
|
||||
{
|
||||
if (group == 0)
|
||||
{
|
||||
if (libwacom_has_ring (device_xi2->wacom_device))
|
||||
return libwacom_get_ring_num_modes (device_xi2->wacom_device);
|
||||
else if (libwacom_get_num_strips (device_xi2->wacom_device) >= 1)
|
||||
return libwacom_get_strips_num_modes (device_xi2->wacom_device);
|
||||
}
|
||||
else if (group == 1)
|
||||
{
|
||||
if (libwacom_has_ring2 (device_xi2->wacom_device))
|
||||
return libwacom_get_ring2_num_modes (device_xi2->wacom_device);
|
||||
else if (libwacom_get_num_strips (device_xi2->wacom_device) >= 2)
|
||||
return libwacom_get_strips_num_modes (device_xi2->wacom_device);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
static int
|
||||
meta_input_device_x11_get_button_group (ClutterInputDevice *device,
|
||||
guint button)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
|
||||
if (device_xi2->wacom_device)
|
||||
{
|
||||
if (button >= libwacom_get_num_buttons (device_xi2->wacom_device))
|
||||
return -1;
|
||||
|
||||
return libwacom_get_button_led_group (device_xi2->wacom_device,
|
||||
'A' + button);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
meta_input_device_x11_is_mode_switch_button (ClutterInputDevice *device,
|
||||
guint group,
|
||||
guint button)
|
||||
{
|
||||
int button_group = -1;
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
button_group = meta_input_device_x11_get_button_group (device, button);
|
||||
#endif
|
||||
|
||||
return button_group == (int) group;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_device_x11_class_init (MetaInputDeviceX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = meta_input_device_x11_constructed;
|
||||
gobject_class->finalize = meta_input_device_x11_finalize;
|
||||
|
||||
device_class->keycode_to_evdev = meta_input_device_x11_keycode_to_evdev;
|
||||
device_class->is_grouped = meta_input_device_x11_is_grouped;
|
||||
device_class->get_group_n_modes = meta_input_device_x11_get_group_n_modes;
|
||||
device_class->is_mode_switch_button = meta_input_device_x11_is_mode_switch_button;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_device_x11_init (MetaInputDeviceX11 *self)
|
||||
{
|
||||
}
|
||||
|
||||
static ClutterModifierType
|
||||
get_modifier_for_button (int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
return CLUTTER_BUTTON1_MASK;
|
||||
case 2:
|
||||
return CLUTTER_BUTTON2_MASK;
|
||||
case 3:
|
||||
return CLUTTER_BUTTON3_MASK;
|
||||
case 4:
|
||||
return CLUTTER_BUTTON4_MASK;
|
||||
case 5:
|
||||
return CLUTTER_BUTTON5_MASK;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_input_device_x11_translate_state (ClutterEvent *event,
|
||||
XIModifierState *modifiers_state,
|
||||
XIButtonState *buttons_state,
|
||||
XIGroupState *group_state)
|
||||
{
|
||||
guint button = 0;
|
||||
guint base = 0;
|
||||
guint latched = 0;
|
||||
guint locked = 0;
|
||||
guint effective;
|
||||
|
||||
if (modifiers_state)
|
||||
{
|
||||
base = (guint) modifiers_state->base;
|
||||
latched = (guint) modifiers_state->latched;
|
||||
locked = (guint) modifiers_state->locked;
|
||||
}
|
||||
|
||||
if (buttons_state)
|
||||
{
|
||||
int len, i;
|
||||
|
||||
len = MIN (N_BUTTONS, buttons_state->mask_len * 8);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (!XIMaskIsSet (buttons_state->mask, i))
|
||||
continue;
|
||||
|
||||
button |= get_modifier_for_button (i);
|
||||
}
|
||||
}
|
||||
|
||||
/* The XIButtonState sent in the event specifies the
|
||||
* state of the buttons before the event. In order to
|
||||
* get the current state of the buttons, we need to
|
||||
* filter out the current button.
|
||||
*/
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
button |= (get_modifier_for_button (event->button.button));
|
||||
break;
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
button &= ~(get_modifier_for_button (event->button.button));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
effective = button | base | latched | locked;
|
||||
if (group_state)
|
||||
effective |= (group_state->effective) << 13;
|
||||
|
||||
_clutter_event_set_state_full (event, button, base, latched, locked, effective);
|
||||
}
|
||||
|
||||
void
|
||||
meta_input_device_x11_update_tool (ClutterInputDevice *device,
|
||||
ClutterInputDeviceTool *tool)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
g_set_object (&device_xi2->current_tool, tool);
|
||||
}
|
||||
|
||||
ClutterInputDeviceTool *
|
||||
meta_input_device_x11_get_current_tool (ClutterInputDevice *device)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
return device_xi2->current_tool;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_input_device_x11_query_pointer_location (MetaInputDeviceX11 *device_xi2)
|
||||
{
|
||||
Window xroot_window, xchild_window;
|
||||
double xroot_x, xroot_y, xwin_x, xwin_y;
|
||||
XIButtonState button_state;
|
||||
XIModifierState mod_state;
|
||||
XIGroupState group_state;
|
||||
int result;
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
result = XIQueryPointer (clutter_x11_get_default_display (),
|
||||
device_xi2->device_id,
|
||||
clutter_x11_get_root_window (),
|
||||
&xroot_window,
|
||||
&xchild_window,
|
||||
&xroot_x, &xroot_y,
|
||||
&xwin_x, &xwin_y,
|
||||
&button_state,
|
||||
&mod_state,
|
||||
&group_state);
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
if (!result)
|
||||
return FALSE;
|
||||
|
||||
device_xi2->current_x = (float) xroot_x;
|
||||
device_xi2->current_y = (float) xroot_y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clear_inhibit_pointer_query_cb (gpointer data)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (data);
|
||||
|
||||
device_xi2->inhibit_pointer_query_timer = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_input_device_x11_get_pointer_location (ClutterInputDevice *device,
|
||||
float *x,
|
||||
float *y)
|
||||
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
|
||||
g_return_val_if_fail (META_IS_INPUT_DEVICE_X11 (device), FALSE);
|
||||
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, FALSE);
|
||||
|
||||
/* Throttle XServer queries and roundtrips using an idle timeout */
|
||||
if (device_xi2->inhibit_pointer_query_timer == 0)
|
||||
{
|
||||
device_xi2->query_status =
|
||||
meta_input_device_x11_query_pointer_location (device_xi2);
|
||||
device_xi2->inhibit_pointer_query_timer =
|
||||
clutter_threads_add_idle (clear_inhibit_pointer_query_cb, device_xi2);
|
||||
}
|
||||
|
||||
*x = device_xi2->current_x;
|
||||
*y = device_xi2->current_y;
|
||||
|
||||
return device_xi2->query_status;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
void
|
||||
meta_input_device_x11_ensure_wacom_info (ClutterInputDevice *device,
|
||||
WacomDeviceDatabase *wacom_db)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
const gchar *node_path;
|
||||
|
||||
node_path = clutter_input_device_get_device_node (device);
|
||||
device_xi2->wacom_device = libwacom_new_from_path (wacom_db, node_path,
|
||||
WFALLBACK_NONE, NULL);
|
||||
}
|
||||
|
||||
guint
|
||||
meta_input_device_x11_get_pad_group_mode (ClutterInputDevice *device,
|
||||
guint group)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
|
||||
if (group >= device_xi2->group_modes->len)
|
||||
return 0;
|
||||
|
||||
return g_array_index (device_xi2->group_modes, guint, group);
|
||||
}
|
||||
|
||||
void
|
||||
meta_input_device_x11_update_pad_state (ClutterInputDevice *device,
|
||||
guint button,
|
||||
guint state,
|
||||
guint *group,
|
||||
guint *mode)
|
||||
{
|
||||
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device);
|
||||
guint button_group, *group_mode;
|
||||
gboolean is_mode_switch = FALSE;
|
||||
|
||||
button_group = meta_input_device_x11_get_button_group (device, button);
|
||||
is_mode_switch = button_group >= 0;
|
||||
|
||||
/* Assign all non-mode-switch buttons to group 0 so far */
|
||||
button_group = MAX (0, button_group);
|
||||
|
||||
if (button_group >= device_xi2->group_modes->len)
|
||||
return;
|
||||
|
||||
group_mode = &g_array_index (device_xi2->group_modes, guint, button_group);
|
||||
|
||||
if (is_mode_switch && state)
|
||||
{
|
||||
guint next, n_modes;
|
||||
|
||||
n_modes = clutter_input_device_get_group_n_modes (device, button_group);
|
||||
next = (*group_mode + 1) % n_modes;
|
||||
*group_mode = next;
|
||||
}
|
||||
|
||||
if (group)
|
||||
*group = button_group;
|
||||
if (mode)
|
||||
*mode = *group_mode;
|
||||
}
|
||||
#endif
|
74
src/backends/x11/meta-input-device-x11.h
Normal file
74
src/backends/x11/meta-input-device-x11.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright © 2011 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef META_INPUT_DEVICE_X11_H
|
||||
#define META_INPUT_DEVICE_X11_H
|
||||
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
#include <libwacom/libwacom.h>
|
||||
#endif
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_INPUT_DEVICE_X11 (meta_input_device_x11_get_type ())
|
||||
#define META_INPUT_DEVICE_X11(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), META_TYPE_INPUT_DEVICE_X11, MetaInputDeviceX11))
|
||||
#define META_IS_INPUT_DEVICE_X11(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), META_TYPE_INPUT_DEVICE_X11))
|
||||
#define META_INPUT_DEVICE_X11_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), META_TYPE_INPUT_DEVICE_X11, MetaInputDeviceX11Class))
|
||||
#define META_IS_INPUT_DEVICE_X11_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), META_TYPE_INPUT_DEVICE_X11))
|
||||
#define META_INPUT_DEVICE_X11_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), META_TYPE_INPUT_DEVICE_X11, MetaInputDeviceX11Class))
|
||||
|
||||
typedef struct _MetaInputDeviceX11 MetaInputDeviceX11;
|
||||
typedef struct _MetaInputDeviceX11Class MetaInputDeviceX11Class;
|
||||
|
||||
GType meta_input_device_x11_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void meta_input_device_x11_translate_state (ClutterEvent *event,
|
||||
XIModifierState *modifiers_state,
|
||||
XIButtonState *buttons_state,
|
||||
XIGroupState *group_state);
|
||||
void meta_input_device_x11_update_tool (ClutterInputDevice *device,
|
||||
ClutterInputDeviceTool *tool);
|
||||
ClutterInputDeviceTool * meta_input_device_x11_get_current_tool (ClutterInputDevice *device);
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
void meta_input_device_x11_ensure_wacom_info (ClutterInputDevice *device,
|
||||
WacomDeviceDatabase *wacom_db);
|
||||
|
||||
guint meta_input_device_x11_get_pad_group_mode (ClutterInputDevice *device,
|
||||
guint group);
|
||||
|
||||
void meta_input_device_x11_update_pad_state (ClutterInputDevice *device,
|
||||
guint button,
|
||||
guint state,
|
||||
guint *group,
|
||||
guint *mode);
|
||||
|
||||
#endif
|
||||
|
||||
gboolean meta_input_device_x11_get_pointer_location (ClutterInputDevice *device,
|
||||
float *x,
|
||||
float *y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_INPUT_DEVICE_X11_H */
|
947
src/backends/x11/meta-keymap-x11.c
Normal file
947
src/backends/x11/meta-keymap-x11.c
Normal file
@ -0,0 +1,947 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/XKBlib.h>
|
||||
|
||||
#include "backends/x11/meta-keymap-x11.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
|
||||
typedef struct _DirectionCacheEntry DirectionCacheEntry;
|
||||
typedef struct _ClutterKeymapKey ClutterKeymapKey;
|
||||
|
||||
struct _ClutterKeymapKey
|
||||
{
|
||||
guint keycode;
|
||||
guint group;
|
||||
guint level;
|
||||
};
|
||||
|
||||
struct _DirectionCacheEntry
|
||||
{
|
||||
guint serial;
|
||||
Atom group_atom;
|
||||
PangoDirection direction;
|
||||
};
|
||||
|
||||
struct _MetaKeymapX11
|
||||
{
|
||||
ClutterKeymap parent_instance;
|
||||
|
||||
ClutterBackend *backend;
|
||||
|
||||
int min_keycode;
|
||||
int max_keycode;
|
||||
|
||||
ClutterModifierType modmap[8];
|
||||
|
||||
ClutterModifierType num_lock_mask;
|
||||
ClutterModifierType scroll_lock_mask;
|
||||
ClutterModifierType level3_shift_mask;
|
||||
|
||||
PangoDirection current_direction;
|
||||
|
||||
XkbDescPtr xkb_desc;
|
||||
int xkb_event_base;
|
||||
guint xkb_map_serial;
|
||||
Atom current_group_atom;
|
||||
guint current_cache_serial;
|
||||
DirectionCacheEntry group_direction_cache[4];
|
||||
int current_group;
|
||||
|
||||
GHashTable *reserved_keycodes;
|
||||
GQueue *available_keycodes;
|
||||
|
||||
guint keymap_serial;
|
||||
|
||||
guint caps_lock_state : 1;
|
||||
guint num_lock_state : 1;
|
||||
guint has_direction : 1;
|
||||
|
||||
guint use_xkb : 1;
|
||||
guint have_xkb_autorepeat : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_BACKEND,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
|
||||
|
||||
G_DEFINE_TYPE (MetaKeymapX11, meta_keymap_x11, CLUTTER_TYPE_KEYMAP)
|
||||
|
||||
/* code adapted from gdk/x11/gdkkeys-x11.c - update_modmap */
|
||||
static void
|
||||
update_modmap (Display *display,
|
||||
MetaKeymapX11 *keymap_x11)
|
||||
{
|
||||
static struct {
|
||||
const gchar *name;
|
||||
Atom atom;
|
||||
ClutterModifierType mask;
|
||||
} vmods[] = {
|
||||
{ "Meta", 0, CLUTTER_META_MASK },
|
||||
{ "Super", 0, CLUTTER_SUPER_MASK },
|
||||
{ "Hyper", 0, CLUTTER_HYPER_MASK },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
int i, j, k;
|
||||
|
||||
if (vmods[0].atom == 0)
|
||||
for (i = 0; vmods[i].name; i++)
|
||||
vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
keymap_x11->modmap[i] = 1 << i;
|
||||
|
||||
for (i = 0; i < XkbNumVirtualMods; i++)
|
||||
{
|
||||
for (j = 0; vmods[j].atom; j++)
|
||||
{
|
||||
if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom)
|
||||
{
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k))
|
||||
keymap_x11->modmap[k] |= vmods[j].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XkbDescPtr
|
||||
get_xkb (MetaKeymapX11 *keymap_x11)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
if (keymap_x11->max_keycode == 0)
|
||||
XDisplayKeycodes (xdisplay,
|
||||
&keymap_x11->min_keycode,
|
||||
&keymap_x11->max_keycode);
|
||||
|
||||
if (keymap_x11->xkb_desc == NULL)
|
||||
{
|
||||
int flags = XkbKeySymsMask
|
||||
| XkbKeyTypesMask
|
||||
| XkbModifierMapMask
|
||||
| XkbVirtualModsMask;
|
||||
|
||||
keymap_x11->xkb_desc = XkbGetMap (xdisplay, flags, XkbUseCoreKbd);
|
||||
if (G_UNLIKELY (keymap_x11->xkb_desc == NULL))
|
||||
{
|
||||
g_error ("Failed to get the keymap from XKB");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags = XkbGroupNamesMask | XkbVirtualModNamesMask;
|
||||
XkbGetNames (xdisplay, flags, keymap_x11->xkb_desc);
|
||||
|
||||
update_modmap (xdisplay, keymap_x11);
|
||||
}
|
||||
else if (keymap_x11->xkb_map_serial != keymap_x11->keymap_serial)
|
||||
{
|
||||
int flags = XkbKeySymsMask
|
||||
| XkbKeyTypesMask
|
||||
| XkbModifierMapMask
|
||||
| XkbVirtualModsMask;
|
||||
|
||||
XkbGetUpdatedMap (xdisplay, flags, keymap_x11->xkb_desc);
|
||||
|
||||
flags = XkbGroupNamesMask | XkbVirtualModNamesMask;
|
||||
XkbGetNames (xdisplay, flags, keymap_x11->xkb_desc);
|
||||
|
||||
update_modmap (xdisplay, keymap_x11);
|
||||
|
||||
keymap_x11->xkb_map_serial = keymap_x11->keymap_serial;
|
||||
}
|
||||
|
||||
if (keymap_x11->num_lock_mask == 0)
|
||||
keymap_x11->num_lock_mask = XkbKeysymToModifiers (xdisplay, XK_Num_Lock);
|
||||
|
||||
if (keymap_x11->scroll_lock_mask == 0)
|
||||
keymap_x11->scroll_lock_mask = XkbKeysymToModifiers (xdisplay,
|
||||
XK_Scroll_Lock);
|
||||
if (keymap_x11->level3_shift_mask == 0)
|
||||
keymap_x11->level3_shift_mask = XkbKeysymToModifiers (xdisplay,
|
||||
XK_ISO_Level3_Shift);
|
||||
|
||||
return keymap_x11->xkb_desc;
|
||||
}
|
||||
|
||||
static void
|
||||
update_locked_mods (MetaKeymapX11 *keymap_x11,
|
||||
gint locked_mods)
|
||||
{
|
||||
gboolean old_caps_lock_state, old_num_lock_state;
|
||||
|
||||
old_caps_lock_state = keymap_x11->caps_lock_state;
|
||||
old_num_lock_state = keymap_x11->num_lock_state;
|
||||
|
||||
keymap_x11->caps_lock_state = (locked_mods & CLUTTER_LOCK_MASK) != 0;
|
||||
keymap_x11->num_lock_state = (locked_mods & keymap_x11->num_lock_mask) != 0;
|
||||
|
||||
g_debug ("Locks state changed - Num: %s, Caps: %s",
|
||||
keymap_x11->num_lock_state ? "set" : "unset",
|
||||
keymap_x11->caps_lock_state ? "set" : "unset");
|
||||
|
||||
if ((keymap_x11->caps_lock_state != old_caps_lock_state) ||
|
||||
(keymap_x11->num_lock_state != old_num_lock_state))
|
||||
g_signal_emit_by_name (keymap_x11, "state-changed");
|
||||
}
|
||||
|
||||
/* the code to retrieve the keymap direction and cache it
|
||||
* is taken from GDK:
|
||||
* gdk/x11/gdkkeys-x11.c
|
||||
*/
|
||||
static PangoDirection
|
||||
get_direction (XkbDescPtr xkb,
|
||||
int group)
|
||||
{
|
||||
int rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */
|
||||
int code;
|
||||
|
||||
for (code = xkb->min_key_code;
|
||||
code <= xkb->max_key_code;
|
||||
code += 1)
|
||||
{
|
||||
int level = 0;
|
||||
KeySym sym = XkbKeySymEntry (xkb, code, level, group);
|
||||
PangoDirection dir =
|
||||
_clutter_pango_unichar_direction (clutter_keysym_to_unicode (sym));
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case PANGO_DIRECTION_RTL:
|
||||
rtl_minus_ltr++;
|
||||
break;
|
||||
|
||||
case PANGO_DIRECTION_LTR:
|
||||
rtl_minus_ltr--;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rtl_minus_ltr > 0)
|
||||
return PANGO_DIRECTION_RTL;
|
||||
|
||||
return PANGO_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
static PangoDirection
|
||||
get_direction_from_cache (MetaKeymapX11 *keymap_x11,
|
||||
XkbDescPtr xkb,
|
||||
int group)
|
||||
{
|
||||
Atom group_atom = xkb->names->groups[group];
|
||||
gboolean cache_hit = FALSE;
|
||||
DirectionCacheEntry *cache = keymap_x11->group_direction_cache;
|
||||
PangoDirection direction = PANGO_DIRECTION_NEUTRAL;
|
||||
int i;
|
||||
|
||||
if (keymap_x11->has_direction)
|
||||
{
|
||||
/* look up in the cache */
|
||||
for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
|
||||
{
|
||||
if (cache[i].group_atom == group_atom)
|
||||
{
|
||||
cache_hit = TRUE;
|
||||
cache[i].serial = keymap_x11->current_cache_serial++;
|
||||
direction = cache[i].direction;
|
||||
group_atom = cache[i].group_atom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initialize the cache */
|
||||
for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
|
||||
{
|
||||
cache[i].group_atom = 0;
|
||||
cache[i].direction = PANGO_DIRECTION_NEUTRAL;
|
||||
cache[i].serial = keymap_x11->current_cache_serial;
|
||||
}
|
||||
|
||||
keymap_x11->current_cache_serial += 1;
|
||||
}
|
||||
|
||||
/* insert the new entry in the cache */
|
||||
if (!cache_hit)
|
||||
{
|
||||
int oldest = 0;
|
||||
|
||||
direction = get_direction (xkb, group);
|
||||
|
||||
/* replace the oldest entry */
|
||||
for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
|
||||
{
|
||||
if (cache[i].serial < cache[oldest].serial)
|
||||
oldest = i;
|
||||
}
|
||||
|
||||
cache[oldest].group_atom = group_atom;
|
||||
cache[oldest].direction = direction;
|
||||
cache[oldest].serial = keymap_x11->current_cache_serial++;
|
||||
}
|
||||
|
||||
return direction;
|
||||
}
|
||||
|
||||
static void
|
||||
update_direction (MetaKeymapX11 *keymap_x11,
|
||||
int group)
|
||||
{
|
||||
XkbDescPtr xkb = get_xkb (keymap_x11);
|
||||
Atom group_atom;
|
||||
|
||||
group_atom = xkb->names->groups[group];
|
||||
|
||||
if (!keymap_x11->has_direction || keymap_x11->current_group_atom != group_atom)
|
||||
{
|
||||
keymap_x11->current_direction = get_direction_from_cache (keymap_x11, xkb, group);
|
||||
keymap_x11->current_group_atom = group_atom;
|
||||
keymap_x11->has_direction = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_keymap_x11_constructed (GObject *object)
|
||||
{
|
||||
MetaKeymapX11 *keymap_x11 = META_KEYMAP_X11 (object);
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
gint xkb_major = XkbMajorVersion;
|
||||
gint xkb_minor = XkbMinorVersion;
|
||||
|
||||
g_assert (keymap_x11->backend != NULL);
|
||||
|
||||
if (XkbLibraryVersion (&xkb_major, &xkb_minor))
|
||||
{
|
||||
xkb_major = XkbMajorVersion;
|
||||
xkb_minor = XkbMinorVersion;
|
||||
|
||||
if (XkbQueryExtension (xdisplay,
|
||||
NULL,
|
||||
&keymap_x11->xkb_event_base,
|
||||
NULL,
|
||||
&xkb_major, &xkb_minor))
|
||||
{
|
||||
Bool detectable_autorepeat_supported;
|
||||
|
||||
keymap_x11->use_xkb = TRUE;
|
||||
|
||||
XkbSelectEvents (xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
|
||||
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
|
||||
|
||||
XkbSelectEventDetails (xdisplay,
|
||||
XkbUseCoreKbd, XkbStateNotify,
|
||||
XkbAllStateComponentsMask,
|
||||
XkbGroupLockMask | XkbModifierLockMask);
|
||||
|
||||
/* enable XKB autorepeat */
|
||||
XkbSetDetectableAutoRepeat (xdisplay,
|
||||
True,
|
||||
&detectable_autorepeat_supported);
|
||||
|
||||
keymap_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_keymap_x11_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaKeymapX11 *keymap = META_KEYMAP_X11 (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BACKEND:
|
||||
keymap->backend = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_keymap_x11_refresh_reserved_keycodes (MetaKeymapX11 *keymap_x11)
|
||||
{
|
||||
Display *dpy = clutter_x11_get_default_display ();
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, keymap_x11->reserved_keycodes);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
guint reserved_keycode = GPOINTER_TO_UINT (key);
|
||||
guint reserved_keysym = GPOINTER_TO_UINT (value);
|
||||
guint actual_keysym = XkbKeycodeToKeysym (dpy, reserved_keycode, 0, 0);
|
||||
|
||||
/* If an available keycode is no longer mapped to the stored keysym, then
|
||||
* the keycode should not be considered available anymore and should be
|
||||
* removed both from the list of available and reserved keycodes.
|
||||
*/
|
||||
if (reserved_keysym != actual_keysym)
|
||||
{
|
||||
g_hash_table_iter_remove (&iter);
|
||||
g_queue_remove (keymap_x11->available_keycodes, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_keymap_x11_replace_keycode (MetaKeymapX11 *keymap_x11,
|
||||
KeyCode keycode,
|
||||
KeySym keysym)
|
||||
{
|
||||
if (keymap_x11->use_xkb)
|
||||
{
|
||||
Display *dpy = clutter_x11_get_default_display ();
|
||||
XkbDescPtr xkb = get_xkb (keymap_x11);
|
||||
XkbMapChangesRec changes;
|
||||
|
||||
XFlush (dpy);
|
||||
|
||||
xkb->device_spec = XkbUseCoreKbd;
|
||||
memset (&changes, 0, sizeof(changes));
|
||||
|
||||
if (keysym != NoSymbol)
|
||||
{
|
||||
int types[XkbNumKbdGroups] = { XkbOneLevelIndex };
|
||||
XkbChangeTypesOfKey (xkb, keycode, 1, XkbGroup1Mask, types, &changes);
|
||||
XkbKeySymEntry (xkb, keycode, 0, 0) = keysym;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset to NoSymbol */
|
||||
XkbChangeTypesOfKey (xkb, keycode, 0, XkbGroup1Mask, NULL, &changes);
|
||||
}
|
||||
|
||||
changes.changed = XkbKeySymsMask | XkbKeyTypesMask;
|
||||
changes.first_key_sym = keycode;
|
||||
changes.num_key_syms = 1;
|
||||
changes.first_type = 0;
|
||||
changes.num_types = xkb->map->num_types;
|
||||
XkbChangeMap (dpy, xkb, &changes);
|
||||
|
||||
XFlush (dpy);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_keymap_x11_finalize (GObject *object)
|
||||
{
|
||||
MetaKeymapX11 *keymap;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
keymap = META_KEYMAP_X11 (object);
|
||||
|
||||
meta_keymap_x11_refresh_reserved_keycodes (keymap);
|
||||
g_hash_table_iter_init (&iter, keymap->reserved_keycodes);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
guint keycode = GPOINTER_TO_UINT (key);
|
||||
meta_keymap_x11_replace_keycode (keymap, keycode, NoSymbol);
|
||||
}
|
||||
|
||||
g_hash_table_destroy (keymap->reserved_keycodes);
|
||||
g_queue_free (keymap->available_keycodes);
|
||||
|
||||
if (keymap->xkb_desc != NULL)
|
||||
XkbFreeKeyboard (keymap->xkb_desc, XkbAllComponentsMask, True);
|
||||
|
||||
G_OBJECT_CLASS (meta_keymap_x11_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_keymap_x11_get_num_lock_state (ClutterKeymap *keymap)
|
||||
{
|
||||
MetaKeymapX11 *keymap_x11 = META_KEYMAP_X11 (keymap);
|
||||
|
||||
return keymap_x11->num_lock_state;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_keymap_x11_get_caps_lock_state (ClutterKeymap *keymap)
|
||||
{
|
||||
MetaKeymapX11 *keymap_x11 = META_KEYMAP_X11 (keymap);
|
||||
|
||||
return keymap_x11->caps_lock_state;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_keymap_x11_class_init (MetaKeymapX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterKeymapClass *keymap_class = CLUTTER_KEYMAP_CLASS (klass);
|
||||
|
||||
obj_props[PROP_BACKEND] =
|
||||
g_param_spec_object ("backend",
|
||||
"Backend",
|
||||
"The Clutter backend",
|
||||
CLUTTER_TYPE_BACKEND,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
gobject_class->constructed = meta_keymap_x11_constructed;
|
||||
gobject_class->set_property = meta_keymap_x11_set_property;
|
||||
gobject_class->finalize = meta_keymap_x11_finalize;
|
||||
|
||||
keymap_class->get_num_lock_state = meta_keymap_x11_get_num_lock_state;
|
||||
keymap_class->get_caps_lock_state = meta_keymap_x11_get_caps_lock_state;
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_keymap_x11_init (MetaKeymapX11 *keymap)
|
||||
{
|
||||
keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
|
||||
keymap->current_group = -1;
|
||||
keymap->reserved_keycodes = g_hash_table_new (NULL, NULL);
|
||||
keymap->available_keycodes = g_queue_new ();
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_keymap_x11_handle_event (MetaKeymapX11 *keymap_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
gboolean retval;
|
||||
|
||||
if (!keymap_x11->use_xkb)
|
||||
return FALSE;
|
||||
|
||||
retval = FALSE;
|
||||
|
||||
if (xevent->type == keymap_x11->xkb_event_base)
|
||||
{
|
||||
XkbEvent *xkb_event = (XkbEvent *) xevent;
|
||||
|
||||
switch (xkb_event->any.xkb_type)
|
||||
{
|
||||
case XkbStateNotify:
|
||||
g_debug ("Updating keyboard state");
|
||||
keymap_x11->current_group = XkbStateGroup (&xkb_event->state);
|
||||
update_direction (keymap_x11, keymap_x11->current_group);
|
||||
update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
|
||||
retval = TRUE;
|
||||
break;
|
||||
|
||||
case XkbNewKeyboardNotify:
|
||||
case XkbMapNotify:
|
||||
g_debug ("Updating keyboard mapping");
|
||||
XkbRefreshKeyboardMapping (&xkb_event->map);
|
||||
keymap_x11->keymap_serial += 1;
|
||||
retval = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (xevent->type == MappingNotify)
|
||||
{
|
||||
XRefreshKeyboardMapping (&xevent->xmapping);
|
||||
keymap_x11->keymap_serial += 1;
|
||||
retval = TRUE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
gint
|
||||
meta_keymap_x11_get_key_group (MetaKeymapX11 *keymap,
|
||||
ClutterModifierType state)
|
||||
{
|
||||
return XkbGroupForCoreState (state);
|
||||
}
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
/* XXX - yes, I know that XKeycodeToKeysym() has been deprecated; hopefully,
|
||||
* this code will never get run on any decent system that is also able to
|
||||
* run Clutter. I just don't want to copy the implementation inside GDK for
|
||||
* a fallback path.
|
||||
*/
|
||||
static int
|
||||
translate_keysym (MetaKeymapX11 *keymap,
|
||||
guint hardware_keycode)
|
||||
{
|
||||
gint retval;
|
||||
|
||||
retval = XKeycodeToKeysym (clutter_x11_get_default_display (),
|
||||
hardware_keycode, 0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
gint
|
||||
meta_keymap_x11_translate_key_state (MetaKeymapX11 *keymap,
|
||||
guint hardware_keycode,
|
||||
ClutterModifierType *modifier_state_p,
|
||||
ClutterModifierType *mods_p)
|
||||
{
|
||||
ClutterModifierType unconsumed_modifiers = 0;
|
||||
ClutterModifierType modifier_state = *modifier_state_p;
|
||||
gint retval;
|
||||
|
||||
g_return_val_if_fail (META_IS_KEYMAP_X11 (keymap), 0);
|
||||
|
||||
if (keymap->use_xkb)
|
||||
{
|
||||
XkbDescRec *xkb = get_xkb (keymap);
|
||||
KeySym tmp_keysym;
|
||||
|
||||
if (XkbTranslateKeyCode (xkb, hardware_keycode, modifier_state,
|
||||
&unconsumed_modifiers,
|
||||
&tmp_keysym))
|
||||
{
|
||||
retval = tmp_keysym;
|
||||
}
|
||||
else
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
retval = translate_keysym (keymap, hardware_keycode);
|
||||
|
||||
if (mods_p)
|
||||
*mods_p = unconsumed_modifiers;
|
||||
|
||||
*modifier_state_p = modifier_state & ~(keymap->num_lock_mask |
|
||||
keymap->scroll_lock_mask |
|
||||
LockMask);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_keymap_x11_get_is_modifier (MetaKeymapX11 *keymap,
|
||||
gint keycode)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_KEYMAP_X11 (keymap), FALSE);
|
||||
|
||||
if (keycode < keymap->min_keycode || keycode > keymap->max_keycode)
|
||||
return FALSE;
|
||||
|
||||
if (keymap->use_xkb)
|
||||
{
|
||||
XkbDescRec *xkb = get_xkb (keymap);
|
||||
|
||||
if (xkb->map->modmap && xkb->map->modmap[keycode] != 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PangoDirection
|
||||
meta_keymap_x11_get_direction (MetaKeymapX11 *keymap)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_KEYMAP_X11 (keymap), PANGO_DIRECTION_NEUTRAL);
|
||||
|
||||
if (keymap->use_xkb)
|
||||
{
|
||||
if (!keymap->has_direction)
|
||||
{
|
||||
XkbStateRec state_rec;
|
||||
|
||||
XkbGetState (clutter_x11_get_default_display (),
|
||||
XkbUseCoreKbd, &state_rec);
|
||||
update_direction (keymap, XkbStateGroup (&state_rec));
|
||||
}
|
||||
|
||||
return keymap->current_direction;
|
||||
}
|
||||
else
|
||||
return PANGO_DIRECTION_NEUTRAL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_keymap_x11_get_entries_for_keyval (MetaKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
ClutterKeymapKey **keys,
|
||||
gint *n_keys)
|
||||
{
|
||||
if (keymap_x11->use_xkb)
|
||||
{
|
||||
XkbDescRec *xkb = get_xkb (keymap_x11);
|
||||
GArray *retval;
|
||||
gint keycode;
|
||||
|
||||
keycode = keymap_x11->min_keycode;
|
||||
retval = g_array_new (FALSE, FALSE, sizeof (ClutterKeymapKey));
|
||||
|
||||
while (keycode <= keymap_x11->max_keycode)
|
||||
{
|
||||
gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
|
||||
gint group = 0;
|
||||
gint level = 0;
|
||||
gint total_syms = XkbKeyNumSyms (xkb, keycode);
|
||||
gint i = 0;
|
||||
KeySym *entry;
|
||||
|
||||
/* entry is an array with all syms for group 0, all
|
||||
* syms for group 1, etc. and for each group the
|
||||
* shift level syms are in order
|
||||
*/
|
||||
entry = XkbKeySymsPtr (xkb, keycode);
|
||||
|
||||
while (i < total_syms)
|
||||
{
|
||||
g_assert (i == (group * max_shift_levels + level));
|
||||
|
||||
if (entry[i] == keyval)
|
||||
{
|
||||
ClutterKeymapKey key;
|
||||
|
||||
key.keycode = keycode;
|
||||
key.group = group;
|
||||
key.level = level;
|
||||
|
||||
g_array_append_val (retval, key);
|
||||
|
||||
g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
|
||||
keyval);
|
||||
}
|
||||
|
||||
++level;
|
||||
|
||||
if (level == max_shift_levels)
|
||||
{
|
||||
level = 0;
|
||||
++group;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
++keycode;
|
||||
}
|
||||
|
||||
if (retval->len > 0)
|
||||
{
|
||||
*keys = (ClutterKeymapKey*) retval->data;
|
||||
*n_keys = retval->len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*keys = NULL;
|
||||
*n_keys = 0;
|
||||
}
|
||||
|
||||
g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
|
||||
|
||||
return *n_keys > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
meta_keymap_x11_get_available_keycode (MetaKeymapX11 *keymap_x11)
|
||||
{
|
||||
if (keymap_x11->use_xkb)
|
||||
{
|
||||
meta_keymap_x11_refresh_reserved_keycodes (keymap_x11);
|
||||
|
||||
if (g_hash_table_size (keymap_x11->reserved_keycodes) < 5)
|
||||
{
|
||||
Display *dpy = clutter_x11_get_default_display ();
|
||||
XkbDescPtr xkb = get_xkb (keymap_x11);
|
||||
guint i;
|
||||
|
||||
for (i = xkb->max_key_code; i >= xkb->min_key_code; --i)
|
||||
{
|
||||
if (XkbKeycodeToKeysym (dpy, i, 0, 0) == NoSymbol)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return GPOINTER_TO_UINT (g_queue_pop_head (keymap_x11->available_keycodes));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_keymap_x11_reserve_keycode (MetaKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
guint *keycode_out)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_KEYMAP_X11 (keymap_x11), FALSE);
|
||||
g_return_val_if_fail (keyval != 0, FALSE);
|
||||
g_return_val_if_fail (keycode_out != NULL, FALSE);
|
||||
|
||||
*keycode_out = meta_keymap_x11_get_available_keycode (keymap_x11);
|
||||
|
||||
if (*keycode_out == NoSymbol)
|
||||
{
|
||||
g_warning ("Cannot reserve a keycode for keyval %d: no available keycode", keyval);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!meta_keymap_x11_replace_keycode (keymap_x11, *keycode_out, keyval))
|
||||
{
|
||||
g_warning ("Failed to remap keycode %d to keyval %d", *keycode_out, keyval);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_hash_table_insert (keymap_x11->reserved_keycodes, GUINT_TO_POINTER (*keycode_out), GUINT_TO_POINTER (keyval));
|
||||
g_queue_remove (keymap_x11->available_keycodes, GUINT_TO_POINTER (*keycode_out));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_keymap_x11_release_keycode_if_needed (MetaKeymapX11 *keymap_x11,
|
||||
guint keycode)
|
||||
{
|
||||
g_return_if_fail (META_IS_KEYMAP_X11 (keymap_x11));
|
||||
|
||||
if (!g_hash_table_contains (keymap_x11->reserved_keycodes, GUINT_TO_POINTER (keycode)) ||
|
||||
g_queue_index (keymap_x11->available_keycodes, GUINT_TO_POINTER (keycode)) != -1)
|
||||
return;
|
||||
|
||||
g_queue_push_tail (keymap_x11->available_keycodes, GUINT_TO_POINTER (keycode));
|
||||
}
|
||||
|
||||
void
|
||||
meta_keymap_x11_latch_modifiers (MetaKeymapX11 *keymap_x11,
|
||||
uint32_t level,
|
||||
gboolean enable)
|
||||
{
|
||||
uint32_t modifiers[] = {
|
||||
0,
|
||||
ShiftMask,
|
||||
keymap_x11->level3_shift_mask,
|
||||
keymap_x11->level3_shift_mask | ShiftMask,
|
||||
};
|
||||
uint32_t value = 0;
|
||||
|
||||
if (!keymap_x11->use_xkb)
|
||||
return;
|
||||
|
||||
level = CLAMP (level, 0, G_N_ELEMENTS (modifiers) - 1);
|
||||
|
||||
if (enable)
|
||||
value = modifiers[level];
|
||||
else
|
||||
value = 0;
|
||||
|
||||
XkbLatchModifiers (clutter_x11_get_default_display (),
|
||||
XkbUseCoreKbd, modifiers[level],
|
||||
value);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
meta_keymap_x11_get_current_group (MetaKeymapX11 *keymap_x11)
|
||||
{
|
||||
XkbStateRec state_rec;
|
||||
|
||||
if (keymap_x11->current_group >= 0)
|
||||
return keymap_x11->current_group;
|
||||
|
||||
XkbGetState (clutter_x11_get_default_display (),
|
||||
XkbUseCoreKbd, &state_rec);
|
||||
return XkbStateGroup (&state_rec);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_keymap_x11_keycode_for_keyval (MetaKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
guint *keycode_out,
|
||||
guint *level_out)
|
||||
{
|
||||
ClutterKeymapKey *keys;
|
||||
gint i, n_keys, group;
|
||||
gboolean found = FALSE;
|
||||
|
||||
g_return_val_if_fail (keycode_out != NULL, FALSE);
|
||||
g_return_val_if_fail (level_out != NULL, FALSE);
|
||||
|
||||
group = meta_keymap_x11_get_current_group (keymap_x11);
|
||||
|
||||
if (!meta_keymap_x11_get_entries_for_keyval (keymap_x11, keyval, &keys, &n_keys))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < n_keys && !found; i++)
|
||||
{
|
||||
if (keys[i].group == group)
|
||||
{
|
||||
*keycode_out = keys[i].keycode;
|
||||
*level_out = keys[i].level;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, keymap_x11->reserved_keycodes);
|
||||
while (!found && g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
guint reserved_keycode = GPOINTER_TO_UINT (key);
|
||||
guint reserved_keysym = GPOINTER_TO_UINT (value);
|
||||
|
||||
if (keyval == reserved_keysym)
|
||||
{
|
||||
*keycode_out = reserved_keycode;
|
||||
*level_out = 0;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (keys);
|
||||
return found;
|
||||
}
|
63
src/backends/x11/meta-keymap-x11.h
Normal file
63
src/backends/x11/meta-keymap-x11.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef META_KEYMAP_X11_H
|
||||
#define META_KEYMAP_X11_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <pango/pango.h>
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_KEYMAP_X11 (meta_keymap_x11_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaKeymapX11, meta_keymap_x11,
|
||||
META, KEYMAP_X11, ClutterKeymap)
|
||||
|
||||
gint meta_keymap_x11_get_key_group (MetaKeymapX11 *keymap,
|
||||
ClutterModifierType state);
|
||||
gint meta_keymap_x11_translate_key_state (MetaKeymapX11 *keymap,
|
||||
guint hardware_keycode,
|
||||
ClutterModifierType *modifier_state_p,
|
||||
ClutterModifierType *mods_p);
|
||||
gboolean meta_keymap_x11_get_is_modifier (MetaKeymapX11 *keymap,
|
||||
gint keycode);
|
||||
|
||||
PangoDirection meta_keymap_x11_get_direction (MetaKeymapX11 *keymap);
|
||||
|
||||
gboolean meta_keymap_x11_keycode_for_keyval (MetaKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
guint *keycode_out,
|
||||
guint *level_out);
|
||||
void meta_keymap_x11_latch_modifiers (MetaKeymapX11 *keymap_x11,
|
||||
uint32_t level,
|
||||
gboolean enable);
|
||||
gboolean meta_keymap_x11_reserve_keycode (MetaKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
guint *keycode_out);
|
||||
void meta_keymap_x11_release_keycode_if_needed (MetaKeymapX11 *keymap_x11,
|
||||
guint keycode);
|
||||
|
||||
gboolean meta_keymap_x11_handle_event (MetaKeymapX11 *keymap_x11,
|
||||
XEvent *xevent);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_KEYMAP_X11_H */
|
@ -39,7 +39,7 @@ static ClutterStageWindowInterface *clutter_stage_window_parent_iface = NULL;
|
||||
|
||||
struct _MetaStageX11Nested
|
||||
{
|
||||
ClutterStageX11 parent;
|
||||
MetaStageX11 parent;
|
||||
|
||||
CoglPipeline *pipeline;
|
||||
};
|
||||
@ -48,11 +48,11 @@ static void
|
||||
clutter_stage_window_iface_init (ClutterStageWindowInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaStageX11Nested, meta_stage_x11_nested,
|
||||
CLUTTER_TYPE_STAGE_X11,
|
||||
META_TYPE_STAGE_X11,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
|
||||
clutter_stage_window_iface_init))
|
||||
|
||||
typedef struct _ClutterStageX11View
|
||||
typedef struct _MetaStageX11View
|
||||
{
|
||||
CoglTexture *texture;
|
||||
ClutterStageViewCogl *view;
|
||||
@ -108,7 +108,7 @@ draw_crtc (MetaMonitor *monitor,
|
||||
GError **error)
|
||||
{
|
||||
DrawCrtcData *data = user_data;
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (data->stage_nested);
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (data->stage_nested);
|
||||
CoglFramebuffer *onscreen = COGL_FRAMEBUFFER (stage_x11->onscreen);
|
||||
CoglTexture *texture = data->texture;
|
||||
MetaLogicalMonitor *logical_monitor = data->logical_monitor;
|
||||
@ -247,7 +247,7 @@ static void
|
||||
meta_stage_x11_nested_finish_frame (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11Nested *stage_nested = META_STAGE_X11_NESTED (stage_window);
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
|
@ -26,9 +26,10 @@
|
||||
#define META_STAGE_X11_NESTED_H
|
||||
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "meta-stage-x11.h"
|
||||
|
||||
#define META_TYPE_STAGE_X11_NESTED (meta_stage_x11_nested_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaStageX11Nested, meta_stage_x11_nested,
|
||||
META, STAGE_X11_NESTED, ClutterStageX11)
|
||||
META, STAGE_X11_NESTED, MetaStageX11)
|
||||
|
||||
#endif /* META_STAGE_X11_NESTED_H */
|
||||
|
959
src/backends/x11/meta-stage-x11.c
Normal file
959
src/backends/x11/meta-stage-x11.c
Normal file
@ -0,0 +1,959 @@
|
||||
/*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
* Copyright (C) 2006-2007 OpenedHand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "clutter/x11/clutter-backend-x11.h"
|
||||
#include "cogl/cogl.h"
|
||||
#include "core/display-private.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
#include "meta-backend-x11.h"
|
||||
#include "meta-stage-x11.h"
|
||||
|
||||
#define STAGE_X11_IS_MAPPED(s) ((((MetaStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0)
|
||||
|
||||
static ClutterStageWindowInterface *clutter_stage_window_parent_iface = NULL;
|
||||
|
||||
static void
|
||||
clutter_stage_window_iface_init (ClutterStageWindowInterface *iface);
|
||||
|
||||
static ClutterStageCogl *meta_x11_get_stage_window_from_window (Window win);
|
||||
|
||||
static GHashTable *clutter_stages_by_xid = NULL;
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaStageX11,
|
||||
meta_stage_x11,
|
||||
CLUTTER_TYPE_STAGE_COGL,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
|
||||
clutter_stage_window_iface_init));
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
||||
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
|
||||
|
||||
#define META_STAGE_X11_EVENT_MASK \
|
||||
StructureNotifyMask | \
|
||||
FocusChangeMask | \
|
||||
ExposureMask | \
|
||||
PropertyChangeMask | \
|
||||
EnterWindowMask | \
|
||||
LeaveWindowMask | \
|
||||
KeyPressMask | \
|
||||
KeyReleaseMask | \
|
||||
ButtonPressMask | \
|
||||
ButtonReleaseMask | \
|
||||
PointerMotionMask
|
||||
|
||||
static void
|
||||
meta_stage_x11_fix_window_size (MetaStageX11 *stage_x11,
|
||||
gint new_width,
|
||||
gint new_height)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
guint min_width, min_height;
|
||||
XSizeHints *size_hints;
|
||||
|
||||
size_hints = XAllocSizeHints();
|
||||
|
||||
clutter_stage_get_minimum_size (stage_cogl->wrapper,
|
||||
&min_width,
|
||||
&min_height);
|
||||
|
||||
if (new_width <= 0)
|
||||
new_width = min_width;
|
||||
|
||||
if (new_height <= 0)
|
||||
new_height = min_height;
|
||||
|
||||
size_hints->min_width = new_width;
|
||||
size_hints->min_height = new_height;
|
||||
size_hints->max_width = new_width;
|
||||
size_hints->max_height = new_height;
|
||||
size_hints->flags = PMinSize | PMaxSize;
|
||||
|
||||
XSetWMNormalHints (xdisplay, stage_x11->xwin, size_hints);
|
||||
|
||||
XFree(size_hints);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_set_wm_protocols (MetaStageX11 *stage_x11)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
Atom protocols[2];
|
||||
int n = 0;
|
||||
|
||||
protocols[n++] = backend_x11->atom_WM_DELETE_WINDOW;
|
||||
protocols[n++] = backend_x11->atom_NET_WM_PING;
|
||||
|
||||
XSetWMProtocols (xdisplay, stage_x11->xwin, protocols, n);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_get_geometry (ClutterStageWindow *stage_window,
|
||||
cairo_rectangle_int_t *geometry)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
geometry->x = geometry->y = 0;
|
||||
geometry->width = stage_x11->xwin_width;
|
||||
geometry->height = stage_x11->xwin_height;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_resize (ClutterStageWindow *stage_window,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
{
|
||||
/* Should not happen, if this turns up we need to debug it and
|
||||
* determine the cleanest way to fix.
|
||||
*/
|
||||
g_warning ("X11 stage not allowed to have 0 width or height");
|
||||
width = 1;
|
||||
height = 1;
|
||||
}
|
||||
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
meta_stage_x11_fix_window_size (stage_x11, width, height);
|
||||
|
||||
if (width != stage_x11->xwin_width ||
|
||||
height != stage_x11->xwin_height)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
/* XXX: in this case we can rely on a subsequent
|
||||
* ConfigureNotify that will result in the stage
|
||||
* being reallocated so we don't actively do anything
|
||||
* to affect the stage allocation here. */
|
||||
XResizeWindow (xdisplay,
|
||||
stage_x11->xwin,
|
||||
width,
|
||||
height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if the backing window hasn't been created yet, we just
|
||||
* need to store the new window size
|
||||
*/
|
||||
stage_x11->xwin_width = width;
|
||||
stage_x11->xwin_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_wm_pid (MetaStageX11 *stage_x11)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
long pid;
|
||||
|
||||
if (stage_x11->xwin == None)
|
||||
return;
|
||||
|
||||
/* this will take care of WM_CLIENT_MACHINE and WM_LOCALE_NAME */
|
||||
XSetWMProperties (xdisplay, stage_x11->xwin,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, 0,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
pid = getpid ();
|
||||
XChangeProperty (xdisplay,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_NET_WM_PID, XA_CARDINAL, 32,
|
||||
PropModeReplace,
|
||||
(guchar *) &pid, 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_wm_title (MetaStageX11 *stage_x11)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
if (stage_x11->xwin == None)
|
||||
return;
|
||||
|
||||
if (stage_x11->title == NULL)
|
||||
{
|
||||
XDeleteProperty (xdisplay,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_NET_WM_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
XChangeProperty (xdisplay,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_NET_WM_NAME,
|
||||
backend_x11->atom_UTF8_STRING,
|
||||
8,
|
||||
PropModeReplace,
|
||||
(unsigned char *) stage_x11->title,
|
||||
(int) strlen (stage_x11->title));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_cursor_visible (MetaStageX11 *stage_x11)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
if (stage_x11->xwin == None)
|
||||
return;
|
||||
|
||||
g_debug ("setting cursor state ('%s') over stage window (%u)",
|
||||
stage_x11->is_cursor_visible ? "visible" : "invisible",
|
||||
(unsigned int) stage_x11->xwin);
|
||||
|
||||
if (stage_x11->is_cursor_visible)
|
||||
{
|
||||
XUndefineCursor (xdisplay, stage_x11->xwin);
|
||||
}
|
||||
else
|
||||
{
|
||||
XColor col;
|
||||
Pixmap pix;
|
||||
Cursor curs;
|
||||
|
||||
pix = XCreatePixmap (xdisplay, stage_x11->xwin, 1, 1, 1);
|
||||
memset (&col, 0, sizeof (col));
|
||||
curs = XCreatePixmapCursor (xdisplay,
|
||||
pix, pix,
|
||||
&col, &col,
|
||||
1, 1);
|
||||
XFreePixmap (xdisplay, pix);
|
||||
XDefineCursor (xdisplay, stage_x11->xwin, curs);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_unrealize (ClutterStageWindow *stage_window)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
if (clutter_stages_by_xid != NULL)
|
||||
{
|
||||
g_hash_table_remove (clutter_stages_by_xid,
|
||||
GINT_TO_POINTER (stage_x11->xwin));
|
||||
}
|
||||
|
||||
/* Clutter still uses part of the deprecated stateful API of Cogl
|
||||
* (in particulart cogl_set_framebuffer). It means Cogl can keep an
|
||||
* internal reference to the onscreen object we rendered to. In the
|
||||
* case of foreign window, we want to avoid this, as we don't know
|
||||
* what's going to happen to that window.
|
||||
*
|
||||
* The following call sets the current Cogl framebuffer to a dummy
|
||||
* 1x1 one if we're unrealizing the current one, so Cogl doesn't
|
||||
* keep any reference to the foreign window.
|
||||
*/
|
||||
if (cogl_get_draw_framebuffer () == COGL_FRAMEBUFFER (stage_x11->onscreen))
|
||||
_clutter_backend_reset_cogl_framebuffer (stage_cogl->backend);
|
||||
|
||||
if (stage_x11->frame_closure)
|
||||
{
|
||||
cogl_onscreen_remove_frame_callback (stage_x11->onscreen,
|
||||
stage_x11->frame_closure);
|
||||
stage_x11->frame_closure = NULL;
|
||||
}
|
||||
|
||||
clutter_stage_window_parent_iface->unrealize (stage_window);
|
||||
|
||||
g_list_free (stage_x11->legacy_views);
|
||||
g_clear_object (&stage_x11->legacy_view);
|
||||
g_clear_pointer (&stage_x11->onscreen, cogl_object_unref);
|
||||
}
|
||||
|
||||
void
|
||||
meta_stage_x11_events_device_changed (MetaStageX11 *stage_x11,
|
||||
ClutterInputDevice *device,
|
||||
ClutterDeviceManager *device_manager)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
|
||||
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_FLOATING)
|
||||
_clutter_device_manager_select_stage_events (device_manager,
|
||||
stage_cogl->wrapper);
|
||||
}
|
||||
|
||||
static void
|
||||
stage_events_device_added (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterStageWindow *stage_window = user_data;
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
|
||||
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_FLOATING)
|
||||
_clutter_device_manager_select_stage_events (device_manager,
|
||||
stage_cogl->wrapper);
|
||||
}
|
||||
|
||||
static void
|
||||
frame_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent frame_event,
|
||||
CoglFrameInfo *frame_info,
|
||||
void *user_data)
|
||||
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = user_data;
|
||||
ClutterFrameInfo clutter_frame_info = {
|
||||
.frame_counter = cogl_frame_info_get_frame_counter (frame_info),
|
||||
.presentation_time = cogl_frame_info_get_presentation_time (frame_info),
|
||||
.refresh_rate = cogl_frame_info_get_refresh_rate (frame_info)
|
||||
};
|
||||
|
||||
_clutter_stage_cogl_presented (stage_cogl, frame_event, &clutter_frame_info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_stage_x11_realize (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
ClutterBackend *backend = CLUTTER_BACKEND (stage_cogl->backend);
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
ClutterDeviceManager *device_manager;
|
||||
gfloat width, height;
|
||||
GError *error = NULL;
|
||||
|
||||
clutter_actor_get_size (CLUTTER_ACTOR (stage_cogl->wrapper), &width, &height);
|
||||
|
||||
stage_x11->onscreen = cogl_onscreen_new (backend->cogl_context, width, height);
|
||||
|
||||
stage_x11->frame_closure =
|
||||
cogl_onscreen_add_frame_callback (stage_x11->onscreen,
|
||||
frame_cb,
|
||||
stage_cogl,
|
||||
NULL);
|
||||
|
||||
if (stage_x11->legacy_view)
|
||||
g_object_set (G_OBJECT (stage_x11->legacy_view),
|
||||
"framebuffer", stage_x11->onscreen,
|
||||
NULL);
|
||||
|
||||
/* We just created a window of the size of the actor. No need to fix
|
||||
the size of the stage, just update it. */
|
||||
stage_x11->xwin_width = width;
|
||||
stage_x11->xwin_height = height;
|
||||
|
||||
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (stage_x11->onscreen), &error))
|
||||
{
|
||||
g_warning ("Failed to allocate stage: %s", error->message);
|
||||
g_error_free (error);
|
||||
cogl_object_unref (stage_x11->onscreen);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!(clutter_stage_window_parent_iface->realize (stage_window)))
|
||||
return FALSE;
|
||||
|
||||
stage_x11->xwin = cogl_x11_onscreen_get_window_xid (stage_x11->onscreen);
|
||||
|
||||
if (clutter_stages_by_xid == NULL)
|
||||
clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
|
||||
|
||||
g_hash_table_insert (clutter_stages_by_xid,
|
||||
GINT_TO_POINTER (stage_x11->xwin),
|
||||
stage_x11);
|
||||
|
||||
set_wm_pid (stage_x11);
|
||||
set_wm_title (stage_x11);
|
||||
set_cursor_visible (stage_x11);
|
||||
|
||||
/* we unconditionally select input events even with event retrieval
|
||||
* disabled because we need to guarantee that the Clutter internal
|
||||
* state is maintained when calling clutter_x11_handle_event() without
|
||||
* requiring applications or embedding toolkits to select events
|
||||
* themselves. if we did that, we'd have to document the events to be
|
||||
* selected, and also update applications and embedding toolkits each
|
||||
* time we added a new mask, or a new class of events.
|
||||
*
|
||||
* see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998
|
||||
* for the rationale of why we did conditional selection. it is now
|
||||
* clear that a compositor should clear out the input region, since
|
||||
* it cannot assume a perfectly clean slate coming from us.
|
||||
*
|
||||
* see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228
|
||||
* for an example of things that break if we do conditional event
|
||||
* selection.
|
||||
*/
|
||||
XSelectInput (xdisplay, stage_x11->xwin, META_STAGE_X11_EVENT_MASK);
|
||||
|
||||
/* input events also depent on the actual device, so we need to
|
||||
* use the device manager to let every device select them, using
|
||||
* the event mask we passed to XSelectInput as the template
|
||||
*/
|
||||
device_manager = clutter_device_manager_get_default ();
|
||||
if (G_UNLIKELY (device_manager != NULL))
|
||||
{
|
||||
_clutter_device_manager_select_stage_events (device_manager,
|
||||
stage_cogl->wrapper);
|
||||
|
||||
g_signal_connect (device_manager, "device-added",
|
||||
G_CALLBACK (stage_events_device_added),
|
||||
stage_window);
|
||||
}
|
||||
|
||||
meta_stage_x11_fix_window_size (stage_x11,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height);
|
||||
meta_stage_x11_set_wm_protocols (stage_x11);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
|
||||
gboolean cursor_visible)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
stage_x11->is_cursor_visible = !!cursor_visible;
|
||||
set_cursor_visible (stage_x11);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_set_title (ClutterStageWindow *stage_window,
|
||||
const gchar *title)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
g_free (stage_x11->title);
|
||||
stage_x11->title = g_strdup (title);
|
||||
set_wm_title (stage_x11);
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_wm_hints (MetaStageX11 *stage_x11)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
XWMHints wm_hints;
|
||||
|
||||
if (stage_x11->wm_state & STAGE_X11_WITHDRAWN)
|
||||
return;
|
||||
|
||||
wm_hints.flags = StateHint | InputHint;
|
||||
wm_hints.initial_state = NormalState;
|
||||
wm_hints.input = stage_x11->accept_focus ? True : False;
|
||||
|
||||
XSetWMHints (xdisplay, stage_x11->xwin, &wm_hints);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_set_accept_focus (ClutterStageWindow *stage_window,
|
||||
gboolean accept_focus)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
stage_x11->accept_focus = !!accept_focus;
|
||||
update_wm_hints (stage_x11);
|
||||
}
|
||||
|
||||
static void
|
||||
set_stage_x11_state (MetaStageX11 *stage_x11,
|
||||
MetaStageX11State unset_flags,
|
||||
MetaStageX11State set_flags)
|
||||
{
|
||||
MetaStageX11State new_stage_state, old_stage_state;
|
||||
|
||||
old_stage_state = stage_x11->wm_state;
|
||||
|
||||
new_stage_state = old_stage_state;
|
||||
new_stage_state |= set_flags;
|
||||
new_stage_state &= ~unset_flags;
|
||||
|
||||
if (new_stage_state == old_stage_state)
|
||||
return;
|
||||
|
||||
stage_x11->wm_state = new_stage_state;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_show (ClutterStageWindow *stage_window,
|
||||
gboolean do_raise)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
if (do_raise)
|
||||
{
|
||||
XRaiseWindow (xdisplay, stage_x11->xwin);
|
||||
}
|
||||
|
||||
if (!STAGE_X11_IS_MAPPED (stage_x11))
|
||||
{
|
||||
set_stage_x11_state (stage_x11, STAGE_X11_WITHDRAWN, 0);
|
||||
|
||||
update_wm_hints (stage_x11);
|
||||
}
|
||||
|
||||
g_assert (STAGE_X11_IS_MAPPED (stage_x11));
|
||||
|
||||
clutter_actor_map (CLUTTER_ACTOR (stage_cogl->wrapper));
|
||||
|
||||
XMapWindow (xdisplay, stage_x11->xwin);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_hide (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
if (STAGE_X11_IS_MAPPED (stage_x11))
|
||||
set_stage_x11_state (stage_x11, 0, STAGE_X11_WITHDRAWN);
|
||||
|
||||
g_assert (!STAGE_X11_IS_MAPPED (stage_x11));
|
||||
|
||||
clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper));
|
||||
|
||||
XWithdrawWindow (xdisplay, stage_x11->xwin, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_stage_x11_can_clip_redraws (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
/* while resizing a window, clipped redraws are disabled in order to
|
||||
* avoid artefacts.
|
||||
*/
|
||||
return stage_x11->clipped_redraws_cool_off == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_legacy_view (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
cairo_rectangle_int_t view_layout;
|
||||
CoglFramebuffer *framebuffer;
|
||||
|
||||
if (stage_x11->legacy_view)
|
||||
return;
|
||||
|
||||
_clutter_stage_window_get_geometry (stage_window, &view_layout);
|
||||
framebuffer = COGL_FRAMEBUFFER (stage_x11->onscreen);
|
||||
stage_x11->legacy_view = g_object_new (CLUTTER_TYPE_STAGE_VIEW_COGL,
|
||||
"layout", &view_layout,
|
||||
"framebuffer", framebuffer,
|
||||
NULL);
|
||||
stage_x11->legacy_views = g_list_append (stage_x11->legacy_views,
|
||||
stage_x11->legacy_view);
|
||||
}
|
||||
|
||||
static GList *
|
||||
meta_stage_x11_get_views (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
ensure_legacy_view (stage_window);
|
||||
|
||||
return stage_x11->legacy_views;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
meta_stage_x11_get_frame_counter (ClutterStageWindow *stage_window)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
|
||||
|
||||
return cogl_onscreen_get_frame_counter (stage_x11->onscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_finalize (GObject *object)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = META_STAGE_X11 (object);
|
||||
|
||||
g_free (stage_x11->title);
|
||||
|
||||
G_OBJECT_CLASS (meta_stage_x11_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_class_init (MetaStageX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = meta_stage_x11_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_x11_init (MetaStageX11 *stage)
|
||||
{
|
||||
stage->xwin = None;
|
||||
stage->xwin_width = 640;
|
||||
stage->xwin_height = 480;
|
||||
|
||||
stage->wm_state = STAGE_X11_WITHDRAWN;
|
||||
|
||||
stage->is_cursor_visible = TRUE;
|
||||
stage->accept_focus = TRUE;
|
||||
|
||||
stage->title = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
|
||||
{
|
||||
clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->set_title = meta_stage_x11_set_title;
|
||||
iface->set_cursor_visible = meta_stage_x11_set_cursor_visible;
|
||||
iface->set_accept_focus = meta_stage_x11_set_accept_focus;
|
||||
iface->show = meta_stage_x11_show;
|
||||
iface->hide = meta_stage_x11_hide;
|
||||
iface->resize = meta_stage_x11_resize;
|
||||
iface->get_geometry = meta_stage_x11_get_geometry;
|
||||
iface->realize = meta_stage_x11_realize;
|
||||
iface->unrealize = meta_stage_x11_unrealize;
|
||||
iface->can_clip_redraws = meta_stage_x11_can_clip_redraws;
|
||||
iface->get_views = meta_stage_x11_get_views;
|
||||
iface->get_frame_counter = meta_stage_x11_get_frame_counter;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_user_time (ClutterBackendX11 *backend_x11,
|
||||
MetaStageX11 *stage_x11,
|
||||
long timestamp)
|
||||
{
|
||||
if (timestamp != CLUTTER_CURRENT_TIME)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
XChangeProperty (xdisplay,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_NET_WM_USER_TIME,
|
||||
XA_CARDINAL, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *) ×tamp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
|
||||
MetaStageX11 *stage_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
Atom atom = (Atom) xevent->xclient.data.l[0];
|
||||
|
||||
if (atom == backend_x11->atom_WM_DELETE_WINDOW &&
|
||||
xevent->xany.window == stage_x11->xwin)
|
||||
{
|
||||
set_user_time (backend_x11, stage_x11, xevent->xclient.data.l[1]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (atom == backend_x11->atom_NET_WM_PING &&
|
||||
xevent->xany.window == stage_x11->xwin)
|
||||
{
|
||||
XClientMessageEvent xclient = xevent->xclient;
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
|
||||
xclient.window = backend_x11->xwin_root;
|
||||
XSendEvent (xdisplay, xclient.window,
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
(XEvent *) &xclient);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* do not send any of the WM_PROTOCOLS events to the queue */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clipped_redraws_cool_off_cb (void *data)
|
||||
{
|
||||
MetaStageX11 *stage_x11 = data;
|
||||
|
||||
stage_x11->clipped_redraws_cool_off = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
|
||||
XEvent *xevent,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl;
|
||||
gboolean res = FALSE;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterStage *stage;
|
||||
|
||||
stage_cogl = meta_x11_get_stage_window_from_window (xevent->xany.window);
|
||||
if (stage_cogl == NULL)
|
||||
return FALSE;
|
||||
|
||||
stage = stage_cogl->wrapper;
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case ConfigureNotify:
|
||||
{
|
||||
gboolean size_changed = FALSE;
|
||||
int stage_width;
|
||||
int stage_height;
|
||||
|
||||
g_debug ("ConfigureNotify[%x] (%d, %d)",
|
||||
(unsigned int) stage_x11->xwin,
|
||||
xevent->xconfigure.width,
|
||||
xevent->xconfigure.height);
|
||||
|
||||
if ((stage_x11->xwin_width != xevent->xconfigure.width) ||
|
||||
(stage_x11->xwin_height != xevent->xconfigure.height))
|
||||
{
|
||||
size_changed = TRUE;
|
||||
stage_x11->xwin_width = xevent->xconfigure.width;
|
||||
stage_x11->xwin_height = xevent->xconfigure.height;
|
||||
}
|
||||
|
||||
stage_width = xevent->xconfigure.width;
|
||||
stage_height = xevent->xconfigure.height;
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (stage), stage_width, stage_height);
|
||||
|
||||
if (size_changed)
|
||||
{
|
||||
/* XXX: This is a workaround for a race condition when
|
||||
* resizing windows while there are in-flight
|
||||
* glXCopySubBuffer blits happening.
|
||||
*
|
||||
* The problem stems from the fact that rectangles for the
|
||||
* blits are described relative to the bottom left of the
|
||||
* window and because we can't guarantee control over the X
|
||||
* window gravity used when resizing so the gravity is
|
||||
* typically NorthWest not SouthWest.
|
||||
*
|
||||
* This means if you grow a window vertically the server
|
||||
* will make sure to place the old contents of the window
|
||||
* at the top-left/north-west of your new larger window, but
|
||||
* that may happen asynchronous to GLX preparing to do a
|
||||
* blit specified relative to the bottom-left/south-west of
|
||||
* the window (based on the old smaller window geometry).
|
||||
*
|
||||
* When the GLX issued blit finally happens relative to the
|
||||
* new bottom of your window, the destination will have
|
||||
* shifted relative to the top-left where all the pixels you
|
||||
* care about are so it will result in a nasty artefact
|
||||
* making resizing look very ugly!
|
||||
*
|
||||
* We can't currently fix this completely, in-part because
|
||||
* the window manager tends to trample any gravity we might
|
||||
* set. This workaround instead simply disables blits for a
|
||||
* while if we are notified of any resizes happening so if
|
||||
* the user is resizing a window via the window manager then
|
||||
* they may see an artefact for one frame but then we will
|
||||
* fallback to redrawing the full stage until the cooling
|
||||
* off period is over.
|
||||
*/
|
||||
if (stage_x11->clipped_redraws_cool_off)
|
||||
g_source_remove (stage_x11->clipped_redraws_cool_off);
|
||||
|
||||
stage_x11->clipped_redraws_cool_off =
|
||||
clutter_threads_add_timeout (1000,
|
||||
clipped_redraws_cool_off_cb,
|
||||
stage_x11);
|
||||
|
||||
/* Queue a relayout - we want glViewport to be called
|
||||
* with the correct values, and this is done in ClutterStage
|
||||
* via cogl_onscreen_clutter_backend_set_size ().
|
||||
*
|
||||
* We queue a relayout, because if this ConfigureNotify is
|
||||
* in response to a size we set in the application, the
|
||||
* set_size() call above is essentially a null-op.
|
||||
*
|
||||
* Make sure we do this only when the size has changed,
|
||||
* otherwise we end up relayouting on window moves.
|
||||
*/
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
|
||||
|
||||
/* the resize process is complete, so we can ask the stage
|
||||
* to set up the GL viewport with the new size
|
||||
*/
|
||||
clutter_stage_ensure_viewport (stage);
|
||||
|
||||
/* If this was a result of the Xrandr change when running as a
|
||||
* X11 compositing manager, we need to reset the legacy
|
||||
* stage view, now that it has a new size.
|
||||
*/
|
||||
if (stage_x11->legacy_view)
|
||||
{
|
||||
cairo_rectangle_int_t view_layout = {
|
||||
.width = stage_width,
|
||||
.height = stage_height
|
||||
};
|
||||
|
||||
g_object_set (G_OBJECT (stage_x11->legacy_view),
|
||||
"layout", &view_layout,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FocusIn:
|
||||
if (!_clutter_stage_is_activated (stage_cogl->wrapper))
|
||||
{
|
||||
_clutter_stage_update_state (stage_cogl->wrapper,
|
||||
0,
|
||||
CLUTTER_STAGE_STATE_ACTIVATED);
|
||||
}
|
||||
break;
|
||||
|
||||
case FocusOut:
|
||||
if (_clutter_stage_is_activated (stage_cogl->wrapper))
|
||||
{
|
||||
_clutter_stage_update_state (stage_cogl->wrapper,
|
||||
CLUTTER_STAGE_STATE_ACTIVATED,
|
||||
0);
|
||||
}
|
||||
break;
|
||||
|
||||
case Expose:
|
||||
{
|
||||
XExposeEvent *expose = (XExposeEvent *) xevent;
|
||||
cairo_rectangle_int_t clip;
|
||||
|
||||
g_debug ("expose for stage: win:0x%x - "
|
||||
"redrawing area (x: %d, y: %d, width: %d, height: %d)",
|
||||
(unsigned int) xevent->xany.window,
|
||||
expose->x,
|
||||
expose->y,
|
||||
expose->width,
|
||||
expose->height);
|
||||
|
||||
clip.x = expose->x;
|
||||
clip.y = expose->y;
|
||||
clip.width = expose->width;
|
||||
clip.height = expose->height;
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
|
||||
}
|
||||
break;
|
||||
|
||||
case DestroyNotify:
|
||||
g_debug ("Destroy notification received for stage, win:0x%x",
|
||||
(unsigned int) xevent->xany.window);
|
||||
|
||||
event->any.type = CLUTTER_DESTROY_NOTIFY;
|
||||
event->any.stage = stage;
|
||||
res = TRUE;
|
||||
break;
|
||||
|
||||
case ClientMessage:
|
||||
g_debug ("Client message for stage, win:0x%x",
|
||||
(unsigned int) xevent->xany.window);
|
||||
|
||||
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
|
||||
{
|
||||
event->any.type = CLUTTER_DELETE;
|
||||
event->any.stage = stage;
|
||||
res = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Window
|
||||
meta_x11_get_stage_window (ClutterStage *stage)
|
||||
{
|
||||
ClutterStageWindow *impl;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), None);
|
||||
|
||||
impl = _clutter_stage_get_window (stage);
|
||||
g_assert (META_IS_STAGE_X11 (impl));
|
||||
|
||||
return META_STAGE_X11 (impl)->xwin;
|
||||
}
|
||||
|
||||
static ClutterStageCogl *
|
||||
meta_x11_get_stage_window_from_window (Window win)
|
||||
{
|
||||
if (clutter_stages_by_xid == NULL)
|
||||
return NULL;
|
||||
|
||||
return g_hash_table_lookup (clutter_stages_by_xid,
|
||||
GINT_TO_POINTER (win));
|
||||
}
|
||||
|
||||
ClutterStage *
|
||||
meta_x11_get_stage_from_window (Window win)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl;
|
||||
|
||||
stage_cogl = meta_x11_get_stage_window_from_window (win);
|
||||
|
||||
if (stage_cogl != NULL)
|
||||
return stage_cogl->wrapper;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_stage_x11_set_user_time (MetaStageX11 *stage_x11,
|
||||
guint32 user_time)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
|
||||
|
||||
set_user_time (backend_x11, stage_x11, user_time);
|
||||
}
|
102
src/backends/x11/meta-stage-x11.h
Normal file
102
src/backends/x11/meta-stage-x11.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* Clutter.
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
* Copyright (C) 2006-2007 OpenedHand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_STAGE_X11_H
|
||||
#define META_STAGE_X11_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_STAGE_X11 (meta_stage_x11_get_type ())
|
||||
#define META_STAGE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_STAGE_X11, MetaStageX11))
|
||||
#define META_IS_STAGE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_STAGE_X11))
|
||||
#define META_STAGE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_STAGE_X11, MetaStageX11Class))
|
||||
#define META_IS_STAGE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_STAGE_X11))
|
||||
#define META_STAGE_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_STAGE_X11, MetaStageX11Class))
|
||||
|
||||
typedef struct _MetaStageX11 MetaStageX11;
|
||||
typedef struct _MetaStageX11Class MetaStageX11Class;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaStageX11, g_object_unref)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STAGE_X11_WITHDRAWN = 1 << 1
|
||||
} MetaStageX11State;
|
||||
|
||||
struct _MetaStageX11
|
||||
{
|
||||
ClutterStageCogl parent_instance;
|
||||
|
||||
CoglOnscreen *onscreen;
|
||||
Window xwin;
|
||||
gint xwin_width;
|
||||
gint xwin_height; /* FIXME target_width / height */
|
||||
|
||||
ClutterStageView *legacy_view;
|
||||
GList *legacy_views;
|
||||
|
||||
CoglFrameClosure *frame_closure;
|
||||
|
||||
gchar *title;
|
||||
|
||||
guint clipped_redraws_cool_off;
|
||||
|
||||
MetaStageX11State wm_state;
|
||||
|
||||
guint is_cursor_visible : 1;
|
||||
guint viewport_initialized : 1;
|
||||
guint accept_focus : 1;
|
||||
};
|
||||
|
||||
struct _MetaStageX11Class
|
||||
{
|
||||
ClutterStageCoglClass parent_class;
|
||||
};
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GType meta_stage_x11_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void meta_stage_x11_events_device_changed (MetaStageX11 *stage_x11,
|
||||
ClutterInputDevice *device,
|
||||
ClutterDeviceManager *device_manager);
|
||||
|
||||
/* Private to subclasses */
|
||||
void meta_stage_x11_set_user_time (MetaStageX11 *stage_x11,
|
||||
guint32 user_time);
|
||||
|
||||
gboolean meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
|
||||
XEvent *xevent,
|
||||
ClutterEvent *event);
|
||||
|
||||
ClutterStage *meta_x11_get_stage_from_window (Window win);
|
||||
|
||||
Window meta_x11_get_stage_window (ClutterStage *stage);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_STAGE_H */
|
214
src/backends/x11/meta-virtual-input-device-x11.c
Normal file
214
src/backends/x11/meta-virtual-input-device-x11.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Jonas Ådahl <jadahl@gmail.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <X11/extensions/XTest.h>
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "meta-keymap-x11.h"
|
||||
#include "meta-virtual-input-device-x11.h"
|
||||
|
||||
struct _MetaVirtualInputDeviceX11
|
||||
{
|
||||
ClutterVirtualInputDevice parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaVirtualInputDeviceX11,
|
||||
meta_virtual_input_device_x11,
|
||||
CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE)
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
double dx,
|
||||
double dy)
|
||||
{
|
||||
XTestFakeRelativeMotionEvent (clutter_x11_get_default_display (),
|
||||
(int) dx,
|
||||
(int) dy,
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
XTestFakeMotionEvent (clutter_x11_get_default_display (),
|
||||
clutter_x11_get_default_screen (),
|
||||
(int) x,
|
||||
(int) y,
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_button (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
uint32_t button,
|
||||
ClutterButtonState button_state)
|
||||
{
|
||||
XTestFakeButtonEvent (clutter_x11_get_default_display (),
|
||||
button, button_state == CLUTTER_BUTTON_STATE_PRESSED, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
ClutterScrollDirection direction,
|
||||
ClutterScrollSource scroll_source)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
int button;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case CLUTTER_SCROLL_UP:
|
||||
button = 4;
|
||||
break;
|
||||
case CLUTTER_SCROLL_DOWN:
|
||||
button = 5;
|
||||
break;
|
||||
case CLUTTER_SCROLL_LEFT:
|
||||
button = 6;
|
||||
break;
|
||||
case CLUTTER_SCROLL_RIGHT:
|
||||
button = 7;
|
||||
break;
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
return;
|
||||
}
|
||||
|
||||
XTestFakeButtonEvent (xdisplay, button, True, 0);
|
||||
XTestFakeButtonEvent (xdisplay, button, False, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
double dx,
|
||||
double dy,
|
||||
ClutterScrollSource scroll_source,
|
||||
ClutterScrollFinishFlags finish_flags)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_key (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
uint32_t key,
|
||||
ClutterKeyState key_state)
|
||||
{
|
||||
XTestFakeKeyEvent (clutter_x11_get_default_display (),
|
||||
key, key_state == CLUTTER_KEY_STATE_PRESSED, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
uint32_t keyval,
|
||||
ClutterKeyState key_state)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
MetaKeymapX11 *keymap = META_KEYMAP_X11 (clutter_backend_get_keymap (backend));
|
||||
uint32_t keycode, level;
|
||||
|
||||
if (!meta_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
|
||||
{
|
||||
level = 0;
|
||||
|
||||
if (!meta_keymap_x11_reserve_keycode (keymap, keyval, &keycode))
|
||||
{
|
||||
g_warning ("No keycode found for keyval %x in current group", keyval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!meta_keymap_x11_get_is_modifier (keymap, keycode) &&
|
||||
key_state == CLUTTER_KEY_STATE_PRESSED)
|
||||
meta_keymap_x11_latch_modifiers (keymap, level, TRUE);
|
||||
|
||||
XTestFakeKeyEvent (clutter_x11_get_default_display (),
|
||||
(KeyCode) keycode,
|
||||
key_state == CLUTTER_KEY_STATE_PRESSED, 0);
|
||||
|
||||
|
||||
if (key_state == CLUTTER_KEY_STATE_RELEASED)
|
||||
{
|
||||
if (!meta_keymap_x11_get_is_modifier (keymap, keycode))
|
||||
meta_keymap_x11_latch_modifiers (keymap, level, FALSE);
|
||||
meta_keymap_x11_release_keycode_if_needed (keymap, keycode);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_touch_down (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
int device_slot,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
g_warning ("Virtual touch motion not implemented under X11");
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_touch_motion (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
int device_slot,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
g_warning ("Virtual touch motion not implemented under X11");
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_notify_touch_up (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
int device_slot)
|
||||
{
|
||||
g_warning ("Virtual touch motion not implemented under X11");
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_init (MetaVirtualInputDeviceX11 *virtual_device_x11)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_virtual_input_device_x11_class_init (MetaVirtualInputDeviceX11Class *klass)
|
||||
{
|
||||
ClutterVirtualInputDeviceClass *virtual_input_device_class =
|
||||
CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass);
|
||||
|
||||
virtual_input_device_class->notify_relative_motion = meta_virtual_input_device_x11_notify_relative_motion;
|
||||
virtual_input_device_class->notify_absolute_motion = meta_virtual_input_device_x11_notify_absolute_motion;
|
||||
virtual_input_device_class->notify_button = meta_virtual_input_device_x11_notify_button;
|
||||
virtual_input_device_class->notify_discrete_scroll = meta_virtual_input_device_x11_notify_discrete_scroll;
|
||||
virtual_input_device_class->notify_scroll_continuous = meta_virtual_input_device_x11_notify_scroll_continuous;
|
||||
virtual_input_device_class->notify_key = meta_virtual_input_device_x11_notify_key;
|
||||
virtual_input_device_class->notify_keyval = meta_virtual_input_device_x11_notify_keyval;
|
||||
virtual_input_device_class->notify_touch_down = meta_virtual_input_device_x11_notify_touch_down;
|
||||
virtual_input_device_class->notify_touch_motion = meta_virtual_input_device_x11_notify_touch_motion;
|
||||
virtual_input_device_class->notify_touch_up = meta_virtual_input_device_x11_notify_touch_up;
|
||||
}
|
31
src/backends/x11/meta-virtual-input-device-x11.h
Normal file
31
src/backends/x11/meta-virtual-input-device-x11.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Jonas Ådahl <jadahl@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef META_VIRTUAL_INPUT_DEVICE_X11_H
|
||||
#define META_VIRTUAL_INPUT_DEVICE_X11_H
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
#define META_TYPE_VIRTUAL_INPUT_DEVICE_X11 (meta_virtual_input_device_x11_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaVirtualInputDeviceX11,
|
||||
meta_virtual_input_device_x11,
|
||||
META, VIRTUAL_INPUT_DEVICE_X11,
|
||||
ClutterVirtualInputDevice)
|
||||
|
||||
#endif /* META_VIRTUAL_INPUT_DEVICE_X11_H */
|
334
src/backends/x11/meta-xkb-a11y-x11.c
Normal file
334
src/backends/x11/meta-xkb-a11y-x11.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright © 2001 Ximian, Inc.
|
||||
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
|
||||
* Copyright (C) 2017 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/XKBstr.h>
|
||||
|
||||
#include "backends/x11/meta-xkb-a11y-x11.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "core/display-private.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
|
||||
#define DEFAULT_XKB_SET_CONTROLS_MASK XkbSlowKeysMask | \
|
||||
XkbBounceKeysMask | \
|
||||
XkbStickyKeysMask | \
|
||||
XkbMouseKeysMask | \
|
||||
XkbMouseKeysAccelMask | \
|
||||
XkbAccessXKeysMask | \
|
||||
XkbAccessXTimeoutMask | \
|
||||
XkbAccessXFeedbackMask | \
|
||||
XkbControlsEnabledMask
|
||||
|
||||
static int _xkb_event_base;
|
||||
|
||||
static XkbDescRec *
|
||||
get_xkb_desc_rec (Display *xdisplay)
|
||||
{
|
||||
XkbDescRec *desc;
|
||||
Status status = Success;
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
desc = XkbGetMap (xdisplay, XkbAllMapComponentsMask, XkbUseCoreKbd);
|
||||
if (desc != NULL)
|
||||
{
|
||||
desc->ctrls = NULL;
|
||||
status = XkbGetControls (xdisplay, XkbAllControlsMask, desc);
|
||||
}
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
g_return_val_if_fail (desc != NULL, NULL);
|
||||
g_return_val_if_fail (desc->ctrls != NULL, NULL);
|
||||
g_return_val_if_fail (status == Success, NULL);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void
|
||||
set_xkb_desc_rec (Display *xdisplay,
|
||||
XkbDescRec *desc)
|
||||
{
|
||||
clutter_x11_trap_x_errors ();
|
||||
XkbSetControls (xdisplay, DEFAULT_XKB_SET_CONTROLS_MASK, desc);
|
||||
XSync (xdisplay, FALSE);
|
||||
clutter_x11_untrap_x_errors ();
|
||||
}
|
||||
|
||||
static void
|
||||
check_settings_changed (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
ClutterKbdA11ySettings kbd_a11y_settings;
|
||||
ClutterKeyboardA11yFlags what_changed = 0;
|
||||
XkbDescRec *desc;
|
||||
|
||||
desc = get_xkb_desc_rec (xdisplay);
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
clutter_device_manager_get_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
|
||||
|
||||
if (desc->ctrls->enabled_ctrls & XkbSlowKeysMask &&
|
||||
!(kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED))
|
||||
{
|
||||
what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
|
||||
kbd_a11y_settings.controls |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
|
||||
}
|
||||
else if (!(desc->ctrls->enabled_ctrls & XkbSlowKeysMask) &&
|
||||
kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED)
|
||||
{
|
||||
what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
|
||||
kbd_a11y_settings.controls &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED;
|
||||
}
|
||||
|
||||
if (desc->ctrls->enabled_ctrls & XkbStickyKeysMask &&
|
||||
!(kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED))
|
||||
{
|
||||
what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
|
||||
kbd_a11y_settings.controls |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
|
||||
}
|
||||
else if (!(desc->ctrls->enabled_ctrls & XkbStickyKeysMask) &&
|
||||
kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED)
|
||||
{
|
||||
what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
|
||||
kbd_a11y_settings.controls &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED;
|
||||
}
|
||||
|
||||
if (what_changed)
|
||||
g_signal_emit_by_name (device_manager,
|
||||
"kbd-a11y-flags-changed",
|
||||
kbd_a11y_settings.controls,
|
||||
what_changed);
|
||||
|
||||
XkbFreeKeyboard (desc, XkbAllComponentsMask, TRUE);
|
||||
}
|
||||
|
||||
static ClutterX11FilterReturn
|
||||
xkb_a11y_event_filter (XEvent *xevent,
|
||||
ClutterEvent *clutter_event,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterDeviceManager *device_manager = CLUTTER_DEVICE_MANAGER (data);
|
||||
XkbEvent *xkbev = (XkbEvent *) xevent;
|
||||
|
||||
/* 'event_type' is set to zero on notifying us of updates in
|
||||
* response to client requests (including our own) and non-zero
|
||||
* to notify us of key/mouse events causing changes (like
|
||||
* pressing shift 5 times to enable sticky keys).
|
||||
*
|
||||
* We only want to update out settings when it's in response to an
|
||||
* explicit user input event, so require a non-zero event_type.
|
||||
*/
|
||||
if (xevent->xany.type == (_xkb_event_base + XkbEventCode) &&
|
||||
xkbev->any.xkb_type == XkbControlsNotify && xkbev->ctrls.event_type != 0)
|
||||
check_settings_changed (device_manager);
|
||||
|
||||
return CLUTTER_X11_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_xkb_available (Display *xdisplay)
|
||||
{
|
||||
gint opcode, error_base, event_base, major, minor;
|
||||
|
||||
if (_xkb_event_base)
|
||||
return TRUE;
|
||||
|
||||
if (!XkbQueryExtension (xdisplay,
|
||||
&opcode,
|
||||
&event_base,
|
||||
&error_base,
|
||||
&major,
|
||||
&minor))
|
||||
return FALSE;
|
||||
|
||||
if (!XkbUseExtension (xdisplay, &major, &minor))
|
||||
return FALSE;
|
||||
|
||||
_xkb_event_base = event_base;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
set_value_mask (gboolean flag,
|
||||
unsigned long value,
|
||||
unsigned long mask)
|
||||
{
|
||||
if (flag)
|
||||
return value | mask;
|
||||
|
||||
return value & ~mask;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_xkb_ctrl (XkbDescRec *desc,
|
||||
ClutterKeyboardA11yFlags settings,
|
||||
ClutterKeyboardA11yFlags flag,
|
||||
unsigned long mask)
|
||||
{
|
||||
gboolean result = (settings & flag) == flag;
|
||||
desc->ctrls->enabled_ctrls = set_value_mask (result, desc->ctrls->enabled_ctrls, mask);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
meta_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterKbdA11ySettings *kbd_a11y_settings)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
XkbDescRec *desc;
|
||||
gboolean enable_accessX;
|
||||
|
||||
desc = get_xkb_desc_rec (xdisplay);
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
|
||||
/* general */
|
||||
enable_accessX = kbd_a11y_settings->controls & CLUTTER_A11Y_KEYBOARD_ENABLED;
|
||||
|
||||
desc->ctrls->enabled_ctrls = set_value_mask (enable_accessX,
|
||||
desc->ctrls->enabled_ctrls,
|
||||
XkbAccessXKeysMask);
|
||||
|
||||
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_TIMEOUT_ENABLED,
|
||||
XkbAccessXTimeoutMask))
|
||||
{
|
||||
desc->ctrls->ax_timeout = kbd_a11y_settings->timeout_delay;
|
||||
/* disable only the master flag via the server we will disable
|
||||
* the rest on the rebound without affecting settings state
|
||||
* don't change the option flags at all.
|
||||
*/
|
||||
desc->ctrls->axt_ctrls_mask = XkbAccessXKeysMask | XkbAccessXFeedbackMask;
|
||||
desc->ctrls->axt_ctrls_values = 0;
|
||||
desc->ctrls->axt_opts_mask = 0;
|
||||
}
|
||||
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP,
|
||||
desc->ctrls->ax_options,
|
||||
XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask);
|
||||
|
||||
/* bounce keys */
|
||||
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
|
||||
CLUTTER_A11Y_BOUNCE_KEYS_ENABLED, XkbBounceKeysMask))
|
||||
{
|
||||
desc->ctrls->debounce_delay = kbd_a11y_settings->debounce_delay;
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT,
|
||||
desc->ctrls->ax_options,
|
||||
XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask);
|
||||
}
|
||||
|
||||
/* mouse keys */
|
||||
if (clutter_keymap_get_num_lock_state (clutter_backend_get_keymap (backend)))
|
||||
{
|
||||
/* Disable mousekeys when NumLock is ON */
|
||||
desc->ctrls->enabled_ctrls &= ~(XkbMouseKeysMask | XkbMouseKeysAccelMask);
|
||||
}
|
||||
else if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
|
||||
CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
|
||||
{
|
||||
gint mk_max_speed;
|
||||
gint mk_accel_time;
|
||||
|
||||
desc->ctrls->mk_interval = 100; /* msec between mousekey events */
|
||||
desc->ctrls->mk_curve = 50;
|
||||
|
||||
/* We store pixels / sec, XKB wants pixels / event */
|
||||
mk_max_speed = kbd_a11y_settings->mousekeys_max_speed;
|
||||
desc->ctrls->mk_max_speed = mk_max_speed / (1000 / desc->ctrls->mk_interval);
|
||||
if (desc->ctrls->mk_max_speed <= 0)
|
||||
desc->ctrls->mk_max_speed = 1;
|
||||
|
||||
mk_accel_time = kbd_a11y_settings->mousekeys_accel_time;
|
||||
desc->ctrls->mk_time_to_max = mk_accel_time / desc->ctrls->mk_interval;
|
||||
|
||||
if (desc->ctrls->mk_time_to_max <= 0)
|
||||
desc->ctrls->mk_time_to_max = 1;
|
||||
|
||||
desc->ctrls->mk_delay = kbd_a11y_settings->mousekeys_init_delay;
|
||||
}
|
||||
|
||||
/* slow keys */
|
||||
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
|
||||
CLUTTER_A11Y_SLOW_KEYS_ENABLED, XkbSlowKeysMask))
|
||||
{
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS,
|
||||
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask);
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT,
|
||||
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask);
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT,
|
||||
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask);
|
||||
desc->ctrls->slow_keys_delay = kbd_a11y_settings->slowkeys_delay;
|
||||
/* anything larger than 500 seems to loose all keyboard input */
|
||||
if (desc->ctrls->slow_keys_delay > 500)
|
||||
desc->ctrls->slow_keys_delay = 500;
|
||||
}
|
||||
|
||||
/* sticky keys */
|
||||
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
|
||||
CLUTTER_A11Y_STICKY_KEYS_ENABLED, XkbStickyKeysMask))
|
||||
{
|
||||
desc->ctrls->ax_options |= XkbAX_LatchToLockMask;
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF,
|
||||
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask);
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_BEEP,
|
||||
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask);
|
||||
}
|
||||
|
||||
/* toggle keys */
|
||||
desc->ctrls->ax_options =
|
||||
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED,
|
||||
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_IndicatorFBMask);
|
||||
|
||||
set_xkb_desc_rec (xdisplay, desc);
|
||||
XkbFreeKeyboard (desc, XkbAllComponentsMask, TRUE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_device_manager_x11_a11y_init (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
Display *xdisplay = clutter_x11_get_default_display ();
|
||||
guint event_mask;
|
||||
|
||||
if (!is_xkb_available (xdisplay))
|
||||
return FALSE;
|
||||
|
||||
event_mask = XkbControlsNotifyMask | XkbAccessXNotifyMask;
|
||||
|
||||
XkbSelectEvents (xdisplay, XkbUseCoreKbd, event_mask, event_mask);
|
||||
|
||||
clutter_x11_add_filter (xkb_a11y_event_filter, device_manager);
|
||||
|
||||
return TRUE;
|
||||
}
|
38
src/backends/x11/meta-xkb-a11y-x11.h
Normal file
38
src/backends/x11/meta-xkb-a11y-x11.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
*
|
||||
* Copyright © 2001 Ximian, Inc.
|
||||
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
|
||||
* Copyright (C) 2017 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_XKB_A11Y_X11_H
|
||||
#define META_XKB_A11Y_X11_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
void
|
||||
meta_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager *device_manager,
|
||||
ClutterKbdA11ySettings *kbd_a11y_settings);
|
||||
|
||||
gboolean
|
||||
meta_device_manager_x11_a11y_init (ClutterDeviceManager *device_manager);
|
||||
|
||||
#endif /* META_XKB_A11Y_X11_H */
|
@ -57,6 +57,9 @@
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#include "backends/meta-dnd-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/meta-event-x11.h"
|
||||
#include "backends/x11/meta-stage-x11.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "compositor/meta-window-actor-x11.h"
|
||||
#include "compositor/meta-window-actor-wayland.h"
|
||||
@ -289,7 +292,7 @@ meta_focus_stage_window (MetaDisplay *display,
|
||||
if (!stage)
|
||||
return;
|
||||
|
||||
window = clutter_x11_get_stage_window (stage);
|
||||
window = meta_x11_get_stage_window (stage);
|
||||
|
||||
if (window == None)
|
||||
return;
|
||||
@ -312,7 +315,7 @@ meta_stage_is_focused (MetaDisplay *display)
|
||||
if (!stage)
|
||||
return FALSE;
|
||||
|
||||
window = clutter_x11_get_stage_window (stage);
|
||||
window = meta_x11_get_stage_window (stage);
|
||||
|
||||
if (window == None)
|
||||
return FALSE;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/meta-event-x11.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "compositor/meta-sync-ring.h"
|
||||
#include "core/display-private.h"
|
||||
@ -94,7 +95,7 @@ meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11,
|
||||
* stage is invisible
|
||||
*/
|
||||
if (xevent->type == MapNotify)
|
||||
clutter_x11_handle_event (xevent);
|
||||
meta_x11_handle_event (xevent);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "core/display-private.h"
|
||||
#include "backends/meta-dnd-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/meta-stage-x11.h"
|
||||
#include "meta/meta-dnd.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
|
||||
@ -184,7 +185,7 @@ meta_dnd_handle_xdnd_event (MetaBackend *backend,
|
||||
output_window = meta_compositor_x11_get_output_xwindow (compositor_x11);
|
||||
stage = meta_compositor_get_stage (compositor);
|
||||
if (xev->xany.window != output_window &&
|
||||
xev->xany.window != clutter_x11_get_stage_window (stage))
|
||||
xev->xany.window != meta_x11_get_stage_window (stage))
|
||||
return FALSE;
|
||||
|
||||
if (xev->xclient.message_type == XInternAtom (xdisplay, "XdndPosition", TRUE))
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/meta-event-x11.h"
|
||||
#include "backends/x11/cm/meta-backend-x11-cm.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "compositor/compositor-private.h"
|
||||
@ -630,7 +631,7 @@ gesture_tracker_state_changed (MetaGestureTracker *tracker,
|
||||
|
||||
XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
clutter_x11_event_sequence_get_touch_detail (sequence),
|
||||
meta_x11_event_sequence_get_touch_detail (sequence),
|
||||
DefaultRootWindow (display->x11_display->xdisplay), event_mode);
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ if have_x11
|
||||
xcb_randr_dep,
|
||||
xcb_res_dep,
|
||||
xau_dep,
|
||||
xtst_dep,
|
||||
]
|
||||
|
||||
if have_sm
|
||||
@ -241,18 +242,34 @@ mutter_sources = [
|
||||
'backends/x11/meta-crtc-xrandr.h',
|
||||
'backends/x11/meta-cursor-renderer-x11.c',
|
||||
'backends/x11/meta-cursor-renderer-x11.h',
|
||||
'backends/x11/meta-device-manager-x11.c',
|
||||
'backends/x11/meta-device-manager-x11.h',
|
||||
'backends/x11/meta-event-x11.c',
|
||||
'backends/x11/meta-event-x11.h',
|
||||
'backends/x11/meta-gpu-xrandr.c',
|
||||
'backends/x11/meta-gpu-xrandr.h',
|
||||
'backends/x11/meta-input-device-x11.c',
|
||||
'backends/x11/meta-input-device-x11.h',
|
||||
'backends/x11/meta-input-device-tool-x11.c',
|
||||
'backends/x11/meta-input-device-tool-x11.h',
|
||||
'backends/x11/meta-input-settings-x11.c',
|
||||
'backends/x11/meta-input-settings-x11.h',
|
||||
'backends/x11/meta-keymap-x11.c',
|
||||
'backends/x11/meta-keymap-x11.h',
|
||||
'backends/x11/meta-monitor-manager-xrandr.c',
|
||||
'backends/x11/meta-monitor-manager-xrandr.h',
|
||||
'backends/x11/meta-output-xrandr.c',
|
||||
'backends/x11/meta-output-xrandr.h',
|
||||
'backends/x11/meta-renderer-x11.c',
|
||||
'backends/x11/meta-renderer-x11.h',
|
||||
'backends/x11/meta-stage-x11.c',
|
||||
'backends/x11/meta-stage-x11.h',
|
||||
'backends/x11/meta-stage-x11-nested.c',
|
||||
'backends/x11/meta-stage-x11-nested.h',
|
||||
'backends/x11/meta-virtual-input-device-x11.c',
|
||||
'backends/x11/meta-virtual-input-device-x11.h',
|
||||
'backends/x11/meta-xkb-a11y-x11.c',
|
||||
'backends/x11/meta-xkb-a11y-x11.h',
|
||||
'backends/x11/nested/meta-backend-x11-nested.c',
|
||||
'backends/x11/nested/meta-backend-x11-nested.h',
|
||||
'backends/x11/nested/meta-cursor-renderer-x11-nested.c',
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-settings-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/meta-stage-x11.h"
|
||||
#include "core/frame.h"
|
||||
#include "core/meta-workspace-manager-private.h"
|
||||
#include "core/util-private.h"
|
||||
@ -2225,7 +2226,7 @@ meta_x11_display_set_stage_input_region (MetaX11Display *x11_display,
|
||||
|
||||
g_return_if_fail (!meta_is_wayland_compositor ());
|
||||
|
||||
stage_xwindow = clutter_x11_get_stage_window (stage);
|
||||
stage_xwindow = meta_x11_get_stage_window (stage);
|
||||
XFixesSetWindowShapeRegion (xdisplay, stage_xwindow,
|
||||
ShapeInput, 0, 0, region);
|
||||
|
||||
|
Reference in New Issue
Block a user