toolkit/xre/nsNativeAppSupportUnix.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:c7d027b63f8b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsNativeAppSupportBase.h"
7 #include "nsCOMPtr.h"
8 #include "nsXPCOM.h"
9 #include "nsISupportsPrimitives.h"
10 #include "nsIObserverService.h"
11 #include "nsIAppStartup.h"
12 #include "nsServiceManagerUtils.h"
13 #include "prlink.h"
14 #include "nsXREDirProvider.h"
15 #include "nsReadableUtils.h"
16
17 #include "nsIFile.h"
18 #include "nsDirectoryServiceDefs.h"
19 #include "nsICommandLineRunner.h"
20 #include "nsIWindowMediator.h"
21 #include "nsPIDOMWindow.h"
22 #include "nsIDocShell.h"
23 #include "nsIBaseWindow.h"
24 #include "nsIWidget.h"
25 #include "nsIWritablePropertyBag2.h"
26 #include "nsIPrefService.h"
27 #include "mozilla/Services.h"
28
29 #include <stdlib.h>
30 #include <glib.h>
31 #include <glib-object.h>
32 #include <gtk/gtk.h>
33
34 #ifdef MOZ_X11
35 #include <gdk/gdkx.h>
36 #include <X11/Xatom.h>
37 #endif
38
39 #ifdef MOZ_ENABLE_DBUS
40 #include <dbus/dbus.h>
41 #endif
42
43 #define MIN_GTK_MAJOR_VERSION 2
44 #define MIN_GTK_MINOR_VERSION 10
45 #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\
46 You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
47 Please upgrade your GTK+ library if you wish to use this application."
48
49 typedef struct _GnomeProgram GnomeProgram;
50 typedef struct _GnomeModuleInfo GnomeModuleInfo;
51 typedef struct _GnomeClient GnomeClient;
52
53 typedef enum {
54 GNOME_SAVE_GLOBAL,
55 GNOME_SAVE_LOCAL,
56 GNOME_SAVE_BOTH
57 } GnomeSaveStyle;
58
59 typedef enum {
60 GNOME_INTERACT_NONE,
61 GNOME_INTERACT_ERRORS,
62 GNOME_INTERACT_ANY
63 } GnomeInteractStyle;
64
65 typedef enum {
66 GNOME_DIALOG_ERROR,
67 GNOME_DIALOG_NORMAL
68 } GnomeDialogType;
69
70 typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
71 const GnomeModuleInfo *, int,
72 char **, const char *, ...);
73 typedef GnomeProgram * (*_gnome_program_get_fn)(void);
74 typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
75 typedef GnomeClient * (*_gnome_master_client_fn)(void);
76 typedef void (*_gnome_client_set_restart_command_fn)(GnomeClient*, gint, gchar*[]);
77
78 static _gnome_client_set_restart_command_fn gnome_client_set_restart_command;
79
80 gboolean save_yourself_cb(GnomeClient *client, gint phase,
81 GnomeSaveStyle style, gboolean shutdown,
82 GnomeInteractStyle interact, gboolean fast,
83 gpointer user_data)
84 {
85 nsCOMPtr<nsIObserverService> obsServ =
86 mozilla::services::GetObserverService();
87
88 nsCOMPtr<nsISupportsPRBool> didSaveSession =
89 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
90
91 if (!obsServ || !didSaveSession)
92 return TRUE; // OOM
93
94 // Notify observers to save the session state
95 didSaveSession->SetData(false);
96 obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
97
98 bool status;
99 didSaveSession->GetData(&status);
100
101 // If there was no session saved and the save_yourself request is
102 // caused by upcoming shutdown we like to prepare for it
103 if (!status && shutdown) {
104 nsCOMPtr<nsISupportsPRBool> cancelQuit =
105 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
106
107 cancelQuit->SetData(false);
108 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
109
110 bool abortQuit;
111 cancelQuit->GetData(&abortQuit);
112 }
113
114 return TRUE;
115 }
116
117 void die_cb(GnomeClient *client, gpointer user_data)
118 {
119 nsCOMPtr<nsIAppStartup> appService =
120 do_GetService("@mozilla.org/toolkit/app-startup;1");
121
122 if (appService)
123 appService->Quit(nsIAppStartup::eForceQuit);
124 }
125
126 class nsNativeAppSupportUnix : public nsNativeAppSupportBase
127 {
128 public:
129 NS_IMETHOD Start(bool* aRetVal);
130 NS_IMETHOD Stop(bool *aResult);
131 NS_IMETHOD Enable();
132
133 private:
134 };
135
136 NS_IMETHODIMP
137 nsNativeAppSupportUnix::Start(bool *aRetVal)
138 {
139 NS_ASSERTION(gAppData, "gAppData must not be null.");
140
141 // The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService,
142 // from diffrent threads. This could lead to race conditions if the dbus is not
143 // initialized before making any other library calls.
144 #ifdef MOZ_ENABLE_DBUS
145 dbus_threads_init_default();
146 #endif
147
148 #if (MOZ_WIDGET_GTK == 2)
149 if (gtk_major_version < MIN_GTK_MAJOR_VERSION ||
150 (gtk_major_version == MIN_GTK_MAJOR_VERSION && gtk_minor_version < MIN_GTK_MINOR_VERSION)) {
151 GtkWidget* versionErrDialog = gtk_message_dialog_new(nullptr,
152 GtkDialogFlags(GTK_DIALOG_MODAL |
153 GTK_DIALOG_DESTROY_WITH_PARENT),
154 GTK_MESSAGE_ERROR,
155 GTK_BUTTONS_OK,
156 UNSUPPORTED_GTK_MSG,
157 gtk_major_version,
158 gtk_minor_version,
159 MIN_GTK_MAJOR_VERSION,
160 MIN_GTK_MINOR_VERSION);
161 gtk_dialog_run(GTK_DIALOG(versionErrDialog));
162 gtk_widget_destroy(versionErrDialog);
163 exit(0);
164 }
165 #endif
166
167 *aRetVal = true;
168
169 #if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
170
171 PRLibrary *gnomeuiLib = PR_LoadLibrary("libgnomeui-2.so.0");
172 if (!gnomeuiLib)
173 return NS_OK;
174
175 PRLibrary *gnomeLib = PR_LoadLibrary("libgnome-2.so.0");
176 if (!gnomeLib) {
177 PR_UnloadLibrary(gnomeuiLib);
178 return NS_OK;
179 }
180
181 _gnome_program_init_fn gnome_program_init =
182 (_gnome_program_init_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_init");
183 _gnome_program_get_fn gnome_program_get =
184 (_gnome_program_get_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_get");
185 _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)PR_FindFunctionSymbol(gnomeuiLib, "libgnomeui_module_info_get");
186 if (!gnome_program_init || !gnome_program_get || !libgnomeui_module_info_get) {
187 PR_UnloadLibrary(gnomeuiLib);
188 PR_UnloadLibrary(gnomeLib);
189 return NS_OK;
190 }
191
192 #endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
193
194 #ifdef ACCESSIBILITY
195 // We will load gail, atk-bridge by ourself later
196 // We can't run atk-bridge init here, because gail get the control
197 // Set GNOME_ACCESSIBILITY to 0 can avoid this
198 static const char *accEnv = "GNOME_ACCESSIBILITY";
199 const char *accOldValue = getenv(accEnv);
200 setenv(accEnv, "0", 1);
201 #endif
202
203 #if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
204 if (!gnome_program_get()) {
205 gnome_program_init("Gecko", "1.0", libgnomeui_module_info_get(),
206 gArgc, gArgv, nullptr);
207 }
208 #endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
209
210 #ifdef ACCESSIBILITY
211 if (accOldValue) {
212 setenv(accEnv, accOldValue, 1);
213 } else {
214 unsetenv(accEnv);
215 }
216 #endif
217
218 // Careful! These libraries cannot be unloaded after this point because
219 // gnome_program_init causes atexit handlers to be registered. Strange
220 // crashes will occur if these libraries are unloaded.
221
222 // TODO GTK3 - see Bug 694570 - Stop using libgnome and libgnomeui on Linux
223 #if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
224 gnome_client_set_restart_command = (_gnome_client_set_restart_command_fn)
225 PR_FindFunctionSymbol(gnomeuiLib, "gnome_client_set_restart_command");
226
227 _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
228 PR_FindFunctionSymbol(gnomeuiLib, "gnome_master_client");
229
230 GnomeClient *client = gnome_master_client();
231 g_signal_connect(client, "save-yourself", G_CALLBACK(save_yourself_cb), nullptr);
232 g_signal_connect(client, "die", G_CALLBACK(die_cb), nullptr);
233
234 // Set the correct/requested restart command in any case.
235
236 // Is there a request to suppress default binary launcher?
237 nsAutoCString path;
238 char* argv1 = getenv("MOZ_APP_LAUNCHER");
239
240 if(!argv1) {
241 // Tell the desktop the command for restarting us so that we can be part of XSMP session restore
242 NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
243 nsCOMPtr<nsIFile> executablePath;
244 nsresult rv;
245
246 bool dummy;
247 rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath));
248
249 if (NS_SUCCEEDED(rv)) {
250 // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does
251 nsAutoCString leafName;
252 rv = executablePath->GetNativeLeafName(leafName);
253 if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) {
254 leafName.SetLength(leafName.Length() - strlen("-bin"));
255 executablePath->SetNativeLeafName(leafName);
256 }
257
258 executablePath->GetNativePath(path);
259 argv1 = (char*)(path.get());
260 }
261 }
262
263 if (argv1) {
264 gnome_client_set_restart_command(client, 1, &argv1);
265 }
266 #endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
267
268 return NS_OK;
269 }
270
271 NS_IMETHODIMP
272 nsNativeAppSupportUnix::Stop(bool *aResult)
273 {
274 NS_ENSURE_ARG(aResult);
275 *aResult = true;
276 return NS_OK;
277 }
278
279 NS_IMETHODIMP
280 nsNativeAppSupportUnix::Enable()
281 {
282 return NS_OK;
283 }
284
285 nsresult
286 NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
287 {
288 nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
289 if (!native)
290 return NS_ERROR_OUT_OF_MEMORY;
291
292 *aResult = native;
293 NS_ADDREF(*aResult);
294
295 return NS_OK;
296 }

mercurial