bug 546538 - crash reporter ui for maemo. r=mfinkle
authorTed Mielczarek <ted.mielczarek@gmail.com>
Wed, 07 Apr 2010 13:06:17 -0400
changeset 40606 8d99566a95942e465e1b725939cb208113cf778b
parent 40605 a0734d2d06265fb64fb0b4117fe3911e949a38ef
child 40607 9707858ee63b34f290f3e156ef5e81f0cc9ca0ac
push idunknown
push userunknown
push dateunknown
reviewersmfinkle
bugs546538
milestone1.9.3a5pre
bug 546538 - crash reporter ui for maemo. r=mfinkle
toolkit/crashreporter/client/Makefile.in
toolkit/crashreporter/client/crashreporter_gtk_common.cpp
toolkit/crashreporter/client/crashreporter_gtk_common.h
toolkit/crashreporter/client/crashreporter_linux.cpp
toolkit/crashreporter/client/crashreporter_maemo_gtk.cpp
toolkit/crashreporter/client/crashreporter_unix.cpp
toolkit/crashreporter/client/crashreporter_unix_common.cpp
--- a/toolkit/crashreporter/client/Makefile.in
+++ b/toolkit/crashreporter/client/Makefile.in
@@ -64,29 +64,35 @@ LIBS += \
 LOCAL_INCLUDES += -I$(srcdir)
 RCINCLUDE = crashreporter.rc
 DEFINES += -DUNICODE -D_UNICODE
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 shell32 wininet shlwapi)
 MOZ_WINCONSOLE = 0
 endif
 
 ifeq ($(OS_ARCH),Darwin)
-CPPSRCS += crashreporter_unix.cpp
+CPPSRCS += crashreporter_unix_common.cpp
 CMMSRCS += crashreporter_osx.mm
 OS_LIBS += -framework Cocoa
 LIBS += \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/mac/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/mac/$(LIB_PREFIX)breakpad_mac_common_s.$(LIB_SUFFIX) \
   $(NULL)
 
 LOCAL_INCLUDES += -I$(srcdir) -I$(srcdir)/../google-breakpad/src/common/mac/
 endif
 
 ifeq ($(OS_ARCH),Linux)
-CPPSRCS += crashreporter_linux.cpp crashreporter_unix.cpp
+CPPSRCS += crashreporter_gtk_common.cpp crashreporter_unix_common.cpp
+ifdef MOZ_PLATFORM_MAEMO
+CPPSRCS += crashreporter_maemo_gtk.cpp
+else
+CPPSRCS += crashreporter_linux.cpp
+endif
+
 LIBS += \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/linux/$(LIB_PREFIX)breakpad_linux_common_s.$(LIB_SUFFIX) \
   $(NULL)
 LOCAL_INCLUDES += -I$(srcdir)
 OS_CXXFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_GTHREAD_CFLAGS)
 OS_LIBS += $(MOZ_GTK2_LIBS) $(MOZ_GTHREAD_LIBS)
 FORCE_USE_PIC=1
 endif
copy from toolkit/crashreporter/client/crashreporter_linux.cpp
copy to toolkit/crashreporter/client/crashreporter_gtk_common.cpp
--- a/toolkit/crashreporter/client/crashreporter_linux.cpp
+++ b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp
@@ -7,24 +7,25 @@
  * 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 Toolkit Crash Reporter
+ * The Original Code is Mozilla Toolkit Crash Reporter.
  *
  * The Initial Developer of the Original Code is
- * Ted Mielczarek <ted.mielczarek@gmail.com>
- * Portions created by the Initial Developer are Copyright (C) 2006
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Ted Mielczarek <ted.mielczarek@gmail.com>
  *
  * 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
@@ -32,135 +33,65 @@
  * 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 "crashreporter.h"
 
+#include <dlfcn.h>
+#include <errno.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dlfcn.h>
 
 #include <algorithm>
-#include <cctype>
-
-#include <signal.h>
-
-#include <gtk/gtk.h>
-#include <glib.h>
-#include <string.h>
+#include <string>
+#include <vector>
 
 #include "common/linux/http_upload.h"
+#include "crashreporter.h"
+#include "crashreporter_gtk_common.h"
 
 using std::string;
 using std::vector;
 
 using namespace CrashReporter;
 
-static GtkWidget* gWindow = 0;
-static GtkWidget* gSubmitReportCheck = 0;
-static GtkWidget* gViewReportButton = 0;
-static GtkWidget* gCommentText = 0;
-static GtkWidget* gIncludeURLCheck = 0;
-static GtkWidget* gEmailMeCheck = 0;
-static GtkWidget* gEmailEntry = 0;
-static GtkWidget* gThrobber = 0;
-static GtkWidget* gProgressLabel = 0;
-static GtkWidget* gCloseButton = 0;
-static GtkWidget* gRestartButton = 0;
-
-static bool gInitialized = false;
-static bool gDidTrySend = false;
-static string gDumpFile;
-static StringTable gQueryParameters;
-static string gSendURL;
-static string gHttpProxy;
-static string gAuth;
-static vector<string> gRestartArgs;
-static string gURLParameter;
-
-static bool gEmailFieldHint = true;
-static bool gCommentFieldHint = true;
-
-static GThread* gSendThreadID;
-
-// handle from dlopen'ing libgnome
-static void* gnomeLib = NULL;
-// handle from dlopen'ing libgnomeui
-static void* gnomeuiLib = NULL;
-
-static const char kIniFile[] = "crashreporter.ini";
-
-static void LoadSettings()
-{
-  /*
-   * NOTE! This code needs to stay in sync with the preference checking
-   *       code in in nsExceptionHandler.cpp.
-   */
+GtkWidget* gWindow = 0;
+GtkWidget* gSubmitReportCheck = 0;
+GtkWidget* gIncludeURLCheck = 0;
+GtkWidget* gThrobber = 0;
+GtkWidget* gProgressLabel = 0;
+GtkWidget* gCloseButton = 0;
+GtkWidget* gRestartButton = 0;
 
-  StringTable settings;
-  if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) {
-    if (settings.find("Email") != settings.end()) {
-      gtk_entry_set_text(GTK_ENTRY(gEmailEntry), settings["Email"].c_str());
-      gEmailFieldHint = false;
-    }
-    if (settings.find("EmailMe") != settings.end()) {
-      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gEmailMeCheck),
-                                   settings["EmailMe"][0] != '0');
-    }
-    if (settings.find("IncludeURL") != settings.end() &&
-        gIncludeURLCheck != 0) {
-      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck),
-                                   settings["IncludeURL"][0] != '0');
-    }
-    bool enabled;
-    if (settings.find("SubmitReport") != settings.end())
-      enabled = settings["SubmitReport"][0] != '0';
-    else
-      enabled = ShouldEnableSending();
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck),
-                                 enabled);
-  }
-}
+bool gInitialized = false;
+bool gDidTrySend = false;
+string gDumpFile;
+StringTable gQueryParameters;
+string gHttpProxy;
+string gAuth;
+string gSendURL;
+string gURLParameter;
+vector<string> gRestartArgs;
+GThread* gSendThreadID;
 
