diff options
author | Руслан Ижбулатов <lrn1986@gmail.com> | 2018-03-29 23:42:49 +0000 |
---|---|---|
committer | Руслан Ижбулатов <lrn1986@gmail.com> | 2018-03-29 23:59:31 +0000 |
commit | 795572710c99d7612bd7d71d538e8dab60d84309 (patch) | |
tree | d77151119bb2ab9ab8ba50a87b214ae9c20f9091 /gdk | |
parent | a82d67bb7d9290693e8d8c503e65694bb62b44ca (diff) | |
download | gtk+-795572710c99d7612bd7d71d538e8dab60d84309.tar.gz |
GDK W32: Remember surface cursor, implicit surface grablrn/issue-147
This commit ensures that each GdkSurface impl remembers the
cursor that GDK sets for it, and that this cursor is set
each time WM_SETCURSOR is called for that sufrace's HWND.
This is needed because W32, unlike X, has no per-window cursors -
the cursor on W32 is a global resource, and we need to keep track
of which cursor should be set when pointer is over which surface
ourselves (WM_SETCURSOR exists exactly for this reason).
This commit also makes GDK remember the surface that has an implicit
grab (since implicit grabs are gone from the upper levels of the toolkit),
and ensures that crossing events are correctly synthesized and the grab
is broken when surface focus changes. This fixes a bug where opening
a new window (by clicking something in some other, pre-existing window)
will make that new window not get any mouse input due to the fact
that the mouse-button-down event from that click caused an implicit
grab on the pre-existing window, and that grab was not released afterward.
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/win32/gdkdevice-virtual.c | 2 | ||||
-rw-r--r-- | gdk/win32/gdkevents-win32.c | 46 |
2 files changed, 36 insertions, 12 deletions
diff --git a/gdk/win32/gdkdevice-virtual.c b/gdk/win32/gdkdevice-virtual.c index 30fc95c884..0826ee3013 100644 --- a/gdk/win32/gdkdevice-virtual.c +++ b/gdk/win32/gdkdevice-virtual.c @@ -108,6 +108,8 @@ gdk_device_virtual_set_surface_cursor (GdkDevice *device, */ if (win32_hcursor != NULL) SetCursor (gdk_win32_hcursor_get_handle (win32_hcursor)); + + g_set_object (&GDK_SURFACE_IMPL_WIN32 (window->impl)->cursor, win32_hcursor); } static void diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 733a533888..685c5df185 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -126,6 +126,15 @@ static GSourceFuncs event_funcs = { NULL }; +/* Whenever we do an implicit grab (call SetCapture() after + * a mouse button is held down), we ref the capturing surface + * and keep that ref here. When mouse buttons are released, + * we remove the implicit grab and synthesize a crossing + * event from the grab surface to whatever surface is now + * under cursor. + */ +static GdkSurface *implicit_grab_surface = NULL; + static GdkSurface *mouse_window = NULL; static GdkSurface *mouse_window_ignored_leave = NULL; static gint current_x, current_y; @@ -2224,7 +2233,6 @@ gdk_event_translate (MSG *msg, POINT point; MINMAXINFO *mmi; HWND hwnd; - GdkCursor *cursor; BYTE key_state[256]; HIMC himc; WINDOWPOS *windowpos; @@ -2661,7 +2669,10 @@ gdk_event_translate (MSG *msg, if (pointer_grab == NULL) { SetCapture (GDK_SURFACE_HWND (window)); + g_set_object (&implicit_grab_surface, g_object_ref (window)); } + else + g_set_object (&implicit_grab_surface, NULL); generate_button_event (GDK_BUTTON_PRESS, button, window, msg); @@ -2694,15 +2705,13 @@ gdk_event_translate (MSG *msg, g_set_object (&window, find_window_for_mouse_event (window, msg)); - if (pointer_grab != NULL && pointer_grab->implicit) + if (pointer_grab == NULL && implicit_grab_surface != NULL) { gint state = build_pointer_event_state (msg); /* We keep the implicit grab until no buttons at all are held down */ if ((state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (button - 1))) == 0) { - GdkSurface *native_surface = pointer_grab->native_surface; - ReleaseCapture (); new_window = NULL; @@ -2718,16 +2727,19 @@ gdk_event_translate (MSG *msg, } synthesize_crossing_events (display, - native_surface, new_window, + implicit_grab_surface, new_window, GDK_CROSSING_UNGRAB, &msg->pt, 0, /* TODO: Set right mask */ msg->time, FALSE); + g_set_object (&implicit_grab_surface, NULL); g_set_object (&mouse_window, new_window); mouse_window_ignored_leave = NULL; } } + else + g_set_object (&implicit_grab_surface, NULL); generate_button_event (GDK_BUTTON_RELEASE, button, window, msg); @@ -3071,23 +3083,33 @@ gdk_event_translate (MSG *msg, if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT) break; - if (grab_window != NULL) + return_val = FALSE; + + if (grab_window != NULL && + !GDK_SURFACE_DESTROYED (grab_window)) { win32_display = GDK_WIN32_DISPLAY (gdk_surface_get_display (grab_window)); if (win32_display->grab_cursor != NULL) - cursor = win32_display->grab_cursor; + { + GDK_NOTE (EVENTS, g_print (" (grab SetCursor(%p)", gdk_win32_hcursor_get_handle (win32_display->grab_cursor))); + SetCursor (gdk_win32_hcursor_get_handle (win32_display->grab_cursor)); + return_val = TRUE; + *ret_valp = TRUE; + } } - else - cursor = NULL; - if (cursor != NULL) + if (!return_val && + !GDK_SURFACE_DESTROYED (window) && + GDK_SURFACE_IMPL_WIN32 (window->impl)->cursor != NULL) { - GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", cursor)); - SetCursor (g_hash_table_lookup (win32_display->cursors, cursor)); + win32_display = GDK_WIN32_DISPLAY (gdk_surface_get_display (window)); + GDK_NOTE (EVENTS, g_print (" (window SetCursor(%p)", gdk_win32_hcursor_get_handle (GDK_SURFACE_IMPL_WIN32 (window->impl)->cursor))); + SetCursor (gdk_win32_hcursor_get_handle (GDK_SURFACE_IMPL_WIN32 (window->impl)->cursor)); return_val = TRUE; *ret_valp = TRUE; } + break; case WM_SYSMENU: |