summaryrefslogtreecommitdiff
path: root/gdk/x11
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2003-07-05 03:02:21 +0000
committerOwen Taylor <otaylor@src.gnome.org>2003-07-05 03:02:21 +0000
commit60149b3275048d86a317c808702b12c96f1e6720 (patch)
tree5c859eeab1631b892f84a6a4bcff9be815774c94 /gdk/x11
parent8625065817ddaaf501f17b27b84a19e9968c8d8d (diff)
downloadgtk+-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.c141
-rw-r--r--gdk/x11/gdkasync.h19
-rw-r--r--gdk/x11/gdkdnd-x11.c217
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",