-static void SaveSettings()
-{
-  /*
-   * NOTE! This code needs to stay in sync with the preference setting
-   *       code in in nsExceptionHandler.cpp.
-   */
-
-  StringTable settings;
-
-  ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true);
-  if (!gEmailFieldHint)
-    settings["Email"] = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
-  else
-    settings.erase("Email");
-
-  settings["EmailMe"] =
-    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)) ? "1" : "0";
-  if (gIncludeURLCheck != 0)
-    settings["IncludeURL"] =
-      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))
-      ? "1" : "0";
-  settings["SubmitReport"] =
-    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))
-    ? "1" : "0";
-
-  WriteStringsToFile(gSettingsPath + "/" + kIniFile,
-                     "Crash Reporter", settings, true);
-}
+// From crashreporter_linux.cpp or crashreporter_maemo_gtk.cpp
+void SaveSettings();
+void SendReport();
+void TryInitGnome();
+void UpdateSubmit();
 
 static bool RestartApplication()
 {
   char** argv = reinterpret_cast<char**>(
     malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
 
   if (!argv) return false;
 
@@ -199,17 +130,17 @@ static gboolean ReportCompleted(gpointer
   gtk_label_set_text(GTK_LABEL(gProgressLabel), str.c_str());
   g_timeout_add(5000, CloseApp, 0);
   return FALSE;
 }
 
 #ifdef MOZ_ENABLE_GCONF
 #define HTTP_PROXY_DIR "/system/http_proxy"
 
-static void LoadProxyinfo()
+void LoadProxyinfo()
 {
   class GConfClient;
   typedef GConfClient * (*_gconf_default_fn)();
   typedef gboolean (*_gconf_bool_fn)(GConfClient *, const gchar *, GError **);
   typedef gint (*_gconf_int_fn)(GConfClient *, const gchar *, GError **);
   typedef gchar * (*_gconf_string_fn)(GConfClient *, const gchar *, GError **);
 
   if (getenv ("http_proxy"))
@@ -276,17 +207,17 @@ static void LoadProxyinfo()
   }
 
   g_object_unref(conf);
 
   // Don't dlclose gconfLib as libORBit-2 uses atexit().
 }
 #endif
 
-static gpointer SendThread(gpointer args)
+gpointer SendThread(gpointer args)
 {
   string response, error;
 
   bool success = google_breakpad::HTTPUpload::SendRequest
     (gSendURL,
      gQueryParameters,
      gDumpFile,
      "upload_file_minidump",
@@ -304,68 +235,17 @@ static gpointer SendThread(gpointer args
   // Apparently glib is threadsafe, and will schedule this
   // on the main thread, see:
   // http://library.gnome.org/devel/gtk-faq/stable/x499.html
   g_idle_add(ReportCompleted, (gpointer)success);
 
   return NULL;
 }
 
-static void SendReport()
-{
-  // disable all our gui controls, show the throbber + change the progress text
-  gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
-  gtk_widget_set_sensitive(gViewReportButton, FALSE);
-  gtk_widget_set_sensitive(gCommentText, FALSE);
-  if (gIncludeURLCheck)
-    gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
-  gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
-  gtk_widget_set_sensitive(gEmailEntry, FALSE);
-  gtk_widget_set_sensitive(gCloseButton, FALSE);
-  if (gRestartButton)
-    gtk_widget_set_sensitive(gRestartButton, FALSE);
-  gtk_widget_show_all(gThrobber);
-  gtk_label_set_text(GTK_LABEL(gProgressLabel),
-                     gStrings[ST_REPORTDURINGSUBMIT].c_str());
-
-#ifdef MOZ_ENABLE_GCONF
-  LoadProxyinfo();
-#endif
-
-  // and spawn a thread to do the sending
-  GError* err;
-  gSendThreadID = g_thread_create(SendThread, NULL, TRUE, &err);
-}
-
-static void ShowReportInfo(GtkTextView* viewReportTextView)
-{
-  GtkTextBuffer* buffer =
-    gtk_text_view_get_buffer(viewReportTextView);
-
-  GtkTextIter start, end;
-  gtk_text_buffer_get_start_iter(buffer, &start);
-  gtk_text_buffer_get_end_iter(buffer, &end);
-
-  gtk_text_buffer_delete(buffer, &start, &end);
-
-  for (StringTable::iterator iter = gQueryParameters.begin();
-       iter != gQueryParameters.end();
-       iter++) {
-    gtk_text_buffer_insert(buffer, &end, iter->first.c_str(), -1);
-    gtk_text_buffer_insert(buffer, &end, ": ", -1);
-    gtk_text_buffer_insert(buffer, &end, iter->second.c_str(), -1);
-    gtk_text_buffer_insert(buffer, &end, "\n", -1);
-  }
-
-  gtk_text_buffer_insert(buffer, &end, "\n", -1);
-  gtk_text_buffer_insert(buffer, &end,
-                         gStrings[ST_EXTRAREPORTINFO].c_str(), -1);
-}
-
-static gboolean WindowDeleted(GtkWidget* window,
+gboolean WindowDeleted(GtkWidget* window,
                               GdkEvent* event,
                               gpointer userData)
 {
   SaveSettings();
   gtk_main_quit();
   return TRUE;
 }
 
@@ -374,254 +254,48 @@ static void MaybeSubmitReport()
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
     gDidTrySend = true;
     SendReport();
   } else {
     gtk_main_quit();
   }
 }
 
-static void CloseClicked(GtkButton* button,
-                         gpointer userData)
+void CloseClicked(GtkButton* button,
+                  gpointer userData)
 {
   SaveSettings();
   MaybeSubmitReport();
 }
 
-static void RestartClicked(GtkButton* button,
-                           gpointer userData)
+void RestartClicked(GtkButton* button,
+                    gpointer userData)
 {
   SaveSettings();
   RestartApplication();
   MaybeSubmitReport();
 }
 
-static void UpdateSubmit()
-{
-  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
-    gtk_widget_set_sensitive(gViewReportButton, TRUE);
-    gtk_widget_set_sensitive(gCommentText, TRUE);
-    if (gIncludeURLCheck)
-      gtk_widget_set_sensitive(gIncludeURLCheck, TRUE);
-    gtk_widget_set_sensitive(gEmailMeCheck, TRUE);
-    gtk_widget_set_sensitive(gEmailEntry,
-                             gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)));
-    gtk_label_set_text(GTK_LABEL(gProgressLabel),
-                       gStrings[ST_REPORTPRESUBMIT].c_str());
-  } else {
-    gtk_widget_set_sensitive(gViewReportButton, FALSE);
-    gtk_widget_set_sensitive(gCommentText, FALSE);
-    if (gIncludeURLCheck)
-      gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
-    gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
-    gtk_widget_set_sensitive(gEmailEntry, FALSE);
-    gtk_label_set_text(GTK_LABEL(gProgressLabel), "");
-  }
-}
-
-static void SubmitReportChecked(GtkButton* sender, gpointer userData)
-{
-  UpdateSubmit();
-}
-
-static void ViewReportClicked(GtkButton* button,
-                              gpointer userData)
-{
-  GtkDialog* dialog =
-    GTK_DIALOG(gtk_dialog_new_with_buttons(gStrings[ST_VIEWREPORTTITLE].c_str(),
-                                           GTK_WINDOW(gWindow),
-                                           GTK_DIALOG_MODAL,
-                                           GTK_STOCK_OK,
-                                           GTK_RESPONSE_OK,
-                                           NULL));
-
-  GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
-  gtk_container_add(GTK_CONTAINER(dialog->vbox), scrolled);
-  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
-                                 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
-                                      GTK_SHADOW_IN);
-
-  GtkWidget* viewReportTextView = gtk_text_view_new();
-  gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView);
-  gtk_text_view_set_editable(GTK_TEXT_VIEW(viewReportTextView), FALSE);
-  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(viewReportTextView),
-                              GTK_WRAP_WORD);
-  gtk_widget_set_size_request(GTK_WIDGET(viewReportTextView), -1, 100);
-
-  ShowReportInfo(GTK_TEXT_VIEW(viewReportTextView));
-
-  gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
-  gtk_widget_set_size_request(GTK_WIDGET(dialog), 400, 200);
-  gtk_widget_show_all(GTK_WIDGET(dialog));
-  gtk_dialog_run(dialog);
-  gtk_widget_destroy(GTK_WIDGET(dialog));
-}
-
-static void CommentChanged(GtkTextBuffer* buffer, gpointer userData)
-{
-  GtkTextIter start, end;
-  gtk_text_buffer_get_start_iter(buffer, &start);
-  gtk_text_buffer_get_end_iter(buffer, &end);
-  const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
-  if (comment[0] == '\0' || gCommentFieldHint)
-    gQueryParameters.erase("Comments");
-  else
-    gQueryParameters["Comments"] = comment;
-}
-
-static void CommentInsert(GtkTextBuffer* buffer,
-                          GtkTextIter* location,
-                          gchar* text,
-                          gint len,
-                          gpointer userData)
-{
-  GtkTextIter start, end;
-  gtk_text_buffer_get_start_iter(buffer, &start);
-  gtk_text_buffer_get_end_iter(buffer, &end);
-  const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
-
-  // limit to 500 bytes in utf-8
-  if (strlen(comment) + len > MAX_COMMENT_LENGTH) {
-    g_signal_stop_emission_by_name(buffer, "insert-text");
-  }
-}
-
-static void UpdateHintText(GtkWidget* widget, gboolean gainedFocus,
-                           bool* hintShowing, const char* hintText)
-{
-  GtkTextBuffer* buffer = NULL;
-  if (GTK_IS_TEXT_VIEW(widget))
-    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
-
-  if (gainedFocus) {
-    if (*hintShowing) {
-      if (buffer == NULL) { // sort of cheating
-        gtk_entry_set_text(GTK_ENTRY(widget), "");
-      }
-      else { // GtkTextView
-        gtk_text_buffer_set_text(buffer, "", 0);
-      }
-      gtk_widget_modify_text(widget, GTK_STATE_NORMAL, NULL);
-      *hintShowing = false;
-    }
-  }
-  else {
-    // lost focus
-    const char* text = NULL;
-    if (buffer == NULL) {
-      text = gtk_entry_get_text(GTK_ENTRY(widget));
-    }
-    else {
-      GtkTextIter start, end;
-      gtk_text_buffer_get_start_iter(buffer, &start);
-      gtk_text_buffer_get_end_iter(buffer, &end);
-      text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
-    }
-
-    if (text == NULL || text[0] == '\0') {
-      *hintShowing = true;
-
-      if (buffer == NULL) {
-        gtk_entry_set_text(GTK_ENTRY(widget), hintText);
-      }
-      else {
-        gtk_text_buffer_set_text(buffer, hintText, -1);
-      }
-
-      gtk_widget_modify_text(widget, GTK_STATE_NORMAL,
-                              &gtk_widget_get_style(widget)->text[GTK_STATE_INSENSITIVE]);
-    }
-  }
-}
-
-static gboolean CommentFocusChange(GtkWidget* widget, GdkEventFocus* event,
-                                   gpointer userData)
-{
-  UpdateHintText(widget, event->in, &gCommentFieldHint,
-                 gStrings[ST_COMMENTGRAYTEXT].c_str());
-
-  return FALSE;
-}
-
 static void UpdateURL()
 {
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))) {
     gQueryParameters["URL"] = gURLParameter;
   } else {
     gQueryParameters.erase("URL");
   }
 }
 
