errors.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity X error handling */
00004 
00005 /* 
00006  * Copyright (C) 2001 Havoc Pennington, error trapping inspired by GDK
00007  * code copyrighted by the GTK team.
00008  * 
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License as
00011  * published by the Free Software Foundation; either version 2 of the
00012  * License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00022  * 02111-1307, USA.
00023  */
00024 
00025 #include <config.h>
00026 #include "errors.h"
00027 #include "display-private.h"
00028 #include <errno.h>
00029 #include <stdlib.h>
00030 #include <gdk/gdk.h>
00031 
00032 static int x_error_handler    (Display     *display,
00033                                XErrorEvent *error);
00034 static int x_io_error_handler (Display     *display);
00035 
00036 void
00037 meta_errors_init (void)
00038 {
00039   XSetErrorHandler (x_error_handler);
00040   XSetIOErrorHandler (x_io_error_handler);
00041 }
00042 
00043 typedef struct ForeignDisplay ForeignDisplay;
00044 
00045 struct ForeignDisplay
00046 {
00047     Display *dpy;
00048     ErrorHandler handler;
00049     gpointer data;
00050     ForeignDisplay *next;
00051 };
00052 
00053 static ForeignDisplay *foreign_displays;
00054 
00055 void
00056 meta_errors_register_foreign_display (Display      *foreign_dpy,
00057                                       ErrorHandler  handler,
00058                                       gpointer      data)
00059 {
00060     ForeignDisplay *info = g_new0 (ForeignDisplay, 1);
00061     info->dpy = foreign_dpy;
00062     info->handler = handler;
00063     info->data = data;
00064     info->next = foreign_displays;
00065     foreign_displays = info;
00066 }
00067 
00068 static void
00069 meta_error_trap_push_internal (MetaDisplay *display,
00070                                gboolean     need_sync)
00071 {
00072   /* GDK resets the error handler on each push */
00073   int (* old_error_handler) (Display     *,
00074                              XErrorEvent *);
00075 
00076   if (need_sync)
00077     {
00078       XSync (display->xdisplay, False);
00079     }
00080   
00081   gdk_error_trap_push ();
00082 
00083   /* old_error_handler will just be equal to x_error_handler
00084    * for nested traps
00085    */
00086   old_error_handler = XSetErrorHandler (x_error_handler);
00087   
00088   /* Replace GDK handler, but save it so we can chain up */
00089   if (display->error_trap_handler == NULL)
00090     {
00091       g_assert (display->error_traps == 0);
00092       display->error_trap_handler = old_error_handler;
00093       g_assert (display->error_trap_handler != x_error_handler);
00094     }
00095 
00096   display->error_traps += 1;
00097 
00098   meta_topic (META_DEBUG_ERRORS, "%d traps remain\n", display->error_traps);
00099 }
00100 
00101 static int
00102 meta_error_trap_pop_internal  (MetaDisplay *display,
00103                                gboolean     need_sync)
00104 {
00105   int result;
00106 
00107   g_assert (display->error_traps > 0);
00108 
00109   if (need_sync)
00110     {
00111       XSync (display->xdisplay, False);
00112     }
00113 
00114   result = gdk_error_trap_pop ();
00115 
00116   display->error_traps -= 1;
00117   
00118   if (display->error_traps == 0)
00119     {
00120       /* check that GDK put our handler back; this
00121        * assumes that there are no pending GDK traps from GDK itself
00122        */
00123       
00124       int (* restored_error_handler) (Display     *,
00125                                       XErrorEvent *);
00126 
00127       restored_error_handler = XSetErrorHandler (x_error_handler);
00128 
00129       /* remove this */
00130       display->error_trap_handler = NULL;
00131     }
00132 
00133   meta_topic (META_DEBUG_ERRORS, "%d traps\n", display->error_traps);
00134   
00135   return result;
00136 }
00137 
00138 void
00139 meta_error_trap_push (MetaDisplay *display)
00140 {
00141   meta_error_trap_push_internal (display, FALSE);
00142 }
00143 
00144 void
00145 meta_error_trap_pop (MetaDisplay *display,
00146                      gboolean     last_request_was_roundtrip)
00147 {
00148   gboolean need_sync;
00149 
00150   /* we only have to sync when popping the outermost trap */
00151   need_sync = (display->error_traps == 1 && !last_request_was_roundtrip);
00152 
00153   if (need_sync)
00154     meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_pop, traps = %d, roundtrip = %d\n",
00155                 display->error_traps, last_request_was_roundtrip);
00156 
00157   display->error_trap_synced_at_last_pop = need_sync || last_request_was_roundtrip;
00158   
00159   meta_error_trap_pop_internal (display, need_sync);
00160 }
00161 
00162 void
00163 meta_error_trap_push_with_return (MetaDisplay *display)
00164 {
00165   gboolean need_sync;
00166 
00167   /* We don't sync on push_with_return if there are no traps
00168    * currently, because we assume that any errors were either covered
00169    * by a previous pop, or were fatal.
00170    *
00171    * More generally, we don't sync if we were synchronized last time
00172    * we popped. This is known to be the case if there are no traps,
00173    * but we also keep a flag so we know whether it's the case otherwise.
00174    */
00175 
00176   if (!display->error_trap_synced_at_last_pop)
00177     need_sync = TRUE;
00178   else
00179     need_sync = FALSE;
00180 
00181   if (need_sync)
00182     meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_push_with_return, traps = %d\n",
00183                 display->error_traps);
00184   
00185   meta_error_trap_push_internal (display, FALSE);
00186 }
00187 
00188 int
00189 meta_error_trap_pop_with_return  (MetaDisplay *display,
00190                                   gboolean     last_request_was_roundtrip)
00191 {
00192   if (!last_request_was_roundtrip)
00193     meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_pop_with_return, traps = %d, roundtrip = %d\n",
00194                 display->error_traps, last_request_was_roundtrip);
00195 
00196   display->error_trap_synced_at_last_pop = TRUE;
00197   
00198   return meta_error_trap_pop_internal (display,
00199                                        !last_request_was_roundtrip);
00200 }
00201 
00202 static int
00203 x_error_handler (Display     *xdisplay,
00204                  XErrorEvent *error)
00205 {
00206   int retval;
00207   gchar buf[64];
00208   MetaDisplay *display;
00209   ForeignDisplay *foreign;
00210 
00211   for (foreign = foreign_displays; foreign != NULL; foreign = foreign->next)
00212   {
00213       if (foreign->dpy == xdisplay)
00214       {
00215           foreign->handler (xdisplay, error, foreign->data);
00216 
00217           return 0;
00218       }
00219   }
00220   
00221   XGetErrorText (xdisplay, error->error_code, buf, 63);  
00222 
00223   display = meta_display_for_x_display (xdisplay);
00224 
00225   /* Display can be NULL here because the compositing manager
00226    * has its own Display, but Xlib only has one global error handler
00227    */
00228   if (display->error_traps > 0)
00229     {
00230       /* we're in an error trap, chain to the trap handler
00231        * saved from GDK
00232        */
00233       meta_verbose ("X error: %s serial %ld error_code %d request_code %d minor_code %d)\n",
00234                     buf,
00235                     error->serial, 
00236                     error->error_code, 
00237                     error->request_code,
00238                     error->minor_code);
00239 
00240       g_assert (display->error_trap_handler != NULL);
00241       g_assert (display->error_trap_handler != x_error_handler);
00242       
00243       retval = (* display->error_trap_handler) (xdisplay, error);
00244     }
00245   else
00246     {
00247       meta_bug ("Unexpected X error: %s serial %ld error_code %d request_code %d minor_code %d)\n",
00248                 buf,
00249                 error->serial, 
00250                 error->error_code, 
00251                 error->request_code,
00252                 error->minor_code);
00253 
00254       retval = 1; /* compiler warning */
00255     }
00256 
00257   return retval;
00258 }
00259 
00260 static int
00261 x_io_error_handler (Display *xdisplay)
00262 {
00263   MetaDisplay *display;
00264 
00265   display = meta_display_for_x_display (xdisplay);
00266 
00267   if (display == NULL)
00268     meta_bug ("IO error received for unknown display?\n");
00269   
00270   if (errno == EPIPE)
00271     {
00272       meta_warning (_("Lost connection to the display '%s';\n"
00273                       "most likely the X server was shut down or you killed/destroyed\n"
00274                       "the window manager.\n"),
00275                     display->name);
00276     }
00277   else
00278     {
00279       meta_warning (_("Fatal IO error %d (%s) on display '%s'.\n"),
00280                     errno, g_strerror (errno),
00281                     display->name);
00282     }
00283 
00284   /* Xlib would force an exit anyhow */
00285   exit (1);
00286   
00287   return 0;
00288 }

Generated on Sat Aug 23 22:04:16 2008 for metacity by  doxygen 1.5.5