Function to get a range of information about all the children of a window
Fri Jul 4 23:49:22 2003 Owen Taylor <otaylor@redhat.com> * gdk/x11/gdkasync.[ch] (_gdk_x11_get_window_child_info): Function to get a range of information about all the children of a window in a single pass. * gdk/x11/gdkdnd-x11.c (get_client_window_at_coords_recurse) gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Use _gdk_x11_get_window_child_info() to greatly reduce the number of roundtrips.
This commit is contained in:
		| @ -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; | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Owen Taylor
					Owen Taylor