-static void UpdateEmail()
+void SubmitReportChecked(GtkButton* sender, gpointer userData)
 {
-  const char* email = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
-  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))) {
-    gtk_widget_set_sensitive(gEmailEntry, TRUE);
-  } else {
-    email = "";
-    gtk_widget_set_sensitive(gEmailEntry, FALSE);
-  }
-  if (email[0] == '\0' || gEmailFieldHint)
-    gQueryParameters.erase("Email");
-  else
-    gQueryParameters["Email"] = email;
-}
-
-static void IncludeURLClicked(GtkButton* sender, gpointer userData)
-{
-  UpdateURL();
-}
-
-static void EmailMeClicked(GtkButton* sender, gpointer userData)
-{
-  UpdateEmail();
-}
-
-static void EmailChanged(GtkEditable* editable, gpointer userData)
-{
-  UpdateEmail();
+  UpdateSubmit();
 }
 
-static gboolean EmailFocusChange(GtkWidget* widget, GdkEventFocus* event,
-                         gpointer userData)
-{
-  UpdateHintText(widget, event->in, &gEmailFieldHint,
-                 gStrings[ST_EMAILGRAYTEXT].c_str());
-
-  return FALSE;
-}
-
-typedef struct _GnomeProgram GnomeProgram;
-typedef struct _GnomeModuleInfo GnomeModuleInfo;
-typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
-                                                 const GnomeModuleInfo *, int,
-                                                 char **, const char *, ...);
-typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
-
-static void TryInitGnome()
+void IncludeURLClicked(GtkButton* sender, gpointer userData)
 {
-  gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY);
-  if (!gnomeLib)
-    return;
-
-  gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY);
-  if (!gnomeuiLib)
-    return;
-
-  _gnome_program_init_fn gnome_program_init =
-    (_gnome_program_init_fn)(dlsym(gnomeLib, "gnome_program_init"));
-  _libgnomeui_module_info_get_fn libgnomeui_module_info_get =
-    (_libgnomeui_module_info_get_fn)(dlsym(gnomeuiLib, "libgnomeui_module_info_get"));
-
-  if (gnome_program_init && libgnomeui_module_info_get) {
-    gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(),
-                       gArgc, gArgv, NULL);
-  }
-
+  UpdateURL();
 }
 
 /* === Crashreporter UI Functions === */
 
 bool UIInit()
 {
   // breakpad probably left us with blocked signals, unblock them here
   sigset_t signals, old;
@@ -633,221 +307,38 @@ bool UIInit()
 
   if (gtk_init_check(&gArgc, &gArgv)) {
     gInitialized = true;
 
     if (gStrings.find("isRTL") != gStrings.end() &&
         gStrings["isRTL"] == "yes")
       gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
 
+#ifndef MOZ_PLATFORM_MAEMO
     TryInitGnome();
+#endif
     return true;
   }
 
   return false;
 }
 
