00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00084
00085
00086 old_error_handler = XSetErrorHandler (x_error_handler);
00087
00088
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
00121
00122
00123
00124 int (* restored_error_handler) (Display *,
00125 XErrorEvent *);
00126
00127 restored_error_handler = XSetErrorHandler (x_error_handler);
00128
00129
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
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
00168
00169
00170
00171
00172
00173
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
00226
00227
00228 if (display->error_traps > 0)
00229 {
00230
00231
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;
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
00285 exit (1);
00286
00287 return 0;
00288 }