commit ff25a24d387887bc3bbacfb5bcaf2756695df096 Author: Hiroyuki Ikezoe Date: Sat Jun 26 19:55:40 2010 +0900 Watch DevicePresenceNotify event. Some devices are not reported by xserver at the time of startiung up of gnome-settings-daemon, so we need to watch DevicePresenceNotify event at that time. Fix for bug #609050. diff --git a/modules/gnome-settings-daemon-plugins/gsd-pointing-device-plugin.c b/modules/gnome-settings-daemon-plugins/gsd-pointing-device-plugin.c index 31dd336..8a2d98f 100644 --- a/modules/gnome-settings-daemon-plugins/gsd-pointing-device-plugin.c +++ b/modules/gnome-settings-daemon-plugins/gsd-pointing-device-plugin.c @@ -24,10 +24,13 @@ #include #include #include +#include +#include #include "gsd-pointing-device-manager.h" #include "gpds-gconf.h" #include "gpds-xinput-pointer-info.h" +#include "gpds-xinput-utils.h" #define GSD_TYPE_POINTING_DEVICE_PLUGIN (gsd_pointing_device_plugin_get_type ()) #define GSD_POINTING_DEVICE_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_POINTING_DEVICE_PLUGIN, GsdPointingDevicePlugin)) @@ -61,44 +64,90 @@ gsd_pointing_device_plugin_init (GsdPointingDevicePlugin *plugin) plugin->managers = NULL; } -static GList * -collect_pointer_device_infos_from_gconf (void) +static gboolean +has_manager (GsdPointingDevicePlugin *plugin, const gchar *device_name) { - GConfClient *gconf; - GSList *dirs, *node; - GList *infos = NULL; - - gconf = gconf_client_get_default(); - dirs = gconf_client_all_dirs(gconf, GPDS_GCONF_DIR, NULL); - - for (node = dirs; node; node = g_slist_next(node)) { - const gchar *dir = node->data; - gchar *device_type; - gchar *device_type_key; - - device_type_key = gconf_concat_dir_and_key(dir, GPDS_GCONF_DEVICE_TYPE_KEY); - device_type = gconf_client_get_string(gconf, device_type_key, NULL); - if (device_type) { - GpdsXInputPointerInfo *info; - gchar *device_name, *unescaped_device_name; - - device_name = g_path_get_basename(dir); - unescaped_device_name = gconf_unescape_key(device_name, -1); - info = gpds_xinput_pointer_info_new(unescaped_device_name, device_type); - infos = g_list_prepend(infos, info); - g_free(unescaped_device_name); - g_free(device_name); + GList *node; + + for (node = plugin->managers; node; node = g_list_next(node)) { + GsdPointingDeviceManager *manager = node->data; + + if (g_str_equal(gsd_pointing_device_manager_get_device_name(manager), device_name)) + return TRUE; + } + + return FALSE; +} + +static GdkFilterReturn +device_presence_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XEvent *xev = (XEvent *)xevent; + XEventClass class_presence; + int xi_presence; + GsdPointingDevicePlugin *plugin = GSD_POINTING_DEVICE_PLUGIN(data); + + DevicePresence(gdk_x11_get_default_xdisplay(), xi_presence, class_presence); + + if (xev->type == xi_presence) { + XDeviceInfo *device_info = NULL; + XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xev; + + device_info = gpds_xinput_utils_get_device_info_from_id(notify_event->deviceid, NULL); + if (notify_event->devchange == DeviceEnabled) { + GsdPointingDeviceManager *manager; + + if (has_manager(plugin, device_info->name)) + return GDK_FILTER_CONTINUE; + + manager = gsd_pointing_device_manager_new(gdk_x11_get_xatom_name(device_info->type), + device_info->name); + if (manager) { + gsd_pointing_device_manager_start(manager, NULL); + plugin->managers = g_list_prepend(plugin->managers, manager); + } + } else if (notify_event->devchange == DeviceRemoved) { } + } - g_free(device_type_key); - g_free(device_type); + return GDK_FILTER_CONTINUE; +} + +static void +add_device_presence_filter (GsdPointingDevicePlugin *plugin) +{ + Display *display; + XEventClass class_presence; + gint xi_presence; + + gint op_code, event, error; + + if (!XQueryExtension(GDK_DISPLAY(), + "XInputExtension", + &op_code, + &event, + &error)) { + return; } - g_slist_foreach(dirs, (GFunc)g_free, NULL); - g_slist_free(dirs); - g_object_unref(gconf); + display = gdk_x11_get_default_xdisplay(); - return infos; + gdk_error_trap_push(); + DevicePresence(display, xi_presence, class_presence); + XSelectExtensionEvent(display, + RootWindow(display, DefaultScreen(display)), + &class_presence, 1); + gdk_flush(); + if (!gdk_error_trap_pop()) + gdk_window_add_filter(NULL, device_presence_filter, plugin); +} + +static void +remove_device_presence_filter (GsdPointingDevicePlugin *plugin) +{ + gdk_window_remove_filter(NULL, device_presence_filter, plugin); } static void @@ -109,7 +158,10 @@ activate (GnomeSettingsPlugin *plugin) pointing_device_plugin = GSD_POINTING_DEVICE_PLUGIN(plugin); - pointer_device_infos = collect_pointer_device_infos_from_gconf(); + add_device_presence_filter(pointing_device_plugin); + + pointer_device_infos = gpds_xinput_utils_collect_pointer_infos(); + for (node = pointer_device_infos; node; node = g_list_next(node)) { GsdPointingDeviceManager *manager; GpdsXInputPointerInfo *info = node->data; @@ -133,6 +185,8 @@ stop_all_managers (GsdPointingDevicePlugin *plugin) { GList *node; + remove_device_presence_filter(plugin); + for (node = plugin->managers; node; node = g_list_next(node)) { GsdPointingDeviceManager *manager = node->data; diff --git a/src/gpds-xinput-utils.c b/src/gpds-xinput-utils.c index 48dc2a5..0f7ceea 100644 --- a/src/gpds-xinput-utils.c +++ b/src/gpds-xinput-utils.c @@ -62,6 +62,33 @@ gpds_xinput_utils_get_device_info (const gchar *device_name, GError **error) return NULL; } +XDeviceInfo * +gpds_xinput_utils_get_device_info_from_id (XID id, GError **error) +{ + XDeviceInfo *device_infos; + gint i, n_device_infos; + + device_infos = XListInputDevices(GDK_DISPLAY(), &n_device_infos); + + for (i = 0; i < n_device_infos; i++) { + if (device_infos[i].use != IsXExtensionPointer) + continue; + if (device_infos[i].id == id) { + XFreeDeviceList(device_infos); + return &device_infos[i]; + } + } + + XFreeDeviceList(device_infos); + + g_set_error(error, + GPDS_XINPUT_UTILS_ERROR, + GPDS_XINPUT_UTILS_ERROR_NO_DEVICE, + _("No device found for %d."), (int)id); + + return NULL; +} + gshort gpds_xinput_utils_get_device_num_buttons (const gchar *device_name, GError **error) { diff --git a/src/gpds-xinput-utils.h b/src/gpds-xinput-utils.h index 9cc4564..74e491a 100644 --- a/src/gpds-xinput-utils.h +++ b/src/gpds-xinput-utils.h @@ -38,6 +38,8 @@ typedef enum GQuark gpds_xinput_utils_error_quark (void); XDeviceInfo *gpds_xinput_utils_get_device_info (const gchar *device_name, GError **error); +XDeviceInfo *gpds_xinput_utils_get_device_info_from_id (XID id, + GError **error); XDevice *gpds_xinput_utils_open_device (const gchar *device_name, GError **error); Atom gpds_xinput_utils_get_float_atom (GError **error); gshort gpds_xinput_utils_get_device_num_buttons (const gchar *device_name, GError **error); diff --git a/test/test-xinput-utils.c b/test/test-xinput-utils.c index 29b3f4e..a06dcbc 100644 --- a/test/test-xinput-utils.c +++ b/test/test-xinput-utils.c @@ -6,6 +6,7 @@ void test_exist_device (void); void test_get_float_atom (void); void test_get_device_info (void); +void test_get_device_info_from_id (void); void test_open_device (void); void test_open_no_device (void); void test_get_device_num_buttons (void); @@ -49,7 +50,7 @@ test_get_float_atom (void) void test_get_device_info (void) { - XDeviceInfo *device_info = NULL; + XDeviceInfo *device_info = NULL; device_info = gpds_xinput_utils_get_device_info(DEVICE_NAME, &error); cut_assert(device_info); @@ -57,6 +58,19 @@ test_get_device_info (void) } void +test_get_device_info_from_id (void) +{ + XDeviceInfo *device_info = NULL; + device_info = gpds_xinput_utils_get_device_info(DEVICE_NAME, &error); + cut_assert(device_info); + + gcut_assert_error(error); + + device_info = gpds_xinput_utils_get_device_info_from_id(device_info->id, &error); + cut_assert_equal_string(DEVICE_NAME, device_info->name); +} + +void test_open_device (void) { device = gpds_xinput_utils_open_device(DEVICE_NAME, &error);