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
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.
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"
43 #include "nsISupportsPrimitives.h"
44 #include "nsIObserverService.h"
45 #include "nsIAppStartup.h"
46 #include "nsServiceManagerUtils.h"
48 #include "nsXREDirProvider.h"
49 #include "nsReadableUtils.h"
53 #include <glib-object.h>
57 struct DBusMessage
; /* libosso.h references internals of dbus */
59 #include <dbus/dbus.h>
60 #include <dbus/dbus-protocol.h>
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
;
83 GNOME_INTERACT_ERRORS
,
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
,
99 typedef void (*_gnome_client_request_interaction_fn
)(GnomeClient
*,
101 GnomeInteractFunction
,
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
);
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
,
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
)
145 didSaveSession
->SetData(PR_FALSE
);
146 obsServ
->NotifyObservers(didSaveSession
, "session-save", nsnull
);
149 didSaveSession
->GetData(&status
);
151 // Didn't save, or no way of saving. So signal for quit-application.
153 if (interact
== GNOME_INTERACT_ANY
)
154 gnome_client_request_interaction(client
, GNOME_DIALOG_NORMAL
,
155 interact_cb
, nsnull
);
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
;
165 rv
= gDirServiceProvider
->GetFile(XRE_EXECUTABLE_FILE
, &dummy
, getter_AddRefs(executablePath
));
167 if (NS_SUCCEEDED(rv
)) {
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
);
188 void die_cb(GnomeClient
*client
, gpointer user_data
)
190 nsCOMPtr
<nsIAppStartup
> appService
=
191 do_GetService("@mozilla.org/toolkit/app-startup;1");
194 appService
->Quit(nsIAppStartup::eForceQuit
);
197 class nsNativeAppSupportUnix
: public nsNativeAppSupportBase
200 NS_IMETHOD
Start(PRBool
* aRetVal
);
201 NS_IMETHOD
Stop( PRBool
*aResult
);
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
;
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");
226 appService
->Quit(nsIAppStartup::eForceQuit
);
230 if (state
->memory_low_ind
) {
231 if (! ourState
->memory_low_ind
) {
232 nsCOMPtr
<nsIObserverService
> os
= do_GetService("@mozilla.org/observer-service;1");
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");
243 if (state
->system_inactivity_ind
)
244 os
->NotifyObservers(nsnull
, "system-idle", nsnull
);
246 os
->NotifyObservers(nsnull
, "system-active", nsnull
);
249 memcpy(ourState
, state
, sizeof(osso_hw_state_t
));
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
),
269 MIN_GTK_MAJOR_VERSION
,
270 MIN_GTK_MINOR_VERSION
);
271 gtk_dialog_run(GTK_DIALOG(versionErrDialog
));
272 gtk_widget_destroy(versionErrDialog
);
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",
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
,
308 OssoHardwareCallback
,
317 PRLibrary
*gnomeuiLib
= PR_LoadLibrary("libgnomeui-2.so.0");
321 PRLibrary
*gnomeLib
= PR_LoadLibrary("libgnome-2.so.0");
323 PR_UnloadLibrary(gnomeuiLib
);
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
);
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);
348 gnome_program_init("Gecko", "1.0", libgnomeui_module_info_get(), gArgc
, gArgv
, NULL
);
353 setenv(accEnv
, accOldValue
, 1);
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.
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
);
383 nsNativeAppSupportUnix::Stop( PRBool
*aResult
)
385 NS_ENSURE_ARG( aResult
);
391 osso_hw_unset_event_cb(m_osso_context
, nsnull
);
392 osso_deinitialize(m_osso_context
);
393 m_osso_context
= nsnull
;
400 NS_CreateNativeAppSupport(nsINativeAppSupport
**aResult
)
402 nsNativeAppSupportBase
* native
= new nsNativeAppSupportUnix();
404 return NS_ERROR_OUT_OF_MEMORY
;