diff options
Diffstat (limited to 'gdk/x11')
-rw-r--r-- | gdk/x11/gdkasync.c | 301 | ||||
-rw-r--r-- | gdk/x11/gdkasync.h | 22 | ||||
-rw-r--r-- | gdk/x11/gdkdnd-x11.c | 134 |
3 files changed, 373 insertions, 84 deletions
diff --git a/gdk/x11/gdkasync.c b/gdk/x11/gdkasync.c index 1ba90be295..06dc6d8ca7 100644 --- a/gdk/x11/gdkasync.c +++ b/gdk/x11/gdkasync.c @@ -47,9 +47,37 @@ in this Software without prior written authorization from The Open Group. #include "gdkasync.h" #include "gdkx.h" +typedef struct _ChildInfoChildState ChildInfoChildState; +typedef struct _ChildInfoState ChildInfoState; typedef struct _SendEventState SendEventState; typedef struct _SetInputFocusState SetInputFocusState; +typedef enum { + CHILD_INFO_GET_PROPERTY, + CHILD_INFO_GET_WA, + CHILD_INFO_GET_GEOMETRY +} ChildInfoReq; + +struct _ChildInfoChildState +{ + gulong seq[3]; +}; + +struct _ChildInfoState +{ + gboolean get_wm_state; + Window *children; + guint nchildren; + GdkChildInfoX11 *child_info; + ChildInfoChildState *child_states; + + guint current_child; + guint n_children_found; + gint current_request; + gboolean have_error; + gboolean child_has_error; +}; + struct _SendEventState { Display *dpy; @@ -81,13 +109,11 @@ send_event_handler (Display *dpy, if (dpy->last_request_read == state->send_event_req) { - if (rep->generic.type == X_Error) + if (rep->generic.type == X_Error && + rep->error.errorCode == BadWindow) { - if (rep->error.errorCode == BadWindow) - { - state->have_error = TRUE; - return True; - } + state->have_error = TRUE; + return True; } } else if (dpy->last_request_read == state->get_input_focus_req) @@ -97,6 +123,9 @@ send_event_handler (Display *dpy, if (rep->generic.type != X_Error) { + /* Actually does nothing, since there are no additional bytes + * to read, but maintain good form. + */ repl = (xGetInputFocusReply *) _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2, @@ -108,22 +137,20 @@ send_event_handler (Display *dpy, DeqAsyncHandler(state->dpy, &state->async); - g_free (state); - - return True; + return (rep->generic.type != X_Error); } return False; } void -_gdk_send_xevent_async (GdkDisplay *display, - Window window, - gboolean propagate, - glong event_mask, - XEvent *event_send, - GdkSendXEventCallback callback, - gpointer data) +_gdk_x11_send_xevent_async (GdkDisplay *display, + Window window, + gboolean propagate, + glong event_mask, + XEvent *event_send, + GdkSendXEventCallback callback, + gpointer data) { Display *dpy; SendEventState *state; @@ -288,3 +315,245 @@ _gdk_x11_set_input_focus_safe (GdkDisplay *display, UnlockDisplay(dpy); SyncHandle(); } + +static void +handle_get_wa_reply (Display *dpy, + ChildInfoState *state, + xGetWindowAttributesReply *repl) +{ + GdkChildInfoX11 *child = &state->child_info[state->n_children_found]; + child->is_mapped = repl->mapState != IsUnmapped; + child->window_class = repl->class; +} + +static void +handle_get_geometry_reply (Display *dpy, + ChildInfoState *state, + xGetGeometryReply *repl) +{ + GdkChildInfoX11 *child = &state->child_info[state->n_children_found]; + + child->x = cvtINT16toInt (repl->x); + child->y = cvtINT16toInt (repl->y); + child->width = repl->width; + child->height = repl->height; +} + +static void +handle_get_property_reply (Display *dpy, + ChildInfoState *state, + xGetPropertyReply *repl) +{ + GdkChildInfoX11 *child = &state->child_info[state->n_children_found]; + child->has_wm_state = repl->propertyType != None; + + /* Since we called GetProperty with longLength of 0, we don't + * have to worry about consuming the property data that would + * normally follow after the reply + */ +} + +static void +next_child (ChildInfoState *state) +{ + if (state->current_request == CHILD_INFO_GET_GEOMETRY) + { + if (!state->have_error && !state->child_has_error) + { + state->child_info[state->n_children_found].window = state->children[state->current_child]; + state->n_children_found++; + } + state->current_child++; + if (state->get_wm_state) + state->current_request = CHILD_INFO_GET_PROPERTY; + else + state->current_request = CHILD_INFO_GET_WA; + state->child_has_error = FALSE; + state->have_error = FALSE; + } + else + state->current_request++; +} + +static Bool +get_child_info_handler (Display *dpy, + xReply *rep, + char *buf, + int len, + XPointer data) +{ + Bool result = True; + + ChildInfoState *state = (ChildInfoState *)data; + + if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request]) + return False; + + if (rep->generic.type == X_Error) + { + state->child_has_error = TRUE; + if (rep->error.errorCode != BadDrawable || + rep->error.errorCode != BadWindow) + { + state->have_error = TRUE; + result = False; + } + } + else + { + switch (state->current_request) + { + case CHILD_INFO_GET_PROPERTY: + { + xGetPropertyReply replbuf; + xGetPropertyReply *repl; + + repl = (xGetPropertyReply *) + _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, + (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2, + True); + + handle_get_property_reply (dpy, state, repl); + } + break; + case CHILD_INFO_GET_WA: + { + xGetWindowAttributesReply replbuf; + xGetWindowAttributesReply *repl; + + repl = (xGetWindowAttributesReply *) + _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, + (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2, + True); + + handle_get_wa_reply (dpy, state, repl); + } + break; + case CHILD_INFO_GET_GEOMETRY: + { + xGetGeometryReply replbuf; + xGetGeometryReply *repl; + + repl = (xGetGeometryReply *) + _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, + (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2, + True); + + handle_get_geometry_reply (dpy, state, repl); + } + break; + } + } + + next_child (state); + + return result; +} + +gboolean +_gdk_x11_get_window_child_info (GdkDisplay *display, + Window window, + gboolean get_wm_state, + GdkChildInfoX11 **children, + guint *nchildren) +{ + Display *dpy; + _XAsyncHandler async; + ChildInfoState state; + Window root, parent; + Atom wm_state_atom; + Bool result; + guint i; + + *children = NULL; + *nchildren = 0; + + dpy = GDK_DISPLAY_XDISPLAY (display); + wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"); + + gdk_error_trap_push (); + result = XQueryTree (dpy, window, &root, &parent, + &state.children, &state.nchildren); + gdk_error_trap_pop (); + if (!result) + return FALSE; + + state.get_wm_state = get_wm_state; + state.child_info = g_new (GdkChildInfoX11, state.nchildren); + state.child_states = g_new (ChildInfoChildState, state.nchildren); + state.current_child = 0; + state.n_children_found = 0; + if (get_wm_state) + state.current_request = CHILD_INFO_GET_PROPERTY; + else + state.current_request = CHILD_INFO_GET_WA; + state.have_error = FALSE; + state.child_has_error = FALSE; + + LockDisplay(dpy); + + async.next = dpy->async_handlers; + async.handler = get_child_info_handler; + async.data = (XPointer) &state; + dpy->async_handlers = &async; + + for (i = 0; i < state.nchildren; i++) + { + xResourceReq *resource_req; + xGetPropertyReq *prop_req; + Window window = state.children[i]; + + if (get_wm_state) + { + GetReq (GetProperty, prop_req); + prop_req->window = window; + prop_req->property = wm_state_atom; + prop_req->type = AnyPropertyType; + prop_req->delete = False; + prop_req->longOffset = 0; + prop_req->longLength = 0; + + state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request; + } + + GetResReq(GetWindowAttributes, window, resource_req); + state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request; + + GetResReq(GetGeometry, window, resource_req); + state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request; + } + + if (i != 0) + { + /* Wait for the last reply + */ + xGetGeometryReply rep; + + /* On error, our async handler will get called + */ + if (_XReply (dpy, (xReply *)&rep, 0, xTrue)) + handle_get_geometry_reply (dpy, &state, &rep); + + next_child (&state); + } + + if (!state.have_error) + { + *children = state.child_info; + *nchildren = state.n_children_found; + } + else + { + g_free (state.child_info); + } + + XFree (state.children); + g_free (state.child_states); + + DeqAsyncHandler(dpy, &async); + UnlockDisplay(dpy); + SyncHandle(); + + return !state.have_error; +} + diff --git a/gdk/x11/gdkasync.h b/gdk/x11/gdkasync.h index ea2d7b0746..36f76997f7 100644 --- a/gdk/x11/gdkasync.h +++ b/gdk/x11/gdkasync.h @@ -26,11 +26,25 @@ G_BEGIN_DECLS +typedef struct _GdkChildInfoX11 GdkChildInfoX11; + typedef void (*GdkSendXEventCallback) (Window window, gboolean success, gpointer data); -void _gdk_send_xevent_async (GdkDisplay *display, +struct _GdkChildInfoX11 +{ + Window window; + gint x; + gint y; + gint width; + gint height; + guint is_mapped : 1; + guint has_wm_state : 1; + guint window_class : 2; +}; + +void _gdk_x11_send_xevent_async (GdkDisplay *display, Window window, gboolean propagate, glong event_mask, @@ -42,6 +56,12 @@ void _gdk_x11_set_input_focus_safe (GdkDisplay *display, int revert_to, Time time); +gboolean _gdk_x11_get_window_child_info (GdkDisplay *display, + Window window, + gboolean get_wm_state, + GdkChildInfoX11 **children, + guint *nchildren); + G_END_DECLS #endif /* __GDK_ASYNC_H__ */ diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c index 00df75ca37..5b06b6371a 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -449,11 +449,10 @@ static GdkWindowCache * gdk_window_cache_new (GdkScreen *screen) { XWindowAttributes xwa; - Window root, parent, *children; - unsigned int nchildren; - int i; Display *xdisplay = GDK_SCREEN_XDISPLAY (screen); GdkWindow *root_window = gdk_screen_get_root_window (screen); + GdkChildInfoX11 *children; + guint nchildren, i; GdkWindowCache *result = g_new (GdkWindowCache, 1); @@ -467,25 +466,19 @@ gdk_window_cache_new (GdkScreen *screen) result->old_event_mask | SubstructureNotifyMask); gdk_window_add_filter (root_window, gdk_window_cache_filter, result); - gdk_error_trap_push (); + if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen), + GDK_WINDOW_XWINDOW (root_window), + FALSE, &children, &nchildren)) + return result; - if (!XQueryTree(xdisplay, GDK_WINDOW_XWINDOW (root_window), - &root, &parent, &children, &nchildren)) - { - gdk_error_trap_pop (); - return result; - } - for (i = 0; i < nchildren ; i++) { - if (XGetWindowAttributes (xdisplay, children[i], &xwa)) - gdk_window_cache_add (result, children[i], - xwa.x, xwa.y, xwa.width, xwa.height, - xwa.map_state != IsUnmapped); + gdk_window_cache_add (result, children[i].window, + children[i].x, children[i].y, children[i].width, children[i].height, + children[i].is_mapped); } - XFree (children); - gdk_error_trap_pop (); + g_free (children); return result; } @@ -507,67 +500,70 @@ gdk_window_cache_destroy (GdkWindowCache *cache) g_free (cache); } -static Window -get_client_window_at_coords_recurse (GdkDisplay *display, - Window win, - gint x, - gint y) +static gboolean +window_has_wm_state (GdkDisplay *display, + Window win) { - Window root, tmp_parent, *children; - unsigned int nchildren; - int i; - Window child = None; Atom type = None; int format; unsigned long nitems, after; unsigned char *data; - + if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY(display), win, gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"), 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data) != Success) - return None; - + return FALSE; + if (type != None) { XFree (data); - return win; + return TRUE; } -#if 0 - /* This is beautiful! Damn Enlightenment and click-to-focus */ - if (!XTranslateCoordinates (gdk_display, _gdk_root_window, win, - x_root, y_root, &dest_x, &dest_y, &child)) + return FALSE; +} + +static Window +get_client_window_at_coords_recurse (GdkDisplay *display, + Window win, + gint x, + gint y) +{ + GdkChildInfoX11 *children; + unsigned int nchildren; + int i; + gboolean found_child = FALSE; + GdkChildInfoX11 child; + + if (!_gdk_x11_get_window_child_info (display, win, TRUE, + &children, &nchildren)) return None; - -#else - if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), win, - &root, &tmp_parent, &children, &nchildren)) - return 0; - - for (i = nchildren - 1; (i >= 0) && (child == None); i--) + + for (i = nchildren - 1; (i >= 0) && !found_child; i--) { - XWindowAttributes xwa; - - if (XGetWindowAttributes (GDK_DISPLAY_XDISPLAY (display), - children[i], &xwa)) - { - if ((xwa.map_state == IsViewable) && (xwa.class == InputOutput) && - (x >= xwa.x) && (x < xwa.x + (gint)xwa.width) && - (y >= xwa.y) && (y < xwa.y + (gint)xwa.height)) - { - x -= xwa.x; - y -= xwa.y; - child = children[i]; - } - } + GdkChildInfoX11 *cur_child = &children[i]; + + if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) && + (x >= cur_child->x) && (x < cur_child->x + cur_child->width) && + (y >= cur_child->y) && (y < cur_child->y + cur_child->height)) + { + x -= cur_child->x; + y -= cur_child->y; + child = *cur_child; + found_child = TRUE; + } + } + + g_free (children); + + if (found_child) + { + if (child.has_wm_state) + return child.window; + else + return get_client_window_at_coords_recurse (display, child.window, x, y); } - - XFree (children); -#endif - - if (child) - return get_client_window_at_coords_recurse (display, child, x, y); else return None; } @@ -594,10 +590,13 @@ get_client_window_at_coords (GdkWindowCache *cache, if ((x_root >= child->x) && (x_root < child->x + child->width) && (y_root >= child->y) && (y_root < child->y + child->height)) { - retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen), - child->xid, - x_root - child->x, - y_root - child->y); + if (window_has_wm_state (gdk_screen_get_display (cache->screen), child->xid)) + retval = child->xid; + else + retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen), + child->xid, + x_root - child->x, + y_root - child->y); if (!retval) retval = child->xid; } @@ -2160,8 +2159,9 @@ send_xevent_async (GdkDragContext *context, g_object_ref (context); - _gdk_send_xevent_async (display, window, propagate, event_mask, event_send, - send_xevent_async_cb, context); + _gdk_x11_send_xevent_async (display, window, + propagate, event_mask, event_send, + send_xevent_async_cb, context); } static gboolean |