diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index 44cee62b4a..d7ec27cec5 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -69,7 +69,6 @@ gdk_get_use_xshm gdk_set_use_xshm #endif gdk_keyboard_grab -gdk_pointer_grab #endif #endif @@ -715,6 +714,7 @@ gdk_window_set_user_data gdk_window_thaw_toplevel_updates_libgtk_only gdk_window_thaw_updates gdk_window_set_composited +gdk_pointer_grab #endif #endif diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 288f518f6d..b6da9bb1dd 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -453,6 +453,13 @@ GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display, gint *win_x, gint *win_y, GdkModifierType *mask); +GdkGrabStatus _gdk_windowing_pointer_grab (GdkWindow *window, + GdkWindow *native, + gboolean owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + GdkCursor *cursor, + guint32 time); void _gdk_windowing_got_event (GdkDisplay *display, GList *event_link, GdkEvent *event, diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 178a4eca20..76a9f82aee 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -8434,6 +8434,112 @@ _gdk_display_set_window_under_pointer (GdkDisplay *display, _gdk_display_enable_motion_hints (display); } +static GdkWindow * +gdk_window_get_offscreen_parent (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindow *res; + + res = NULL; + g_signal_emit_by_name (private->impl_window, + "get-offscreen-parent", + &res); + + return res; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ +GdkGrabStatus +gdk_pointer_grab (GdkWindow * window, + gboolean owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + GdkWindow *native; + GdkDisplay *display; + GdkGrabStatus res; + gulong serial; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); + + /* We need a native window for confine to to work, ensure we have one */ + if (confine_to) + { + if (!gdk_window_ensure_native (confine_to)) + { + g_warning ("Can't confine to grabbed window, not native"); + confine_to = NULL; + } + } + + /* Non-viewable client side window => fail */ + if (!_gdk_window_has_impl (window) && + !gdk_window_is_viewable (window)) + return GDK_GRAB_NOT_VIEWABLE; + + native = gdk_window_get_toplevel (window); + while (gdk_window_is_offscreen ((GdkWindowObject *)native)) + { + native = gdk_window_get_offscreen_parent (native); + + if (native == NULL || + (!_gdk_window_has_impl (native) && + !gdk_window_is_viewable (native))) + return GDK_GRAB_NOT_VIEWABLE; + + native = gdk_window_get_toplevel (native); + } + + display = gdk_drawable_get_display (window); + + serial = _gdk_windowing_window_get_next_serial (display); + + res = _gdk_windowing_pointer_grab (window, + native, + owner_events, + event_mask, + confine_to, + cursor, + time); + + if (res == GDK_GRAB_SUCCESS) + _gdk_display_add_pointer_grab (display, + window, + native, + owner_events, + event_mask, + serial, + time, + FALSE); + + return res; +} + void gdk_window_set_has_offscreen_children (GdkWindow *window, gboolean has_offscreen_children) diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index 471a8f2b3c..f12c7094b8 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -138,16 +138,6 @@ gdk_x11_convert_grab_status (gint status) return 0; } -struct XPointerGrabInfo { - GdkDisplay *display; - GdkWindow *window; - GdkWindow *native_window; - gboolean owner_events; - gulong serial; - guint event_mask; - guint32 time; -}; - static void has_pointer_grab_callback (GdkDisplay *display, gpointer data, @@ -156,81 +146,38 @@ has_pointer_grab_callback (GdkDisplay *display, _gdk_display_pointer_grab_update (display, serial); } -/* - *-------------------------------------------------------------- - * gdk_pointer_grab - * - * Grabs the pointer to a specific window - * - * Arguments: - * "window" is the window which will receive the grab - * "owner_events" specifies whether events will be reported as is, - * or relative to "window" - * "event_mask" masks only interesting events - * "confine_to" limits the cursor movement to the specified window - * "cursor" changes the cursor for the duration of the grab - * "time" specifies the time - * - * Results: - * - * Side effects: - * requires a corresponding call to gdk_pointer_ungrab - * - *-------------------------------------------------------------- - */ - GdkGrabStatus -gdk_pointer_grab (GdkWindow * window, - gboolean owner_events, - GdkEventMask event_mask, - GdkWindow * confine_to, - GdkCursor * cursor, - guint32 time) +_gdk_windowing_pointer_grab (GdkWindow *window, + GdkWindow *native, + gboolean owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + GdkCursor *cursor, + guint32 time) { gint return_val; GdkCursorPrivate *cursor_private; - GdkWindow *native; GdkDisplayX11 *display_x11; guint xevent_mask; Window xwindow; Window xconfine_to; Cursor xcursor; - unsigned long serial; int i; - - g_return_val_if_fail (window != NULL, 0); - g_return_val_if_fail (GDK_IS_WINDOW (window), 0); - g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); - native = gdk_window_get_toplevel (window); - - /* We need a native window for confine to to work, ensure we have one */ - if (confine_to) - gdk_window_ensure_native (confine_to); - - /* TODO: What do we do for offscreens and their children? We need to proxy the grab somehow */ - if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl)) - return GDK_GRAB_SUCCESS; - - if (!_gdk_window_has_impl (window) && - !gdk_window_is_viewable (window)) - return GDK_GRAB_NOT_VIEWABLE; - if (confine_to) confine_to = _gdk_window_get_impl_window (confine_to); display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native)); cursor_private = (GdkCursorPrivate*) cursor; - + xwindow = GDK_WINDOW_XID (native); - serial = NextRequest (GDK_WINDOW_XDISPLAY (native)); - + if (!confine_to || GDK_WINDOW_DESTROYED (confine_to)) xconfine_to = None; else xconfine_to = GDK_WINDOW_XID (confine_to); - + if (!cursor) xcursor = None; else @@ -238,7 +185,7 @@ gdk_pointer_grab (GdkWindow * window, _gdk_x11_cursor_update_theme (cursor); xcursor = cursor_private->xcursor; } - + xevent_mask = 0; for (i = 0; i < _gdk_nenvent_masks; i++) { @@ -250,7 +197,7 @@ gdk_pointer_grab (GdkWindow * window, * hints. If we set a native one we just wouldn't get any events. */ xevent_mask &= ~PointerMotionHintMask; - + return_val = _gdk_input_grab_pointer (window, native, owner_events, @@ -258,7 +205,7 @@ gdk_pointer_grab (GdkWindow * window, confine_to, time); - if (return_val == GrabSuccess || + if (return_val == GrabSuccess || G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed)) { if (!GDK_WINDOW_DESTROYED (native)) @@ -280,22 +227,11 @@ gdk_pointer_grab (GdkWindow * window, else return_val = AlreadyGrabbed; } - - if (return_val == GrabSuccess) - { - _gdk_display_add_pointer_grab (GDK_DISPLAY_OBJECT (display_x11), - window, - native, - owner_events, - event_mask, - serial, - time, - FALSE); - _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11), - has_pointer_grab_callback, - NULL); - } + if (return_val == GrabSuccess) + _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11), + has_pointer_grab_callback, + NULL); return gdk_x11_convert_grab_status (return_val); }