toolkit/xre/nsNativeAppSupportUnix.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/xre/nsNativeAppSupportUnix.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,296 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsNativeAppSupportBase.h"
    1.10 +#include "nsCOMPtr.h"
    1.11 +#include "nsXPCOM.h"
    1.12 +#include "nsISupportsPrimitives.h"
    1.13 +#include "nsIObserverService.h"
    1.14 +#include "nsIAppStartup.h"
    1.15 +#include "nsServiceManagerUtils.h"
    1.16 +#include "prlink.h"
    1.17 +#include "nsXREDirProvider.h"
    1.18 +#include "nsReadableUtils.h"
    1.19 +
    1.20 +#include "nsIFile.h"
    1.21 +#include "nsDirectoryServiceDefs.h"
    1.22 +#include "nsICommandLineRunner.h"
    1.23 +#include "nsIWindowMediator.h"
    1.24 +#include "nsPIDOMWindow.h"
    1.25 +#include "nsIDocShell.h"
    1.26 +#include "nsIBaseWindow.h"
    1.27 +#include "nsIWidget.h"
    1.28 +#include "nsIWritablePropertyBag2.h"
    1.29 +#include "nsIPrefService.h"
    1.30 +#include "mozilla/Services.h"
    1.31 +
    1.32 +#include <stdlib.h>
    1.33 +#include <glib.h>
    1.34 +#include <glib-object.h>
    1.35 +#include <gtk/gtk.h>
    1.36 +
    1.37 +#ifdef MOZ_X11
    1.38 +#include <gdk/gdkx.h>
    1.39 +#include <X11/Xatom.h>
    1.40 +#endif
    1.41 +
    1.42 +#ifdef MOZ_ENABLE_DBUS
    1.43 +#include <dbus/dbus.h>
    1.44 +#endif
    1.45 +
    1.46 +#define MIN_GTK_MAJOR_VERSION 2
    1.47 +#define MIN_GTK_MINOR_VERSION 10
    1.48 +#define UNSUPPORTED_GTK_MSG "We're sorry, this application requires a version of the GTK+ library that is not installed on your computer.\n\n\
    1.49 +You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
    1.50 +Please upgrade your GTK+ library if you wish to use this application."
    1.51 +
    1.52 +typedef struct _GnomeProgram GnomeProgram;
    1.53 +typedef struct _GnomeModuleInfo GnomeModuleInfo;
    1.54 +typedef struct _GnomeClient GnomeClient;
    1.55 +
    1.56 +typedef enum {
    1.57 +  GNOME_SAVE_GLOBAL,
    1.58 +  GNOME_SAVE_LOCAL,
    1.59 +  GNOME_SAVE_BOTH
    1.60 +} GnomeSaveStyle;
    1.61 +
    1.62 +typedef enum {
    1.63 +  GNOME_INTERACT_NONE,
    1.64 +  GNOME_INTERACT_ERRORS,
    1.65 +  GNOME_INTERACT_ANY
    1.66 +} GnomeInteractStyle;
    1.67 +
    1.68 +typedef enum {
    1.69 +  GNOME_DIALOG_ERROR,
    1.70 +  GNOME_DIALOG_NORMAL
    1.71 +} GnomeDialogType;
    1.72 +
    1.73 +typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
    1.74 +                                                 const GnomeModuleInfo *, int,
    1.75 +                                                 char **, const char *, ...);
    1.76 +typedef GnomeProgram * (*_gnome_program_get_fn)(void);
    1.77 +typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
    1.78 +typedef GnomeClient * (*_gnome_master_client_fn)(void);
    1.79 +typedef void (*_gnome_client_set_restart_command_fn)(GnomeClient*, gint, gchar*[]);
    1.80 +
    1.81 +static _gnome_client_set_restart_command_fn gnome_client_set_restart_command;
    1.82 +
    1.83 +gboolean save_yourself_cb(GnomeClient *client, gint phase,
    1.84 +                          GnomeSaveStyle style, gboolean shutdown,
    1.85 +                          GnomeInteractStyle interact, gboolean fast,
    1.86 +                          gpointer user_data)
    1.87 +{
    1.88 +  nsCOMPtr<nsIObserverService> obsServ =
    1.89 +    mozilla::services::GetObserverService();
    1.90 +
    1.91 +  nsCOMPtr<nsISupportsPRBool> didSaveSession =
    1.92 +    do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
    1.93 +
    1.94 +  if (!obsServ || !didSaveSession)
    1.95 +    return TRUE; // OOM
    1.96 +
    1.97 +  // Notify observers to save the session state
    1.98 +  didSaveSession->SetData(false);
    1.99 +  obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
   1.100 +
   1.101 +  bool status;
   1.102 +  didSaveSession->GetData(&status);
   1.103 +
   1.104 +  // If there was no session saved and the save_yourself request is
   1.105 +  // caused by upcoming shutdown we like to prepare for it
   1.106 +  if (!status && shutdown) {
   1.107 +    nsCOMPtr<nsISupportsPRBool> cancelQuit =
   1.108 +      do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
   1.109 +
   1.110 +    cancelQuit->SetData(false);
   1.111 +    obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
   1.112 +
   1.113 +    bool abortQuit;
   1.114 +    cancelQuit->GetData(&abortQuit);
   1.115 +  }
   1.116 +
   1.117 +  return TRUE;
   1.118 +}
   1.119 +
   1.120 +void die_cb(GnomeClient *client, gpointer user_data)
   1.121 +{
   1.122 +  nsCOMPtr<nsIAppStartup> appService =
   1.123 +    do_GetService("@mozilla.org/toolkit/app-startup;1");
   1.124 +
   1.125 +  if (appService)
   1.126 +    appService->Quit(nsIAppStartup::eForceQuit);
   1.127 +}
   1.128 +
   1.129 +class nsNativeAppSupportUnix : public nsNativeAppSupportBase
   1.130 +{
   1.131 +public:
   1.132 +  NS_IMETHOD Start(bool* aRetVal);
   1.133 +  NS_IMETHOD Stop(bool *aResult);
   1.134 +  NS_IMETHOD Enable();
   1.135 +
   1.136 +private:
   1.137 +};
   1.138 +
   1.139 +NS_IMETHODIMP
   1.140 +nsNativeAppSupportUnix::Start(bool *aRetVal)
   1.141 +{
   1.142 +  NS_ASSERTION(gAppData, "gAppData must not be null.");
   1.143 +
   1.144 +// The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService,
   1.145 +// from diffrent threads. This could lead to race conditions if the dbus is not
   1.146 +// initialized before making any other library calls.
   1.147 +#ifdef MOZ_ENABLE_DBUS
   1.148 +  dbus_threads_init_default();
   1.149 +#endif
   1.150 +
   1.151 +#if (MOZ_WIDGET_GTK == 2)
   1.152 +  if (gtk_major_version < MIN_GTK_MAJOR_VERSION ||
   1.153 +      (gtk_major_version == MIN_GTK_MAJOR_VERSION && gtk_minor_version < MIN_GTK_MINOR_VERSION)) {
   1.154 +    GtkWidget* versionErrDialog = gtk_message_dialog_new(nullptr,
   1.155 +                     GtkDialogFlags(GTK_DIALOG_MODAL |
   1.156 +                                    GTK_DIALOG_DESTROY_WITH_PARENT),
   1.157 +                     GTK_MESSAGE_ERROR,
   1.158 +                     GTK_BUTTONS_OK,
   1.159 +                     UNSUPPORTED_GTK_MSG,
   1.160 +                     gtk_major_version,
   1.161 +                     gtk_minor_version,
   1.162 +                     MIN_GTK_MAJOR_VERSION,
   1.163 +                     MIN_GTK_MINOR_VERSION);
   1.164 +    gtk_dialog_run(GTK_DIALOG(versionErrDialog));
   1.165 +    gtk_widget_destroy(versionErrDialog);
   1.166 +    exit(0);
   1.167 +  }
   1.168 +#endif
   1.169 +
   1.170 +  *aRetVal = true;
   1.171 +
   1.172 +#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
   1.173 +
   1.174 +  PRLibrary *gnomeuiLib = PR_LoadLibrary("libgnomeui-2.so.0");
   1.175 +  if (!gnomeuiLib)
   1.176 +    return NS_OK;
   1.177 +
   1.178 +  PRLibrary *gnomeLib = PR_LoadLibrary("libgnome-2.so.0");
   1.179 +  if (!gnomeLib) {
   1.180 +    PR_UnloadLibrary(gnomeuiLib);
   1.181 +    return NS_OK;
   1.182 +  }
   1.183 +
   1.184 +  _gnome_program_init_fn gnome_program_init =
   1.185 +    (_gnome_program_init_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_init");
   1.186 +  _gnome_program_get_fn gnome_program_get =
   1.187 +    (_gnome_program_get_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_get"); 
   1.188 + _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)PR_FindFunctionSymbol(gnomeuiLib, "libgnomeui_module_info_get");
   1.189 +  if (!gnome_program_init || !gnome_program_get || !libgnomeui_module_info_get) {
   1.190 +    PR_UnloadLibrary(gnomeuiLib);
   1.191 +    PR_UnloadLibrary(gnomeLib);
   1.192 +    return NS_OK;
   1.193 +  }
   1.194 +
   1.195 +#endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
   1.196 +
   1.197 +#ifdef ACCESSIBILITY
   1.198 +  // We will load gail, atk-bridge by ourself later
   1.199 +  // We can't run atk-bridge init here, because gail get the control
   1.200 +  // Set GNOME_ACCESSIBILITY to 0 can avoid this
   1.201 +  static const char *accEnv = "GNOME_ACCESSIBILITY";
   1.202 +  const char *accOldValue = getenv(accEnv);
   1.203 +  setenv(accEnv, "0", 1);
   1.204 +#endif
   1.205 +
   1.206 +#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
   1.207 +  if (!gnome_program_get()) {
   1.208 +    gnome_program_init("Gecko", "1.0", libgnomeui_module_info_get(),
   1.209 +                       gArgc, gArgv, nullptr);
   1.210 +  }
   1.211 +#endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
   1.212 +
   1.213 +#ifdef ACCESSIBILITY
   1.214 +  if (accOldValue) { 
   1.215 +    setenv(accEnv, accOldValue, 1);
   1.216 +  } else {
   1.217 +    unsetenv(accEnv);
   1.218 +  }
   1.219 +#endif
   1.220 +
   1.221 +  // Careful! These libraries cannot be unloaded after this point because
   1.222 +  // gnome_program_init causes atexit handlers to be registered. Strange
   1.223 +  // crashes will occur if these libraries are unloaded.
   1.224 +
   1.225 +  // TODO GTK3 - see Bug 694570 - Stop using libgnome and libgnomeui on Linux
   1.226 +#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
   1.227 +  gnome_client_set_restart_command = (_gnome_client_set_restart_command_fn)
   1.228 +    PR_FindFunctionSymbol(gnomeuiLib, "gnome_client_set_restart_command");
   1.229 +
   1.230 +  _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
   1.231 +    PR_FindFunctionSymbol(gnomeuiLib, "gnome_master_client");
   1.232 +
   1.233 +  GnomeClient *client = gnome_master_client();
   1.234 +  g_signal_connect(client, "save-yourself", G_CALLBACK(save_yourself_cb), nullptr);
   1.235 +  g_signal_connect(client, "die", G_CALLBACK(die_cb), nullptr);
   1.236 +
   1.237 +  // Set the correct/requested restart command in any case.
   1.238 +
   1.239 +  // Is there a request to suppress default binary launcher?
   1.240 +  nsAutoCString path;
   1.241 +  char* argv1 = getenv("MOZ_APP_LAUNCHER");
   1.242 +
   1.243 +  if(!argv1) {
   1.244 +    // Tell the desktop the command for restarting us so that we can be part of XSMP session restore
   1.245 +    NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
   1.246 +    nsCOMPtr<nsIFile> executablePath;
   1.247 +    nsresult rv;
   1.248 +
   1.249 +    bool dummy;
   1.250 +    rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath));
   1.251 +
   1.252 +    if (NS_SUCCEEDED(rv)) {
   1.253 +      // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does
   1.254 +      nsAutoCString leafName;
   1.255 +      rv = executablePath->GetNativeLeafName(leafName);
   1.256 +      if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) {
   1.257 +        leafName.SetLength(leafName.Length() - strlen("-bin"));
   1.258 +        executablePath->SetNativeLeafName(leafName);
   1.259 +      }
   1.260 +
   1.261 +      executablePath->GetNativePath(path);
   1.262 +      argv1 = (char*)(path.get());
   1.263 +    }
   1.264 +  }
   1.265 +
   1.266 +  if (argv1) {
   1.267 +    gnome_client_set_restart_command(client, 1, &argv1);
   1.268 +  }
   1.269 +#endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
   1.270 +
   1.271 +  return NS_OK;
   1.272 +}
   1.273 +
   1.274 +NS_IMETHODIMP
   1.275 +nsNativeAppSupportUnix::Stop(bool *aResult)
   1.276 +{
   1.277 +  NS_ENSURE_ARG(aResult);
   1.278 +  *aResult = true;
   1.279 +  return NS_OK;
   1.280 +}
   1.281 +
   1.282 +NS_IMETHODIMP
   1.283 +nsNativeAppSupportUnix::Enable()
   1.284 +{
   1.285 +  return NS_OK;
   1.286 +}
   1.287 +
   1.288 +nsresult
   1.289 +NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
   1.290 +{
   1.291 +  nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
   1.292 +  if (!native)
   1.293 +    return NS_ERROR_OUT_OF_MEMORY;
   1.294 +
   1.295 +  *aResult = native;
   1.296 +  NS_ADDREF(*aResult);
   1.297 +
   1.298 +  return NS_OK;
   1.299 +}

mercurial