[gtk+/gtk-3-22] GDK W32: Handle drivers that do not send WT_CSRCHANGE after WT_PROXIMITY



commit f9df0fc94c7b83f598b1dabedf5b45e09c0c6c47
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date:   Fri Feb 10 10:49:00 2017 +0000

    GDK W32: Handle drivers that do not send WT_CSRCHANGE after WT_PROXIMITY
    
    Some drivers don't do that (not sure whether that is the correct behaviour
    or not). Remember each WT_PROXIMITY with LOWORD(lParam) != 0 that we get,
    then look for a WT_CSRCHANGE. If WT_CSRCHANGE doesn't come, but a WT_PACKET
    does, assume that this device is the one that sent WT_PROXIMITY.
    
    Also include fallback code to ensure that WT_PACKETs for an enabled device
    disable the system pointer, because WT_PROXIMITY handler might have
    enabled it by mistake, since it's not possible to know which device left
    the proximity (it might have been a disabled device).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778328

 gdk/win32/gdkdevicemanager-win32.c |   93 ++++++++++++++++++++++++++++--------
 gdk/win32/gdkdevicemanager-win32.h |    6 ++
 gdk/win32/gdkdisplay-win32.c       |    2 +-
 gdk/win32/gdkevents-win32.c        |    4 +-
 gdk/win32/gdkglobals-win32.c       |    2 +-
 gdk/win32/gdkprivate-win32.h       |    2 +-
 6 files changed, 83 insertions(+), 26 deletions(-)
---
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
index 73ba2ad..c474074 100644
--- a/gdk/win32/gdkdevicemanager-win32.c
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -990,6 +990,54 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
   switch (msg->message)
     {
     case WT_PACKET:
+      source_device = gdk_device_manager_find_wintab_device (device_manager,
+                                                            (HCTX) msg->lParam,
+                                                            packet.pkCursor);
+
+      /* Check this first, as we get WT_PROXIMITY for disabled devices too */
+      if (device_manager->dev_entered_proximity > 0)
+       {
+         /* This is the same code as in WT_CSRCHANGE. Some drivers send
+          * WT_CSRCHANGE after each WT_PROXIMITY with LOWORD(lParam) != 0,
+          * this code is for those that don't.
+          */
+         device_manager->dev_entered_proximity -= 1;
+
+         if (source_device != NULL &&
+             source_device->sends_core &&
+             gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED)
+           {
+             _gdk_device_virtual_set_active (device_manager->core_pointer,
+                                             GDK_DEVICE (source_device));
+             _gdk_input_ignore_core += 1;
+           }
+       }
+      else if (source_device != NULL &&
+              source_device->sends_core &&
+              gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED &&
+               _gdk_input_ignore_core == 0)
+        {
+          /* A fallback for cases when two devices (disabled and enabled)
+           * were in proximity simultaneously.
+           * In this case the removal of a disabled device would also
+           * make the system pointer active, as we don't know which
+           * device was removed and assume it was the enabled one.
+           * If we are still getting packets for the enabled device,
+           * it means that the device that was removed was the disabled
+           * device, so we must make the enabled device active again and
+           * start ignoring the core pointer events. In practice this means that
+           * removing a disabled device while an enabled device is still
+           * in proximity might briefly make the core pointer active/visible.
+           */
+         _gdk_device_virtual_set_active (device_manager->core_pointer,
+                                         GDK_DEVICE (source_device));
+         _gdk_input_ignore_core += 1;
+        }
+
+      if (source_device == NULL ||
+         gdk_device_get_mode (GDK_DEVICE (source_device)) == GDK_MODE_DISABLED)
+       return FALSE;
+
       /* Don't produce any button or motion events while a window is being
        * moved or resized, see bug #151090.
        */
@@ -999,14 +1047,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
           return FALSE;
         }
 
-      if ((source_device = gdk_device_manager_find_wintab_device (device_manager,
-                                                                  (HCTX) msg->lParam,
-                                                                  packet.pkCursor)) == NULL)
-        return FALSE;
-
-      if (gdk_device_get_mode (GDK_DEVICE (source_device)) == GDK_MODE_DISABLED)
-        return FALSE;
-
       last_grab = _gdk_display_get_last_device_grab (display, GDK_DEVICE (source_device));
 
       if (last_grab && last_grab->window)
@@ -1180,18 +1220,20 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
       return TRUE;
 
     case WT_CSRCHANGE:
-      if ((source_device = gdk_device_manager_find_wintab_device (device_manager,
-                                                                  (HCTX) msg->lParam,
-                                                                  packet.pkCursor)) == NULL)
-        return FALSE;
+      if (device_manager->dev_entered_proximity > 0)
+       device_manager->dev_entered_proximity -= 1;
 
