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 +}