[gnome-settings-daemon] cursor: Show the cursor only when a mouse gets used



commit 285b0e497af18b853c9f67f93f3b3bbab7a6c241
Author: Bastien Nocera <hadess hadess net>
Date:   Tue Nov 13 10:53:53 2012 +0100

    cursor: Show the cursor only when a mouse gets used
    
    - On startup, we're responsible for showing the cursor when
    the mouse gets moved the first time.
    - During run-time, when switching to a touchscreen, hide the cursor,
      and show it again when switching back to the mouse.
    
    (Note: in the above text, mouse is a shortcut to "pointer device
     that isn't a touchscreen, it works just as well for touchpads)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=687791

 configure.ac                        |    2 +-
 plugins/cursor/gsd-cursor-manager.c |  299 +++++++++++++++++------------------
 2 files changed, 144 insertions(+), 157 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index a6e5b21..2d6bdbd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,7 +159,7 @@ dnl ---------------------------------------------------------------------------
 dnl - cursor
 dnl ---------------------------------------------------------------------------
 
-PKG_CHECK_MODULES(CURSOR, xfixes)
+PKG_CHECK_MODULES(CURSOR, xfixes gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
 
 dnl ---------------------------------------------------------------------------
 dnl - xsettings
diff --git a/plugins/cursor/gsd-cursor-manager.c b/plugins/cursor/gsd-cursor-manager.c
index 2c01ba7..a9ce146 100644
--- a/plugins/cursor/gsd-cursor-manager.c
+++ b/plugins/cursor/gsd-cursor-manager.c
@@ -38,25 +38,26 @@
 #include <X11/Xatom.h>
 #include <X11/extensions/Xfixes.h>
 
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-idle-monitor.h>
+
 #include "gnome-settings-profile.h"
 #include "gsd-cursor-manager.h"
 #include "gsd-input-helper.h"
 
 #define XFIXES_CURSOR_HIDING_MAJOR 4
 
+#define IDLE_TIME 1
+
 #define GSD_CURSOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_CURSOR_MANAGER, GsdCursorManagerPrivate))
 
 struct GsdCursorManagerPrivate
 {
-        guint start_idle_id;
         guint added_id;
         guint removed_id;
         guint changed_id;
         gboolean cursor_shown;
-};
-
-enum {
-        PROP_0,
+        GHashTable *monitors;
 };
 
 static void     gsd_cursor_manager_class_init  (GsdCursorManagerClass *klass);
@@ -67,134 +68,85 @@ G_DEFINE_TYPE (GsdCursorManager, gsd_cursor_manager, G_TYPE_OBJECT)
 
 static gpointer manager_object = NULL;
 
-static gboolean
-device_is_xtest (XDevice *xdevice)
-{
-        Atom realtype, prop;
-        int realformat;
-        unsigned long nitems, bytes_after;
-        unsigned char *data;
-
-        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XTEST Device", False);
-        if (!prop)
-                return FALSE;
-
-        gdk_error_trap_push ();
-        if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False,
-                                XA_INTEGER, &realtype, &realformat, &nitems,
-                                &bytes_after, &data) == Success) && (realtype != None)) {
-                gdk_error_trap_pop_ignored ();
-                XFree (data);
-                return TRUE;
-        }
-        gdk_error_trap_pop_ignored ();
+static void add_all_devices (GsdCursorManager *manager, GdkDevice *exception);
 
-        return FALSE;
-}
+typedef void (*ForeachScreenFunc) (GdkDisplay *display, GdkScreen *screen, GsdCursorManager *manager, gpointer user_data);
 
 static void
-set_cursor_visibility (GsdCursorManager *manager,
-                       gboolean          visible)
+foreach_screen (GsdCursorManager  *manager,
+                ForeachScreenFunc  func,
+                gpointer           user_data)
 {
-        Display *xdisplay;
         GdkDisplay *display;
         guint n_screens;
         guint i;
 
-        g_debug ("Attempting to %s the cursor", visible ? "show" : "hide");
-
         display = gdk_display_get_default ();
-        xdisplay = GDK_DISPLAY_XDISPLAY (display);
-
         n_screens = gdk_display_get_n_screens (display);
-
-        gdk_error_trap_push ();
-
         for (i = 0; i < n_screens; i++) {
                 GdkScreen *screen;
 
                 screen = gdk_display_get_screen (display, i);
-
-                if (visible)
-                        XFixesShowCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen)));
-                else
-                        XFixesHideCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen)));
-        }
-        if (gdk_error_trap_pop ()) {
-                g_warning ("An error occurred trying to %s the cursor",
-                           visible ? "show" : "hide");
+                (func) (display, screen, manager, user_data);
         }
-
-        manager->priv->cursor_shown = visible;
 }
 
-static gboolean
-device_info_is_ps2_mouse (XDeviceInfo *info)
+static void
+set_cursor_visibility_foreach (GdkDisplay       *display,
+                               GdkScreen        *screen,
+                               GsdCursorManager *manager,
+                               gpointer          user_data)
 {
-	return (g_strcmp0 (info->name, "ImPS/2 Generic Wheel Mouse") == 0);
+        Display *xdisplay;
+        gboolean visible = GPOINTER_TO_INT (user_data);
+
+        xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+        if (visible)
+                XFixesShowCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen)));
+        else
+                XFixesHideCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen)));
 }
 
 static void
-update_cursor_for_current (GsdCursorManager *manager)
+set_cursor_visibility (GsdCursorManager *manager,
+                       gboolean          visible)
 {
-        XDeviceInfo *device_info;
-        guint num_mice;
-        int n_devices;
-        guint i;
-
-        /* List all the pointer devices
-         * ignore the touchscreens
-         * ignore the XTest devices
-         * see if there's anything left */
+        g_debug ("Attempting to %s the cursor", visible ? "show" : "hide");
 
-        device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
-        if (device_info == NULL)
+        if (manager->priv->cursor_shown == visible)
                 return;
 
-        num_mice = 0;
-
-        for (i = 0; i < n_devices; i++) {
-                XDevice *device;
-
-                if (device_info[i].use != IsXExtensionPointer)
-                        continue;
-
-                if (device_info_is_touchscreen (&device_info[i]))
-                        continue;
-
-                if (device_info_is_ps2_mouse (&device_info[i]))
-                        continue;
-
-                gdk_error_trap_push ();
-                device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id);
-                if (gdk_error_trap_pop () || (device == NULL))
-                        continue;
+        gdk_error_trap_push ();
+        foreach_screen (manager, set_cursor_visibility_foreach, GINT_TO_POINTER (visible));
+        if (gdk_error_trap_pop ()) {
+                g_warning ("An error occurred trying to %s the cursor",
+                           visible ? "show" : "hide");
+        }
 
-                if (device_is_xtest (device)) {
-                        XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device);
-                        continue;
-                }
+        manager->priv->cursor_shown = visible;
+}
 
-                g_debug ("Counting '%s' as mouse", device_info[i].name);
+static void
+monitor_became_active (GnomeIdleMonitor *monitor,
+                       GsdCursorManager *manager)
+{
+        GdkDevice *device;
 
-                num_mice++;
-        }
-        XFreeDeviceList (device_info);
+        /* Oh, so you're active? */
+        g_object_get (G_OBJECT (monitor), "device", &device, NULL);
+        g_debug ("Device %d '%s' became active", gdk_x11_device_get_id (device), gdk_device_get_name (device));
+        set_cursor_visibility (manager,
+                               gdk_device_get_source (device) != GDK_SOURCE_TOUCHSCREEN);
 
-        g_debug ("Found %d devices that aren't touchscreens or fake devices", num_mice);
+        /* Remove the device from the watch */
+        g_hash_table_remove (manager->priv->monitors, device);
 
-        if (num_mice > 0) {
-                g_debug ("Mice are present");
+        /* Make sure that all the other devices are watched
+         * (but not the one we just stopped monitoring */
+        add_all_devices (manager, device);
 
-                if (manager->priv->cursor_shown == FALSE) {
-                        set_cursor_visibility (manager, TRUE);
-                }
-        } else {
-                g_debug ("No mice present");
-                if (manager->priv->cursor_shown != FALSE) {
-                        set_cursor_visibility (manager, FALSE);
-                }
-        }
+        g_object_unref (device);
 }
 
 static void
