diff options
author | Owen Taylor <otaylor@redhat.com> | 2003-07-05 03:02:21 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2003-07-05 03:02:21 +0000 |
commit | 60149b3275048d86a317c808702b12c96f1e6720 (patch) | |
tree | 5c859eeab1631b892f84a6a4bcff9be815774c94 /gdk/x11 | |
parent | 8625065817ddaaf501f17b27b84a19e9968c8d8d (diff) | |
download | gtk+-60149b3275048d86a317c808702b12c96f1e6720.tar.gz |
Add a function to XSendEvent() and call a calback on failure/success.
Fri Jul 4 22:57:18 2003 Owen Taylor <otaylor@redhat.com>
* gdk/x11/gdkasync.[ch] (_gdk_send_xevent_async): Add
a function to XSendEvent() and call a calback on
failure/success.
* gdk/x11/gdkdnd-x11.c (xdnd_send_xevent): Short-circuit
messages to the same process, use _gdk_send_xevent_async().
Diffstat (limited to 'gdk/x11')
-rw-r--r-- | gdk/x11/gdkasync.c | 141 | ||||
-rw-r--r-- | gdk/x11/gdkasync.h | 19 | ||||
-rw-r--r-- | gdk/x11/gdkdnd-x11.c | 217 |
3 files changed, 300 insertions, 77 deletions
diff --git a/gdk/x11/gdkasync.c b/gdk/x11/gdkasync.c index c087862e05..1ba90be295 100644 --- a/gdk/x11/gdkasync.c +++ b/gdk/x11/gdkasync.c @@ -47,18 +47,156 @@ in this Software without prior written authorization from The Open Group. #include "gdkasync.h" #include "gdkx.h" +typedef struct _SendEventState SendEventState; typedef struct _SetInputFocusState SetInputFocusState; -struct _SetInputFocusState +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; }; 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) + { + if (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; + + if (rep->generic.type != X_Error) + { + repl = (xGetInputFocusReply *) + _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, + (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2, + True); + } + + if (state->callback) + state->callback (state->window, !state->have_error, state->data); + + DeqAsyncHandler(state->dpy, &state->async); + + g_free (state); + + return True; + } + + return False; +} + +void +_gdk_send_xevent_async (GdkDisplay *display, + Window window, + gboolean propagate, + glong event_mask, + XEvent *event_send, + GdkSendXEventCallback callback, + gpointer data) +{ + Display *dpy; + SendEventState *state; + Status status; + + 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; + register Status (**fp)(); + + /* call through display to find proper conversion routine */ + + fp = &dpy->wire_vec[event_send->type & 0177]; + if (*fp == NULL) *fp = _XEventToWire; + status = (**fp)(dpy, event_send, &ev); + + if (!status) + { + g_warning ("Error converting event to wire"); + DeqAsyncHandler(dpy, &state->async); + UnlockDisplay(dpy); + SyncHandle(); + g_free (state); + + return; + } + + 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) + */ + { + xReq *req; + + GetEmptyReq(GetInputFocus, req); + state->get_input_focus_req = dpy->request; + } + + UnlockDisplay(dpy); + SyncHandle(); +} + +static Bool set_input_focus_handler (Display *dpy, xReply *rep, char *buf, @@ -119,7 +257,6 @@ _gdk_x11_set_input_focus_safe (GdkDisplay *display, state = g_new (SetInputFocusState, 1); state->dpy = dpy; - state->window = window; LockDisplay(dpy); diff --git a/gdk/x11/gdkasync.h b/gdk/x11/gdkasync.h index 2da6040304..ea2d7b0746 100644 --- a/gdk/x11/gdkasync.h +++ b/gdk/x11/gdkasync.h @@ -26,10 +26,21 @@ G_BEGIN_DECLS -void _gdk_x11_set_input_focus_safe (GdkDisplay *display, - Window window, - int revert_to, - Time time); +typedef void (*GdkSendXEventCallback) (Window window, + gboolean success, + gpointer data); + +void _gdk_send_xevent_async (GdkDisplay *display, + Window window, + gboolean propagate, + glong event_mask, + XEvent *event_send, + GdkSendXEventCallback callback, + gpointer data); +void _gdk_x11_set_input_focus_safe (GdkDisplay *display, + Window window, + int revert_to, + Time time); G_END_DECLS diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c index c962894ccb..00df75ca37 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -30,6 +30,7 @@ #include "gdk.h" /* For gdk_flush() */ #include "gdkx.h" +#include "gdkasync.h" #include "gdkdnd.h" #include "gdkproperty.h" #include "gdkprivate-x11.h" @@ -98,29 +99,24 @@ static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev, GdkEvent *event, gpointer data); -static GdkFilterReturn xdnd_enter_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data); - -static GdkFilterReturn xdnd_leave_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data); - +static GdkFilterReturn xdnd_enter_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data); +static GdkFilterReturn xdnd_leave_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data); static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev, GdkEvent *event, gpointer data); - -static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data); - +static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data); static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data); - -static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data); + GdkEvent *event, + gpointer data); +static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data); static void xdnd_manage_source_filter (GdkDragContext *context, GdkWindow *window, @@ -133,6 +129,18 @@ static void gdk_drag_context_finalize (GObject *object); static gpointer parent_class = NULL; static GList *contexts; +const static struct { + const char *atom_name; + GdkFilterFunc func; +} xdnd_filters[] = { + { "XdndEnter", xdnd_enter_filter }, + { "XdndLeave", xdnd_leave_filter }, + { "XdndPosition", xdnd_position_filter }, + { "XdndStatus", xdnd_status_filter }, + { "XdndFinished", xdnd_finished_filter }, + { "XdndDrop", xdnd_drop_filter }, +}; + GType gdk_drag_context_get_type (void) { @@ -2090,28 +2098,116 @@ xdnd_set_actions (GdkDragContext *context) private->xdnd_actions = context->actions; } -/************************************************************* - * xdnd_send_xevent: - * Like gdk_send_event, but if the target is the root - * window, sets an event mask of ButtonPressMask, otherwise - * an event mask of 0. - * arguments: - * - * results: - *************************************************************/ +static void +send_xevent_async_cb (Window window, + gboolean success, + gpointer data) +{ + GdkDragContext *context = data; + GDK_NOTE (DND, + g_message ("Got async callback for #%lx, success = %d", + window, success)); + + /* On failure, we immediately continue with the protocol + * so we don't end up blocking for a timeout + */ + if (!success && + context->dest_window && + window == GDK_WINDOW_XID (context->dest_window)) + { + GdkEvent temp_event; + GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); + + g_object_unref (context->dest_window); + context->dest_window = NULL; + context->action = 0; + + private->drag_status = GDK_DRAG_STATUS_DRAG; + + temp_event.dnd.type = GDK_DRAG_STATUS; + temp_event.dnd.window = context->source_window; + temp_event.dnd.send_event = TRUE; + temp_event.dnd.context = context; + temp_event.dnd.time = GDK_CURRENT_TIME; + + gdk_event_put (&temp_event); + } + + g_object_unref (context); +} + + +static GdkDisplay * +gdk_drag_context_get_display (GdkDragContext *context) +{ + if (context->source_window) + return GDK_DRAWABLE_DISPLAY (context->source_window); + else if (context->dest_window) + return GDK_DRAWABLE_DISPLAY (context->dest_window); + + g_assert_not_reached (); + return NULL; +} + +static void +send_xevent_async (GdkDragContext *context, + Window window, + gboolean propagate, + glong event_mask, + XEvent *event_send) +{ + GdkDisplay *display = gdk_drag_context_get_display (context); + + g_object_ref (context); + + _gdk_send_xevent_async (display, window, propagate, event_mask, event_send, + send_xevent_async_cb, context); +} static gboolean -xdnd_send_xevent (GdkDisplay *display, - Window window, - gboolean propagate, - XEvent *event_send) +xdnd_send_xevent (GdkDragContext *context, + GdkWindow *window, + gboolean propagate, + XEvent *event_send) { - if (_gdk_x11_display_is_root_window (display, window)) - return _gdk_send_xevent (display, window, propagate, ButtonPressMask, event_send); + GdkDisplay *display = gdk_drag_context_get_display (context); + Window xwindow; + glong event_mask; + + /* We short-circuit messages to ourselves */ + if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN && + event_send->xany.type == ClientMessage) + { + gint i; + + for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++) + { + if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) == + event_send->xclient.message_type) + { + GdkEvent temp_event; + temp_event.any.window = window; + + if ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE) + gdk_event_put (&temp_event); + + return TRUE; + } + } + } + + xwindow = GDK_WINDOW_XWINDOW (window); + + if (_gdk_x11_display_is_root_window (display, xwindow)) + event_mask = ButtonPressMask; else - return _gdk_send_xevent (display, window, propagate, 0, event_send); -} + event_mask = 0; + + send_xevent_async (context, xwindow, propagate, event_mask, event_send); + return TRUE; +} + static void xdnd_send_enter (GdkDragContext *context) { @@ -2154,8 +2250,7 @@ xdnd_send_enter (GdkDragContext *context) } } - if (!xdnd_send_xevent (display, - GDK_DRAWABLE_XID (context->dest_window), + if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, @@ -2186,8 +2281,7 @@ xdnd_send_leave (GdkDragContext *context) xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - if (!xdnd_send_xevent (display, - GDK_DRAWABLE_XID (context->dest_window), + if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, @@ -2217,8 +2311,7 @@ xdnd_send_drop (GdkDragContext *context, guint32 time) xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - if (!xdnd_send_xevent (display, - GDK_DRAWABLE_XID (context->dest_window), + if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, @@ -2252,8 +2345,7 @@ xdnd_send_motion (GdkDragContext *context, xev.xclient.data.l[3] = time; xev.xclient.data.l[4] = xdnd_action_to_atom (display, action); - if (!xdnd_send_xevent (display, - GDK_DRAWABLE_XID (context->dest_window), + if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, @@ -2700,36 +2792,21 @@ xdnd_drop_filter (GdkXEvent *xev, void _gdk_dnd_init (GdkDisplay *display) { + int i; init_byte_order (); gdk_display_add_client_message_filter ( display, gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE), motif_dnd_filter, NULL); - gdk_display_add_client_message_filter ( - display, - gdk_atom_intern ("XdndEnter", FALSE), - xdnd_enter_filter, NULL); - gdk_display_add_client_message_filter ( - display, - gdk_atom_intern ("XdndLeave", FALSE), - xdnd_leave_filter, NULL); - gdk_display_add_client_message_filter ( - display, - gdk_atom_intern ("XdndPosition", FALSE), - xdnd_position_filter, NULL); - gdk_display_add_client_message_filter ( - display, - gdk_atom_intern ("XdndStatus", FALSE), - xdnd_status_filter, NULL); - gdk_display_add_client_message_filter ( + + for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++) + { + gdk_display_add_client_message_filter ( display, - gdk_atom_intern ("XdndFinished", FALSE), - xdnd_finished_filter, NULL); - gdk_display_add_client_message_filter ( - display, - gdk_atom_intern ("XdndDrop", FALSE), - xdnd_drop_filter, NULL); + gdk_atom_intern (xdnd_filters[i].atom_name, FALSE), + xdnd_filters[i].func, NULL); + } } /* Source side */ @@ -3321,8 +3398,7 @@ gdk_drag_status (GdkDragContext *context, xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = xdnd_action_to_atom (display, action); - if (!xdnd_send_xevent (display, - GDK_DRAWABLE_XID (context->source_window), + if (!xdnd_send_xevent (context, context->source_window, FALSE, &xev)) GDK_NOTE (DND, g_message ("Send event to %lx failed", @@ -3421,8 +3497,7 @@ gdk_drop_finish (GdkDragContext *context, xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - if (!xdnd_send_xevent (display, - GDK_DRAWABLE_XID (context->source_window), + if (!xdnd_send_xevent (context, context->source_window, FALSE, &xev)) GDK_NOTE (DND, g_message ("Send event to %lx failed", |