--- a/dom/plugins/PPluginModule.ipdl
+++ b/dom/plugins/PPluginModule.ipdl
@@ -94,12 +94,14 @@ parent:
returns (NPError aError,
bool aBoolVal);
// Wake up and process a few native events. Periodically called by
// Gtk-specific code upon detecting that the plugin process has
// entered a nested event loop. If the browser doesn't process
// native events, then "livelock" and some other glitches can occur.
rpc ProcessSomeEvents();
+
+ sync AppendNotesToCrashReport(nsCString aNotes);
};
} // namespace plugins
} // namespace mozilla
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -348,16 +348,20 @@ PluginModuleChild::InitGraphics()
real_gtk_plug_embedded = *embedded;
*embedded = wrap_gtk_plug_embedded;
#elif defined(MOZ_WIDGET_QT)
if (!qApp)
gQApp = new QApplication(0, NULL);
#else
// may not be necessary on all platforms
#endif
+#ifdef MOZ_X11
+ // Do this after initializing GDK, or GDK will install its own handler.
+ XRE_InstallX11ErrorHandler();
+#endif
return true;
}
bool
PluginModuleChild::AnswerNP_Shutdown(NPError *rv)
{
AssertPluginThread();
--- a/dom/plugins/PluginModuleParent.cpp
+++ b/dom/plugins/PluginModuleParent.cpp
@@ -187,19 +187,32 @@ PluginModuleParent::WriteExtraDataForMin
else
filePos++;
WriteExtraDataEntry(stream, "PluginFilename",
pluginFile.substr(filePos).c_str());
//TODO: add plugin name and version: bug 539841
// (as PluginName, PluginVersion)
WriteExtraDataEntry(stream, "PluginName", "");
WriteExtraDataEntry(stream, "PluginVersion", "");
+
+ if (!mCrashNotes.IsEmpty()) {
+ WriteExtraDataEntry(stream, "Notes", mCrashNotes.get());
+ }
+
stream->Close();
}
+
+bool
+PluginModuleParent::RecvAppendNotesToCrashReport(const nsCString& aNotes)
+{
+ mCrashNotes.Append(aNotes);
+ return true;
+}
+
int
PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
{
AssertPluginThread();
NS_ABORT_IF_FALSE(!strcmp(aPref, kTimeoutPref),
"unexpected pref callback");
PRInt32 timeoutSecs = nsContentUtils::GetIntPref(kTimeoutPref, 0);
--- a/dom/plugins/PluginModuleParent.h
+++ b/dom/plugins/PluginModuleParent.h
@@ -152,16 +152,19 @@ protected:
virtual bool
AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,
NPError* aError,
bool* aBoolVal);
NS_OVERRIDE
virtual bool AnswerProcessSomeEvents();
+ virtual bool
+ RecvAppendNotesToCrashReport(const nsCString& aNotes);
+
static PluginInstanceParent* InstCast(NPP instance);
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s);
private:
void SetPluginFuncs(NPPluginFuncs* aFuncs);
// Implement the module-level functions from NPAPI; these are
// normally resolved directly from the DSO.
@@ -221,16 +224,17 @@ private:
private:
void WriteExtraDataForMinidump(nsIFile* dumpFile);
void WriteExtraDataEntry(nsIFileOutputStream* stream,
const char* key,
const char* value);
void CleanupFromTimeout();
static int TimeoutChanged(const char* aPref, void* aModule);
+ nsCString mCrashNotes;
PluginProcessParent* mSubprocess;
bool mShutdown;
const NPNetscapeFuncs* mNPNIface;
nsTHashtable<nsVoidPtrHashKey> mValidIdentifiers;
nsNPAPIPlugin* mPlugin;
time_t mProcessStartTime;
};
--- a/dom/plugins/PluginThreadChild.cpp
+++ b/dom/plugins/PluginThreadChild.cpp
@@ -99,10 +99,21 @@ PluginThreadChild::Init()
void
PluginThreadChild::CleanUp()
{
mPlugin.CleanUp();
MozillaChildThread::CleanUp();
}
+/* static */
+void
+PluginThreadChild::AppendNotesToCrashReport(const nsCString& aNotes)
+{
+ AssertPluginThread();
+
+ if (gInstance) {
+ gInstance->mPlugin.SendAppendNotesToCrashReport(aNotes);
+ }
+}
+
} // namespace plugins
} // namespace mozilla
--- a/dom/plugins/PluginThreadChild.h
+++ b/dom/plugins/PluginThreadChild.h
@@ -58,16 +58,19 @@ class PluginThreadChild : public mozilla
public:
PluginThreadChild(ProcessHandle aParentHandle);
~PluginThreadChild();
static PluginThreadChild* current() {
return gInstance;
}
+ // For use on the plugin thread.
+ static void AppendNotesToCrashReport(const nsCString& aNotes);
+
private:
static PluginThreadChild* gInstance;
// Thread implementation:
virtual void Init();
virtual void CleanUp();
PluginModuleChild mPlugin;
--- a/gfx/src/thebes/nsSystemFontsGTK2.h
+++ b/gfx/src/thebes/nsSystemFontsGTK2.h
@@ -34,17 +34,18 @@
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _NS_SYSTEMFONTSGTK2_H_
#define _NS_SYSTEMFONTSGTK2_H_
-#include <gfxFont.h>
+#include "gfxFont.h"
+typedef struct _GtkWidget GtkWidget;
class nsSystemFontsGTK2
{
public:
nsSystemFontsGTK2();
~nsSystemFontsGTK2();
nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
--- a/gfx/src/thebes/nsThebesDeviceContext.cpp
+++ b/gfx/src/thebes/nsThebesDeviceContext.cpp
@@ -52,34 +52,16 @@
#include "nsThebesRenderingContext.h"
#include "gfxUserFontSet.h"
#include "gfxPlatform.h"
#include "nsIWidget.h"
#include "nsIView.h"
#include "nsILookAndFeel.h"
-#ifdef MOZ_ENABLE_GTK2
-// for getenv
-#include <cstdlib>
-// for round
-#include <cmath>
-
-#include <gtk/gtk.h>
-#include <gdk/gdk.h>
-
-#include "nsFont.h"
-
-#include <pango/pango.h>
-#ifdef MOZ_X11
-#include <gdk/gdkx.h>
-#endif /* MOZ_X11 */
-#include <pango/pango-fontmap.h>
-#endif /* GTK2 */
-
#include "gfxImageSurface.h"
#ifdef MOZ_ENABLE_GTK2
#include "nsSystemFontsGTK2.h"
#include "gfxPDFSurface.h"
#include "gfxPSSurface.h"
static nsSystemFontsGTK2 *gSystemFonts = nsnull;
#elif XP_WIN
@@ -104,25 +86,16 @@ static nsSystemFontsBeOS *gSystemFonts =
static nsSystemFontsMac *gSystemFonts = nsnull;
#elif defined(MOZ_WIDGET_QT)
#include "nsSystemFontsQt.h"
static nsSystemFontsQt *gSystemFonts = nsnull;
#else
#error Need to declare gSystemFonts!
#endif
-#if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
-extern "C" {
-static int x11_error_handler (Display *dpy, XErrorEvent *err) {
- NS_ASSERTION(PR_FALSE, "X Error");
- return 0;
-}
-}
-#endif
-
#ifdef PR_LOGGING
PRLogModuleInfo* gThebesGFXLog = nsnull;
#endif
class nsFontCache
{
public:
nsFontCache();
@@ -735,25 +708,16 @@ nsThebesDeviceContext::Init(nsIWidget *a
#endif
// register as a memory-pressure observer to free font resources
// in low-memory situations.
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
if (obs)
obs->AddObserver(this, "memory-pressure", PR_TRUE);
-#if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
- if (getenv ("MOZ_X_SYNC")) {
- PR_LOG (gThebesGFXLog, PR_LOG_DEBUG, ("+++ Enabling XSynchronize\n"));
- XSynchronize (gdk_x11_get_default_xdisplay(), True);
- XSetErrorHandler(x11_error_handler);
- }
-
-#endif
-
mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
return NS_OK;
}
NS_IMETHODIMP
nsThebesDeviceContext::CreateRenderingContext(nsIView *aView,
nsIRenderingContext *&aContext)
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -116,16 +116,20 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
CMMSRCS += MacLaunchHelper.mm
CPPSRCS += nsCommandLineServiceMac.cpp
OS_CXXFLAGS += -fexceptions
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
CMMSRCS += MacApplicationDelegate.mm
endif
+ifdef MOZ_X11
+CPPSRCS += nsX11ErrorHandler.cpp
+endif
+
SHARED_LIBRARY_LIBS += ../profile/src/$(LIB_PREFIX)profile_s.$(LIB_SUFFIX)
ifdef MOZ_ENABLE_XREMOTE
SHARED_LIBRARY_LIBS += $(DEPTH)/widget/src/xremoteclient/$(LIB_PREFIX)xremote_client_s.$(LIB_SUFFIX)
LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/xremoteclient
endif
ifdef MOZ_CRASHREPORTER
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -235,16 +235,17 @@ public:
}
protected:
HANDLE mHandle;
};
#endif
extern void InstallSignalHandlers(const char *ProgramName);
+#include "nsX11ErrorHandler.h"
#define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
int gArgc;
char **gArgv;
static char gToolkitVersion[20];
static char gToolkitBuildID[40];
@@ -3128,16 +3129,20 @@ XRE_main(int argc, char* argv[], const n
_gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
(_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
if (_gtk_window_set_auto_startup_notification) {
_gtk_window_set_auto_startup_notification(PR_FALSE);
}
gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
#endif /* MOZ_WIDGET_GTK2 */
+#ifdef MOZ_X11
+ // Do this after initializing GDK, or GDK will install its own handler.
+ InstallX11ErrorHandler();
+#endif
// Call the code to install our handler
#ifdef MOZ_JPROF
setupProfilingStuff();
#endif
// Try to allocate "native app support."
nsCOMPtr<nsINativeAppSupport> nativeApp;
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -71,16 +71,17 @@
#include "nsStaticComponents.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "nsWidgetsCID.h"
#include "nsXPFEComponentsCID.h"
#include "nsXREDirProvider.h"
#ifdef MOZ_IPC
+#include "nsX11ErrorHandler.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 "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/ipc/BrowserProcessSubThread.h"
@@ -485,10 +486,18 @@ XRE_ShutdownChildProcess()
NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!");
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order");
ioLoop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
+#ifdef MOZ_X11
+void
+XRE_InstallX11ErrorHandler()
+{
+ InstallX11ErrorHandler();
+}
+#endif
+
#endif // MOZ_IPC
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsX11ErrorHandler.cpp
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Karl Tomlinson <karlt+@karlt.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsX11ErrorHandler.h"
+
+#ifdef MOZ_IPC
+#include "mozilla/plugins/PluginThreadChild.h"
+using mozilla::plugins::PluginThreadChild;
+#endif
+
+#include "prenv.h"
+#include "nsXULAppAPI.h"
+#include "nsExceptionHandler.h"
+#include "nsDebug.h"
+
+#include <X11/Xlib.h>
+#ifdef MOZ_WIDGET_GTK2
+#include <gdk/gdkx.h>
+#endif
+
+#define BUFSIZE 2048 // What Xlib uses with XGetErrorDatabaseText
+
+extern "C" {
+static int
+IgnoreError(Display *display, XErrorEvent *event) {
+ return 0; // This return value is ignored.
+}
+
+static int
+X11Error(Display *display, XErrorEvent *event) {
+ nsCAutoString notes;
+ char buffer[BUFSIZE];
+
+ // Get an indication of how long ago the request that caused the error was
+ // made. Do this before querying extensions etc below.
+ unsigned long age = NextRequest(display) - event->serial;
+
+ // Ignore subsequent errors, which may get processed during the extension
+ // queries below for example.
+ XSetErrorHandler(IgnoreError);
+
+ // Get a string to represent the request that caused the error.
+ nsCAutoString message;
+ if (event->request_code < 128) {
+ // Core protocol request
+ message.AppendInt(event->request_code);
+ } else {
+ // Extension request
+ int nExts;
+ char** extNames = XListExtensions(display, &nExts);
+ if (extNames) {
+ for (int i = 0; i < nExts; ++i) {
+ int major_opcode, first_event, first_error;
+ if (XQueryExtension(display, extNames[i],
+ &major_opcode, &first_event, &first_error)
+ && major_opcode == event->request_code) {
+ message.Append(extNames[i]);
+ message.Append('.');
+ message.AppendInt(event->minor_code);
+ break;
+ }
+ }
+
+ XFreeExtensionList(extNames);
+ }
+ }
+
+ if (message.IsEmpty()) {
+ buffer[0] = '\0';
+ } else {
+ XGetErrorDatabaseText(display, "XRequest", message.get(), "",
+ buffer, sizeof(buffer));
+ }
+
+ if (buffer[0]) {
+ notes.Append(buffer);
+ } else {
+ notes.Append("Request ");
+ notes.AppendInt(event->request_code);
+ notes.Append('.');
+ notes.AppendInt(event->minor_code);
+ }
+
+ notes.Append(": ");
+
+ // Get a string to describe the error.
+ XGetErrorText(display, event->error_code, buffer, sizeof(buffer));
+ notes.Append(buffer);
+
+ // For requests where Xlib gets the reply synchronously, |age| will be 1
+ // and the stack will include the function making the request. For
+ // asynchronous requests, the current stack will often be unrelated to the
+ // point of making the request, even if |age| is 1, but sometimes this may
+ // help us count back to the point of the request. With XSynchronize on,
+ // the stack will include the function making the request, even though
+ // |age| will be 2 for asynchronous requests because XSynchronize is
+ // implemented by an empty request from an XSync, which has not yet been
+ // processed.
+ if (age > 1) {
+ // XSynchronize returns the previous "after function". If a second
+ // XSynchronize call returns the same function after an enable call then
+ // synchronization must have already been enabled.
+ if (XSynchronize(display, True) == XSynchronize(display, False)) {
+ notes.Append("; sync");
+ } else {
+ notes.Append("; ");
+ notes.AppendInt(age);
+ notes.Append(" requests ago");
+ }
+ }
+
+#ifdef MOZ_CRASHREPORTER
+ switch (XRE_GetProcessType()) {
+ case GeckoProcessType_Default:
+ CrashReporter::AppendAppNotesToCrashReport(notes);
+ break;
+#ifdef MOZ_IPC
+ case GeckoProcessType_Plugin:
+ if (CrashReporter::GetEnabled()) {
+ // This is assuming that X operations are performed on the plugin
+ // thread. If plugins are using X on another thread, then we'll need to
+ // handle that differently.
+ PluginThreadChild::AppendNotesToCrashReport(notes);
+ }
+ break;
+#endif
+ default:
+ ; // crash report notes not supported.
+ }
+#endif
+
+#ifdef DEBUG
+ // The resource id is unlikely to be useful in a crash report without
+ // context of other ids, but add it to the debug console output.
+ notes.Append("; id=0x");
+ notes.AppendInt(event->resourceid, 16);
+#ifdef MOZ_WIDGET_GTK2
+ // Actually, for requests where Xlib gets the reply synchronously,
+ // MOZ_X_SYNC=1 will not be necessary, but we don't have a table to tell us
+ // which requests get a synchronous reply.
+ if (!PR_GetEnv("MOZ_X_SYNC")) {
+ notes.Append("\nRe-running with MOZ_X_SYNC=1 in the environment may give a more helpful backtrace.");
+ }
+#endif
+#endif
+
+ NS_RUNTIMEABORT(notes.get());
+ return 0; // not reached
+}
+}
+
+void
+InstallX11ErrorHandler()
+{
+ XSetErrorHandler(X11Error);
+
+#ifdef MOZ_WIDGET_GTK2
+ NS_ASSERTION(GDK_DISPLAY(), "No GDK display");
+ if (PR_GetEnv("MOZ_X_SYNC")) {
+ XSynchronize(GDK_DISPLAY(), True);
+ }
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsX11ErrorHandler.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Karl Tomlinson <karlt+@karlt.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef MOZ_X11
+void InstallX11ErrorHandler();
+#endif
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -501,9 +501,11 @@ struct JSString;
XRE_API(bool,
XRE_SendTestShellCommand, (JSContext* aCx,
JSString* aCommand,
void* aCallback))
XRE_API(bool,
XRE_ShutdownTestShell, ())
+XRE_API(void,
+ XRE_InstallX11ErrorHandler, ())
#endif // _nsXULAppAPI_h__