-void UIShutdown()
-{
-  if (gnomeuiLib)
-    dlclose(gnomeuiLib);
-  // Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit().
-}
-
 void UIShowDefaultUI()
 {
   GtkWidget* errorDialog =
     gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
                            GTK_MESSAGE_ERROR,
                            GTK_BUTTONS_CLOSE,
                            "%s", gStrings[ST_CRASHREPORTERDEFAULT].c_str());
 
   gtk_window_set_title(GTK_WINDOW(errorDialog),
                        gStrings[ST_CRASHREPORTERTITLE].c_str());
   gtk_dialog_run(GTK_DIALOG(errorDialog));
 }
 
-bool UIShowCrashUI(const string& dumpfile,
-                   const StringTable& queryParameters,
-                   const string& sendURL,
-                   const vector<string>& restartArgs)
-{
-  gDumpFile = dumpfile;
-  gQueryParameters = queryParameters;
-  gSendURL = sendURL;
-  gRestartArgs = restartArgs;
-  if (gQueryParameters.find("URL") != gQueryParameters.end())
-    gURLParameter = gQueryParameters["URL"];
-
-  gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title(GTK_WINDOW(gWindow),
-                       gStrings[ST_CRASHREPORTERTITLE].c_str());
-  gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE);
-  gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER);
-  gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12);
-  g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0);
-
-  GtkWidget* vbox = gtk_vbox_new(FALSE, 6);
-  gtk_container_add(GTK_CONTAINER(gWindow), vbox);
-
-  GtkWidget* titleLabel = gtk_label_new("");
-  gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0);
-  gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
-  char* markup = g_strdup_printf("<b>%s</b>",
-                                 gStrings[ST_CRASHREPORTERHEADER].c_str());
-  gtk_label_set_markup(GTK_LABEL(titleLabel), markup);
-  g_free(markup);
-
-  GtkWidget* descriptionLabel =
-    gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str());
-  gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0);
-  // force the label to line wrap
-  gtk_widget_set_size_request(descriptionLabel, 400, -1);
-  gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE);
-  gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE);
-  gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5);
-
-  // this is honestly how they suggest you indent a section
-  GtkWidget* indentBox = gtk_hbox_new(FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(vbox), indentBox, FALSE, FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(indentBox), gtk_label_new(""), FALSE, FALSE, 6);
-
-  GtkWidget* innerVBox1 = gtk_vbox_new(FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(indentBox), innerVBox1, TRUE, TRUE, 0);
-
-  gSubmitReportCheck =
-    gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str());
-  gtk_box_pack_start(GTK_BOX(innerVBox1), gSubmitReportCheck, FALSE, FALSE, 0);
-  g_signal_connect(gSubmitReportCheck, "clicked",
-                   G_CALLBACK(SubmitReportChecked), 0);
-
-  // indent again, below the "submit report" checkbox
-  GtkWidget* indentBox2 = gtk_hbox_new(FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(innerVBox1), indentBox2, FALSE, FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(indentBox2), gtk_label_new(""), FALSE, FALSE, 6);
-
-  GtkWidget* innerVBox = gtk_vbox_new(FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(indentBox2), innerVBox, TRUE, TRUE, 0);
-  gtk_box_set_spacing(GTK_BOX(innerVBox), 6);
-
-  GtkWidget* viewReportButtonBox = gtk_hbutton_box_new();
-  gtk_box_pack_start(GTK_BOX(innerVBox), viewReportButtonBox, FALSE, FALSE, 0);
-  gtk_box_set_spacing(GTK_BOX(viewReportButtonBox), 6);
-  gtk_button_box_set_layout(GTK_BUTTON_BOX(viewReportButtonBox), GTK_BUTTONBOX_START);
-
-  gViewReportButton =
-    gtk_button_new_with_label(gStrings[ST_VIEWREPORT].c_str());
-  gtk_box_pack_start(GTK_BOX(viewReportButtonBox), gViewReportButton, FALSE, FALSE, 0);
-  g_signal_connect(gViewReportButton, "clicked", G_CALLBACK(ViewReportClicked), 0);
-
-  GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
-  gtk_container_add(GTK_CONTAINER(innerVBox), scrolled);
-  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
-                                 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
-                                      GTK_SHADOW_IN);
-
-  gCommentText = gtk_text_view_new();
-  gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(gCommentText), FALSE);
-  g_signal_connect(gCommentText, "focus-in-event", G_CALLBACK(CommentFocusChange), 0);
-  g_signal_connect(gCommentText, "focus-out-event", G_CALLBACK(CommentFocusChange), 0);
-
-  GtkTextBuffer* commentBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gCommentText));
-  g_signal_connect(commentBuffer, "changed", G_CALLBACK(CommentChanged), 0);
-  g_signal_connect(commentBuffer, "insert-text", G_CALLBACK(CommentInsert), 0);
-
-  gtk_container_add(GTK_CONTAINER(scrolled), gCommentText);
-  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gCommentText),
-                              GTK_WRAP_WORD);
-  gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100);
-
-  if (gQueryParameters.find("URL") != gQueryParameters.end()) {
-    gIncludeURLCheck =
-      gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str());
-    gtk_box_pack_start(GTK_BOX(innerVBox), gIncludeURLCheck, FALSE, FALSE, 0);
-    g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), 0);
-    // on by default
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE);
-  }
-
-  gEmailMeCheck =
-    gtk_check_button_new_with_label(gStrings[ST_CHECKEMAIL].c_str());
-  gtk_box_pack_start(GTK_BOX(innerVBox), gEmailMeCheck, FALSE, FALSE, 0);
-  g_signal_connect(gEmailMeCheck, "clicked", G_CALLBACK(EmailMeClicked), 0);
-
-  GtkWidget* emailIndentBox = gtk_hbox_new(FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(innerVBox), emailIndentBox, FALSE, FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(emailIndentBox), gtk_label_new(""),
-                     FALSE, FALSE, 9);
-
-  gEmailEntry = gtk_entry_new();
-  gtk_box_pack_start(GTK_BOX(emailIndentBox), gEmailEntry, TRUE, TRUE, 0);
-  g_signal_connect(gEmailEntry, "changed", G_CALLBACK(EmailChanged), 0);
-  g_signal_connect(gEmailEntry, "focus-in-event", G_CALLBACK(EmailFocusChange), 0);
-  g_signal_connect(gEmailEntry, "focus-out-event", G_CALLBACK(EmailFocusChange), 0);
-
-  GtkWidget* progressBox = gtk_hbox_new(FALSE, 6);
-  gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0);
-
-  // Get the throbber image from alongside the executable
-  char* dir = g_path_get_dirname(gArgv[0]);
-  char* path = g_build_filename(dir, "Throbber-small.gif", NULL);
-  g_free(dir);
-  gThrobber = gtk_image_new_from_file(path);
-  gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0);
-
-  gProgressLabel =
-    gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str());
-  gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0);
-  // force the label to line wrap
-  gtk_widget_set_size_request(gProgressLabel, 400, -1);
-  gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE);
-
-  GtkWidget* buttonBox = gtk_hbutton_box_new();
-  gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0);
-  gtk_box_set_spacing(GTK_BOX(buttonBox), 6);
-  gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
-
-  gCloseButton =
-    gtk_button_new_with_label(gStrings[ST_QUIT].c_str());
-  gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0);
-  GTK_WIDGET_SET_FLAGS(gCloseButton, GTK_CAN_DEFAULT);
-  g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0);
-
-  gRestartButton = 0;
-  if (restartArgs.size() > 0) {
-    gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str());
-    gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0);
-    GTK_WIDGET_SET_FLAGS(gRestartButton, GTK_CAN_DEFAULT);
-    g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0);
-  }
-
-  gtk_widget_grab_focus(gSubmitReportCheck);
-
-  gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton);
-
-  LoadSettings();
-
-  UpdateEmail();
-  UpdateSubmit();
-
-  UpdateHintText(gCommentText, FALSE, &gCommentFieldHint,
-                 gStrings[ST_COMMENTGRAYTEXT].c_str());
-  UpdateHintText(gEmailEntry, FALSE, &gEmailFieldHint,
-                 gStrings[ST_EMAILGRAYTEXT].c_str());
-
-  gtk_widget_show_all(gWindow);
-  // stick this here to avoid the show_all above...
-  gtk_widget_hide_all(gThrobber);
-
-  gtk_main();
-
-  return gDidTrySend;
-}
-
 void UIError_impl(const string& message)
 {
   if (!gInitialized) {
     // Didn't initialize, this is the best we can do
     printf("Error: %s\n", message.c_str());
     return;
   }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/crashreporter_gtk_common.h
@@ -0,0 +1,44 @@
+#ifndef CRASHREPORTER_GTK_COMMON_H__
+#define CRASHREPORTER_GTK_COMMON_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <string>
+#include <vector>
+
+const char kIniFile[] = "crashreporter.ini";
+
+extern GtkWidget* gWindow;
+extern GtkWidget* gSubmitReportCheck;
+extern GtkWidget* gIncludeURLCheck;
+extern GtkWidget* gThrobber;
+extern GtkWidget* gProgressLabel;
+extern GtkWidget* gCloseButton;
+extern GtkWidget* gRestartButton;
+
+extern std::vector<std::string> gRestartArgs;
+extern GThread* gSendThreadID;
+
+extern bool gInitialized;
+extern bool gDidTrySend;
+extern std::string gDumpFile;
+extern StringTable gQueryParameters;
+extern std::string gHttpProxy;
+extern std::string gAuth;
+extern std::string gSendURL;
+extern std::string gURLParameter;
+
+void LoadProxyinfo();
+gpointer SendThread(gpointer args);
+gboolean WindowDeleted(GtkWidget* window,
+                       GdkEvent* event,
+                       gpointer userData);
+void SubmitReportChecked(GtkButton* sender, gpointer userData);
+void IncludeURLClicked(GtkButton* sender, gpointer userData);
+void CloseClicked(GtkButton* button,
+                  gpointer userData);
+void RestartClicked(GtkButton* button,
+                    gpointer userData);
+
+#endif // CRASHREPORTER_GTK_COMMON_H__
--- a/toolkit/crashreporter/client/crashreporter_linux.cpp
+++ b/toolkit/crashreporter/client/crashreporter_linux.cpp
@@ -30,77 +30,45 @@
  * 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 "crashreporter.h"
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <string.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dlfcn.h>
-
-#include <algorithm>
 #include <cctype>
 
-#include <signal.h>
-
-#include <gtk/gtk.h>
-#include <glib.h>
-#include <string.h>
-
-#include "common/linux/http_upload.h"
+#include "crashreporter.h"
+#include "crashreporter_gtk_common.h"
 
 using std::string;
 using std::vector;
 
 using namespace CrashReporter;
 
-static GtkWidget* gWindow = 0;
-static GtkWidget* gSubmitReportCheck = 0;
 static GtkWidget* gViewReportButton = 0;
 static GtkWidget* gCommentText = 0;
-static GtkWidget* gIncludeURLCheck = 0;
 static GtkWidget* gEmailMeCheck = 0;
 static GtkWidget* gEmailEntry = 0;
-static GtkWidget* gThrobber = 0;
-static GtkWidget* gProgressLabel = 0;
-static GtkWidget* gCloseButton = 0;
-static GtkWidget* gRestartButton = 0;
-
-static bool gInitialized = false;
-static bool gDidTrySend = false;
-static string gDumpFile;
-static StringTable gQueryParameters;
-static string gSendURL;
-static string gHttpProxy;
-static string gAuth;
-static vector<string> gRestartArgs;
-static string gURLParameter;
 
 static bool gEmailFieldHint = true;
 static bool gCommentFieldHint = true;
 
-static GThread* gSendThreadID;
-
 // handle from dlopen'ing libgnome
 static void* gnomeLib = NULL;
 // handle from dlopen'ing libgnomeui
 static void* gnomeuiLib = NULL;
 
-static const char kIniFile[] = "crashreporter.ini";
-
 static void LoadSettings()
 {
   /*
    * NOTE! This code needs to stay in sync with the preference checking
    *       code in in nsExceptionHandler.cpp.
    */
 
   StringTable settings;
@@ -123,17 +91,17 @@ static void LoadSettings()
       enabled = settings["SubmitReport"][0] != '0';
     else
       enabled = ShouldEnableSending();
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck),
                                  enabled);
   }
 }
 
