Commit 02ed1e9b authored by Matthias Clasen's avatar Matthias Clasen Committed by Matthias Clasen

Make GTK+ work as an untrusted X client. (#136571, Ed Catmur)

2006-05-25  Matthias Clasen  <mclasen@redhat.com>

	Make GTK+ work as an untrusted X client. (#136571,
	Ed Catmur)
parent 685d8ecf
2006-05-25 Matthias Clasen <mclasen@redhat.com>
Make GTK+ work as an untrusted X client. (#136571,
Ed Catmur)
* gdk/x11/gdkdisplay-x11.h:
* gdk/x11/gdkdisplay-x11.c (gdk_display_open): When
opening a display, determine if we are untrusted.
* gdk/x11/gdkdisplay-x11.c (gdk_notify_startup_complete):
Just bail out when we are untrusted.
* gdk/x11/gdkwindow-x11.c (gdk_window_new): Work around
a bug in the Xorg XSECURITY implementation by coercing
toplevel InputOnly windows to InputOutput.
* gdk/x11/gdkwindow-x11.c (_gdk_windowing_get_pointer):
(_gdk_windowing_window_get_pointer):
When untrusted, call XQueryPointer on an auxiliary
window, not on the root window.
* gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_at_pointer):
If untrusted, loop through all GDK-aware toplevels on all
screens in the hope we hit one containing the pointer;
then use that as the basis of the current XQueryPointer
child recursion.
* gdk/x11/gdkmain-x11.c (gdk_pointer_grab):
(gdk_keyboard_grab): Ignore failed grabs when untrusted.
* gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Only
cache our own toplevels when untrusted.
* gdk/x11/gdkdnd-x11.c (motif_send_enter): Don't try
to do Motif DND as untrusted client.
* gdk/x11/gdkevents-x11.c (fetch_net_wm_check_window):
(gdk_x11_screen_get_window_manager_name):
(gdk_x11_screen_supports_net_wm_hint):
Bail out early if untrusted.
* gtk/gtkcolorsel.c (grab_color_at_mouse): If getting
the color under the pointer by screenshooting the root
window fails, it tries to get the color from our own
window.
* gtk/gtkcolorsel.c (get_screen_color): Make the
dropper_grab_widget a child of the dialog, not a
toplevel.
* gtk/gtkinvisible.c (gtk_invisible_realize): Respect
a parent window that has been set before realizing.
* gtk/gtkwidget.c (gtk_widget_get_parent_window):
Always return a previously set parent window.
2006-05-24 Matthias Clasen <mclasen@redhat.com> 2006-05-24 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfontbutton.c (gtk_font_button_clicked): * gtk/gtkfontbutton.c (gtk_font_button_clicked):
......
2006-05-25 Matthias Clasen <mclasen@redhat.com>
Make GTK+ work as an untrusted X client. (#136571,
Ed Catmur)
* gdk/x11/gdkdisplay-x11.h:
* gdk/x11/gdkdisplay-x11.c (gdk_display_open): When
opening a display, determine if we are untrusted.
* gdk/x11/gdkdisplay-x11.c (gdk_notify_startup_complete):
Just bail out when we are untrusted.
* gdk/x11/gdkwindow-x11.c (gdk_window_new): Work around
a bug in the Xorg XSECURITY implementation by coercing
toplevel InputOnly windows to InputOutput.
* gdk/x11/gdkwindow-x11.c (_gdk_windowing_get_pointer):
(_gdk_windowing_window_get_pointer):
When untrusted, call XQueryPointer on an auxiliary
window, not on the root window.
* gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_at_pointer):
If untrusted, loop through all GDK-aware toplevels on all
screens in the hope we hit one containing the pointer;
then use that as the basis of the current XQueryPointer
child recursion.
* gdk/x11/gdkmain-x11.c (gdk_pointer_grab):
(gdk_keyboard_grab): Ignore failed grabs when untrusted.
* gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Only
cache our own toplevels when untrusted.
* gdk/x11/gdkdnd-x11.c (motif_send_enter): Don't try
to do Motif DND as untrusted client.
* gdk/x11/gdkevents-x11.c (fetch_net_wm_check_window):
(gdk_x11_screen_get_window_manager_name):
(gdk_x11_screen_supports_net_wm_hint):
Bail out early if untrusted.
* gtk/gtkcolorsel.c (grab_color_at_mouse): If getting
the color under the pointer by screenshooting the root
window fails, it tries to get the color from our own
window.
* gtk/gtkcolorsel.c (get_screen_color): Make the
dropper_grab_widget a child of the dialog, not a
toplevel.
* gtk/gtkinvisible.c (gtk_invisible_realize): Respect
a parent window that has been set before realizing.
* gtk/gtkwidget.c (gtk_widget_get_parent_window):
Always return a previously set parent window.
2006-05-24 Matthias Clasen <mclasen@redhat.com> 2006-05-24 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfontbutton.c (gtk_font_button_clicked): * gtk/gtkfontbutton.c (gtk_font_button_clicked):
......
...@@ -219,6 +219,24 @@ gdk_display_open (const gchar *display_name) ...@@ -219,6 +219,24 @@ gdk_display_open (const gchar *display_name)
} }
#endif #endif
display_x11->trusted_client = TRUE;
{
Window root, child;
int rootx, rooty, winx, winy;
unsigned int xmask;
gdk_error_trap_push ();
XQueryPointer (display_x11->xdisplay,
GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
gdk_flush ();
if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow))
{
g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
display_x11->trusted_client = FALSE;
}
}
if (_gdk_synchronize) if (_gdk_synchronize)
XSynchronize (display_x11->xdisplay, True); XSynchronize (display_x11->xdisplay, True);
...@@ -1056,6 +1074,9 @@ gdk_notify_startup_complete (void) ...@@ -1056,6 +1074,9 @@ gdk_notify_startup_complete (void)
if (display_x11->startup_notification_id == NULL) if (display_x11->startup_notification_id == NULL)
return; return;
if (!G_LIKELY (display_x11->trusted_client))
return;
escaped_id = escape_for_xmessage (display_x11->startup_notification_id); escaped_id = escape_for_xmessage (display_x11->startup_notification_id);
message = g_strdup_printf ("remove: ID=%s", escaped_id); message = g_strdup_printf ("remove: ID=%s", escaped_id);
g_free (escaped_id); g_free (escaped_id);
......
...@@ -81,6 +81,11 @@ struct _GdkDisplayX11 ...@@ -81,6 +81,11 @@ struct _GdkDisplayX11
gboolean have_xfixes; gboolean have_xfixes;
gint xfixes_event_base; gint xfixes_event_base;
/* If the SECURITY extension is in place, whether this client holds
* a trusted authorization and so is allowed to make various requests
* (grabs, properties etc.) Otherwise always TRUE. */
gboolean trusted_client;
/* Information about current pointer and keyboard grabs held by this /* Information about current pointer and keyboard grabs held by this
* client. If gdk_pointer_xgrab_window or gdk_keyboard_xgrab_window * client. If gdk_pointer_xgrab_window or gdk_keyboard_xgrab_window
* window is NULL, then the other associated fields are ignored * window is NULL, then the other associated fields are ignored
......
...@@ -460,6 +460,25 @@ gdk_window_cache_new (GdkScreen *screen) ...@@ -460,6 +460,25 @@ gdk_window_cache_new (GdkScreen *screen)
XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa); XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
result->old_event_mask = xwa.your_event_mask; result->old_event_mask = xwa.your_event_mask;
if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client))
{
GList *toplevel_windows, *list;
GdkWindow *window;
gint x, y, width, height;
toplevel_windows = gdk_screen_get_toplevel_windows (screen);
for (list = toplevel_windows; list; list = list->next) {
window = GDK_WINDOW (list->data);
gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
gdk_window_cache_add (result, GDK_WINDOW_XID (window),
x, y, width, height,
gdk_window_is_visible (window));
}
g_list_free (toplevel_windows);
return result;
}
XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window), XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
result->old_event_mask | SubstructureNotifyMask); result->old_event_mask | SubstructureNotifyMask);
gdk_window_add_filter (root_window, gdk_window_cache_filter, result); gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
...@@ -1287,6 +1306,9 @@ motif_send_enter (GdkDragContext *context, ...@@ -1287,6 +1306,9 @@ motif_send_enter (GdkDragContext *context,
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window); GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
XEvent xev; XEvent xev;
if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
return; /* Motif Dnd requires getting properties on the root window */
xev.xclient.type = ClientMessage; xev.xclient.type = ClientMessage;
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE"); xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
xev.xclient.format = 8; xev.xclient.format = 8;
......
...@@ -2574,6 +2574,8 @@ fetch_net_wm_check_window (GdkScreen *screen) ...@@ -2574,6 +2574,8 @@ fetch_net_wm_check_window (GdkScreen *screen)
screen_x11 = GDK_SCREEN_X11 (screen); screen_x11 = GDK_SCREEN_X11 (screen);
display = screen_x11->display; display = screen_x11->display;
g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
if (screen_x11->wmspec_check_window != None) if (screen_x11->wmspec_check_window != None)
return; /* already have it */ return; /* already have it */
...@@ -2631,6 +2633,9 @@ gdk_x11_screen_get_window_manager_name (GdkScreen *screen) ...@@ -2631,6 +2633,9 @@ gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
screen_x11 = GDK_SCREEN_X11 (screen); screen_x11 = GDK_SCREEN_X11 (screen);
if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
return screen_x11->window_manager_name;
fetch_net_wm_check_window (screen); fetch_net_wm_check_window (screen);
if (screen_x11->need_refetch_wm_name) if (screen_x11->need_refetch_wm_name)
...@@ -2726,6 +2731,9 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen, ...@@ -2726,6 +2731,9 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
screen_x11 = GDK_SCREEN_X11 (screen); screen_x11 = GDK_SCREEN_X11 (screen);
display = screen_x11->display; display = screen_x11->display;
if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
return FALSE;
supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms"); supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
if (!supported_atoms) if (!supported_atoms)
{ {
......
...@@ -191,6 +191,7 @@ gdk_pointer_grab (GdkWindow * window, ...@@ -191,6 +191,7 @@ gdk_pointer_grab (GdkWindow * window,
{ {
gint return_val; gint return_val;
GdkCursorPrivate *cursor_private; GdkCursorPrivate *cursor_private;
GdkDisplayX11 *display_x11;
guint xevent_mask; guint xevent_mask;
Window xwindow; Window xwindow;
Window xconfine_to; Window xconfine_to;
...@@ -202,6 +203,8 @@ gdk_pointer_grab (GdkWindow * window, ...@@ -202,6 +203,8 @@ gdk_pointer_grab (GdkWindow * window,
g_return_val_if_fail (GDK_IS_WINDOW (window), 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); g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
cursor_private = (GdkCursorPrivate*) cursor; cursor_private = (GdkCursorPrivate*) cursor;
xwindow = GDK_WINDOW_XID (window); xwindow = GDK_WINDOW_XID (window);
...@@ -233,7 +236,8 @@ gdk_pointer_grab (GdkWindow * window, ...@@ -233,7 +236,8 @@ gdk_pointer_grab (GdkWindow * window,
confine_to, confine_to,
time); time);
if (return_val == GrabSuccess) if (return_val == GrabSuccess ||
G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
{ {
if (!GDK_WINDOW_DESTROYED (window)) if (!GDK_WINDOW_DESTROYED (window))
{ {
...@@ -257,7 +261,6 @@ gdk_pointer_grab (GdkWindow * window, ...@@ -257,7 +261,6 @@ gdk_pointer_grab (GdkWindow * window,
if (return_val == GrabSuccess) if (return_val == GrabSuccess)
{ {
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
if (display_x11->pointer_xgrab_window != NULL && if (display_x11->pointer_xgrab_window != NULL &&
display_x11->pointer_xgrab_window != (GdkWindowObject *)window) display_x11->pointer_xgrab_window != (GdkWindowObject *)window)
generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
...@@ -338,10 +341,13 @@ gdk_keyboard_grab (GdkWindow * window, ...@@ -338,10 +341,13 @@ gdk_keyboard_grab (GdkWindow * window,
{ {
gint return_val; gint return_val;
unsigned long serial; unsigned long serial;
GdkDisplayX11 *display_x11;
g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (window != NULL, 0);
g_return_val_if_fail (GDK_IS_WINDOW (window), 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
serial = NextRequest (GDK_WINDOW_XDISPLAY (window)); serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
if (!GDK_WINDOW_DESTROYED (window)) if (!GDK_WINDOW_DESTROYED (window))
...@@ -356,13 +362,16 @@ gdk_keyboard_grab (GdkWindow * window, ...@@ -356,13 +362,16 @@ gdk_keyboard_grab (GdkWindow * window,
owner_events, owner_events,
GrabModeAsync, GrabModeAsync, GrabModeAsync, GrabModeAsync,
time); time);
if (G_UNLIKELY (!display_x11->trusted_client &&
return_val == AlreadyGrabbed))
/* we can't grab the keyboard, but we can do a GTK-local grab */
return_val = GrabSuccess;
} }
else else
return_val = AlreadyGrabbed; return_val = AlreadyGrabbed;
if (return_val == GrabSuccess) if (return_val == GrabSuccess)
{ {
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
if (display_x11->keyboard_xgrab_window != NULL && if (display_x11->keyboard_xgrab_window != NULL &&
display_x11->keyboard_xgrab_window != (GdkWindowObject *)window) display_x11->keyboard_xgrab_window != (GdkWindowObject *)window)
generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
......
...@@ -88,6 +88,7 @@ static void gdk_window_add_colormap_windows (GdkWindow *window); ...@@ -88,6 +88,7 @@ static void gdk_window_add_colormap_windows (GdkWindow *window);
static void set_wm_name (GdkDisplay *display, static void set_wm_name (GdkDisplay *display,
Window xwindow, Window xwindow,
const gchar *name); const gchar *name);
static void move_to_current_desktop (GdkWindow *window);
static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable); static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable);
static void gdk_window_impl_x11_set_colormap (GdkDrawable *drawable, static void gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
...@@ -731,6 +732,17 @@ gdk_window_new (GdkWindow *parent, ...@@ -731,6 +732,17 @@ gdk_window_new (GdkWindow *parent,
else else
private->window_type = attributes->window_type; private->window_type = attributes->window_type;
/* Work around a bug where Xorg refuses to map toplevel InputOnly windows
* from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988
*/
if (attributes->wclass == GDK_INPUT_ONLY &&
GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT &&
!G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client))
{
g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server");
attributes->wclass = GDK_INPUT_OUTPUT;
}
_gdk_window_init_position (GDK_WINDOW (private)); _gdk_window_init_position (GDK_WINDOW (private));
if (impl->position_info.big) if (impl->position_info.big)
private->guffaw_gravity = TRUE; private->guffaw_gravity = TRUE;
...@@ -2007,7 +2019,13 @@ gdk_x11_window_move_to_current_desktop (GdkWindow *window) ...@@ -2007,7 +2019,13 @@ gdk_x11_window_move_to_current_desktop (GdkWindow *window)
if (toplevel->on_all_desktops) if (toplevel->on_all_desktops)
return; return;
move_to_current_desktop (window);
}
static void
move_to_current_desktop (GdkWindow *window)
{
if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
gdk_atom_intern_static_string ("_NET_WM_DESKTOP"))) gdk_atom_intern_static_string ("_NET_WM_DESKTOP")))
{ {
...@@ -3428,6 +3446,8 @@ _gdk_windowing_get_pointer (GdkDisplay *display, ...@@ -3428,6 +3446,8 @@ _gdk_windowing_get_pointer (GdkDisplay *display,
GdkModifierType *mask) GdkModifierType *mask)
{ {
GdkScreen *default_screen; GdkScreen *default_screen;
Display *xdisplay;
Window xwindow;
Window root = None; Window root = None;
Window child; Window child;
int rootx, rooty; int rootx, rooty;
...@@ -3439,10 +3459,27 @@ _gdk_windowing_get_pointer (GdkDisplay *display, ...@@ -3439,10 +3459,27 @@ _gdk_windowing_get_pointer (GdkDisplay *display,
return; return;
default_screen = gdk_display_get_default_screen (display); default_screen = gdk_display_get_default_screen (display);
xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
xwindow = GDK_SCREEN_XROOTWIN (default_screen);
XQueryPointer (GDK_SCREEN_XDISPLAY (default_screen), if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
GDK_SCREEN_XROOTWIN (default_screen), {
&root, &child, &rootx, &rooty, &winx, &winy, &xmask); XQueryPointer (xdisplay, xwindow,
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
}
else
{
XSetWindowAttributes attributes;
Window w;
w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
CopyFromParent, InputOnly, CopyFromParent,
0, &attributes);
XQueryPointer (xdisplay, w,
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
XDestroyWindow (xdisplay, w);
}
if (root != None) if (root != None)
{ {
...@@ -3476,13 +3513,28 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, ...@@ -3476,13 +3513,28 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display,
_gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
return_val = NULL; return_val = NULL;
if (!GDK_WINDOW_DESTROYED (window) && if (!GDK_WINDOW_DESTROYED (window))
XQueryPointer (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
&root, &child, &rootx, &rooty, &winx, &winy, &xmask))
{ {
if (child) if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child); {
if (XQueryPointer (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
&root, &child, &rootx, &rooty, &winx, &winy, &xmask))
{
if (child)
return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child);
}
}
else
{
GdkScreen *screen;
int originx, originy;
_gdk_windowing_get_pointer (gdk_drawable_get_display (window), &screen,
&rootx, &rooty, &xmask);
gdk_window_get_origin (window, &originx, &originy);
winx = rootx - originx;
winy = rooty - originy;
}
} }
*x = winx + xoffset; *x = winx + xoffset;
...@@ -3555,24 +3607,89 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, ...@@ -3555,24 +3607,89 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
* and the result. * and the result.
*/ */
gdk_x11_display_grab (display); gdk_x11_display_grab (display);
XQueryPointer (xdisplay, xwindow, if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
if (root == xwindow)
xwindow = child;
else
xwindow = root;
while (xwindow)
{ {
xwindow_last = xwindow;
XQueryPointer (xdisplay, xwindow, XQueryPointer (xdisplay, xwindow,
&root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask); &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
if (root == xwindow)
xwindow = child;
else
xwindow = root;
while (xwindow)
{
xwindow_last = xwindow;
XQueryPointer (xdisplay, xwindow,
&root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
}
}
else
{
gint i, screens, width, height;
GList *toplevels, *list;
Window pointer_window;
pointer_window = None;
screens = gdk_display_get_n_screens (display);
for (i = 0; i < screens; ++i) {
screen = gdk_display_get_screen (display, i);
toplevels = gdk_screen_get_toplevel_windows (screen);
for (list = toplevels; list != NULL; list = g_list_next (list)) {
window = GDK_WINDOW (list->data);
xwindow = GDK_WINDOW_XWINDOW (window);
gdk_error_trap_push ();
XQueryPointer (xdisplay, xwindow,
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
gdk_flush ();
if (gdk_error_trap_pop ())
continue;
if (child != None)
{
pointer_window = child;
break;
}
gdk_window_get_geometry (window, NULL, NULL, &width, &height, NULL);
if (winx >= 0 && winy >= 0 && winx < width && winy < height)
{
/* A childless toplevel, or below another window? */
XSetWindowAttributes attributes;
Window w;
w = XCreateWindow (xdisplay, xwindow, winx, winy, 1, 1, 0,
CopyFromParent, InputOnly, CopyFromParent,
0, &attributes);
XMapWindow (xdisplay, w);
XQueryPointer (xdisplay, xwindow,
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
XDestroyWindow (xdisplay, w);
if (child == w)
{
pointer_window = xwindow;
break;
}
}
}
g_list_free (toplevels);
if (pointer_window != None)
break;
}
xwindow = pointer_window;
while (xwindow)
{
xwindow_last = xwindow;
gdk_error_trap_push ();
XQueryPointer (xdisplay, xwindow,
&root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
gdk_flush ();
if (gdk_error_trap_pop ())
break;
}
} }
gdk_x11_display_ungrab (display); gdk_x11_display_ungrab (display);
window = gdk_window_lookup_for_display (GDK_SCREEN_DISPLAY(screen),