device-manager/xi2: Fix device hotplugging

Hierarchy and Device changed events come through with the X window set
to be the root window, not the stage window. We need to whitelist them
so that we can actually support hotplugging and device changes.
This commit is contained in:
Emmanuele Bassi 2011-01-21 11:41:36 +00:00
parent 7514f5fe92
commit 0e99346915
2 changed files with 95 additions and 20 deletions

View File

@ -235,9 +235,6 @@ add_device (ClutterDeviceManagerXI2 *manager_xi2,
/* we don't go through the DeviceManager::add_device() vfunc because /* we don't go through the DeviceManager::add_device() vfunc because
* that emits the signal, and we only do it conditionally * that emits the signal, and we only do it conditionally
*
* FIXME: add a boolean "emit_signal" argument to the add_device()
* wrapper in ClutterDeviceManager, and emit the signal only if true
*/ */
g_hash_table_replace (manager_xi2->devices_by_id, g_hash_table_replace (manager_xi2->devices_by_id,
GINT_TO_POINTER (info->deviceid), GINT_TO_POINTER (info->deviceid),
@ -329,6 +326,8 @@ translate_hierarchy_event (ClutterBackendX11 *backend_x11,
XIDeviceInfo *info; XIDeviceInfo *info;
int n_devices; int n_devices;
CLUTTER_NOTE (EVENT, "Hierarchy event: device enabled");
info = XIQueryDevice (backend_x11->xdpy, info = XIQueryDevice (backend_x11->xdpy,
ev->info[i].deviceid, ev->info[i].deviceid,
&n_devices); &n_devices);
@ -336,6 +335,8 @@ translate_hierarchy_event (ClutterBackendX11 *backend_x11,
} }
else if (ev->info[i].flags & XIDeviceDisabled) else if (ev->info[i].flags & XIDeviceDisabled)
{ {
CLUTTER_NOTE (EVENT, "Hierarchy event: device disabled");
remove_device (manager_xi2, ev->info[i].deviceid); remove_device (manager_xi2, ev->info[i].deviceid);
} }
else if ((ev->info[i].flags & XISlaveAttached) || else if ((ev->info[i].flags & XISlaveAttached) ||
@ -345,6 +346,11 @@ translate_hierarchy_event (ClutterBackendX11 *backend_x11,
XIDeviceInfo *info; XIDeviceInfo *info;
int n_devices; int n_devices;
CLUTTER_NOTE (EVENT, "Hierarchy event: slave %s",
(ev->info[i].flags & XISlaveAttached)
? "attached"
: "detached");
slave = g_hash_table_lookup (manager_xi2->devices_by_id, slave = g_hash_table_lookup (manager_xi2->devices_by_id,
GINT_TO_POINTER (ev->info[i].deviceid)); GINT_TO_POINTER (ev->info[i].deviceid));
master = clutter_input_device_get_associated_device (slave); master = clutter_input_device_get_associated_device (slave);
@ -533,8 +539,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (translator); ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (translator);
ClutterTranslateReturn retval = CLUTTER_TRANSLATE_CONTINUE; ClutterTranslateReturn retval = CLUTTER_TRANSLATE_CONTINUE;
ClutterBackendX11 *backend_x11; ClutterBackendX11 *backend_x11;
ClutterStageX11 *stage_x11; ClutterStageX11 *stage_x11 = NULL;
ClutterStage *stage; ClutterStage *stage = NULL;
ClutterInputDevice *device; ClutterInputDevice *device;
XGenericEventCookie *cookie; XGenericEventCookie *cookie;
XIEvent *xi_event; XIEvent *xi_event;
@ -558,14 +564,18 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
xi_event = (XIEvent *) cookie->data; xi_event = (XIEvent *) cookie->data;
if (!(xi_event->evtype == XI_HierarchyChanged ||
xi_event->evtype == XI_DeviceChanged))
{
stage = get_event_stage (translator, xi_event); stage = get_event_stage (translator, xi_event);
if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage)) if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
{ {
XFreeEventData (backend_x11->xdpy, cookie); XFreeEventData (backend_x11->xdpy, cookie);
return CLUTTER_TRANSLATE_CONTINUE; return CLUTTER_TRANSLATE_CONTINUE;
} }
else
stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)); stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
}
event->any.stage = stage; event->any.stage = stage;

View File

@ -4,9 +4,9 @@
#include <clutter/x11/clutter-x11.h> #include <clutter/x11/clutter-x11.h>
typedef struct { typedef struct {
ClutterActor *stage;
GHashTable *devices; GHashTable *devices;
} TestDevicesApp; } TestDevicesApp;
static const gchar * static const gchar *
@ -79,9 +79,8 @@ axis_type_name (ClutterInputAxis axis)
static gboolean static gboolean
stage_button_event_cb (ClutterActor *actor, stage_button_event_cb (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer userdata) TestDevicesApp *app)
{ {
TestDevicesApp *app = (TestDevicesApp *)userdata;
ClutterInputDevice *device; ClutterInputDevice *device;
ClutterInputDevice *source_device; ClutterInputDevice *source_device;
ClutterActor *hand = NULL; ClutterActor *hand = NULL;
@ -130,9 +129,8 @@ stage_button_event_cb (ClutterActor *actor,
static gboolean static gboolean
stage_motion_event_cb (ClutterActor *actor, stage_motion_event_cb (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer userdata) TestDevicesApp *app)
{ {
TestDevicesApp *app = (TestDevicesApp *)userdata;
ClutterInputDevice *device; ClutterInputDevice *device;
ClutterActor *hand = NULL; ClutterActor *hand = NULL;
@ -152,6 +150,65 @@ stage_motion_event_cb (ClutterActor *actor,
return FALSE; return FALSE;
} }
static void
manager_device_added_cb (ClutterDeviceManager *manager,
ClutterInputDevice *device,
TestDevicesApp *app)
{
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("got a %s device '%s' with id %d\n",
device_type_name (device),
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
clutter_input_device_set_enabled (device, TRUE);
hand = clutter_texture_new_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
NULL);
g_hash_table_insert (app->devices, device, hand);
clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand);
}
}
static void
manager_device_removed_cb (ClutterDeviceManager *manager,
ClutterInputDevice *device,
TestDevicesApp *app)
{
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("removed a %s device '%s' with id %d\n",
device_type_name (device),
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
hand = g_hash_table_lookup (app->devices, device);
if (hand != NULL)
clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand);
g_hash_table_remove (app->devices, device);
}
}
G_MODULE_EXPORT int G_MODULE_EXPORT int
test_devices_main (int argc, char **argv) test_devices_main (int argc, char **argv)
{ {
@ -181,10 +238,18 @@ test_devices_main (int argc, char **argv)
g_signal_connect (stage, g_signal_connect (stage,
"button-press-event", G_CALLBACK (stage_button_event_cb), "button-press-event", G_CALLBACK (stage_button_event_cb),
app); app);
app->stage = stage;
clutter_actor_show_all (stage); clutter_actor_show_all (stage);
manager = clutter_device_manager_get_default (); manager = clutter_device_manager_get_default ();
g_signal_connect (manager,
"device-added", G_CALLBACK (manager_device_added_cb),
app);
g_signal_connect (manager,
"device-removed", G_CALLBACK (manager_device_removed_cb),
app);
stage_devices = clutter_device_manager_peek_devices (manager); stage_devices = clutter_device_manager_peek_devices (manager);
if (stage_devices == NULL) if (stage_devices == NULL)