-static void SaveSettings()
+void SaveSettings()
 {
   /*
    * NOTE! This code needs to stay in sync with the preference setting
    *       code in in nsExceptionHandler.cpp.
    */
 
   StringTable settings;
 
@@ -152,169 +120,17 @@ static void SaveSettings()
   settings["SubmitReport"] =
     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))
     ? "1" : "0";
 
   WriteStringsToFile(gSettingsPath + "/" + kIniFile,
                      "Crash Reporter", settings, true);
 }
 
-static bool RestartApplication()
-{
-  char** argv = reinterpret_cast<char**>(
-    malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
-
-  if (!argv) return false;
-
-  unsigned int i;
-  for (i = 0; i < gRestartArgs.size(); i++) {
-    argv[i] = (char*)gRestartArgs[i].c_str();
-  }
-  argv[i] = 0;
-
-  pid_t pid = fork();
-  if (pid == -1)
-    return false;
-  else if (pid == 0) {
-    (void)execv(argv[0], argv);
-    _exit(1);
-  }
-
-  free(argv);
-
-  return true;
-}
-
-// Quit the app, used as a timeout callback
-static gboolean CloseApp(gpointer data)
-{
-  gtk_main_quit();
-  g_thread_join(gSendThreadID);
-  return FALSE;
-}
-
-static gboolean ReportCompleted(gpointer success)
-{
-  gtk_widget_hide_all(gThrobber);
-  string str = success ? gStrings[ST_REPORTSUBMITSUCCESS]
-                       : gStrings[ST_SUBMITFAILED];
-  gtk_label_set_text(GTK_LABEL(gProgressLabel), str.c_str());
-  g_timeout_add(5000, CloseApp, 0);
-  return FALSE;
-}
-
-#ifdef MOZ_ENABLE_GCONF
-#define HTTP_PROXY_DIR "/system/http_proxy"
-
-static void LoadProxyinfo()
-{
-  class GConfClient;
-  typedef GConfClient * (*_gconf_default_fn)();
-  typedef gboolean (*_gconf_bool_fn)(GConfClient *, const gchar *, GError **);
-  typedef gint (*_gconf_int_fn)(GConfClient *, const gchar *, GError **);
-  typedef gchar * (*_gconf_string_fn)(GConfClient *, const gchar *, GError **);
-
-  if (getenv ("http_proxy"))
-    return; // libcurl can use the value from the environment
-
-  static void* gconfLib = dlopen("libgconf-2.so.4", RTLD_LAZY);
-  if (!gconfLib)
-    return;
-
-  _gconf_default_fn gconf_client_get_default =
-    (_gconf_default_fn)dlsym(gconfLib, "gconf_client_get_default");
-  _gconf_bool_fn gconf_client_get_bool =
-    (_gconf_bool_fn)dlsym(gconfLib, "gconf_client_get_bool");
-  _gconf_int_fn gconf_client_get_int =
-    (_gconf_int_fn)dlsym(gconfLib, "gconf_client_get_int");
-  _gconf_string_fn gconf_client_get_string =
-    (_gconf_string_fn)dlsym(gconfLib, "gconf_client_get_string");
-
-  if(!(gconf_client_get_default &&
-       gconf_client_get_bool &&
-       gconf_client_get_int &&
-       gconf_client_get_string)) {
-    dlclose(gconfLib);
-    return;
-  }
-
-  GConfClient *conf = gconf_client_get_default();
-
-  if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_http_proxy", NULL)) {
-    gint port;
-    gchar *host = NULL, *httpproxy = NULL;
-
-    host = gconf_client_get_string(conf, HTTP_PROXY_DIR "/host", NULL);
-    port = gconf_client_get_int(conf, HTTP_PROXY_DIR "/port", NULL);
-
-    if (port && host && host != '\0') {
-      httpproxy = g_strdup_printf("http://%s:%d/", host, port);
-      gHttpProxy = httpproxy;
-    }
-
-    g_free(host);
-    g_free(httpproxy);
-
-    if(gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_authentication", NULL)) {
-      gchar *user, *password, *auth = NULL;
-
-      user = gconf_client_get_string(conf,
-                                     HTTP_PROXY_DIR "/authentication_user",
-                                     NULL);
-      password = gconf_client_get_string(conf,
-                                         HTTP_PROXY_DIR
-                                         "/authentication_password",
-                                         NULL);
-
-      if (user && password) {
-        auth = g_strdup_printf("%s:%s", user, password);
-        gAuth = auth;
-      }
-
-      g_free(user);
-      g_free(password);
-      g_free(auth);
-    }
-  }
-
-  g_object_unref(conf);
-
-  // Don't dlclose gconfLib as libORBit-2 uses atexit().
-}
-#endif
-
-static gpointer SendThread(gpointer args)
-{
-  string response, error;
-
-  bool success = google_breakpad::HTTPUpload::SendRequest
-    (gSendURL,
-     gQueryParameters,
-     gDumpFile,
-     "upload_file_minidump",
-     gHttpProxy, gAuth,
-     &response,
-     &error);
-  if (success) {
-    LogMessage("Crash report submitted successfully");
-  }
-  else {
-    LogMessage("Crash report submission failed: " + error);
-  }
-
-  SendCompleted(success, response);
-  // Apparently glib is threadsafe, and will schedule this
-  // on the main thread, see:
-  // http://library.gnome.org/devel/gtk-faq/stable/x499.html
-  g_idle_add(ReportCompleted, (gpointer)success);
-
-  return NULL;
-}
-
-static void SendReport()
+void SendReport()
 {
   // disable all our gui controls, show the throbber + change the progress text
   gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
   gtk_widget_set_sensitive(gViewReportButton, FALSE);
   gtk_widget_set_sensitive(gCommentText, FALSE);
   if (gIncludeURLCheck)
     gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
   gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
@@ -355,51 +171,17 @@ static void ShowReportInfo(GtkTextView* 
     gtk_text_buffer_insert(buffer, &end, "\n", -1);
   }
 
   gtk_text_buffer_insert(buffer, &end, "\n", -1);
   gtk_text_buffer_insert(buffer, &end,
                          gStrings[ST_EXTRAREPORTINFO].c_str(), -1);
 }
 
