summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrhp <rhp>2001-05-31 03:30:58 +0000
committerrhp <rhp>2001-05-31 03:30:58 +0000
commit1785975f3880c82824b05f82e8d6f2ef923d28bb (patch)
tree6438be2d49e7e113651368df0d85a09fc7e60c0c
parent287b6b15d3840d6546bbc55f9dbd7b3d098429c3 (diff)
downloadmetacity-1785975f3880c82824b05f82e8d6f2ef923d28bb.tar.gz
metacity-1785975f3880c82824b05f82e8d6f2ef923d28bb.tar.bz2
...
-rw-r--r--src/display.c66
-rw-r--r--src/display.h3
-rw-r--r--src/errors.c153
-rw-r--r--src/errors.h33
-rw-r--r--src/main.c3
-rwxr-xr-xsrc/run-metacity.sh5
-rw-r--r--src/screen.c51
-rw-r--r--src/util.c22
-rw-r--r--src/util.h2
9 files changed, 317 insertions, 21 deletions
diff --git a/src/display.c b/src/display.c
index 054407b..c53d2bb 100644
--- a/src/display.c
+++ b/src/display.c
@@ -60,6 +60,7 @@ meta_display_open (const char *name)
{
MetaDisplay *display;
Display *xdisplay;
+ GSList *screens;
int i;
meta_verbose ("Opening display '%s'\n", XDisplayName (name));
@@ -72,27 +73,48 @@ meta_display_open (const char *name)
XDisplayName (name));
return FALSE;
}
-
- display = g_new (MetaDisplay, 1);
+ display = g_new (MetaDisplay, 1);
+
display->name = g_strdup (XDisplayName (name));
display->xdisplay = xdisplay;
- display->events = meta_event_queue_new (display->xdisplay,
- event_queue_callback,
- display);
+ display->error_traps = NULL;
- display->window_ids = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
-
+ /* we have to go ahead and do this so error handlers work */
all_displays = g_slist_prepend (all_displays, display);
- display->screens = NULL;
+ screens = NULL;
i = 0;
while (i < ScreenCount (xdisplay))
{
- display->screens = g_slist_prepend (display->screens,
- meta_screen_new (display, i));
+ MetaScreen *screen;
+
+ screen = meta_screen_new (display, i);
+
+ if (screen)
+ screens = g_slist_prepend (screens, screen);
++i;
}
+
+ if (screens == NULL)
+ {
+ /* This would typically happen because all the screens already
+ * have window managers
+ */
+ XCloseDisplay (xdisplay);
+ all_displays = g_slist_remove (all_displays, display);
+ g_free (display->name);
+ g_free (display);
+ return FALSE;
+ }
+
+ display->screens = screens;
+
+ display->events = meta_event_queue_new (display->xdisplay,
+ event_queue_callback,
+ display);
+
+ display->window_ids = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
return TRUE;
}
@@ -110,6 +132,9 @@ free_window (gpointer key, gpointer value, gpointer data)
void
meta_display_close (MetaDisplay *display)
{
+ if (display->error_traps)
+ meta_bug ("Display closed with error traps pending\n");
+
g_hash_table_foreach (display->window_ids,
free_window,
NULL);
@@ -126,7 +151,7 @@ meta_display_close (MetaDisplay *display)
if (all_displays == NULL)
{
- meta_verbose ("Last display closed, quitting\n");
+ meta_verbose ("Last display closed, exiting\n");
meta_quit (META_EXIT_SUCCESS);
}
}
@@ -151,6 +176,25 @@ meta_display_screen_for_root (MetaDisplay *display,
return NULL;
}
+MetaDisplay*
+meta_display_for_x_display (Display *xdisplay)
+{
+ GSList *tmp;
+
+ tmp = all_displays;
+ while (tmp != NULL)
+ {
+ MetaDisplay *display = tmp->data;
+
+ if (display->xdisplay == xdisplay)
+ return display;
+
+ tmp = tmp->next;
+ }
+
+ return NULL;
+}
+
static gboolean dump_events = TRUE;
static void
diff --git a/src/display.h b/src/display.h
index ec73a27..a32be38 100644
--- a/src/display.h
+++ b/src/display.h
@@ -39,6 +39,7 @@ struct _MetaDisplay
MetaEventQueue *events;
GSList *screens;
GHashTable *window_ids;
+ GSList *error_traps;
};
gboolean meta_display_open (const char *name);
@@ -51,6 +52,6 @@ MetaWindow* meta_display_lookup_window (MetaDisplay *display,
void meta_display_register_window (MetaDisplay *display,
MetaWindow *window);
-
+MetaDisplay* meta_display_for_x_display (Display *xdisplay);
#endif
diff --git a/src/errors.c b/src/errors.c
new file mode 100644
index 0000000..24e59f7
--- /dev/null
+++ b/src/errors.c
@@ -0,0 +1,153 @@
+/* Metacity X error handling */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington, error trapping inspired by GDK
+ * code copyrighted by the GTK team.
+ *
+ * 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
+ * License, 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 "errors.h"
+#include <errno.h>
+
+typedef struct _ErrorTrap ErrorTrap;
+
+struct _ErrorTrap
+{
+ int error_code;
+};
+
+static int x_error_handler (Display *display,
+ XErrorEvent *error);
+static int x_io_error_handler (Display *display);
+
+void
+meta_errors_init (void)
+{
+ XSetErrorHandler (x_error_handler);
+ XSetIOErrorHandler (x_io_error_handler);
+}
+
+void
+meta_error_trap_push (MetaDisplay *display)
+{
+ ErrorTrap *et;
+
+ et = g_new (ErrorTrap, 1);
+
+ et->error_code = Success;
+ display->error_traps = g_slist_prepend (display->error_traps, et);
+}
+
+int
+meta_error_trap_pop (MetaDisplay *display)
+{
+ int result;
+ ErrorTrap *et;
+ GSList *next;
+
+ if (display->error_traps == NULL)
+ meta_bug ("No error trap to pop\n");
+
+ XSync (display->xdisplay, False);
+
+ et = display->error_traps->data;
+
+ result = et->error_code;
+
+ next = display->error_traps->next;
+ g_slist_free_1 (display->error_traps);
+ display->error_traps = next;
+
+ g_free (et);
+
+ return result;
+}
+
+
+static int
+x_error_handler (Display *xdisplay,
+ XErrorEvent *error)
+{
+ if (error->error_code)
+ {
+ MetaDisplay *display;
+
+ display = meta_display_for_x_display (xdisplay);
+
+ if (display == NULL)
+ meta_bug ("Error received for unknown display?\n");
+
+ if (display->error_traps == NULL)
+ {
+ gchar buf[64];
+
+ XGetErrorText (xdisplay, error->error_code, buf, 63);
+
+ meta_fatal ("Received an X Window System error without handling it.\n"
+ "The error was '%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);
+ }
+ else
+ {
+ ErrorTrap *et;
+
+ et = display->error_traps->data;
+
+ et->error_code = error->error_code;
+ }
+ }
+
+ return 0;
+}
+
+static int
+x_io_error_handler (Display *xdisplay)
+{
+ MetaDisplay *display;
+
+ display = meta_display_for_x_display (xdisplay);
+
+ if (display == NULL)
+ meta_bug ("Error received for unknown display?\n");
+
+ if (errno == EPIPE)
+ {
+ meta_warning (_("Lost connection to the display '%s';\n"
+ "most likely the X server was shut down or you killed/destroyed\n"
+ "the window manager.\n"),
+ display->name);
+ }
+ else
+ {
+ meta_warning (_("Fatal IO error %d (%s) on display '%s'.\n"),
+ errno, g_strerror (errno),
+ display->name);
+ }
+
+ meta_display_close (display);
+
+ /* I believe Xlib will force an exit after we return, which
+ * seems sort of broken to me, but if true we should probably just
+ * exit for ourselves. But for now I'm not doing it.
+ */
+ return 0;
+}
diff --git a/src/errors.h b/src/errors.h
new file mode 100644
index 0000000..b1a90e4
--- /dev/null
+++ b/src/errors.h
@@ -0,0 +1,33 @@
+/* Metacity X error handling */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ *
+ * 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
+ * License, 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 META_ERRORS_H
+#define META_ERRORS_H
+
+#include "util.h"
+#include "display.h"
+
+void meta_errors_init (void);
+void meta_error_trap_push (MetaDisplay *display);
+/* returns X error code, or 0 for no error */
+int meta_error_trap_pop (MetaDisplay *display);
+
+#endif
diff --git a/src/main.c b/src/main.c
index 6f5c40e..a22cce2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -22,6 +22,7 @@
#include "main.h"
#include "util.h"
#include "display.h"
+#include "errors.h"
#include <stdlib.h>
@@ -33,6 +34,8 @@ main (int argc, char **argv)
{
meta_main_loop = g_main_loop_new (NULL, FALSE);
+ meta_errors_init ();
+
if (!meta_display_open (NULL))
meta_exit (META_EXIT_ERROR);
diff --git a/src/run-metacity.sh b/src/run-metacity.sh
new file mode 100755
index 0000000..f221134
--- /dev/null
+++ b/src/run-metacity.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+Xnest :1 -scrns 2 -geometry 200x200 &
+sleep 1
+DISPLAY=:1 unst ./metacity
diff --git a/src/screen.c b/src/screen.c
index e723cda..df18f60 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -20,26 +20,59 @@
*/
#include "screen.h"
#include "util.h"
+#include "errors.h"
MetaScreen*
meta_screen_new (MetaDisplay *display,
int number)
{
MetaScreen *screen;
+ Window xroot;
+ Display *xdisplay;
- meta_verbose ("Adding screen %d on display '%s'\n", number, display->name);
+ /* Only display->name, display->xdisplay, and display->error_traps
+ * can really be used in this function, since normally screens are
+ * created from the MetaDisplay constructor
+ */
+
+ xdisplay = display->xdisplay;
+
+ meta_verbose ("Trying screen %d on display '%s'\n",
+ number, display->name);
+
+ xroot = RootWindow (xdisplay, number);
+
+ /* FVWM checks for None here, I don't know if this
+ * ever actually happens
+ */
+ if (xroot == None)
+ {
+ meta_warning (_("Screen %d on display '%s' is invalid\n"),
+ number, display->name);
+ return NULL;
+ }
+
+ /* Select our root window events */
+ meta_error_trap_push (display);
+ XSelectInput (xdisplay,
+ xroot,
+ SubstructureRedirectMask | SubstructureNotifyMask |
+ ColormapChangeMask | PropertyChangeMask |
+ LeaveWindowMask | EnterWindowMask |
+ ButtonPressMask | ButtonReleaseMask);
+ if (meta_error_trap_pop (display) != Success)
+ {
+ meta_warning (_("Screen %d on display '%s' already has a window manager\n"),
+ number, display->name);
+ return NULL;
+ }
screen = g_new (MetaScreen, 1);
- screen->display = display;
+ screen->display = NULL;
screen->number = number;
- screen->xscreen = ScreenOfDisplay (display->xdisplay, number);
- screen->xroot = RootWindow (display->xdisplay, number);
-
- /* Select our root window events */
- XSelectInput (display->xdisplay,
- screen->xroot,
- SubstructureNotifyMask);
+ screen->xscreen = ScreenOfDisplay (xdisplay, number);
+ screen->xroot = xroot;
return screen;
}
diff --git a/src/util.c b/src/util.c
index 73fe1a1..3f6f3ea 100644
--- a/src/util.c
+++ b/src/util.c
@@ -23,6 +23,7 @@
#include "main.h"
#include <stdio.h>
+#include <stdlib.h>
static gboolean is_verbose = TRUE;
@@ -81,6 +82,27 @@ meta_verbose (const char *format, ...)
}
void
+meta_bug (const char *format, ...)
+{
+ va_list args;
+ gchar *str;
+
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ str = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ fputs ("Bug in window manager: ", stderr);
+ fputs (str, stderr);
+
+ g_free (str);
+
+ /* stop us in a debugger */
+ abort ();
+}
+
+void
meta_warning (const char *format, ...)
{
va_list args;
diff --git a/src/util.h b/src/util.h
index 985b633..db8156b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -31,6 +31,8 @@ void meta_debug_spew (const char *format,
...) G_GNUC_PRINTF (1, 2);
void meta_verbose (const char *format,
...) G_GNUC_PRINTF (1, 2);
+void meta_bug (const char *format,
+ ...) G_GNUC_PRINTF (1, 2);
void meta_warning (const char *format,
...) G_GNUC_PRINTF (1, 2);
void meta_fatal (const char *format,