Blame gdk/x11/gdkasync.c

Packit 98cdb6
/* GTK - The GIMP Toolkit
Packit 98cdb6
 * gdkasync.c: Utility functions using the Xlib asynchronous interfaces
Packit 98cdb6
 * Copyright (C) 2003, Red Hat, Inc.
Packit 98cdb6
 *
Packit 98cdb6
 * This library is free software; you can redistribute it and/or
Packit 98cdb6
 * modify it under the terms of the GNU Lesser General Public
Packit 98cdb6
 * License as published by the Free Software Foundation; either
Packit 98cdb6
 * version 2 of the License, or (at your option) any later version.
Packit 98cdb6
 *
Packit 98cdb6
 * This library is distributed in the hope that it will be useful,
Packit 98cdb6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 98cdb6
 * Lesser General Public License for more details.
Packit 98cdb6
 *
Packit 98cdb6
 * You should have received a copy of the GNU Lesser General Public
Packit 98cdb6
 * License along with this library; if not, write to the
Packit 98cdb6
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 98cdb6
 * Boston, MA 02111-1307, USA.
Packit 98cdb6
 */
Packit 98cdb6
/* Portions of code in this file are based on code from Xlib
Packit 98cdb6
 */
Packit 98cdb6
/*
Packit 98cdb6
Copyright 1986, 1998  The Open Group
Packit 98cdb6
Packit 98cdb6
Permission to use, copy, modify, distribute, and sell this software and its
Packit 98cdb6
documentation for any purpose is hereby granted without fee, provided that
Packit 98cdb6
the above copyright notice appear in all copies and that both that
Packit 98cdb6
copyright notice and this permission notice appear in supporting
Packit 98cdb6
documentation.
Packit 98cdb6
Packit 98cdb6
The above copyright notice and this permission notice shall be included in
Packit 98cdb6
all copies or substantial portions of the Software.
Packit 98cdb6
Packit 98cdb6
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 98cdb6
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 98cdb6
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit 98cdb6
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit 98cdb6
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 98cdb6
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 98cdb6
Packit 98cdb6
Except as contained in this notice, the name of The Open Group shall not be
Packit 98cdb6
used in advertising or otherwise to promote the sale, use or other dealings
Packit 98cdb6
in this Software without prior written authorization from The Open Group.
Packit 98cdb6
Packit 98cdb6
*/
Packit 98cdb6
#include "config.h"
Packit 98cdb6
#ifdef NEED_XIPROTO_H_FOR_XREPLY
Packit 98cdb6
#include <X11/extensions/XIproto.h>
Packit 98cdb6
#endif
Packit 98cdb6
#include <X11/Xlibint.h>
Packit 98cdb6
#include "gdkasync.h"
Packit 98cdb6
#include "gdkx.h"
Packit 98cdb6
#include "gdkalias.h"
Packit 98cdb6
Packit 98cdb6
typedef struct _ChildInfoChildState ChildInfoChildState;
Packit 98cdb6
typedef struct _ChildInfoState ChildInfoState;
Packit 98cdb6
typedef struct _ListChildrenState ListChildrenState;
Packit 98cdb6
typedef struct _SendEventState SendEventState;
Packit 98cdb6
typedef struct _SetInputFocusState SetInputFocusState;
Packit 98cdb6
typedef struct _RoundtripState RoundtripState;
Packit 98cdb6
Packit 98cdb6
typedef enum {
Packit 98cdb6
  CHILD_INFO_GET_PROPERTY,
Packit 98cdb6
  CHILD_INFO_GET_WA,
Packit 98cdb6
  CHILD_INFO_GET_GEOMETRY
Packit 98cdb6
} ChildInfoReq;
Packit 98cdb6
Packit 98cdb6
struct _ChildInfoChildState
Packit 98cdb6
{
Packit 98cdb6
  gulong seq[3];
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct _ChildInfoState
Packit 98cdb6
{
Packit 98cdb6
  gboolean get_wm_state;
Packit 98cdb6
  Window *children;
Packit 98cdb6
  guint nchildren;
Packit 98cdb6
  GdkChildInfoX11 *child_info;
Packit 98cdb6
  ChildInfoChildState *child_states;
Packit 98cdb6
Packit 98cdb6
  guint current_child;
Packit 98cdb6
  guint n_children_found;
Packit 98cdb6
  gint current_request;
Packit 98cdb6
  gboolean have_error;
Packit 98cdb6
  gboolean child_has_error;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct _ListChildrenState
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  gulong get_property_req;
Packit 98cdb6
  gboolean have_error;
Packit 98cdb6
  gboolean has_wm_state;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct _SendEventState
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  Window window;
Packit 98cdb6
  _XAsyncHandler async;
Packit 98cdb6
  gulong send_event_req;
Packit 98cdb6
  gulong get_input_focus_req;
Packit 98cdb6
  gboolean have_error;
Packit 98cdb6
  GdkSendXEventCallback callback;
Packit 98cdb6
  gpointer data;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct _SetInputFocusState
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  _XAsyncHandler async;
Packit 98cdb6
  gulong set_input_focus_req;
Packit 98cdb6
  gulong get_input_focus_req;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct _RoundtripState
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  _XAsyncHandler async;
Packit 98cdb6
  gulong get_input_focus_req;
Packit 98cdb6
  GdkDisplay *display;
Packit 98cdb6
  GdkRoundTripCallback callback;
Packit 98cdb6
  gpointer data;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
static gboolean
Packit 98cdb6
callback_idle (gpointer data)
Packit 98cdb6
{
Packit 98cdb6
  SendEventState *state = (SendEventState *)data;  
Packit 98cdb6
  
Packit 98cdb6
  state->callback (state->window, !state->have_error, state->data);
Packit 98cdb6
Packit 98cdb6
  g_free (state);
Packit 98cdb6
Packit 98cdb6
  return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static Bool
Packit 98cdb6
send_event_handler (Display *dpy,
Packit 98cdb6
		    xReply  *rep,
Packit 98cdb6
		    char    *buf,
Packit 98cdb6
		    int      len,
Packit 98cdb6
		    XPointer data)
Packit 98cdb6
{
Packit 98cdb6
  SendEventState *state = (SendEventState *)data;  
Packit 98cdb6
Packit 98cdb6
  if (dpy->last_request_read == state->send_event_req)
Packit 98cdb6
    {
Packit 98cdb6
      if (rep->generic.type == X_Error &&
Packit 98cdb6
	  rep->error.errorCode == BadWindow)
Packit 98cdb6
	{
Packit 98cdb6
	  state->have_error = TRUE;
Packit 98cdb6
	  return True;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
  else if (dpy->last_request_read == state->get_input_focus_req)
Packit 98cdb6
    {
Packit 98cdb6
      xGetInputFocusReply replbuf;
Packit 98cdb6
      xGetInputFocusReply *repl;
Packit 98cdb6
      
Packit 98cdb6
      if (rep->generic.type != X_Error)
Packit 98cdb6
	{
Packit 98cdb6
	  /* Actually does nothing, since there are no additional bytes
Packit 98cdb6
	   * to read, but maintain good form.
Packit 98cdb6
	   */
Packit 98cdb6
	  repl = (xGetInputFocusReply *)
Packit 98cdb6
	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			    True);
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      if (state->callback)
Packit 98cdb6
        gdk_threads_add_idle (callback_idle, state);
Packit 98cdb6
Packit 98cdb6
      DeqAsyncHandler(state->dpy, &state->async);
Packit 98cdb6
Packit 98cdb6
      return (rep->generic.type != X_Error);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return False;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
client_message_to_wire (XClientMessageEvent *ev,
Packit 98cdb6
			xEvent              *event)
Packit 98cdb6
{
Packit 98cdb6
  int i;
Packit 98cdb6
  event->u.clientMessage.window = ev->window;
Packit 98cdb6
  event->u.u.type = ev->type;
Packit 98cdb6
  event->u.u.detail = ev->format;
Packit 98cdb6
  switch (ev->format)
Packit 98cdb6
    {
Packit 98cdb6
    case 8:	
Packit 98cdb6
      event->u.clientMessage.u.b.type   = ev->message_type;
Packit 98cdb6
      for (i = 0; i < 20; i++)
Packit 98cdb6
	event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
Packit 98cdb6
      break;
Packit 98cdb6
    case 16:
Packit 98cdb6
      event->u.clientMessage.u.s.type   = ev->message_type;
Packit 98cdb6
      event->u.clientMessage.u.s.shorts0   = ev->data.s[0];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts1   = ev->data.s[1];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts2   = ev->data.s[2];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts3   = ev->data.s[3];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts4   = ev->data.s[4];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts5   = ev->data.s[5];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts6   = ev->data.s[6];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts7   = ev->data.s[7];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts8   = ev->data.s[8];
Packit 98cdb6
      event->u.clientMessage.u.s.shorts9   = ev->data.s[9];
Packit 98cdb6
      break;
Packit 98cdb6
    case 32:
Packit 98cdb6
      event->u.clientMessage.u.l.type   = ev->message_type;
Packit 98cdb6
      event->u.clientMessage.u.l.longs0   = ev->data.l[0];
Packit 98cdb6
      event->u.clientMessage.u.l.longs1   = ev->data.l[1];
Packit 98cdb6
      event->u.clientMessage.u.l.longs2   = ev->data.l[2];
Packit 98cdb6
      event->u.clientMessage.u.l.longs3   = ev->data.l[3];
Packit 98cdb6
      event->u.clientMessage.u.l.longs4   = ev->data.l[4];
Packit 98cdb6
      break;
Packit 98cdb6
    default:
Packit 98cdb6
      /* client passing bogus data, let server complain */
Packit 98cdb6
      break;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gdk_x11_send_client_message_async (GdkDisplay           *display, 
Packit 98cdb6
				    Window                window, 
Packit 98cdb6
				    gboolean              propagate,
Packit 98cdb6
				    glong                 event_mask,
Packit 98cdb6
				    XClientMessageEvent  *event_send,
Packit 98cdb6
				    GdkSendXEventCallback callback,
Packit 98cdb6
				    gpointer              data)
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  SendEventState *state;
Packit 98cdb6
  
Packit 98cdb6
  dpy = GDK_DISPLAY_XDISPLAY (display);
Packit 98cdb6
Packit 98cdb6
  state = g_new (SendEventState, 1);
Packit 98cdb6
Packit 98cdb6
  state->dpy = dpy;
Packit 98cdb6
  state->window = window;
Packit 98cdb6
  state->callback = callback;
Packit 98cdb6
  state->data = data;
Packit 98cdb6
  state->have_error = FALSE;
Packit 98cdb6
  
Packit 98cdb6
  LockDisplay(dpy);
Packit 98cdb6
Packit 98cdb6
  state->async.next = dpy->async_handlers;
Packit 98cdb6
  state->async.handler = send_event_handler;
Packit 98cdb6
  state->async.data = (XPointer) state;
Packit 98cdb6
  dpy->async_handlers = &state->async;
Packit 98cdb6
Packit 98cdb6
  {
Packit 98cdb6
    register xSendEventReq *req;
Packit 98cdb6
    xEvent ev;
Packit 98cdb6
    
Packit 98cdb6
    client_message_to_wire (event_send, &ev;;
Packit 98cdb6
      
Packit 98cdb6
    GetReq(SendEvent, req);
Packit 98cdb6
    req->destination = window;
Packit 98cdb6
    req->propagate = propagate;
Packit 98cdb6
    req->eventMask = event_mask;
Packit 98cdb6
    /* gross, matches Xproto.h */
Packit 98cdb6
#ifdef WORD64			
Packit 98cdb6
    memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
Packit 98cdb6
#else    
Packit 98cdb6
    memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
Packit 98cdb6
#endif
Packit 98cdb6
    
Packit 98cdb6
    state->send_event_req = dpy->request;
Packit 98cdb6
  }
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * XSync (dpy, 0)
Packit 98cdb6
   */
Packit 98cdb6
  {
Packit 98cdb6
    xReq *req;
Packit 98cdb6
    
Packit 98cdb6
    GetEmptyReq(GetInputFocus, req);
Packit 98cdb6
    state->get_input_focus_req = dpy->request;
Packit 98cdb6
  }
Packit 98cdb6
  
Packit 98cdb6
  UnlockDisplay(dpy);
Packit 98cdb6
  SyncHandle();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static Bool
Packit 98cdb6
set_input_focus_handler (Display *dpy,
Packit 98cdb6
			 xReply  *rep,
Packit 98cdb6
			 char    *buf,
Packit 98cdb6
			 int      len,
Packit 98cdb6
			 XPointer data)
Packit 98cdb6
{
Packit 98cdb6
  SetInputFocusState *state = (SetInputFocusState *)data;  
Packit 98cdb6
Packit 98cdb6
  if (dpy->last_request_read == state->set_input_focus_req)
Packit 98cdb6
    {
Packit 98cdb6
      if (rep->generic.type == X_Error &&
Packit 98cdb6
	  rep->error.errorCode == BadMatch)
Packit 98cdb6
	{
Packit 98cdb6
	  /* Consume BadMatch errors, since we have no control
Packit 98cdb6
	   * over them.
Packit 98cdb6
	   */
Packit 98cdb6
	  return True;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  if (dpy->last_request_read == state->get_input_focus_req)
Packit 98cdb6
    {
Packit 98cdb6
      xGetInputFocusReply replbuf;
Packit 98cdb6
      xGetInputFocusReply *repl;
Packit 98cdb6
      
Packit 98cdb6
      if (rep->generic.type != X_Error)
Packit 98cdb6
	{
Packit 98cdb6
	  /* Actually does nothing, since there are no additional bytes
Packit 98cdb6
	   * to read, but maintain good form.
Packit 98cdb6
	   */
Packit 98cdb6
	  repl = (xGetInputFocusReply *)
Packit 98cdb6
	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			    True);
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      DeqAsyncHandler(state->dpy, &state->async);
Packit 98cdb6
Packit 98cdb6
      g_free (state);
Packit 98cdb6
      
Packit 98cdb6
      return (rep->generic.type != X_Error);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return False;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gdk_x11_set_input_focus_safe (GdkDisplay             *display,
Packit 98cdb6
			       Window                  window,
Packit 98cdb6
			       int                     revert_to,
Packit 98cdb6
			       Time                    time)
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  SetInputFocusState *state;
Packit 98cdb6
  
Packit 98cdb6
  dpy = GDK_DISPLAY_XDISPLAY (display);
Packit 98cdb6
Packit 98cdb6
  state = g_new (SetInputFocusState, 1);
Packit 98cdb6
Packit 98cdb6
  state->dpy = dpy;
Packit 98cdb6
  
Packit 98cdb6
  LockDisplay(dpy);
Packit 98cdb6
Packit 98cdb6
  state->async.next = dpy->async_handlers;
Packit 98cdb6
  state->async.handler = set_input_focus_handler;
Packit 98cdb6
  state->async.data = (XPointer) state;
Packit 98cdb6
  dpy->async_handlers = &state->async;
Packit 98cdb6
Packit 98cdb6
  {
Packit 98cdb6
    xSetInputFocusReq *req;
Packit 98cdb6
    
Packit 98cdb6
    GetReq(SetInputFocus, req);
Packit 98cdb6
    req->focus = window;
Packit 98cdb6
    req->revertTo = revert_to;
Packit 98cdb6
    req->time = time;
Packit 98cdb6
    state->set_input_focus_req = dpy->request;
Packit 98cdb6
  }
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * XSync (dpy, 0)
Packit 98cdb6
   */
Packit 98cdb6
  {
Packit 98cdb6
    xReq *req;
Packit 98cdb6
    
Packit 98cdb6
    GetEmptyReq(GetInputFocus, req);
Packit 98cdb6
    state->get_input_focus_req = dpy->request;
Packit 98cdb6
  }
Packit 98cdb6
  
Packit 98cdb6
  UnlockDisplay(dpy);
Packit 98cdb6
  SyncHandle();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static Bool
Packit 98cdb6
list_children_handler (Display *dpy,
Packit 98cdb6
		       xReply  *rep,
Packit 98cdb6
		       char    *buf,
Packit 98cdb6
		       int      len,
Packit 98cdb6
		       XPointer data)
Packit 98cdb6
{
Packit 98cdb6
  ListChildrenState *state = (ListChildrenState *)data;
Packit 98cdb6
Packit 98cdb6
  if (dpy->last_request_read != state->get_property_req)
Packit 98cdb6
    return False;
Packit 98cdb6
  
Packit 98cdb6
  if (rep->generic.type == X_Error)
Packit 98cdb6
    {
Packit 98cdb6
      state->have_error = TRUE;
Packit 98cdb6
      return False;
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    {
Packit 98cdb6
      xGetPropertyReply replbuf;
Packit 98cdb6
      xGetPropertyReply *repl;
Packit 98cdb6
	    
Packit 98cdb6
      repl = (xGetPropertyReply *)
Packit 98cdb6
	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			(sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			True);
Packit 98cdb6
Packit 98cdb6
      state->has_wm_state = repl->propertyType != None;
Packit 98cdb6
      /* Since we called GetProperty with longLength of 0, we don't
Packit 98cdb6
       * have to worry about consuming the property data that would
Packit 98cdb6
       * normally follow after the reply
Packit 98cdb6
       */
Packit 98cdb6
Packit 98cdb6
      return True;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static gboolean
Packit 98cdb6
list_children_and_wm_state (Display      *dpy,
Packit 98cdb6
			    Window        w,
Packit 98cdb6
			    Atom          wm_state_atom,
Packit 98cdb6
			    gboolean     *has_wm_state,
Packit 98cdb6
			    Window      **children,
Packit 98cdb6
			    unsigned int *nchildren)
Packit 98cdb6
{
Packit 98cdb6
  ListChildrenState state;
Packit 98cdb6
  _XAsyncHandler async;
Packit 98cdb6
  long nbytes;
Packit 98cdb6
  xQueryTreeReply rep;
Packit 98cdb6
  register xResourceReq *req;
Packit 98cdb6
  xGetPropertyReq *prop_req;
Packit 98cdb6
Packit 98cdb6
  LockDisplay(dpy);
Packit 98cdb6
Packit 98cdb6
  *children = NULL;
Packit 98cdb6
  *nchildren = 0;
Packit 98cdb6
  *has_wm_state = FALSE;
Packit 98cdb6
  
Packit 98cdb6
  state.have_error = FALSE;
Packit 98cdb6
  state.has_wm_state = FALSE;
Packit 98cdb6
Packit 98cdb6
  if (wm_state_atom)
Packit 98cdb6
    {
Packit 98cdb6
      async.next = dpy->async_handlers;
Packit 98cdb6
      async.handler = list_children_handler;
Packit 98cdb6
      async.data = (XPointer) &stat;;
Packit 98cdb6
      dpy->async_handlers = &asyn;;
Packit 98cdb6
Packit 98cdb6
      GetReq (GetProperty, prop_req);
Packit 98cdb6
      prop_req->window = w;
Packit 98cdb6
      prop_req->property = wm_state_atom;
Packit 98cdb6
      prop_req->type = AnyPropertyType;
Packit 98cdb6
      prop_req->delete = False;
Packit 98cdb6
      prop_req->longOffset = 0;
Packit 98cdb6
      prop_req->longLength = 0;
Packit 98cdb6
      
Packit 98cdb6
      state.get_property_req = dpy->request;
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  GetResReq(QueryTree, w, req);
Packit 98cdb6
  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
Packit 98cdb6
    {
Packit 98cdb6
      state.have_error = TRUE;
Packit 98cdb6
      goto out;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (rep.nChildren != 0)
Packit 98cdb6
    {
Packit 98cdb6
      nbytes = rep.nChildren << 2;
Packit 98cdb6
      if (state.have_error)
Packit 98cdb6
	{
Packit 98cdb6
	  _XEatData(dpy, (unsigned long) nbytes);
Packit 98cdb6
	  goto out;
Packit 98cdb6
	}
Packit 98cdb6
      *children = g_new (Window, rep.nChildren);
Packit 98cdb6
      _XRead32 (dpy, (long *) *children, nbytes);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  *nchildren = rep.nChildren;
Packit 98cdb6
  *has_wm_state = state.has_wm_state;
Packit 98cdb6
Packit 98cdb6
 out:
Packit 98cdb6
  if (wm_state_atom)
Packit 98cdb6
    DeqAsyncHandler(dpy, &async);
Packit 98cdb6
  UnlockDisplay(dpy);
Packit 98cdb6
  SyncHandle();
Packit 98cdb6
  
Packit 98cdb6
  return !state.have_error;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
handle_get_wa_reply (Display                   *dpy,
Packit 98cdb6
		     ChildInfoState            *state,
Packit 98cdb6
		     xGetWindowAttributesReply *repl)
Packit 98cdb6
{
Packit 98cdb6
  GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
Packit 98cdb6
  child->is_mapped = repl->mapState != IsUnmapped;
Packit 98cdb6
  child->window_class = repl->class;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
handle_get_geometry_reply (Display           *dpy,
Packit 98cdb6
			   ChildInfoState    *state,
Packit 98cdb6
			   xGetGeometryReply *repl)
Packit 98cdb6
{
Packit 98cdb6
  GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
Packit 98cdb6
  
Packit 98cdb6
  child->x = cvtINT16toInt (repl->x);
Packit 98cdb6
  child->y = cvtINT16toInt (repl->y);
Packit 98cdb6
  child->width = repl->width;
Packit 98cdb6
  child->height = repl->height;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
handle_get_property_reply (Display           *dpy,
Packit 98cdb6
			   ChildInfoState    *state,
Packit 98cdb6
			   xGetPropertyReply *repl)
Packit 98cdb6
{
Packit 98cdb6
  GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
Packit 98cdb6
  child->has_wm_state = repl->propertyType != None;
Packit 98cdb6
Packit 98cdb6
  /* Since we called GetProperty with longLength of 0, we don't
Packit 98cdb6
   * have to worry about consuming the property data that would
Packit 98cdb6
   * normally follow after the reply
Packit 98cdb6
   */
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
next_child (ChildInfoState *state)
Packit 98cdb6
{
Packit 98cdb6
  if (state->current_request == CHILD_INFO_GET_GEOMETRY)
Packit 98cdb6
    {
Packit 98cdb6
      if (!state->have_error && !state->child_has_error)
Packit 98cdb6
	{
Packit 98cdb6
	  state->child_info[state->n_children_found].window = state->children[state->current_child];
Packit 98cdb6
	  state->n_children_found++;
Packit 98cdb6
	}
Packit 98cdb6
      state->current_child++;
Packit 98cdb6
      if (state->get_wm_state)
Packit 98cdb6
	state->current_request = CHILD_INFO_GET_PROPERTY;
Packit 98cdb6
      else
Packit 98cdb6
	state->current_request = CHILD_INFO_GET_WA;
Packit 98cdb6
      state->child_has_error = FALSE;
Packit 98cdb6
      state->have_error = FALSE;
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    state->current_request++;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static Bool
Packit 98cdb6
get_child_info_handler (Display *dpy,
Packit 98cdb6
			xReply  *rep,
Packit 98cdb6
			char    *buf,
Packit 98cdb6
			int      len,
Packit 98cdb6
			XPointer data)
Packit 98cdb6
{
Packit 98cdb6
  Bool result = True;
Packit 98cdb6
  
Packit 98cdb6
  ChildInfoState *state = (ChildInfoState *)data;
Packit 98cdb6
Packit 98cdb6
  if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
Packit 98cdb6
    return False;
Packit 98cdb6
  
Packit 98cdb6
  if (rep->generic.type == X_Error)
Packit 98cdb6
    {
Packit 98cdb6
      state->child_has_error = TRUE;
Packit 98cdb6
      if (rep->error.errorCode != BadDrawable ||
Packit 98cdb6
	  rep->error.errorCode != BadWindow)
Packit 98cdb6
	{
Packit 98cdb6
	  state->have_error = TRUE;
Packit 98cdb6
	  result = False;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    {
Packit 98cdb6
      switch (state->current_request)
Packit 98cdb6
	{
Packit 98cdb6
	case CHILD_INFO_GET_PROPERTY:
Packit 98cdb6
	  {
Packit 98cdb6
	    xGetPropertyReply replbuf;
Packit 98cdb6
	    xGetPropertyReply *repl;
Packit 98cdb6
	    
Packit 98cdb6
	    repl = (xGetPropertyReply *)
Packit 98cdb6
	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			      (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			      True);
Packit 98cdb6
	    
Packit 98cdb6
	    handle_get_property_reply (dpy, state, repl);
Packit 98cdb6
	  }
Packit 98cdb6
	  break;
Packit 98cdb6
	case CHILD_INFO_GET_WA:
Packit 98cdb6
	  {
Packit 98cdb6
	    xGetWindowAttributesReply replbuf;
Packit 98cdb6
	    xGetWindowAttributesReply *repl;
Packit 98cdb6
	    
Packit 98cdb6
	    repl = (xGetWindowAttributesReply *)
Packit 98cdb6
	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			      (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			      True);
Packit 98cdb6
	    
Packit 98cdb6
	    handle_get_wa_reply (dpy, state, repl);
Packit 98cdb6
	  }
Packit 98cdb6
	  break;
Packit 98cdb6
	case CHILD_INFO_GET_GEOMETRY:
Packit 98cdb6
	  {
Packit 98cdb6
	    xGetGeometryReply replbuf;
Packit 98cdb6
	    xGetGeometryReply *repl;
Packit 98cdb6
	    
Packit 98cdb6
	    repl = (xGetGeometryReply *)
Packit 98cdb6
	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			      (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			      True);
Packit 98cdb6
	    
Packit 98cdb6
	    handle_get_geometry_reply (dpy, state, repl);
Packit 98cdb6
	  }
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  next_child (state);
Packit 98cdb6
Packit 98cdb6
  return result;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gdk_x11_get_window_child_info (GdkDisplay       *display,
Packit 98cdb6
				Window            window,
Packit 98cdb6
				gboolean          get_wm_state,
Packit 98cdb6
				gboolean         *win_has_wm_state,
Packit 98cdb6
				GdkChildInfoX11 **children,
Packit 98cdb6
				guint            *nchildren)
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  _XAsyncHandler async;
Packit 98cdb6
  ChildInfoState state;
Packit 98cdb6
  Atom wm_state_atom;
Packit 98cdb6
  gboolean has_wm_state;
Packit 98cdb6
  Bool result;
Packit 98cdb6
  guint i;
Packit 98cdb6
Packit 98cdb6
  *children = NULL;
Packit 98cdb6
  *nchildren = 0;
Packit 98cdb6
  
Packit 98cdb6
  dpy = GDK_DISPLAY_XDISPLAY (display);
Packit 98cdb6
  if (get_wm_state)
Packit 98cdb6
    wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
Packit 98cdb6
  else
Packit 98cdb6
    wm_state_atom = None;
Packit 98cdb6
Packit 98cdb6
  state.children = NULL;
Packit 98cdb6
  state.nchildren = 0;
Packit 98cdb6
Packit 98cdb6
  gdk_error_trap_push ();
Packit 98cdb6
  result = list_children_and_wm_state (dpy, window,
Packit 98cdb6
				       win_has_wm_state ? wm_state_atom : None,
Packit 98cdb6
				       &has_wm_state,
Packit 98cdb6
				       &state.children, &state.nchildren);
Packit 98cdb6
  gdk_error_trap_pop ();
Packit 98cdb6
  if (!result)
Packit 98cdb6
    {
Packit 98cdb6
      g_free (state.children);
Packit 98cdb6
      return FALSE;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (has_wm_state)
Packit 98cdb6
    {
Packit 98cdb6
      if (win_has_wm_state)
Packit 98cdb6
	*win_has_wm_state = TRUE;
Packit 98cdb6
      g_free (state.children);
Packit 98cdb6
      return TRUE;
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    {
Packit 98cdb6
      if (win_has_wm_state)
Packit 98cdb6
	*win_has_wm_state = FALSE;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  state.get_wm_state = get_wm_state;
Packit 98cdb6
  state.child_info = g_new (GdkChildInfoX11, state.nchildren);
Packit 98cdb6
  state.child_states = g_new (ChildInfoChildState, state.nchildren);
Packit 98cdb6
  state.current_child = 0;
Packit 98cdb6
  state.n_children_found = 0;
Packit 98cdb6
  if (get_wm_state)
Packit 98cdb6
    state.current_request = CHILD_INFO_GET_PROPERTY;
Packit 98cdb6
  else
Packit 98cdb6
    state.current_request = CHILD_INFO_GET_WA;
Packit 98cdb6
  state.have_error = FALSE;
Packit 98cdb6
  state.child_has_error = FALSE;
Packit 98cdb6
Packit 98cdb6
  LockDisplay(dpy);
Packit 98cdb6
Packit 98cdb6
  async.next = dpy->async_handlers;
Packit 98cdb6
  async.handler = get_child_info_handler;
Packit 98cdb6
  async.data = (XPointer) &stat;;
Packit 98cdb6
  dpy->async_handlers = &asyn;;
Packit 98cdb6
  
Packit 98cdb6
  for (i = 0; i < state.nchildren; i++)
Packit 98cdb6
    {
Packit 98cdb6
      xResourceReq *resource_req;
Packit 98cdb6
      xGetPropertyReq *prop_req;
Packit 98cdb6
      Window window = state.children[i];
Packit 98cdb6
      
Packit 98cdb6
      if (get_wm_state)
Packit 98cdb6
	{
Packit 98cdb6
	  GetReq (GetProperty, prop_req);
Packit 98cdb6
	  prop_req->window = window;
Packit 98cdb6
	  prop_req->property = wm_state_atom;
Packit 98cdb6
	  prop_req->type = AnyPropertyType;
Packit 98cdb6
	  prop_req->delete = False;
Packit 98cdb6
	  prop_req->longOffset = 0;
Packit 98cdb6
	  prop_req->longLength = 0;
Packit 98cdb6
Packit 98cdb6
	  state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
Packit 98cdb6
	}
Packit 98cdb6
      
Packit 98cdb6
      GetResReq(GetWindowAttributes, window, resource_req);
Packit 98cdb6
      state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
Packit 98cdb6
      
Packit 98cdb6
      GetResReq(GetGeometry, window, resource_req);
Packit 98cdb6
      state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (i != 0)
Packit 98cdb6
    {
Packit 98cdb6
      /* Wait for the last reply
Packit 98cdb6
       */
Packit 98cdb6
      xGetGeometryReply rep;
Packit 98cdb6
Packit 98cdb6
      /* On error, our async handler will get called
Packit 98cdb6
       */
Packit 98cdb6
      if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
Packit 98cdb6
	handle_get_geometry_reply (dpy, &state, &rep;;
Packit 98cdb6
Packit 98cdb6
      next_child (&state);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (!state.have_error)
Packit 98cdb6
    {
Packit 98cdb6
      *children = state.child_info;
Packit 98cdb6
      *nchildren = state.n_children_found;
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    {
Packit 98cdb6
      g_free (state.child_info);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_free (state.children);
Packit 98cdb6
  g_free (state.child_states);
Packit 98cdb6
  
Packit 98cdb6
  DeqAsyncHandler(dpy, &async);
Packit 98cdb6
  UnlockDisplay(dpy);
Packit 98cdb6
  SyncHandle();
Packit 98cdb6
Packit 98cdb6
  return !state.have_error;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static gboolean
Packit 98cdb6
roundtrip_callback_idle (gpointer data)
Packit 98cdb6
{
Packit 98cdb6
  RoundtripState *state = (RoundtripState *)data;  
Packit 98cdb6
  
Packit 98cdb6
  state->callback (state->display, state->data, state->get_input_focus_req);
Packit 98cdb6
Packit 98cdb6
  g_free (state);
Packit 98cdb6
Packit 98cdb6
  return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static Bool
Packit 98cdb6
roundtrip_handler (Display *dpy,
Packit 98cdb6
		   xReply  *rep,
Packit 98cdb6
		   char    *buf,
Packit 98cdb6
		   int      len,
Packit 98cdb6
		   XPointer data)
Packit 98cdb6
{
Packit 98cdb6
  RoundtripState *state = (RoundtripState *)data;  
Packit 98cdb6
  
Packit 98cdb6
  if (dpy->last_request_read == state->get_input_focus_req)
Packit 98cdb6
    {
Packit 98cdb6
      xGetInputFocusReply replbuf;
Packit 98cdb6
      xGetInputFocusReply *repl;
Packit 98cdb6
      
Packit 98cdb6
      if (rep->generic.type != X_Error)
Packit 98cdb6
	{
Packit 98cdb6
	  /* Actually does nothing, since there are no additional bytes
Packit 98cdb6
	   * to read, but maintain good form.
Packit 98cdb6
	   */
Packit 98cdb6
	  repl = (xGetInputFocusReply *)
Packit 98cdb6
	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
Packit 98cdb6
			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
Packit 98cdb6
			    True);
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      
Packit 98cdb6
      if (state->callback)
Packit 98cdb6
        gdk_threads_add_idle (roundtrip_callback_idle, state);
Packit 98cdb6
Packit 98cdb6
      DeqAsyncHandler(state->dpy, &state->async);
Packit 98cdb6
Packit 98cdb6
      return (rep->generic.type != X_Error);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return False;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gdk_x11_roundtrip_async (GdkDisplay           *display, 
Packit 98cdb6
			  GdkRoundTripCallback callback,
Packit 98cdb6
			  gpointer              data)
Packit 98cdb6
{
Packit 98cdb6
  Display *dpy;
Packit 98cdb6
  RoundtripState *state;
Packit 98cdb6
  
Packit 98cdb6
  dpy = GDK_DISPLAY_XDISPLAY (display);
Packit 98cdb6
Packit 98cdb6
  state = g_new (RoundtripState, 1);
Packit 98cdb6
Packit 98cdb6
  state->display = display;
Packit 98cdb6
  state->dpy = dpy;
Packit 98cdb6
  state->callback = callback;
Packit 98cdb6
  state->data = data;
Packit 98cdb6
  
Packit 98cdb6
  LockDisplay(dpy);
Packit 98cdb6
Packit 98cdb6
  state->async.next = dpy->async_handlers;
Packit 98cdb6
  state->async.handler = roundtrip_handler;
Packit 98cdb6
  state->async.data = (XPointer) state;
Packit 98cdb6
  dpy->async_handlers = &state->async;
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * XSync (dpy, 0)
Packit 98cdb6
   */
Packit 98cdb6
  {
Packit 98cdb6
    xReq *req;
Packit 98cdb6
    
Packit 98cdb6
    GetEmptyReq(GetInputFocus, req);
Packit 98cdb6
    state->get_input_focus_req = dpy->request;
Packit 98cdb6
  }
Packit 98cdb6
  
Packit 98cdb6
  UnlockDisplay(dpy);
Packit 98cdb6
  SyncHandle();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
#define __GDK_ASYNC_C__
Packit 98cdb6
#include "gdkaliasdef.c"