-static gboolean WindowDeleted(GtkWidget* window,
-                              GdkEvent* event,
-                              gpointer userData)
-{
-  SaveSettings();
-  gtk_main_quit();
-  return TRUE;
-}
-
-static void MaybeSubmitReport()
-{
-  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
-    gDidTrySend = true;
-    SendReport();
-  } else {
-    gtk_main_quit();
-  }
-}
-
-static void CloseClicked(GtkButton* button,
-                         gpointer userData)
-{
-  SaveSettings();
-  MaybeSubmitReport();
-}
-
-static void RestartClicked(GtkButton* button,
-                           gpointer userData)
-{
-  SaveSettings();
-  RestartApplication();
-  MaybeSubmitReport();
-}
-
-static void UpdateSubmit()
+void UpdateSubmit()
 {
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
     gtk_widget_set_sensitive(gViewReportButton, TRUE);
     gtk_widget_set_sensitive(gCommentText, TRUE);
     if (gIncludeURLCheck)
       gtk_widget_set_sensitive(gIncludeURLCheck, TRUE);
     gtk_widget_set_sensitive(gEmailMeCheck, TRUE);
     gtk_widget_set_sensitive(gEmailEntry,
@@ -412,21 +194,16 @@ static void UpdateSubmit()
     if (gIncludeURLCheck)
       gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
     gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
     gtk_widget_set_sensitive(gEmailEntry, FALSE);
     gtk_label_set_text(GTK_LABEL(gProgressLabel), "");
   }
 }
 
-static void SubmitReportChecked(GtkButton* sender, gpointer userData)
-{
-  UpdateSubmit();
-}
-
 static void ViewReportClicked(GtkButton* button,
                               gpointer userData)
 {
   GtkDialog* dialog =
     GTK_DIALOG(gtk_dialog_new_with_buttons(gStrings[ST_VIEWREPORTTITLE].c_str(),
                                            GTK_WINDOW(gWindow),
                                            GTK_DIALOG_MODAL,
                                            GTK_STOCK_OK,
@@ -537,45 +314,31 @@ static gboolean CommentFocusChange(GtkWi
                                    gpointer userData)
 {
   UpdateHintText(widget, event->in, &gCommentFieldHint,
                  gStrings[ST_COMMENTGRAYTEXT].c_str());
 
   return FALSE;
 }
 
-static void UpdateURL()
-{
-  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))) {
-    gQueryParameters["URL"] = gURLParameter;
-  } else {
-    gQueryParameters.erase("URL");
-  }
-}
-
 static void UpdateEmail()
 {
   const char* email = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))) {
     gtk_widget_set_sensitive(gEmailEntry, TRUE);
   } else {
     email = "";
     gtk_widget_set_sensitive(gEmailEntry, FALSE);
   }
   if (email[0] == '\0' || gEmailFieldHint)
     gQueryParameters.erase("Email");
   else
     gQueryParameters["Email"] = email;
 }
 
