summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2007-04-18 01:51:12 -0400
committerRay Strode <rstrode@redhat.com>2007-04-18 01:51:12 -0400
commitfac22f053b37386dd13152f9063cde817a466aa8 (patch)
treec796eb6e93aa96193f0d43cce510cf39e5d35768
parent3594f0a035002ec08bfdf10cc391bc96222f54bd (diff)
add experiment x reply event source
-rw-r--r--src/pop-x-reply-watch.c312
-rw-r--r--src/pop-x-reply-watch.h47
2 files changed, 359 insertions, 0 deletions
diff --git a/src/pop-x-reply-watch.c b/src/pop-x-reply-watch.c
new file mode 100644
index 0000000..9a34bb3
--- /dev/null
+++ b/src/pop-x-reply-watch.c
@@ -0,0 +1,312 @@
+/* pop-x-reply-watch.c - event source for asynchronous X replies
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "config.h"
+#include <glib.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+#include <gtk/gtk.h>
+
+typedef struct _PopXReplyWatchSource PopXReplyWatchSource;
+
+struct _PopXReplyWatchSource
+{
+ GSource source;
+ GdkDisplay *display;
+ gulong request_id;
+ Status status;
+ XErrorEvent *error;
+
+ GSource *timeout_source;
+};
+
+static gboolean
+pop_x_reply_watch_prepare (GSource *source,
+ gint *timeout)
+{
+ /* we don't need to poll because we'll always
+ * get checked after the X event queue has been
+ * processed
+ */
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+pop_x_reply_watch_check (GSource *source)
+{
+ gulong last_processed_request_id;
+ PopXReplyWatchSource *x_reply_watch_source;
+
+ x_reply_watch_source = (PopXReplyWatchSource *) source;
+
+ last_processed_request_id = LastKnownRequestProcessed (GDK_DISPLAY_XDISPLAY (x_reply_watch_source->display));
+
+ return last_processed_request_id >= x_reply_watch_source->request_id;
+}
+
+static gboolean
+pop_x_reply_watch_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ PopXReplyWatchSource *x_reply_watch_source;
+ PopXReplyWatchFunc x_reply_watch_func;
+
+ if (callback == NULL)
+ return FALSE;
+
+ x_reply_watch_source = (PopXReplyWatchSource *) source;
+
+ x_reply_watch_func = (PopXReplyWatchFunc) callback;
+
+ x_reply_watch_func (x_reply_watch_source->display,
+ x_reply_watch_source->status,
+ x_reply_watch_source->error, user_data);
+
+ return FALSE;
+}
+
+static void
+pop_x_reply_watch_finalize (GSource *source)
+{
+ GList *pending_sources;
+ PopXReplyWatchSource *x_reply_watch_source;
+
+ x_reply_watch_source = (PopXReplyWatchSource *) source;
+
+ pending_sources = g_object_get_data (G_OBJECT (x_reply_watch_source->display),
+ "pop-x-reply-sources");
+
+ pending_sources = g_list_remove (pending_sources, source);
+ g_object_set_data (G_OBJECT (x_reply_watch_source->display),
+ "pop-x-reply-sources",
+ pending_sources);
+
+ if (x_reply_watch_source->error != NULL)
+ g_slice_free (XErrorEvent, x_reply_watch_source->error);
+
+ if (!g_source_is_destroyed (x_reply_watch_source->timeout_source))
+ g_source_destroy (x_reply_watch_source->timeout_source);
+
+ g_source_unref (x_reply_watch_source->timeout_source);
+ x_reply_watch_source->timeout_source = NULL;
+}
+
+static GSourceFuncs pop_x_reply_watch_funcs =
+{
+ pop_x_reply_watch_prepare,
+ pop_x_reply_watch_check,
+ pop_x_reply_watch_dispatch,
+ pop_x_reply_watch_finalize,
+};
+
+static XErrorHandler old_error_handler = NULL;
+
+typedef struct
+{
+ XErrorEvent *error;
+ PopXReplyWatchSource *source;
+} PopXReplyWatchErrorAndSource;
+
+static gboolean
+add_error_to_source_idle_handler (gpointer data)
+{
+ PopXReplyWatchErrorAndSource *error_and_source = (PopXReplyWatchErrorAndSource *) data;
+
+ g_assert (error_and_source->source != NULL);
+
+ error_and_source->source->error = error_and_source->error;
+ error_and_source->source->status = error_and_source->error->error_code;
+
+ g_slice_free (PopXReplyWatchErrorAndSource, error_and_source);
+ return FALSE;
+}
+
+static int
+pop_x_reply_watch_error_handler (Display *x_display,
+ XErrorEvent *error)
+{
+ GList *pending_sources, *tmp;
+ GdkDisplay *display;
+
+ display = gdk_x11_lookup_xdisplay (x_display);
+
+ g_assert (display != NULL);
+
+ pending_sources = g_object_get_data (G_OBJECT (display),
+ "pop-x-reply-sources");
+
+ for (tmp = pending_sources; tmp != NULL; tmp = tmp->next)
+ {
+ GSource *source;
+ PopXReplyWatchSource *x_reply_watch_source;
+ x_reply_watch_source = (PopXReplyWatchSource *) tmp->data;
+ source = (GSource *) tmp->data;
+
+ if (x_reply_watch_source->request_id == error->serial)
+ {
+ GSource *idle_source;
+ PopXReplyWatchErrorAndSource *error_and_source;
+
+ error_and_source = g_slice_new (PopXReplyWatchErrorAndSource);
+ error_and_source->error = g_slice_new (XErrorEvent);
+ *error_and_source->error = *error;
+ error_and_source->source = x_reply_watch_source;
+
+ idle_source = g_idle_source_new ();
+ g_source_set_priority (idle_source, 0);
+ g_source_set_callback (idle_source,
+ add_error_to_source_idle_handler,
+ error_and_source, NULL);
+ g_source_attach (idle_source, g_source_get_context (source));
+ g_source_unref (idle_source);
+
+ return 0;
+ }
+ }
+
+ if (old_error_handler != NULL)
+ return old_error_handler (x_display, error);
+
+ return 0;
+}
+
+static void
+pop_x_reply_watch_setup_error_handler (void)
+{
+ XErrorHandler current_error_handler;
+
+ current_error_handler = XSetErrorHandler (NULL);
+
+ if (current_error_handler != pop_x_reply_watch_error_handler)
+ {
+ old_error_handler = current_error_handler;
+ XSetErrorHandler (pop_x_reply_watch_error_handler);
+ return;
+ }
+
+ XSetErrorHandler (current_error_handler);
+}
+
+static void
+pop_x_reply_watch_source_register_with_display (GSource *source,
+ GdkDisplay *display)
+{
+ GList *pending_sources;
+ PopXReplyWatchSource *x_reply_watch_source;
+
+ x_reply_watch_source = (PopXReplyWatchSource *) source;
+
+ pending_sources = g_object_get_data (G_OBJECT (display),
+ "pop-x-reply-sources");
+
+ pending_sources = g_list_prepend (pending_sources, source);
+ g_object_set_data (G_OBJECT (x_reply_watch_source->display),
+ "pop-x-reply-sources",
+ pending_sources);
+}
+
+GSource *
+pop_x_reply_watch_source_new (GdkDisplay *display,
+ PopXRequestFunc request_func,
+ gpointer request_func_data)
+{
+ GSource *source;
+ gulong request_id, next_request_id;
+ PopXReplyWatchSource *x_reply_watch_source;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+ g_return_val_if_fail (request_func != NULL, NULL);
+
+ pop_x_reply_watch_setup_error_handler ();
+
+ request_id = XNextRequest (GDK_DISPLAY ());
+
+ source = g_source_new (&pop_x_reply_watch_funcs, sizeof (PopXReplyWatchSource));
+ x_reply_watch_source = (PopXReplyWatchSource *) source;
+
+ x_reply_watch_source->display = display;
+ x_reply_watch_source->request_id = request_id;
+ x_reply_watch_source->error = NULL;
+
+ pop_x_reply_watch_source_register_with_display (source, display);
+
+ x_reply_watch_source->status = request_func (display, request_func_data);
+
+ next_request_id = XNextRequest (GDK_DISPLAY ());
+ g_assert (next_request_id >= request_id);
+ if (request_id == next_request_id)
+ {
+ g_warning ("X reply watch source request function didn't "
+ "make an X request\n");
+ g_source_destroy (source);
+ g_source_unref (source);
+ return NULL;
+ }
+
+ /* if we don't get an answer back in a quarter of a second, force
+ * a round trip to ensure the request id gets incremented so the
+ * source gets dispatched
+ */
+ x_reply_watch_source->timeout_source = g_timeout_source_new (250);
+ g_source_set_callback (x_reply_watch_source->timeout_source,
+ (GSourceFunc) gdk_display_sync, display, NULL);
+ g_source_attach (x_reply_watch_source->timeout_source, g_source_get_context (source));
+
+ return source;
+}
+
+guint
+pop_x_reply_watch_add_full (gint priority,
+ GdkDisplay *display,
+ PopXRequestFunc request_func,
+ gpointer request_func_data,
+ PopXReplyWatchFunc reply_func,
+ gpointer reply_func_data,
+ GDestroyNotify notify)
+{
+ GSource *source;
+ guint id;
+
+ source = pop_x_reply_watch_source_new (display, request_func, request_func_data);
+
+ if (priority != G_PRIORITY_DEFAULT)
+ g_source_set_priority (source, priority);
+
+ g_source_set_callback (source, (GSourceFunc) reply_func, reply_func_data, notify);
+ id = g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ return id;
+}
+
+guint
+pop_x_reply_watch_add (GdkDisplay *display,
+ PopXRequestFunc request_func,
+ gpointer request_func_data,
+ PopXReplyWatchFunc reply_func,
+ gpointer reply_func_data)
+{
+ return pop_x_reply_watch_add_full (G_PRIORITY_DEFAULT,
+ display, request_func, request_func_data,
+ reply_func, reply_func_data, NULL);
+}
diff --git a/src/pop-x-reply-watch.h b/src/pop-x-reply-watch.h
new file mode 100644
index 0000000..beb1114
--- /dev/null
+++ b/src/pop-x-reply-watch.h
@@ -0,0 +1,47 @@
+/* pop-x-reply-watch.c - event source for asynchronous X replies
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef POP_X_REPLY_WATCH_H
+#define POP_X_REPLY_WATCH_H
+
+typedef Status (* PopXRequestFunc) (GdkDisplay *display,
+ gpointer user_data);
+typedef void (* PopXReplyWatchFunc) (GdkDisplay *display,
+ Status status,
+ XErrorEvent *error,
+ gpointer user_data);
+
+GSource *pop_x_reply_watch_source_new (GdkDisplay *display,
+ PopXRequestFunc request_func,
+ gpointer request_func_data);
+guint pop_x_reply_watch_add_full (gint priority,
+ GdkDisplay *display,
+ PopXRequestFunc request_func,
+ gpointer request_func_data,
+ PopXReplyWatchFunc reply_func,
+ gpointer reply_func_data,
+ GDestroyNotify notify);
+
+guint pop_x_reply_watch_add (GdkDisplay *display,
+ PopXRequestFunc request_func,
+ gpointer request_func_data,
+ PopXReplyWatchFunc reply_func,
+ gpointer data);
+
+#endif