@@ -202,7 +154,28 @@ device_added_cb (GdkDeviceManager *device_manager,
                  GdkDevice        *device,
                  GsdCursorManager *manager)
 {
-        update_cursor_for_current (manager);
+        GnomeIdleMonitor *monitor;
+
+        if (g_hash_table_lookup (manager->priv->monitors, device) != NULL)
+                return;
+        if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_SLAVE)
+                return;
+        if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+                return;
+        if (strstr (gdk_device_get_name (device), "XTEST") != NULL)
+                return;
+
+        /* Create IdleMonitors for each pointer device */
+        monitor = gnome_idle_monitor_new_for_device (device);
+        g_hash_table_insert (manager->priv->monitors,
+                             device,
+                             monitor);
+        g_signal_connect (monitor, "became-active",
+                          G_CALLBACK (monitor_became_active), manager);
+        /* We become idle very quickly so that the became-active
+         * kicks in fast */
+        gnome_idle_monitor_add_watch (monitor, IDLE_TIME,
+                                      NULL, NULL, NULL);
 }
 
 static void
@@ -210,12 +183,8 @@ device_removed_cb (GdkDeviceManager *device_manager,
                    GdkDevice        *device,
                    GsdCursorManager *manager)
 {
-        /* If devices are removed, then it's unlikely
-         * a mouse appeared */
-        if (manager->priv->cursor_shown == FALSE)
-                return;
-
-        update_cursor_for_current (manager);
+        g_hash_table_remove (manager->priv->monitors,
+                             device);
 }
 
 static void
@@ -223,10 +192,10 @@ device_changed_cb (GdkDeviceManager *device_manager,
                    GdkDevice        *device,
                    GsdCursorManager *manager)
 {
-	if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_FLOATING)
-		device_removed_cb (device_manager, device, manager);
-	else
-		device_added_cb (device_manager, device, manager);
+        if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_FLOATING)
+                device_removed_cb (device_manager, device, manager);
+        else
+                device_added_cb (device_manager, device, manager);
 }
 
 static gboolean
@@ -241,6 +210,32 @@ supports_xfixes (void)
                                 &error);
 }
 
+static void
+initialize_root_cursor_foreach (GdkDisplay       *display,
+                                GdkScreen        *screen,
+                                GsdCursorManager *manager,
+                                Cursor           *xcursor)
+{
+        Display *xdisplay;
+
+        xdisplay = GDK_DISPLAY_XDISPLAY (display);
+        XDefineCursor (xdisplay,
+                       GDK_WINDOW_XID (gdk_screen_get_root_window (screen)),
+                       *xcursor);
+}
+
+static void
+initialize_root_cursor (GsdCursorManager *manager)
+{
+        GdkCursor *cursor;
+        Cursor xcursor;
+
+        cursor = gdk_cursor_new (GDK_LEFT_PTR);
+        xcursor = gdk_x11_cursor_get_xcursor (cursor);
+        foreach_screen (manager, (ForeachScreenFunc) initialize_root_cursor_foreach, &xcursor);
+        g_object_unref (cursor);
+}
+
 static gboolean
 supports_cursor_xfixes (void)
 {
@@ -266,32 +261,49 @@ supports_cursor_xfixes (void)
         return FALSE;
 }
 
