/* GTK - The GIMP Toolkit
* gdkasync . c : Utility functions using the Xlib asynchronous interfaces
* Copyright ( C ) 2003 , Red Hat , Inc .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*/
/* Portions of code in this file are based on code from Xlib
*/
/*
Copyright 1986 , 1998 The Open Group
Permission to use , copy , modify , distribute , and sell this software and its
documentation for any purpose is hereby granted without fee , provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation .
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN
AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
Except as contained in this notice , the name of The Open Group shall not be
used in advertising or otherwise to promote the sale , use or other dealings
in this Software without prior written authorization from The Open Group .
*/
#include "config.h"
#include "gdkasync.h"
#include "gdkprivate-x11.h"
#include "gdkdisplay-x11.h"
#include "gdkprivate.h"
#include <X11/Xlibint.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef struct _ChildInfoChildState ChildInfoChildState;
typedef struct _ChildInfoState ChildInfoState;
typedef struct _ListChildrenState ListChildrenState;
typedef struct _SendEventState SendEventState;
typedef struct _SetInputFocusState SetInputFocusState;
typedef struct _RoundtripState RoundtripState;
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;
int current_request;
gboolean have_error;
gboolean child_has_error;
};
struct _ListChildrenState
{
Display *dpy;
gulong get_property_req;
gboolean have_error;
gboolean has_wm_state;
};
struct _SendEventState
{
Display *dpy;
Window window;
_XAsyncHandler async;
gulong send_event_req;
gulong get_input_focus_req;
gboolean have_error;
GdkSendXEventCallback callback;
gpointer data;
};
struct _SetInputFocusState
{
Display *dpy;
_XAsyncHandler async;
gulong set_input_focus_req;
gulong get_input_focus_req;
};
struct _RoundtripState
{
Display *dpy;
_XAsyncHandler async;
gulong get_input_focus_req;
GdkDisplay *display;
GdkRoundTripCallback callback;
gpointer data;
};
static gboolean
callback_idle (gpointer data)
{
SendEventState *state = (SendEventState *)data;
state->callback (state->window, !state->have_error, state->data);
g_free (state);
return G_SOURCE_REMOVE;
}
static Bool
send_event_handler (Display *dpy,
xReply *rep,
char *buf,
int len,
XPointer data)
{
SendEventState *state = (SendEventState *)data;
if (dpy->last_request_read == state->send_event_req)
{
if (rep->generic.type == X_Error &&
rep->error.errorCode == BadWindow)
{
state->have_error = TRUE ;
return True ;
}
}
else if (dpy->last_request_read == state->get_input_focus_req)
{
xGetInputFocusReply replbuf;
xGetInputFocusReply *repl G_GNUC_UNUSED;
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 ,
True );
}
if (state->callback)
{
guint id;
id = g_idle_add (callback_idle, state);
gdk_source_set_static_name_by_id (id, "[gtk] callback_idle" );
}
DeqAsyncHandler(state->dpy, &state->async);
return (rep->generic.type != X_Error);
}
return False ;
}
static void
client_message_to_wire (XClientMessageEvent *ev,
xEvent *event)
{
int i;
event->u.clientMessage.window = ev->window;
event->u.u.type = ev->type;
event->u.u.detail = ev->format;
switch (ev->format)
{
case 8 :
event->u.clientMessage.u.b.type = ev->message_type;
for (i = 0 ; i < 20 ; i++)
event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
break ;
case 16 :
event->u.clientMessage.u.s.type = ev->message_type;
event->u.clientMessage.u.s.shorts0 = ev->data.s[0 ];
event->u.clientMessage.u.s.shorts1 = ev->data.s[1 ];
event->u.clientMessage.u.s.shorts2 = ev->data.s[2 ];
event->u.clientMessage.u.s.shorts3 = ev->data.s[3 ];
event->u.clientMessage.u.s.shorts4 = ev->data.s[4 ];
event->u.clientMessage.u.s.shorts5 = ev->data.s[5 ];
event->u.clientMessage.u.s.shorts6 = ev->data.s[6 ];
event->u.clientMessage.u.s.shorts7 = ev->data.s[7 ];
event->u.clientMessage.u.s.shorts8 = ev->data.s[8 ];
event->u.clientMessage.u.s.shorts9 = ev->data.s[9 ];
break ;
case 32 :
event->u.clientMessage.u.l.type = ev->message_type;
event->u.clientMessage.u.l.longs0 = ev->data.l[0 ];
event->u.clientMessage.u.l.longs1 = ev->data.l[1 ];
event->u.clientMessage.u.l.longs2 = ev->data.l[2 ];
event->u.clientMessage.u.l.longs3 = ev->data.l[3 ];
event->u.clientMessage.u.l.longs4 = ev->data.l[4 ];
break ;
default :
/* client passing bogus data, let server complain */
break ;
}
}
void
_gdk_x11_send_client_message_async (GdkDisplay *display,
Window window,
gboolean propagate,
glong event_mask,
XClientMessageEvent *event_send,
GdkSendXEventCallback callback,
gpointer data)
{
Display *dpy;
SendEventState *state;
dpy = GDK_DISPLAY_XDISPLAY (display);
state = g_new (SendEventState, 1 );
state->dpy = dpy;
state->window = window;
state->callback = callback;
state->data = data;
state->have_error = FALSE ;
LockDisplay(dpy);
state->async.next = dpy->async_handlers;
state->async.handler = send_event_handler;
state->async.data = (XPointer) state;
dpy->async_handlers = &state->async;
{
register xSendEventReq *req;
xEvent ev;
client_message_to_wire (event_send, &ev);
GetReq(SendEvent, req);
req->destination = window;
req->propagate = propagate;
req->eventMask = event_mask;
/* gross, matches Xproto.h */
#ifdef WORD64
memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF (xEvent));
#else
memcpy ((char *) &req->event, (char *) &ev, SIZEOF (xEvent));
#endif
state->send_event_req = dpy->request;
}
/*
* XSync ( dpy , 0 )
*/
{
G_GNUC_UNUSED xReq *req;
GetEmptyReq(GetInputFocus, req);
state->get_input_focus_req = dpy->request;
}
UnlockDisplay(dpy);
SyncHandle();
}
static Bool
list_children_handler (Display *dpy,
xReply *rep,
char *buf,
int len,
XPointer data)
{
ListChildrenState *state = (ListChildrenState *)data;
if (dpy->last_request_read != state->get_property_req)
return False ;
if (rep->generic.type == X_Error)
{
state->have_error = TRUE ;
return False ;
}
else
{
xGetPropertyReply replbuf;
xGetPropertyReply *repl;
repl = (xGetPropertyReply *)
_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
(sizeof (xGetPropertyReply) - sizeof (xReply)) >> 2 ,
True );
state->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
*/
return True ;
}
}
static gboolean
list_children_and_wm_state (Display *dpy,
Window w,
Atom wm_state_atom,
gboolean *has_wm_state,
Window **children,
unsigned int *nchildren)
{
ListChildrenState state;
_XAsyncHandler async;
long nbytes;
xQueryTreeReply rep;
register xResourceReq *req;
xGetPropertyReq *prop_req;
LockDisplay(dpy);
*children = NULL;
*nchildren = 0 ;
*has_wm_state = FALSE ;
state.have_error = FALSE ;
state.has_wm_state = FALSE ;
if (wm_state_atom)
{
async.next = dpy->async_handlers;
async.handler = list_children_handler;
async.data = (XPointer) &state;
dpy->async_handlers = &async;
GetReq (GetProperty, prop_req);
prop_req->window = w;
prop_req->property = wm_state_atom;
prop_req->type = AnyPropertyType;
prop_req->delete = False ;
prop_req->longOffset = 0 ;
prop_req->longLength = 0 ;
state.get_property_req = dpy->request;
}
GetResReq(QueryTree, w, req);
if (!_XReply(dpy, (xReply *)&rep, 0 , xFalse))
{
state.have_error = TRUE ;
goto out;
}
if (rep.nChildren != 0 )
{
nbytes = rep.nChildren << 2 ;
if (state.have_error)
{
_XEatData(dpy, (unsigned long ) nbytes);
goto out;
}
*children = g_new (Window, rep.nChildren);
_XRead32 (dpy, (long *) *children, nbytes);
}
*nchildren = rep.nChildren;
*has_wm_state = state.has_wm_state;
out:
if (wm_state_atom)
DeqAsyncHandler(dpy, &async);
UnlockDisplay(dpy);
SyncHandle();
return !state.have_error;
}
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 ;
default :
break ;
}
}
next_child (state);
return result;
}
gboolean
_gdk_x11_get_window_child_info (GdkDisplay *display,
Window window,
gboolean get_wm_state,
gboolean *win_has_wm_state,
GdkChildInfoX11 **children,
guint *nchildren)
{
Display *dpy;
_XAsyncHandler async;
ChildInfoState state;
Atom wm_state_atom;
gboolean has_wm_state;
Bool result;
guint i;
*children = NULL;
*nchildren = 0 ;
dpy = GDK_DISPLAY_XDISPLAY (display);
if (get_wm_state)
wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE" );
else
wm_state_atom = None;
state.children = NULL;
state.nchildren = 0 ;
gdk_x11_display_error_trap_push (display);
result = list_children_and_wm_state (dpy, window,
win_has_wm_state ? wm_state_atom : None,
&has_wm_state,
&state.children, &state.nchildren);
gdk_x11_display_error_trap_pop_ignored (display);
if (!result)
{
g_free (state.children);
return FALSE ;
}
if (has_wm_state)
{
if (win_has_wm_state)
*win_has_wm_state = TRUE ;
g_free (state.children);
return TRUE ;
}
else
{
if (win_has_wm_state)
*win_has_wm_state = 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 win = state.children[i];
if (get_wm_state)
{
GetReq (GetProperty, prop_req);
prop_req->window = win;
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, win, resource_req);
state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
GetResReq(GetGeometry, win, 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);
}
g_free (state.children);
g_free (state.child_states);
DeqAsyncHandler(dpy, &async);
UnlockDisplay(dpy);
SyncHandle();
return !state.have_error;
}
static gboolean
roundtrip_callback_idle (gpointer data)
{
RoundtripState *state = (RoundtripState *)data;
state->callback (state->display, state->data, state->get_input_focus_req);
g_free (state);
return G_SOURCE_REMOVE;
}
static Bool
roundtrip_handler (Display *dpy,
xReply *rep,
char *buf,
int len,
XPointer data)
{
RoundtripState *state = (RoundtripState *)data;
if (dpy->last_request_read == state->get_input_focus_req)
{
xGetInputFocusReply replbuf;
xGetInputFocusReply *repl G_GNUC_UNUSED;
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 ,
True );
}
if (state->callback)
{
guint id;
id = g_idle_add (roundtrip_callback_idle, state);
gdk_source_set_static_name_by_id (id, "[gtk] roundtrip_callback_idle" );
}
DeqAsyncHandler(state->dpy, &state->async);
return (rep->generic.type != X_Error);
}
return False ;
}
void
_gdk_x11_roundtrip_async (GdkDisplay *display,
GdkRoundTripCallback callback,
gpointer data)
{
Display *dpy;
RoundtripState *state;
dpy = GDK_DISPLAY_XDISPLAY (display);
state = g_new (RoundtripState, 1 );
state->display = display;
state->dpy = dpy;
state->callback = callback;
state->data = data;
LockDisplay(dpy);
state->async.next = dpy->async_handlers;
state->async.handler = roundtrip_handler;
state->async.data = (XPointer) state;
dpy->async_handlers = &state->async;
/*
* XSync ( dpy , 0 )
*/
{
G_GNUC_UNUSED xReq *req;
GetEmptyReq(GetInputFocus, req);
state->get_input_focus_req = dpy->request;
}
UnlockDisplay(dpy);
SyncHandle();
}
Messung V0.5 in Prozent C=99 H=97 G=97
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland