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
This commit is contained in:
Руслан Ижбулатов 2017-02-10 10:49:00 +00:00
parent 3c9b667d3e
commit d7e2017c28
6 changed files with 83 additions and 26 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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.