-static void IncludeURLClicked(GtkButton* sender, gpointer userData)
-{
-  UpdateURL();
-}
-
 static void EmailMeClicked(GtkButton* sender, gpointer userData)
 {
   UpdateEmail();
 }
 
 static void EmailChanged(GtkEditable* editable, gpointer userData)
 {
   UpdateEmail();
@@ -592,17 +355,17 @@ static gboolean EmailFocusChange(GtkWidg
 
 typedef struct _GnomeProgram GnomeProgram;
 typedef struct _GnomeModuleInfo GnomeModuleInfo;
 typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
                                                  const GnomeModuleInfo *, int,
                                                  char **, const char *, ...);
 typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
 
-static void TryInitGnome()
+void TryInitGnome()
 {
   gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY);
   if (!gnomeLib)
     return;
 
   gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY);
   if (!gnomeuiLib)
     return;
@@ -616,60 +379,38 @@ static void TryInitGnome()
     gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(),
                        gArgc, gArgv, NULL);
   }
 
 }
 
 /* === Crashreporter UI Functions === */
 
-bool UIInit()
-{
-  // breakpad probably left us with blocked signals, unblock them here
-  sigset_t signals, old;
-  sigfillset(&signals);
-  sigprocmask(SIG_UNBLOCK, &signals, &old);
-
-  // tell glib we're going to use threads
-  g_thread_init(NULL);
-
-  if (gtk_init_check(&gArgc, &gArgv)) {
-    gInitialized = true;
-
-    if (gStrings.find("isRTL") != gStrings.end() &&
-        gStrings["isRTL"] == "yes")
-      gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
-
-    TryInitGnome();
-    return true;
-  }
-
-  return false;
-}
+/*
+ * Anything not listed here is in crashreporter_gtk_common.cpp:
+ *  UIInit
+ *  UIShowDefaultUI
+ *  UIError_impl
+ *  UIGetIniPath
+ *  UIGetSettingsPath
+ *  UIEnsurePathExists
+ *  UIFileExists
+ *  UIMoveFile
+ *  UIDeleteFile
+ *  UIOpenRead
+ *  UIOpenWrite
+ */
 
 void UIShutdown()
 {
   if (gnomeuiLib)
     dlclose(gnomeuiLib);
   // Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit().
 }
 
