[mutter/wip/ui-on-own-connection: 6/13] errors: Copy error trap code from GDK into mutter
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/ui-on-own-connection: 6/13] errors: Copy error trap code from GDK into mutter
- Date: Mon, 7 Apr 2014 12:29:32 +0000 (UTC)
commit cc6becb163f87cf676465a4e564cda7af3ba4c3a
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Sun Apr 6 15:51:11 2014 -0400
errors: Copy error trap code from GDK into mutter
In order to kill off using GDK for event handling in X11, we're going
to need to stop using GDK primitives.
src/core/display-private.h | 2 +
src/core/errors.c | 263 ++++++++++++++++++++++++++++++++++++++++----
2 files changed, 241 insertions(+), 24 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 84ee5a8..26b83a0 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -253,6 +253,8 @@ struct _MetaDisplay
/* Closing down the display */
int closing;
+ GSList *error_traps;
+
/* Managed by group.c */
GHashTable *groups_by_leader;
diff --git a/src/core/errors.c b/src/core/errors.c
index f199c69..2e855f2 100644
--- a/src/core/errors.c
+++ b/src/core/errors.c
@@ -1,9 +1,8 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright (C) 2001 Havoc Pennington, error trapping inspired by GDK
- * code copyrighted by the GTK team.
- *
+/*
+ * Copyright (C) 2014 Red Hat
+ *
* 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 of the
@@ -13,9 +12,11 @@
* 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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
*/
/**
@@ -27,36 +28,250 @@
#include <config.h>
#include <meta/errors.h>
#include "display-private.h"
-#include <errno.h>
-#include <stdlib.h>
-#include <gdk/gdk.h>
-
-/* In GTK+-3.0, the error trapping code was significantly rewritten. The new code
- * has some neat features (like knowing automatically if a sync is needed or not
- * and handling errors asynchronously when the error code isn't needed immediately),
- * but it's basically incompatible with the hacks we played with GTK+-2.0 to
- * use a custom error handler along with gdk_error_trap_push().
- *
- * Since the main point of our custom error trap was to get the error logged
- * to the right place, with GTK+-3.0 we simply omit our own error handler and
- * use the GTK+ handling straight-up.
- * (See https://bugzilla.gnome.org/show_bug.cgi?id=630216 for restoring logging.)
- */
+
+/* This is a copy-paste of the error handling code in GDK, modified
+ * so that it works with mutter's internal structures, since we don't
+ * have a GDK display open. */
+
+/* compare X sequence numbers handling wraparound */
+#define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
+
+typedef struct _GdkErrorTrap GdkErrorTrap;
+
+struct _GdkErrorTrap
+{
+ /* Next sequence when trap was pushed, i.e. first sequence to
+ * ignore
+ */
+ gulong start_sequence;
+
+ /* Next sequence when trap was popped, i.e. first sequence
+ * to not ignore. 0 if trap is still active.
+ */
+ gulong end_sequence;
+
+ /* Most recent error code within the sequence */
+ int error_code;
+};
+
+/* delivers an error event from the error handler in gdkmain-x11.c */
+static void
+meta_display_error_event (MetaDisplay *display,
+ XErrorEvent *error)
+{
+ GSList *tmp_list;
+ gboolean ignore;
+
+ ignore = FALSE;
+ for (tmp_list = display->error_traps;
+ tmp_list != NULL;
+ tmp_list = tmp_list->next)
+ {
+ GdkErrorTrap *trap;
+
+ trap = tmp_list->data;
+
+ if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
+ (trap->end_sequence == 0 ||
+ SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
+ {
+ ignore = TRUE;
+ trap->error_code = error->error_code;
+ break; /* only innermost trap gets the error code */
+ }
+ }
+
+ if (!ignore)
+ {
+ gchar buf[64];
+ gchar *msg;
+
+ XGetErrorText (display->xdisplay, error->error_code, buf, 63);
+
+ msg =
+ g_strdup_printf ("mutter received an X Window System error: %s\n"
+ " (Details: serial %ld error_code %d request_code %d minor_code %d)\n",
+ buf,
+ error->serial,
+ error->error_code,
+ error->request_code,
+ error->minor_code);
+
+ g_error ("%s", msg);
+ }
+}
+
+static int
+gdk_x_error (Display *xdisplay,
+ XErrorEvent *error)
+{
+ MetaDisplay *display = meta_display_for_x_display (xdisplay);
+ meta_display_error_event (display, error);
+ return 0;
+}
+
+/* non-GDK previous error handler */
+typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
+static GdkXErrorHandler _gdk_old_error_handler;
+/* number of times we've pushed the GDK error handler */
+static int _gdk_error_handler_push_count = 0;
+
+static void
+_gdk_x11_error_handler_push (void)
+{
+ GdkXErrorHandler previous;
+
+ previous = XSetErrorHandler (gdk_x_error);
+
+ if (_gdk_error_handler_push_count > 0)
+ {
+ if (previous != gdk_x_error)
+ g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
+ }
+ else
+ {
+ _gdk_old_error_handler = previous;
+ }
+
+ _gdk_error_handler_push_count += 1;
+}
+
+static void
+_gdk_x11_error_handler_pop (void)
+{
+ g_return_if_fail (_gdk_error_handler_push_count > 0);
+
+ _gdk_error_handler_push_count -= 1;
+
+ if (_gdk_error_handler_push_count == 0)
+ {
+ XSetErrorHandler (_gdk_old_error_handler);
+ _gdk_old_error_handler = NULL;
+ }
+}
+
+static void
+delete_outdated_error_traps (MetaDisplay *display)
+{
+ GSList *tmp_list;
+ gulong processed_sequence;
+
+ processed_sequence = XLastKnownRequestProcessed (display->xdisplay);
+
+ tmp_list = display->error_traps;
+ while (tmp_list != NULL)
+ {
+ GdkErrorTrap *trap = tmp_list->data;
+
+ if (trap->end_sequence != 0 &&
+ SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
+ {
+ GSList *free_me = tmp_list;
+
+ tmp_list = tmp_list->next;
+ display->error_traps = g_slist_delete_link (display->error_traps, free_me);
+ g_slice_free (GdkErrorTrap, trap);
+ }
+ else
+ {
+ tmp_list = tmp_list->next;
+ }
+ }
+}
void
meta_error_trap_push (MetaDisplay *display)
{
- gdk_error_trap_push ();
+ GdkErrorTrap *trap;
+
+ delete_outdated_error_traps (display);
+
+ /* set up the Xlib callback to tell us about errors */
+ _gdk_x11_error_handler_push ();
+
+ trap = g_slice_new0 (GdkErrorTrap);
+
+ trap->start_sequence = XNextRequest (display->xdisplay);
+ trap->error_code = Success;
+
+ display->error_traps =
+ g_slist_prepend (display->error_traps, trap);
+}
+
+static gint
+meta_error_trap_pop_internal (MetaDisplay *display,
+ gboolean need_code)
+{
+ GdkErrorTrap *trap;
+ GSList *tmp_list;
+ int result;
+
+ g_return_val_if_fail (display->error_traps != NULL, Success);
+
+ /* Find the first trap that hasn't been popped already */
+ trap = NULL; /* quiet gcc */
+ for (tmp_list = display->error_traps;
+ tmp_list != NULL;
+ tmp_list = tmp_list->next)
+ {
+ trap = tmp_list->data;
+
+ if (trap->end_sequence == 0)
+ break;
+ }
+
+ g_return_val_if_fail (trap != NULL, Success);
+ g_assert (trap->end_sequence == 0);
+
+ /* May need to sync to fill in trap->error_code if we care about
+ * getting an error code.
+ */
+ if (need_code)
+ {
+ gulong processed_sequence;
+ gulong next_sequence;
+
+ next_sequence = XNextRequest (display->xdisplay);
+ processed_sequence = XLastKnownRequestProcessed (display->xdisplay);
+
+ /* If our last request was already processed, there is no point
+ * in syncing. i.e. if last request was a round trip (or even if
+ * we got an event with the serial of a non-round-trip)
+ */
+ if ((next_sequence - 1) != processed_sequence)
+ {
+ XSync (display->xdisplay, False);
+ }
+
+ result = trap->error_code;
+ }
+ else
+ {
+ result = Success;
+ }
+
+ /* record end of trap, giving us a range of
+ * error sequences we'll ignore.
+ */
+ trap->end_sequence = XNextRequest (display->xdisplay);
+
+ /* remove the Xlib callback */
+ _gdk_x11_error_handler_pop ();
+
+ /* we may already be outdated */
+ delete_outdated_error_traps (display);
+
+ return result;
}
void
meta_error_trap_pop (MetaDisplay *display)
{
- gdk_error_trap_pop_ignored ();
+ meta_error_trap_pop_internal (display, FALSE);
}
int
meta_error_trap_pop_with_return (MetaDisplay *display)
{
- return gdk_error_trap_pop ();
+ return meta_error_trap_pop_internal (display, TRUE);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]