From 026f9bc1846eae8fa98a307975fedce1f61d9cd5 Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Fri, 28 Sep 2012 08:24:05 +0200 Subject: [PATCH 19/68] Add hack to lock flow of scroll events to window where scroll started A bit evil but there is probably no other way, because this is very different from GDK's usual behavior. There's one quirk left, if you start a scroll and move to another GTK+ window in the same process and click, the click won't be processed until the folow of momentum events has ended. --- gdk/gdkwindow.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 1843873..1dac543 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -434,6 +434,10 @@ accumulate_get_window (GSignalInvocationHint *ihint, } static GQuark quark_pointer_window = 0; +#ifdef GDK_WINDOWING_QUARTZ +static GQuark quark_last_scroll_pointer_window = 0; +static GQuark quark_last_scroll_event_window = 0; +#endif /* GDK_WINDOWING_QUARTZ */ static void gdk_window_class_init (GdkWindowObjectClass *klass) @@ -478,6 +482,12 @@ gdk_window_class_init (GdkWindowObjectClass *klass) drawable_class->get_source_drawable = gdk_window_get_source_drawable; quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window"); +#ifdef GDK_WINDOWING_QUARTZ + quark_last_scroll_pointer_window = + g_quark_from_static_string ("gtk-last-scroll-pointer-window"); + quark_last_scroll_event_window = + g_quark_from_static_string ("gtk-last-scroll-event-window"); +#endif /* GDK_WINDOWING_QUARTZ */ /* Properties */ @@ -10702,6 +10712,64 @@ proxy_pointer_event (GdkDisplay *display, GDK_BUTTON4_MASK | \ GDK_BUTTON5_MASK) +#ifdef GDK_WINDOWING_QUARTZ +static void +last_scroll_event_weak_ref_notify (gpointer data, + GObject *where_the_object_was) +{ + /* If any of pointer_window or event_window is destroyed, we unset + * both values in the display's qdata. + */ + GdkDisplay *display = data; + + g_object_set_qdata (G_OBJECT (display), quark_last_scroll_pointer_window, + NULL); + g_object_set_qdata (G_OBJECT (display), quark_last_scroll_event_window, + NULL); +} + +static void +set_last_scroll_event_windows (GdkDisplay *display, + GdkWindow *pointer_window, + GdkWindow *event_window) +{ + GdkWindow *old_window; + + /* Check whether the values are still set from a previous scroll, + * if so we need to release the weak references. (If they are no + * longer set, we assume the weak ref notify callback was called). + */ + old_window = g_object_get_qdata (G_OBJECT (display), + quark_last_scroll_pointer_window); + if (old_window) + g_object_weak_unref (G_OBJECT (old_window), + last_scroll_event_weak_ref_notify, display); + + old_window = g_object_get_qdata (G_OBJECT (display), + quark_last_scroll_event_window); + if (old_window) + g_object_weak_unref (G_OBJECT (old_window), + last_scroll_event_weak_ref_notify, display); + + /* Set new values and setup weak references. Note that pointer_window + * and event_window can be NULL, in which case GDK won't proxy the + * event. In this case we store NULL into the qdata so that we won't + * store the scroll event. + */ + g_object_set_qdata (G_OBJECT (display), quark_last_scroll_pointer_window, + pointer_window); + if (pointer_window) + g_object_weak_ref (G_OBJECT (pointer_window), + last_scroll_event_weak_ref_notify, display); + + g_object_set_qdata (G_OBJECT (display), quark_last_scroll_event_window, + event_window); + if (event_window) + g_object_weak_ref (G_OBJECT (event_window), + last_scroll_event_weak_ref_notify, display); +} +#endif /* GDK_WINDOWING_QUARTZ */ + static gboolean proxy_button_event (GdkEvent *source_event, gulong serial) @@ -10769,6 +10837,32 @@ proxy_button_event (GdkEvent *source_event, type, state, NULL, serial); +#ifdef GDK_WINDOWING_QUARTZ + /* A Quartz-specific hack we cannot handle from within the backend + * unfortunately. For scroll events with precise deltas (i.e. these + * generated by the Mac touchpad or Magic Mouse, we want to lock the + * flow of events belonging to a single gesture to the window the + * gesture was started on. The default behavior of GDK, which insists + * to send events to the window under the pointer or discard the + * events when there's no GDK window under the pointer, makes it + * impossible to implement this differently. + */ + if (type == GDK_SCROLL && source_event->scroll.has_deltas) + { + if (source_event->scroll.phase == GDK_EVENT_SCROLL_PHASE_START) + { + set_last_scroll_event_windows (display, pointer_window, event_win); + } + else + { + pointer_window = g_object_get_qdata (G_OBJECT (display), + quark_last_scroll_pointer_window); + event_win = g_object_get_qdata (G_OBJECT (display), + quark_last_scroll_event_window); + } + } +#endif /* GDK_WINDOWING_QUARTZ */ + if (event_win == NULL || display->ignore_core_events) return TRUE; -- 1.7.10.2 (Apple Git-33)