diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c index 18e12e554c..9dbf80043a 100644 --- a/gdk/win32/gdkdevicemanager-win32.c +++ b/gdk/win32/gdkdevicemanager-win32.c @@ -923,6 +923,54 @@ gdk_input_other_event (GdkDisplay *display, 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. */ @@ -932,14 +980,6 @@ gdk_input_other_event (GdkDisplay *display, 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) @@ -1113,18 +1153,20 @@ gdk_input_other_event (GdkDisplay *display, return TRUE; case WT_CSRCHANGE: + if (device_manager->dev_entered_proximity > 0) + device_manager->dev_entered_proximity -= 1; + if ((source_device = gdk_device_manager_find_wintab_device (device_manager, - (HCTX) msg->lParam, - packet.pkCursor)) == NULL) - return FALSE; + (HCTX) msg->lParam, + packet.pkCursor)) == NULL) + return FALSE; - if (gdk_device_get_mode (GDK_DEVICE (source_device)) == GDK_MODE_DISABLED) - 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; @@ -1132,10 +1174,19 @@ gdk_input_other_event (GdkDisplay *display, 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 ab82bbad73..8f71335ba8 100644 --- a/gdk/win32/gdkdevicemanager-win32.h +++ b/gdk/win32/gdkdevicemanager-win32.h @@ -41,6 +41,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 a4b40dabf0..44413081df 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -408,7 +408,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_device_manager = g_object_new (GDK_TYPE_DEVICE_MANAGER_WIN32, NULL); diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 1cba4c4fd9..e850eed19e 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -1872,7 +1872,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_device_manager); @@ -2932,7 +2932,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 0af85d6149..35cc221b85 100644 --- a/gdk/win32/gdkglobals-win32.c +++ b/gdk/win32/gdkglobals-win32.c @@ -36,7 +36,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 ccfc601c4c..6834562815 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -273,7 +273,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.