-      if (gdk_device_get_mode (GDK_DEVICE (source_device)) == GDK_MODE_DISABLED)
-        return FALSE;
+      if ((source_device = gdk_device_manager_find_wintab_device (device_manager,
+                                                                 (HCTX) msg->lParam,
+                                                                 packet.pkCursor)) == NULL)
+       return FALSE;
 
-      if (source_device->sends_core)
+      if (source_device->sends_core &&
+         gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED)
        {
-         _gdk_device_virtual_set_active (device_manager->core_pointer, GDK_DEVICE (source_device));
-         _gdk_input_ignore_core = TRUE;
+         _gdk_device_virtual_set_active (device_manager->core_pointer,
+                                         GDK_DEVICE (source_device));
+         _gdk_input_ignore_core += 1;
        }
 
       return FALSE;
@@ -1199,10 +1241,19 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
     case WT_PROXIMITY:
       if (LOWORD (msg->lParam) == 0)
         {
-         _gdk_input_ignore_core = FALSE;
-         _gdk_device_virtual_set_active (device_manager->core_pointer,
-                                         device_manager->system_pointer);
-        }
+          if (_gdk_input_ignore_core > 0)
+            {
+             _gdk_input_ignore_core -= 1;
+
+             if (_gdk_input_ignore_core == 0)
+               _gdk_device_virtual_set_active (device_manager->core_pointer,
+                                               device_manager->system_pointer);
+           }
+       }
+      else
+       {
+         device_manager->dev_entered_proximity += 1;
+       }
 
       return FALSE;
     }
diff --git a/gdk/win32/gdkdevicemanager-win32.h b/gdk/win32/gdkdevicemanager-win32.h
index 08bc4f5..36a7cef 100644
--- a/gdk/win32/gdkdevicemanager-win32.h
+++ b/gdk/win32/gdkdevicemanager-win32.h
@@ -42,6 +42,12 @@ struct _GdkDeviceManagerWin32
   GdkDevice *system_pointer;
   GdkDevice *system_keyboard;
   GList *wintab_devices;
+
+  /* Bumped up every time a wintab device enters the proximity
+   * of our context (WT_PROXIMITY). Bumped down when we either
+   * receive a WT_PACKET, or a WT_CSRCHANGE.
+   */
+  gint dev_entered_proximity;
 };
 
 struct _GdkDeviceManagerWin32Class
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index b72b1c7..da5f2cf 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -404,7 +404,7 @@ _gdk_win32_display_open (const gchar *display_name)
 
   _gdk_events_init (_gdk_display);
 
-  _gdk_input_ignore_core = FALSE;
+  _gdk_input_ignore_core = 0;
 
   _gdk_display->device_manager = g_object_new (GDK_TYPE_DEVICE_MANAGER_WIN32,
                                                "display", _gdk_display,
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 6dc379f..6601a95 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1834,7 +1834,7 @@ generate_button_event (GdkEventType      type,
   GdkDeviceManagerWin32 *device_manager;
   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
-  if (_gdk_input_ignore_core)
+  if (_gdk_input_ignore_core > 0)
     return;
 
   device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (gdk_display_get_default ()));
@@ -2936,7 +2936,7 @@ gdk_event_translate (MSG  *msg,
         {
           gdk_win32_window_do_move_resize_drag (window, current_root_x, current_root_y);
         }
-      else if (!_gdk_input_ignore_core)
+      else if (_gdk_input_ignore_core == 0)
        {
          event = gdk_event_new (GDK_MOTION_NOTIFY);
          event->motion.window = window;
diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c
index 2398ca1..cb352a4 100644
--- a/gdk/win32/gdkglobals-win32.c
+++ b/gdk/win32/gdkglobals-win32.c
@@ -35,7 +35,7 @@ HDC             _gdk_display_hdc;
 HINSTANCE        _gdk_dll_hinstance;
 HINSTANCE        _gdk_app_hmodule;
 
-gboolean         _gdk_input_ignore_core;
+gint             _gdk_input_ignore_core;
 
 HKL              _gdk_input_locale;
 gboolean         _gdk_input_locale_is_ime;
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index 09010b2..27aec8e 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -285,7 +285,7 @@ extern HDC           _gdk_display_hdc;
 extern HINSTANCE        _gdk_dll_hinstance;
 extern HINSTANCE        _gdk_app_hmodule;
 
-extern gboolean                 _gdk_input_ignore_core;
+extern gint             _gdk_input_ignore_core;
 
 /* These are thread specific, but GDK/win32 works OK only when invoked
  * from a single thread anyway.


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