Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / toolkit / xre / nsNativeAppSupportUnix.cpp
blob8b43492efec80cf3cd2f2cd6735fcdacb5cb84c6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Unix Native App Support.
17 * The Initial Developer of the Original Code is
18 * Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Michael Wu <flamingice@sourmilk.net> (original author)
24 * Michael Ventnor <m.ventnor@gmail.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsNativeAppSupportBase.h"
41 #include "nsCOMPtr.h"
42 #include "nsXPCOM.h"
43 #include "nsISupportsPrimitives.h"
44 #include "nsIObserverService.h"
45 #include "nsIAppStartup.h"
46 #include "nsServiceManagerUtils.h"
47 #include "prlink.h"
48 #include "nsXREDirProvider.h"
49 #include "nsReadableUtils.h"
51 #include <stdlib.h>
52 #include <glib.h>
53 #include <glib-object.h>
54 #include <gtk/gtk.h>
56 #ifdef NS_OSSO
57 struct DBusMessage; /* libosso.h references internals of dbus */
59 #include <dbus/dbus.h>
60 #include <dbus/dbus-protocol.h>
61 #include <libosso.h>
63 #endif
65 #define MIN_GTK_MAJOR_VERSION 2
66 #define MIN_GTK_MINOR_VERSION 10
67 #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\
68 You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
69 Please upgrade your GTK+ library if you wish to use this application."
71 typedef struct _GnomeProgram GnomeProgram;
72 typedef struct _GnomeModuleInfo GnomeModuleInfo;
73 typedef struct _GnomeClient GnomeClient;
75 typedef enum {
76 GNOME_SAVE_GLOBAL,
77 GNOME_SAVE_LOCAL,
78 GNOME_SAVE_BOTH
79 } GnomeSaveStyle;
81 typedef enum {
82 GNOME_INTERACT_NONE,
83 GNOME_INTERACT_ERRORS,
84 GNOME_INTERACT_ANY
85 } GnomeInteractStyle;
87 typedef enum {
88 GNOME_DIALOG_ERROR,
89 GNOME_DIALOG_NORMAL
90 } GnomeDialogType;
92 typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
93 const GnomeModuleInfo *, int,
94 char **, const char *, ...);
95 typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
96 typedef GnomeClient * (*_gnome_master_client_fn)(void);
97 typedef void (*GnomeInteractFunction)(GnomeClient *, gint, GnomeDialogType,
98 gpointer);
99 typedef void (*_gnome_client_request_interaction_fn)(GnomeClient *,
100 GnomeDialogType,
101 GnomeInteractFunction,
102 gpointer);
103 typedef void (*_gnome_interaction_key_return_fn)(gint, gboolean);
104 typedef void (*_gnome_client_set_restart_command_fn)(GnomeClient*, gint, gchar*[]);
106 static _gnome_client_request_interaction_fn gnome_client_request_interaction;
107 static _gnome_interaction_key_return_fn gnome_interaction_key_return;
108 static _gnome_client_set_restart_command_fn gnome_client_set_restart_command;
110 void interact_cb(GnomeClient *client, gint key,
111 GnomeDialogType type, gpointer data)
113 nsCOMPtr<nsIObserverService> obsServ =
114 do_GetService("@mozilla.org/observer-service;1");
115 nsCOMPtr<nsISupportsPRBool> cancelQuit =
116 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
118 cancelQuit->SetData(PR_FALSE);
120 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
122 PRBool abortQuit;
123 cancelQuit->GetData(&abortQuit);
125 gnome_interaction_key_return(key, abortQuit);
128 gboolean save_yourself_cb(GnomeClient *client, gint phase,
129 GnomeSaveStyle style, gboolean shutdown,
130 GnomeInteractStyle interact, gboolean fast,
131 gpointer user_data)
133 if (!shutdown)
134 return TRUE;
136 nsCOMPtr<nsIObserverService> obsServ =
137 do_GetService("@mozilla.org/observer-service;1");
139 nsCOMPtr<nsISupportsPRBool> didSaveSession =
140 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
142 if (!obsServ || !didSaveSession)
143 return TRUE; // OOM
145 didSaveSession->SetData(PR_FALSE);
146 obsServ->NotifyObservers(didSaveSession, "session-save", nsnull);
148 PRBool status;
149 didSaveSession->GetData(&status);
151 // Didn't save, or no way of saving. So signal for quit-application.
152 if (!status) {
153 if (interact == GNOME_INTERACT_ANY)
154 gnome_client_request_interaction(client, GNOME_DIALOG_NORMAL,
155 interact_cb, nsnull);
156 return TRUE;
159 // Tell GNOME the command for restarting us so that we can be part of XSMP session restore
160 NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
161 nsCOMPtr<nsIFile> executablePath;
162 nsresult rv;
164 PRBool dummy;
165 rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath));
167 if (NS_SUCCEEDED(rv)) {
168 nsCAutoString path;
169 char* argv[1];
171 // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does
172 nsCAutoString leafName;
173 rv = executablePath->GetNativeLeafName(leafName);
174 if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) {
175 leafName.SetLength(leafName.Length() - strlen("-bin"));
176 executablePath->SetNativeLeafName(leafName);
179 executablePath->GetNativePath(path);
180 argv[0] = (char*)(path.get());
182 gnome_client_set_restart_command(client, 1, argv);
185 return TRUE;
188 void die_cb(GnomeClient *client, gpointer user_data)
190 nsCOMPtr<nsIAppStartup> appService =
191 do_GetService("@mozilla.org/toolkit/app-startup;1");
193 if (appService)
194 appService->Quit(nsIAppStartup::eForceQuit);
197 class nsNativeAppSupportUnix : public nsNativeAppSupportBase
199 public:
200 NS_IMETHOD Start(PRBool* aRetVal);
201 NS_IMETHOD Stop( PRBool *aResult);
203 private:
204 #ifdef NS_OSSO
205 osso_context_t *m_osso_context;
206 /* A note about why we need to have m_hw_state:
207 the osso hardware callback does not tell us what changed, just
208 that something has changed. We need to keep track of state so
209 that we can determine what has changed.
211 osso_hw_state_t m_hw_state;
212 #endif
215 #ifdef NS_OSSO
216 static void OssoHardwareCallback(osso_hw_state_t *state, gpointer data)
218 NS_ASSERTION(state, "osso_hw_state_t must not be null.");
219 NS_ASSERTION(data, "data must not be null.");
221 osso_hw_state_t* ourState = (osso_hw_state_t*) data;
223 if (state->shutdown_ind) {
224 nsCOMPtr<nsIAppStartup> appService = do_GetService("@mozilla.org/toolkit/app-startup;1");
225 if (appService)
226 appService->Quit(nsIAppStartup::eForceQuit);
227 return;
230 if (state->memory_low_ind) {
231 if (! ourState->memory_low_ind) {
232 nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
233 if (os)
234 os->NotifyObservers(nsnull, "memory-pressure", NS_LITERAL_STRING("low-memory").get());
238 if (state->system_inactivity_ind != ourState->system_inactivity_ind) {
239 nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
240 if (!os)
241 return;
243 if (state->system_inactivity_ind)
244 os->NotifyObservers(nsnull, "system-idle", nsnull);
245 else
246 os->NotifyObservers(nsnull, "system-active", nsnull);
249 memcpy(ourState, state, sizeof(osso_hw_state_t));
252 #endif
254 NS_IMETHODIMP
255 nsNativeAppSupportUnix::Start(PRBool *aRetVal)
257 NS_ASSERTION(gAppData, "gAppData must not be null.");
259 if (gtk_major_version < MIN_GTK_MAJOR_VERSION ||
260 (gtk_major_version == MIN_GTK_MAJOR_VERSION && gtk_minor_version < MIN_GTK_MINOR_VERSION)) {
261 GtkWidget* versionErrDialog = gtk_message_dialog_new(NULL,
262 GtkDialogFlags(GTK_DIALOG_MODAL |
263 GTK_DIALOG_DESTROY_WITH_PARENT),
264 GTK_MESSAGE_ERROR,
265 GTK_BUTTONS_OK,
266 UNSUPPORTED_GTK_MSG,
267 gtk_major_version,
268 gtk_minor_version,
269 MIN_GTK_MAJOR_VERSION,
270 MIN_GTK_MINOR_VERSION);
271 gtk_dialog_run(GTK_DIALOG(versionErrDialog));
272 gtk_widget_destroy(versionErrDialog);
273 exit(0);
276 #ifdef NS_OSSO
277 /* zero state out. */
278 memset(&m_hw_state, 0, sizeof(osso_hw_state_t));
280 /* Initialize maemo application
282 The initalization name will be of the form "Vendor.Name".
283 If a Vendor isn't given, then we will just use "Name".
285 Note that this value must match your X-Osso-Service name
286 defined in your desktop file. If it doesn't, the OSSO
287 system will happily kill your process.
289 nsCAutoString applicationName;
290 if(gAppData->vendor) {
291 applicationName.Append(gAppData->vendor);
292 applicationName.Append(".");
294 applicationName.Append(gAppData->name);
296 m_osso_context = osso_initialize(applicationName.get(),
297 gAppData->version ? gAppData->version : "1.0",
298 PR_TRUE,
299 nsnull);
301 /* Check that initilialization was ok */
302 if (m_osso_context == nsnull) {
303 return NS_ERROR_FAILURE;
306 osso_hw_set_event_cb(m_osso_context,
307 nsnull,
308 OssoHardwareCallback,
309 &m_hw_state);
311 #endif
313 *aRetVal = PR_TRUE;
315 #ifdef MOZ_X11
317 PRLibrary *gnomeuiLib = PR_LoadLibrary("libgnomeui-2.so.0");
318 if (!gnomeuiLib)
319 return NS_OK;
321 PRLibrary *gnomeLib = PR_LoadLibrary("libgnome-2.so.0");
322 if (!gnomeLib) {
323 PR_UnloadLibrary(gnomeuiLib);
324 return NS_OK;
327 _gnome_program_init_fn gnome_program_init =
328 (_gnome_program_init_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_init");
329 _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)PR_FindFunctionSymbol(gnomeuiLib, "libgnomeui_module_info_get");
330 if (!gnome_program_init || !libgnomeui_module_info_get) {
331 PR_UnloadLibrary(gnomeuiLib);
332 PR_UnloadLibrary(gnomeLib);
333 return NS_OK;
336 #endif /* MOZ_X11 */
338 #ifdef ACCESSIBILITY
339 // We will load gail, atk-bridge by ourself later
340 // We can't run atk-bridge init here, because gail get the control
341 // Set GNOME_ACCESSIBILITY to 0 can avoid this
342 static const char *accEnv = "GNOME_ACCESSIBILITY";
343 const char *accOldValue = getenv(accEnv);
344 setenv(accEnv, "0", 1);
345 #endif
347 #ifdef MOZ_X11
348 gnome_program_init("Gecko", "1.0", libgnomeui_module_info_get(), gArgc, gArgv, NULL);
349 #endif /* MOZ_X11 */
351 #ifdef ACCESSIBILITY
352 if (accOldValue) {
353 setenv(accEnv, accOldValue, 1);
354 } else {
355 unsetenv(accEnv);
357 #endif
359 // Careful! These libraries cannot be unloaded after this point because
360 // gnome_program_init causes atexit handlers to be registered. Strange
361 // crashes will occur if these libraries are unloaded.
363 #ifdef MOZ_X11
364 gnome_client_request_interaction = (_gnome_client_request_interaction_fn)
365 PR_FindFunctionSymbol(gnomeuiLib, "gnome_client_request_interaction");
366 gnome_interaction_key_return = (_gnome_interaction_key_return_fn)
367 PR_FindFunctionSymbol(gnomeuiLib, "gnome_interaction_key_return");
368 gnome_client_set_restart_command = (_gnome_client_set_restart_command_fn)
369 PR_FindFunctionSymbol(gnomeuiLib, "gnome_client_set_restart_command");
371 _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
372 PR_FindFunctionSymbol(gnomeuiLib, "gnome_master_client");
374 GnomeClient *client = gnome_master_client();
375 g_signal_connect(client, "save-yourself", G_CALLBACK(save_yourself_cb), NULL);
376 g_signal_connect(client, "die", G_CALLBACK(die_cb), NULL);
377 #endif /* MOZ_X11 */
379 return NS_OK;
382 NS_IMETHODIMP
383 nsNativeAppSupportUnix::Stop( PRBool *aResult )
385 NS_ENSURE_ARG( aResult );
386 *aResult = PR_TRUE;
388 #ifdef NS_OSSO
389 if (m_osso_context)
391 osso_hw_unset_event_cb(m_osso_context, nsnull);
392 osso_deinitialize(m_osso_context);
393 m_osso_context = nsnull;
395 #endif
396 return NS_OK;
399 nsresult
400 NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
402 nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
403 if (!native)
404 return NS_ERROR_OUT_OF_MEMORY;
406 *aResult = native;
407 NS_ADDREF(*aResult);
409 return NS_OK;