-void UIShowDefaultUI()
-{
-  GtkWidget* errorDialog =
-    gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
-                           GTK_MESSAGE_ERROR,
-                           GTK_BUTTONS_CLOSE,
-                           "%s", gStrings[ST_CRASHREPORTERDEFAULT].c_str());
-
-  gtk_window_set_title(GTK_WINDOW(errorDialog),
-                       gStrings[ST_CRASHREPORTERTITLE].c_str());
-  gtk_dialog_run(GTK_DIALOG(errorDialog));
-}
-
 bool UIShowCrashUI(const string& dumpfile,
                    const StringTable& queryParameters,
                    const string& sendURL,
                    const vector<string>& restartArgs)
 {
   gDumpFile = dumpfile;
   gQueryParameters = queryParameters;
   gSendURL = sendURL;
@@ -837,133 +578,8 @@ bool UIShowCrashUI(const string& dumpfil
   gtk_widget_show_all(gWindow);
   // stick this here to avoid the show_all above...
   gtk_widget_hide_all(gThrobber);
 
   gtk_main();
 
   return gDidTrySend;
 }
-
-void UIError_impl(const string& message)
-{
-  if (!gInitialized) {
-    // Didn't initialize, this is the best we can do
-    printf("Error: %s\n", message.c_str());
-    return;
-  }
-
-  GtkWidget* errorDialog =
-    gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
-                           GTK_MESSAGE_ERROR,
-                           GTK_BUTTONS_CLOSE,
-                           "%s", message.c_str());
-
-  gtk_window_set_title(GTK_WINDOW(errorDialog),
-                       gStrings[ST_CRASHREPORTERTITLE].c_str());
-  gtk_dialog_run(GTK_DIALOG(errorDialog));
-}
-
-bool UIGetIniPath(string& path)
-{
-  path = gArgv[0];
-  path.append(".ini");
-
-  return true;
-}
-
-/*
- * Settings are stored in ~/.vendor/product, or
- * ~/.product if vendor is empty.
- */
-bool UIGetSettingsPath(const string& vendor,
-                       const string& product,
-                       string& settingsPath)
-{
-  char* home = getenv("HOME");
-
-  if (!home)
-    return false;
-
-  settingsPath = home;
-  settingsPath += "/.";
-  if (!vendor.empty()) {
-    string lc_vendor;
-    std::transform(vendor.begin(), vendor.end(), back_inserter(lc_vendor),
-                   (int(*)(int)) std::tolower);
-    settingsPath += lc_vendor + "/";
-  }
-  string lc_product;
-  std::transform(product.begin(), product.end(), back_inserter(lc_product),
-                 (int(*)(int)) std::tolower);
-  settingsPath += lc_product + "/Crash Reports";
-  return true;
-}
-
-bool UIEnsurePathExists(const string& path)
-{
-  int ret = mkdir(path.c_str(), S_IRWXU);
-  int e = errno;
-  if (ret == -1 && e != EEXIST)
-    return false;
-
-  return true;
-}
-
-bool UIFileExists(const string& path)
-{
-  struct stat sb;
-  int ret = stat(path.c_str(), &sb);
-  if (ret == -1 || !(sb.st_mode & S_IFREG))
-    return false;
-
-  return true;
-}
-
-bool UIMoveFile(const string& file, const string& newfile)
-{
-  if (!rename(file.c_str(), newfile.c_str()))
-    return true;
-  if (errno != EXDEV)
-    return false;
-
-  // use system /bin/mv instead, time to fork
-  pid_t pID = vfork();
-  if (pID < 0) {
-    // Failed to fork
-    return false;
-  }
-  if (pID == 0) {
-    char* const args[4] = {
-      "mv",
-      strdup(file.c_str()),
-      strdup(newfile.c_str()),
-      0
-    };
-    if (args[1] && args[2])
-      execve("/bin/mv", args, 0);
-    if (args[1])
-      free(args[1]);
-    if (args[2])
-      free(args[2]);
-    exit(-1);
-  }
-  int status;
-  waitpid(pID, &status, 0);
-  return UIFileExists(newfile);
-}
-
-bool UIDeleteFile(const string& file)
-{
-  return (unlink(file.c_str()) != -1);
-}
-
-std::ifstream* UIOpenRead(const string& filename)
-{
-  return new std::ifstream(filename.c_str(), std::ios::in);
-}
-
-std::ofstream* UIOpenWrite(const string& filename, bool append) // append=false
-{
-  return new std::ofstream(filename.c_str(),
-                           append ? std::ios::out | std::ios::app
-                                  : std::ios::out);
-}
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/crashreporter_maemo_gtk.cpp
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 2; 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 Toolkit Crash Reporter.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ted Mielczarek <ted.mielczarek@gmail.com>
+ *
+ * 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 <fcntl.h>
+#include <hildon-1/hildon/hildon.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include <cctype>
+
+#include "crashreporter.h"
+#include "crashreporter_gtk_common.h"
+
+using std::string;
+using std::vector;
+
+using namespace CrashReporter;
+
+void LoadSettings()
+{
+  /*
+   * NOTE! This code needs to stay in sync with the preference checking
+   *       code in in nsExceptionHandler.cpp.
+   */
+
+  //XXX: share with desktop linux code?
+  StringTable settings;
+  if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) {
+    if (settings.find("IncludeURL") != settings.end() &&
+        gIncludeURLCheck != 0) {
+      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck),
+                                   settings["IncludeURL"][0] != '0');
+    }
+    bool enabled;
+    if (settings.find("SubmitReport") != settings.end())
+      enabled = settings["SubmitReport"][0] != '0';
+    else
+      enabled = ShouldEnableSending();
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck),
+                                 enabled);
+  }
+}
+
+void SaveSettings()
+{
+  /*
+   * NOTE! This code needs to stay in sync with the preference setting
+   *       code in in nsExceptionHandler.cpp.
+   */
+
+  StringTable settings;
+
+  ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true);
+
+  if (gIncludeURLCheck != 0)
+    settings["IncludeURL"] =
+      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))
+      ? "1" : "0";
+  settings["SubmitReport"] =
+    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))
+    ? "1" : "0";
+
+  WriteStringsToFile(gSettingsPath + "/" + kIniFile,
+                     "Crash Reporter", settings, true);
+}
+
+void SendReport()
+{
+  // disable all our gui controls, show the throbber + change the progress text
+  gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
+  if (gIncludeURLCheck)
+    gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
+  gtk_widget_set_sensitive(gCloseButton, FALSE);
+  if (gRestartButton)
+    gtk_widget_set_sensitive(gRestartButton, FALSE);
+  gtk_widget_show_all(gThrobber);
+  gtk_label_set_text(GTK_LABEL(gProgressLabel),
+                     gStrings[ST_REPORTDURINGSUBMIT].c_str());
+
+#ifdef MOZ_ENABLE_GCONF
+  LoadProxyinfo();
+#endif
+
+  // and spawn a thread to do the sending
+  GError* err;
+  gSendThreadID = g_thread_create(SendThread, NULL, TRUE, &err);
+}
+
+void UpdateSubmit()
+{
+  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
+    if (gIncludeURLCheck)
+      gtk_widget_set_sensitive(gIncludeURLCheck, TRUE);
+    gtk_label_set_text(GTK_LABEL(gProgressLabel),
+                       gStrings[ST_REPORTPRESUBMIT].c_str());
+  } else {
+    if (gIncludeURLCheck)
+      gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
+    gtk_label_set_text(GTK_LABEL(gProgressLabel), "");
+  }
+}
+
+/* === Crashreporter UI Functions === */
+
+/*
+ * Anything not listed here is in crashreporter_gtk_common.cpp:
+ *  UIInit
+ *  UIShowDefaultUI
+ *  UIError_impl
+ *  UIGetIniPath
+ *  UIGetSettingsPath
+ *  UIEnsurePathExists
+ *  UIFileExists
+ *  UIMoveFile
+ *  UIDeleteFile
+ *  UIOpenRead
+ *  UIOpenWrite
+ */
+
+void UIShutdown()
+{
+}
+
+bool UIShowCrashUI(const string& dumpfile,
+                   const StringTable& queryParameters,
+                   const string& sendURL,
+                   const vector<string>& restartArgs)
+{
+  gDumpFile = dumpfile;
+  gQueryParameters = queryParameters;
+  gSendURL = sendURL;
+  gRestartArgs = restartArgs;
+  if (gQueryParameters.find("URL") != gQueryParameters.end())
+    gURLParameter = gQueryParameters["URL"];
+
+  gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title(GTK_WINDOW(gWindow),
+                       gStrings[ST_CRASHREPORTERTITLE].c_str());
+  gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE);
+  gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER);
+  gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12);
+  g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0);
+
+  GtkWidget* vbox = gtk_vbox_new(FALSE, 6);
+  gtk_container_add(GTK_CONTAINER(gWindow), vbox);
+
+  GtkWidget* titleLabel = gtk_label_new("");
+  gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0);
+  gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
+  char* markup = g_strdup_printf("<b>%s</b>",
+                                 gStrings[ST_CRASHREPORTERHEADER].c_str());
+  gtk_label_set_markup(GTK_LABEL(titleLabel), markup);
+  g_free(markup);
+
+  GtkWidget* descriptionLabel =
+    gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str());
+  gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0);
+  // force the label to line wrap
+  gtk_widget_set_size_request(descriptionLabel, -1, -1);
+  gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE);
+  gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE);
+  gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5);
+
+  gSubmitReportCheck =
+    gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str());
+
+  gtk_box_pack_start(GTK_BOX(vbox), gSubmitReportCheck, FALSE, FALSE, 0);
+  g_signal_connect(gSubmitReportCheck, "clicked",
+                   G_CALLBACK(SubmitReportChecked), 0);
+
+  if (gQueryParameters.find("URL") != gQueryParameters.end()) {
+    gIncludeURLCheck =
+      gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str());
+    gtk_box_pack_start(GTK_BOX(vbox), gIncludeURLCheck, FALSE, FALSE, 0);
+    g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), 0);
+    // on by default
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE);
+  }
+
+  GtkWidget* progressBox = gtk_hbox_new(FALSE, 6);
+  gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0);
+
+  // Get the throbber image from alongside the executable
+  char* dir = g_path_get_dirname(gArgv[0]);
+  char* path = g_build_filename(dir, "Throbber-small.gif", NULL);
+  g_free(dir);
+  gThrobber = gtk_image_new_from_file(path);
+  gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0);
+
+  gProgressLabel =
+    gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str());
+  gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0);
+  // force the label to line wrap
+  gtk_widget_set_size_request(gProgressLabel, 500, -1);
+  gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE);
+
+  GtkWidget* buttonBox = gtk_hbutton_box_new();
+  gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0);
+  gtk_box_set_spacing(GTK_BOX(buttonBox), 6);
+  gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
+
+  gCloseButton =
+    gtk_button_new_with_label(gStrings[ST_QUIT].c_str());
+  gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0);
+  GTK_WIDGET_SET_FLAGS(gCloseButton, GTK_CAN_DEFAULT);
+  g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0);
+
+  gRestartButton = 0;
+  if (restartArgs.size() > 0) {
+    gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str());
+    gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0);
+    GTK_WIDGET_SET_FLAGS(gRestartButton, GTK_CAN_DEFAULT);
+    g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0);
+  }
+
+  gtk_widget_grab_focus(gSubmitReportCheck);
+
+  gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton);
+
+  LoadSettings();
+
+  UpdateSubmit();
+
+  gtk_widget_show_all(gWindow);
+  // stick this here to avoid the show_all above...
+  gtk_widget_hide_all(gThrobber);
+
+  gtk_main();
+
+  return gDidTrySend;
+}
rename from toolkit/crashreporter/client/crashreporter_unix.cpp
rename to toolkit/crashreporter/client/crashreporter_unix_common.cpp