-static gboolean
-gsd_cursor_manager_idle_cb (GsdCursorManager *manager)
+static void
+add_all_devices (GsdCursorManager *manager,
+                 GdkDevice        *exception)
+{
+        GdkDeviceManager *device_manager;
+        GList *devices, *l;
+
+        device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
+        devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE);
+        for (l = devices; l != NULL; l = l->next) {
+                GdkDevice *device = l->data;
+                if (device == exception)
+                        continue;
+                device_added_cb (device_manager, device, manager);
+        }
+        g_list_free (devices);
+}
+
+gboolean
+gsd_cursor_manager_start (GsdCursorManager *manager,
+                          GError               **error)
 {
         GdkDeviceManager *device_manager;
 
+        g_debug ("Starting cursor manager");
         gnome_settings_profile_start (NULL);
 
         if (supports_cursor_xfixes () == FALSE) {
                 g_debug ("XFixes cursor extension not available, will not hide the cursor");
+                initialize_root_cursor (manager);
                 return FALSE;
         }
 
         if (supports_xinput_devices () == FALSE) {
                 g_debug ("XInput support not available, will not hide the cursor");
+                initialize_root_cursor (manager);
                 return FALSE;
         }
 
-        /* We assume that the touchscreen is builtin and
-         * won't be appearing in the middle of the session... */
-        if (touchscreen_is_present () == FALSE) {
-                g_debug ("Did not find a touchscreen, will not hide the cursor");
-                gnome_settings_profile_end (NULL);
-                return FALSE;
-        }
-
-        update_cursor_for_current (manager);
+        /* Start by hiding the cursor, and then initialising the default
+         * root window cursor, as the window manager shouldn't do that. */
+        set_cursor_visibility (manager, FALSE);
+        initialize_root_cursor (manager);
 
         device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
         manager->priv->added_id = g_signal_connect (G_OBJECT (device_manager), "device-added",
@@ -301,19 +313,7 @@ gsd_cursor_manager_idle_cb (GsdCursorManager *manager)
         manager->priv->changed_id = g_signal_connect (G_OBJECT (device_manager), "device-changed",
                                                       G_CALLBACK (device_changed_cb), manager);
 
-        gnome_settings_profile_end (NULL);
-
-        return FALSE;
-}
-
-gboolean
-gsd_cursor_manager_start (GsdCursorManager *manager,
-                          GError               **error)
-{
-        g_debug ("Starting cursor manager");
-        gnome_settings_profile_start (NULL);
-
-        manager->priv->start_idle_id = g_idle_add ((GSourceFunc) gsd_cursor_manager_idle_cb, manager);
+        add_all_devices (manager, NULL);
 
         gnome_settings_profile_end (NULL);
 
@@ -344,23 +344,8 @@ gsd_cursor_manager_stop (GsdCursorManager *manager)
                 manager->priv->changed_id = 0;
         }
 
-        if (manager->priv->cursor_shown == FALSE) {
+        if (manager->priv->cursor_shown == FALSE)
                 set_cursor_visibility (manager, TRUE);
-        }
-}
-
-static GObject *
-gsd_cursor_manager_constructor (GType                  type,
-                                guint                  n_construct_properties,
-                                GObjectConstructParam *construct_properties)
-{
-        GsdCursorManager      *cursor_manager;
-
-        cursor_manager = GSD_CURSOR_MANAGER (G_OBJECT_CLASS (gsd_cursor_manager_parent_class)->constructor (type,
-                                                                                                            n_construct_properties,
-                                                                                                            construct_properties));
-
-        return G_OBJECT (cursor_manager);
 }
 
 static void
@@ -368,7 +353,6 @@ gsd_cursor_manager_class_init (GsdCursorManagerClass *klass)
 {
         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
-        object_class->constructor = gsd_cursor_manager_constructor;
         object_class->finalize = gsd_cursor_manager_finalize;
 
         g_type_class_add_private (klass, sizeof (GsdCursorManagerPrivate));
@@ -379,7 +363,10 @@ gsd_cursor_manager_init (GsdCursorManager *manager)
 {
         manager->priv = GSD_CURSOR_MANAGER_GET_PRIVATE (manager);
         manager->priv->cursor_shown = TRUE;
-
+        manager->priv->monitors = g_hash_table_new_full (g_direct_hash,
+                                                         g_direct_equal,
+                                                         NULL,
+                                                         g_object_unref);
 }
 
 static void
@@ -392,7 +379,7 @@ gsd_cursor_manager_finalize (GObject *object)
 
         cursor_manager = GSD_CURSOR_MANAGER (object);
 
-        g_return_if_fail (cursor_manager->priv != NULL);
+        g_clear_pointer (&cursor_manager->priv->monitors, g_hash_table_destroy);
 
         G_OBJECT_CLASS (gsd_cursor_manager_parent_class)->finalize (object);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]