Bug 968196 - Use GDK error handler for X window error events. r=karlt
authorMartin Stransky <stransky@redhat.com>
Mon, 16 Jun 2014 04:54:00 -0400
changeset 188940 9263e3668ab98dfec6f6b94b9b6d1e388ac585c5
parent 188939 51eaa755822f2fc3d3fc5558e6bdc4806836d290
child 188941 bac4e07e1dd2efe4d063f0562c059422215e1f56
push idunknown
push userunknown
push dateunknown
reviewerskarlt
bugs968196
milestone33.0a1
Bug 968196 - Use GDK error handler for X window error events. r=karlt
toolkit/xre/moz.build
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
toolkit/xre/nsGDKErrorHandler.cpp
toolkit/xre/nsGDKErrorHandler.h
toolkit/xre/nsX11ErrorHandler.cpp
toolkit/xre/nsX11ErrorHandler.h
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -51,16 +51,21 @@ elif CONFIG['MOZ_ENABLE_GTK']:
     UNIFIED_SOURCES += [
         'nsNativeAppSupportUnix.cpp',
     ]
 else:
     UNIFIED_SOURCES += [
         'nsNativeAppSupportDefault.cpp',
     ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
+    UNIFIED_SOURCES += [
+        'nsGDKErrorHandler.cpp',
+    ]
+
 if CONFIG['MOZ_X11']:
     UNIFIED_SOURCES += [
         'nsX11ErrorHandler.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     UNIFIED_SOURCES += [
         'nsAndroidStartup.cpp',
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -186,17 +186,16 @@
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
 extern uint32_t gRestartMode;
 extern void InstallSignalHandlers(const char *ProgramName);
-#include "nsX11ErrorHandler.h"
 
 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
 
 int    gArgc;
 char **gArgv;
 
 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
@@ -3528,17 +3527,17 @@ XREMain::XRE_mainStartup(bool* aExitFlag
   }
 
 #if (MOZ_WIDGET_GTK == 2)
   gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
 #endif /* (MOZ_WIDGET_GTK == 2) */
 #endif /* defined(MOZ_WIDGET_GTK) */
 #ifdef MOZ_X11
   // Do this after initializing GDK, or GDK will install its own handler.
-  InstallX11ErrorHandler();
+  XRE_InstallX11ErrorHandler();
 #endif
 
   // Call the code to install our handler
 #ifdef MOZ_JPROF
   setupProfilingStuff();
 #endif
 
   rv = NS_CreateNativeAppSupport(getter_AddRefs(mNativeApp));
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -43,16 +43,17 @@
 #include "nsXREDirProvider.h"
 
 #include "mozilla/Omnijar.h"
 #if defined(XP_MACOSX)
 #include "nsVersionComparator.h"
 #include "chrome/common/mach_ipc_mac.h"
 #endif
 #include "nsX11ErrorHandler.h"
+#include "nsGDKErrorHandler.h"
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/message_loop.h"
 #include "base/process_util.h"
 #include "chrome/common/child_process.h"
 #include "chrome/common/notification_service.h"
 
 #include "mozilla/ipc/BrowserProcessSubThread.h"
@@ -784,17 +785,21 @@ XRE_ShutdownTestShell()
     NS_RELEASE(gContentParent);
     return ret;
 }
 
 #ifdef MOZ_X11
 void
 XRE_InstallX11ErrorHandler()
 {
+#if (MOZ_WIDGET_GTK == 3)
+  InstallGdkErrorHandler();
+#else
   InstallX11ErrorHandler();
+#endif
 }
 #endif
 
 #ifdef XP_WIN
 static WindowsEnvironmentType
 sWindowsEnvironmentType = WindowsEnvironmentType_Desktop;
 
 void
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsGDKErrorHandler.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsGDKErrorHandler.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <errno.h>
+
+#include "nsX11ErrorHandler.h"
+
+#include "prenv.h"
+
+
+/* See https://bugzilla.gnome.org/show_bug.cgi?id=629608#c8
+ *
+ * GDK implements X11 error traps to ignore X11 errors.
+ * Unfortunatelly We don't know which X11 events can be ignored
+ * so we have to utilize the Gdk error handler to avoid
+ * false alarms in Gtk3.
+ */
+static void
+GdkErrorHandler(const gchar *log_domain, GLogLevelFlags log_level,
+                const gchar *message,  gpointer user_data)
+{
+  if (strstr(message, "X Window System error")) {
+    XErrorEvent event;
+    nsDependentCString buffer(message);
+    char *endptr;
+
+    /* Parse Gdk X Window error message which has this format:
+     * (Details: serial XXXX error_code XXXX request_code XXXX (XXXX) minor_code XXXX)
+     */
+    NS_NAMED_LITERAL_CSTRING(serialString, "(Details: serial ");
+    int32_t start = buffer.Find(serialString);
+    if (start == kNotFound)
+      NS_RUNTIMEABORT(message);
+
+    start += serialString.Length();
+    errno = 0;
+    event.serial = strtol(buffer.BeginReading() + start, &endptr, 10);
+    if (errno)
+      NS_RUNTIMEABORT(message);
+
+    NS_NAMED_LITERAL_CSTRING(errorCodeString, " error_code ");    
+    if (!StringBeginsWith(Substring(endptr, buffer.EndReading()), errorCodeString))
+      NS_RUNTIMEABORT(message);
+
+    errno = 0;
+    event.error_code = strtol(endptr + errorCodeString.Length(), &endptr, 10);
+    if (errno)
+      NS_RUNTIMEABORT(message);
+
+    NS_NAMED_LITERAL_CSTRING(requestCodeString, " request_code ");
+    if (!StringBeginsWith(Substring(endptr, buffer.EndReading()), requestCodeString))
+      NS_RUNTIMEABORT(message);
+
+    errno = 0;
+    event.request_code = strtol(endptr + requestCodeString.Length(), &endptr, 10);
+    if (errno)
+      NS_RUNTIMEABORT(message);
+
+    NS_NAMED_LITERAL_CSTRING(minorCodeString, " minor_code ");
+    start = buffer.Find(minorCodeString, endptr - buffer.BeginReading());
+    if (!start)
+      NS_RUNTIMEABORT(message);
+
+    errno = 0;
+    event.minor_code = strtol(buffer.BeginReading() + start + minorCodeString.Length(), nullptr, 10);
+    if (errno)
+      NS_RUNTIMEABORT(message);
+
+    event.display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    // Gdk does not provide resource ID
+    event.resourceid = 0;
+
+    X11Error(event.display, &event);
+  } else {
+    g_log_default_handler(log_domain, log_level, message, user_data);
+    NS_RUNTIMEABORT(message);
+  }
+}
+
+void
+InstallGdkErrorHandler()
+{
+  g_log_set_handler("Gdk",
+                    (GLogLevelFlags)(G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION),
+                    GdkErrorHandler,
+                    nullptr);
+  if (PR_GetEnv("MOZ_X_SYNC")) {
+    XSynchronize(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), True);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsGDKErrorHandler.h
@@ -0,0 +1,8 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if (MOZ_WIDGET_GTK == 3)
+void InstallGdkErrorHandler();
+#endif
--- a/toolkit/xre/nsX11ErrorHandler.cpp
+++ b/toolkit/xre/nsX11ErrorHandler.cpp
@@ -11,17 +11,17 @@
 #include "nsDebug.h"
 
 #include "mozilla/X11Util.h"
 #include <X11/Xlib.h>
 
 #define BUFSIZE 2048 // What Xlib uses with XGetErrorDatabaseText
 
 extern "C" {
-static int
+int
 X11Error(Display *display, XErrorEvent *event) {
   // Get an indication of how long ago the request that caused the error was
   // made.
   unsigned long age = NextRequest(display) - event->serial;
 
   // Get a string to represent the request that caused the error.
   nsAutoCString message;
   if (event->request_code < 128) {
@@ -154,19 +154,21 @@ X11Error(Display *display, XErrorEvent *
   }
 #endif
 
   NS_RUNTIMEABORT(notes.get());
   return 0; // not reached
 }
 }
 
+#if (MOZ_WIDGET_GTK == 2)
 void
 InstallX11ErrorHandler()
 {
   XSetErrorHandler(X11Error);
 
   Display *display = mozilla::DefaultXDisplay();
   NS_ASSERTION(display, "No X display");
   if (PR_GetEnv("MOZ_X_SYNC")) {
     XSynchronize(display, True);
   }
 }
+#endif
--- a/toolkit/xre/nsX11ErrorHandler.h
+++ b/toolkit/xre/nsX11ErrorHandler.h
@@ -1,8 +1,12 @@
 /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_X11
+#include <X11/Xlib.h>
+#if (MOZ_WIDGET_GTK == 2)
 void InstallX11ErrorHandler();
 #endif
+extern "C" int X11Error(Display *display, XErrorEvent *event);
+#endif