123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsNativeAppSupportBase.h"
- #include "nsCOMPtr.h"
- #include "nsXPCOM.h"
- #include "nsISupportsPrimitives.h"
- #include "nsIObserverService.h"
- #include "nsIAppStartup.h"
- #include "nsServiceManagerUtils.h"
- #include "prlink.h"
- #include "nsXREDirProvider.h"
- #include "nsReadableUtils.h"
- #include "nsIFile.h"
- #include "nsDirectoryServiceDefs.h"
- #include "nsICommandLineRunner.h"
- #include "nsIWindowMediator.h"
- #include "nsPIDOMWindow.h"
- #include "nsIDocShell.h"
- #include "nsIBaseWindow.h"
- #include "nsIWidget.h"
- #include "nsIWritablePropertyBag2.h"
- #include "nsIPrefService.h"
- #include "mozilla/Services.h"
- #include <stdlib.h>
- #include <glib.h>
- #include <glib-object.h>
- #include <gtk/gtk.h>
- #ifdef MOZ_X11
- #include <gdk/gdkx.h>
- #include <X11/ICE/ICElib.h>
- #include <X11/SM/SMlib.h>
- #include <fcntl.h>
- #include "nsThreadUtils.h"
- #include <pwd.h>
- #endif
- #ifdef MOZ_ENABLE_DBUS
- #include <dbus/dbus.h>
- #endif
- #define MIN_GTK_MAJOR_VERSION 2
- #define MIN_GTK_MINOR_VERSION 10
- #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\
- You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
- Please upgrade your GTK+ library if you wish to use this application."
- #if MOZ_X11
- #undef IceSetIOErrorHandler
- #undef IceAddConnectionWatch
- #undef IceConnectionNumber
- #undef IceProcessMessages
- #undef IceGetConnectionContext
- #undef SmcInteractDone
- #undef SmcSaveYourselfDone
- #undef SmcInteractRequest
- #undef SmcCloseConnection
- #undef SmcOpenConnection
- #undef SmcSetProperties
- typedef IceIOErrorHandler (*IceSetIOErrorHandlerFn) (IceIOErrorHandler);
- typedef int (*IceAddConnectionWatchFn) (IceWatchProc, IcePointer);
- typedef int (*IceConnectionNumberFn) (IceConn);
- typedef IceProcessMessagesStatus (*IceProcessMessagesFn) (IceConn, IceReplyWaitInfo*, Bool*);
- typedef IcePointer (*IceGetConnectionContextFn) (IceConn);
- typedef void (*SmcInteractDoneFn) (SmcConn, Bool);
- typedef void (*SmcSaveYourselfDoneFn) (SmcConn, Bool);
- typedef int (*SmcInteractRequestFn) (SmcConn, int, SmcInteractProc, SmPointer);
- typedef SmcCloseStatus (*SmcCloseConnectionFn) (SmcConn, int, char**);
- typedef SmcConn (*SmcOpenConnectionFn) (char*, SmPointer, int, int,
- unsigned long, SmcCallbacks*,
- const char*, char**, int, char*);
- typedef void (*SmcSetPropertiesFn) (SmcConn, int, SmProp**);
- static IceSetIOErrorHandlerFn IceSetIOErrorHandlerPtr;
- static IceAddConnectionWatchFn IceAddConnectionWatchPtr;
- static IceConnectionNumberFn IceConnectionNumberPtr;
- static IceProcessMessagesFn IceProcessMessagesPtr;
- static IceGetConnectionContextFn IceGetConnectionContextPtr;
- static SmcInteractDoneFn SmcInteractDonePtr;
- static SmcSaveYourselfDoneFn SmcSaveYourselfDonePtr;
- static SmcInteractRequestFn SmcInteractRequestPtr;
- static SmcCloseConnectionFn SmcCloseConnectionPtr;
- static SmcOpenConnectionFn SmcOpenConnectionPtr;
- static SmcSetPropertiesFn SmcSetPropertiesPtr;
- #define IceSetIOErrorHandler IceSetIOErrorHandlerPtr
- #define IceAddConnectionWatch IceAddConnectionWatchPtr
- #define IceConnectionNumber IceConnectionNumberPtr
- #define IceProcessMessages IceProcessMessagesPtr
- #define IceGetConnectionContext IceGetConnectionContextPtr
- #define SmcInteractDone SmcInteractDonePtr
- #define SmcSaveYourselfDone SmcSaveYourselfDonePtr
- #define SmcInteractRequest SmcInteractRequestPtr
- #define SmcCloseConnection SmcCloseConnectionPtr
- #define SmcOpenConnection SmcOpenConnectionPtr
- #define SmcSetProperties SmcSetPropertiesPtr
- enum ClientState {
- STATE_DISCONNECTED,
- STATE_REGISTERING,
- STATE_IDLE,
- STATE_INTERACTING,
- STATE_SHUTDOWN_CANCELLED
- };
- static const char *gClientStateTable[] = {
- "DISCONNECTED",
- "REGISTERING",
- "IDLE",
- "INTERACTING",
- "SHUTDOWN_CANCELLED"
- };
- static LazyLogModule sMozSMLog("MozSM");
- #endif /* MOZ_X11 */
- class nsNativeAppSupportUnix : public nsNativeAppSupportBase
- {
- public:
- #if MOZ_X11
- nsNativeAppSupportUnix(): mSessionConnection(nullptr),
- mClientState(STATE_DISCONNECTED) {};
- ~nsNativeAppSupportUnix()
- {
- // this goes out of scope after "web-workers-shutdown" async shutdown phase
- // so it's safe to disconnect here (i.e. the application won't lose data)
- DisconnectFromSM();
- };
- void DisconnectFromSM();
- #endif
- NS_IMETHOD Start(bool* aRetVal);
- NS_IMETHOD Stop(bool *aResult);
- NS_IMETHOD Enable();
- private:
- #if MOZ_X11
- static void SaveYourselfCB(SmcConn smc_conn, SmPointer client_data,
- int save_style, Bool shutdown, int interact_style,
- Bool fast);
- static void DieCB(SmcConn smc_conn, SmPointer client_data);
- static void InteractCB(SmcConn smc_conn, SmPointer client_data);
- static void SaveCompleteCB(SmcConn smc_conn, SmPointer client_data) {};
- static void ShutdownCancelledCB(SmcConn smc_conn, SmPointer client_data);
- void DoInteract();
- void SetClientState(ClientState aState)
- {
- mClientState = aState;
- MOZ_LOG(sMozSMLog, LogLevel::Debug, ("New state = %s\n", gClientStateTable[aState]));
- }
- SmcConn mSessionConnection;
- ClientState mClientState;
- #endif
- };
- #if MOZ_X11
- static gboolean
- process_ice_messages(IceConn connection)
- {
- IceProcessMessagesStatus status;
- status = IceProcessMessages(connection, nullptr, nullptr);
- switch (status) {
- case IceProcessMessagesSuccess:
- return TRUE;
- case IceProcessMessagesIOError: {
- nsNativeAppSupportUnix *native =
- static_cast<nsNativeAppSupportUnix *>(IceGetConnectionContext(connection));
- native->DisconnectFromSM();
- }
- return FALSE;
- case IceProcessMessagesConnectionClosed:
- return FALSE;
- default:
- g_assert_not_reached ();
- }
- }
- static gboolean
- ice_iochannel_watch(GIOChannel *channel, GIOCondition condition,
- gpointer client_data)
- {
- return process_ice_messages(static_cast<IceConn>(client_data));
- }
- static void
- ice_connection_watch(IceConn connection, IcePointer client_data,
- Bool opening, IcePointer *watch_data)
- {
- guint watch_id;
- if (opening) {
- GIOChannel *channel;
- int fd = IceConnectionNumber(connection);
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
- channel = g_io_channel_unix_new(fd);
- watch_id = g_io_add_watch(channel,
- static_cast<GIOCondition>(G_IO_IN | G_IO_ERR),
- ice_iochannel_watch, connection);
- g_io_channel_unref(channel);
- *watch_data = GUINT_TO_POINTER(watch_id);
- } else {
- watch_id = GPOINTER_TO_UINT(*watch_data);
- g_source_remove(watch_id);
- }
- }
- static void
- ice_io_error_handler(IceConn connection)
- {
- // override the default handler which would exit the application;
- // do nothing and let ICELib handle the failure of the connection gracefully.
- }
- static void
- ice_init(void)
- {
- static bool initted = false;
- if (!initted) {
- IceSetIOErrorHandler(ice_io_error_handler);
- IceAddConnectionWatch(ice_connection_watch, nullptr);
- initted = true;
- }
- }
- void
- nsNativeAppSupportUnix::InteractCB(SmcConn smc_conn, SmPointer client_data)
- {
- nsNativeAppSupportUnix *self =
- static_cast<nsNativeAppSupportUnix *>(client_data);
- self->SetClientState(STATE_INTERACTING);
- // We do this asynchronously, as we spin the event loop recursively if
- // a dialog is displayed. If we do this synchronously, we don't finish
- // processing the current ICE event whilst the dialog is displayed, which
- // means we won't process any more. libsm hates us if we do the InteractDone
- // with a pending ShutdownCancelled, and we would certainly like to handle Die
- // whilst a dialog is displayed
- NS_DispatchToCurrentThread(NewRunnableMethod(self, &nsNativeAppSupportUnix::DoInteract));
- }
- void
- nsNativeAppSupportUnix::DoInteract()
- {
- nsCOMPtr<nsIObserverService> obsServ =
- mozilla::services::GetObserverService();
- if (!obsServ) {
- SmcInteractDone(mSessionConnection, False);
- SmcSaveYourselfDone(mSessionConnection, True);
- SetClientState(STATE_IDLE);
- return;
- }
- nsCOMPtr<nsISupportsPRBool> cancelQuit =
- do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
- bool abortQuit = false;
- if (cancelQuit) {
- cancelQuit->SetData(false);
- obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
- cancelQuit->GetData(&abortQuit);
- }
- if (!abortQuit && mClientState == STATE_DISCONNECTED) {
- // The session manager disappeared, whilst we were interacting, so
- // quit now
- nsCOMPtr<nsIAppStartup> appService =
- do_GetService("@mozilla.org/toolkit/app-startup;1");
- if (appService) {
- appService->Quit(nsIAppStartup::eForceQuit);
- }
- } else {
- if (mClientState != STATE_SHUTDOWN_CANCELLED) {
- // Only do this if the shutdown wasn't cancelled
- SmcInteractDone(mSessionConnection, !!abortQuit);
- SmcSaveYourselfDone(mSessionConnection, !abortQuit);
- }
- SetClientState(STATE_IDLE);
- }
- }
- void
- nsNativeAppSupportUnix::SaveYourselfCB(SmcConn smc_conn, SmPointer client_data,
- int save_style, Bool shutdown,
- int interact_style, Bool fast)
- {
- nsNativeAppSupportUnix *self =
- static_cast<nsNativeAppSupportUnix *>(client_data);
- // Expect a SaveYourselfCB if we're registering a new client.
- // All properties are already set in Start() so just reply with
- // SmcSaveYourselfDone if the callback matches the expected signature.
- //
- // Ancient versions (?) of xsm do not follow such an early SaveYourself with
- // SaveComplete. This is a problem if the application freezes interaction
- // while waiting for a response to SmcSaveYourselfDone. So never freeze
- // interaction when in STATE_REGISTERING.
- //
- // That aside, we could treat each combination of flags appropriately and not
- // special-case this.
- if (self->mClientState == STATE_REGISTERING) {
- self->SetClientState(STATE_IDLE);
- if (save_style == SmSaveLocal && interact_style == SmInteractStyleNone &&
- !shutdown && !fast) {
- SmcSaveYourselfDone(self->mSessionConnection, True);
- return;
- }
- }
- if (self->mClientState == STATE_SHUTDOWN_CANCELLED) {
- // The last shutdown request was cancelled whilst we were interacting,
- // and we haven't finished interacting yet. Switch the state back again
- self->SetClientState(STATE_INTERACTING);
- }
- nsCOMPtr<nsIObserverService> obsServ =
- mozilla::services::GetObserverService();
- if (!obsServ) {
- SmcSaveYourselfDone(smc_conn, True);
- return;
- }
- bool status = false;
- if (save_style != SmSaveGlobal) {
- nsCOMPtr<nsISupportsPRBool> didSaveSession =
- do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
- if (!didSaveSession) {
- SmcSaveYourselfDone(smc_conn, True);
- return;
- }
- // Notify observers to save the session state
- didSaveSession->SetData(false);
- obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
- didSaveSession->GetData(&status);
- }
- // If the interact style permits us to, we are shutting down and we didn't
- // manage to (or weren't asked to) save the local state, then notify the user
- // in advance that we are doing to quit (assuming that we aren't already
- // doing so)
- if (!status && shutdown && interact_style != SmInteractStyleNone) {
- if (self->mClientState != STATE_INTERACTING) {
- SmcInteractRequest(smc_conn, SmDialogNormal,
- nsNativeAppSupportUnix::InteractCB, client_data);
- }
- } else {
- SmcSaveYourselfDone(smc_conn, True);
- }
- }
- void
- nsNativeAppSupportUnix::DieCB(SmcConn smc_conn, SmPointer client_data)
- {
- nsCOMPtr<nsIAppStartup> appService =
- do_GetService("@mozilla.org/toolkit/app-startup;1");
- if (appService) {
- appService->Quit(nsIAppStartup::eForceQuit);
- }
- // Quit causes the shutdown to begin but the shutdown process is asynchronous
- // so we can't DisconnectFromSM() yet
- }
- void
- nsNativeAppSupportUnix::ShutdownCancelledCB(SmcConn smc_conn,
- SmPointer client_data)
- {
- nsNativeAppSupportUnix *self =
- static_cast<nsNativeAppSupportUnix *>(client_data);
- // Interacting is the only time when we wouldn't already have called
- // SmcSaveYourselfDone. Do that now, then set the state to make sure we
- // don't send it again after finishing interacting
- if (self->mClientState == STATE_INTERACTING) {
- SmcSaveYourselfDone(smc_conn, False);
- self->SetClientState(STATE_SHUTDOWN_CANCELLED);
- }
- }
- void
- nsNativeAppSupportUnix::DisconnectFromSM()
- {
- // the SM is free to exit any time after we disconnect, so callers must be
- // sure to have reached a sufficiently advanced phase of shutdown that there
- // is no risk of data loss:
- // e.g. all async writes are complete by the end of "profile-before-change"
- if (mSessionConnection) {
- SetClientState(STATE_DISCONNECTED);
- SmcCloseConnection(mSessionConnection, 0, nullptr);
- mSessionConnection = nullptr;
- gdk_x11_set_sm_client_id(nullptr); // follow gnome-client behaviour
- }
- }
- static void
- SetSMValue(SmPropValue& val, const nsCString& data)
- {
- val.value = static_cast<SmPointer>(const_cast<char*>(data.get()));
- val.length = data.Length();
- }
- static void
- SetSMProperty(SmProp& prop, const char* name, const char* type, int numVals,
- SmPropValue vals[])
- {
- prop.name = const_cast<char*>(name);
- prop.type = const_cast<char*>(type);
- prop.num_vals = numVals;
- prop.vals = vals;
- }
- #endif /* MOZ_X11 */
- static void RemoveArg(char **argv)
- {
- do {
- *argv = *(argv + 1);
- ++argv;
- } while (*argv);
- --gArgc;
- }
- NS_IMETHODIMP
- nsNativeAppSupportUnix::Start(bool *aRetVal)
- {
- NS_ASSERTION(gAppData, "gAppData must not be null.");
- // The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService,
- // from diffrent threads. This could lead to race conditions if the dbus is not
- // initialized before making any other library calls.
- #ifdef MOZ_ENABLE_DBUS
- dbus_threads_init_default();
- #endif
- #if (MOZ_WIDGET_GTK == 2)
- if (gtk_major_version < MIN_GTK_MAJOR_VERSION ||
- (gtk_major_version == MIN_GTK_MAJOR_VERSION && gtk_minor_version < MIN_GTK_MINOR_VERSION)) {
- GtkWidget* versionErrDialog = gtk_message_dialog_new(nullptr,
- GtkDialogFlags(GTK_DIALOG_MODAL |
- GTK_DIALOG_DESTROY_WITH_PARENT),
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- UNSUPPORTED_GTK_MSG,
- gtk_major_version,
- gtk_minor_version,
- MIN_GTK_MAJOR_VERSION,
- MIN_GTK_MINOR_VERSION);
- gtk_dialog_run(GTK_DIALOG(versionErrDialog));
- gtk_widget_destroy(versionErrDialog);
- MozExpectedExit();
- exit(0);
- }
- #endif
- *aRetVal = true;
- #ifdef MOZ_X11
- gboolean sm_disable = FALSE;
- if (!getenv("SESSION_MANAGER")) {
- sm_disable = TRUE;
- }
- nsAutoCString prev_client_id;
- char **curarg = gArgv + 1;
- while (*curarg) {
- char *arg = *curarg;
- if (arg[0] == '-' && arg[1] == '-') {
- arg += 2;
- if (!strcmp(arg, "sm-disable")) {
- RemoveArg(curarg);
- sm_disable = TRUE;
- continue;
- } else if (!strcmp(arg, "sm-client-id")) {
- RemoveArg(curarg);
- if (*curarg[0] != '-') {
- prev_client_id = *curarg;
- RemoveArg(curarg);
- }
- continue;
- }
- }
- ++curarg;
- }
- if (prev_client_id.IsEmpty()) {
- prev_client_id = getenv("DESKTOP_AUTOSTART_ID");
- }
- // We don't want child processes to use the same ID
- unsetenv("DESKTOP_AUTOSTART_ID");
- char *client_id = nullptr;
- if (!sm_disable) {
- PRLibrary *iceLib = PR_LoadLibrary("libICE.so.6");
- if (!iceLib) {
- return NS_OK;
- }
- PRLibrary *smLib = PR_LoadLibrary("libSM.so.6");
- if (!smLib) {
- PR_UnloadLibrary(iceLib);
- return NS_OK;
- }
- IceSetIOErrorHandler = (IceSetIOErrorHandlerFn)PR_FindFunctionSymbol(iceLib, "IceSetIOErrorHandler");
- IceAddConnectionWatch = (IceAddConnectionWatchFn)PR_FindFunctionSymbol(iceLib, "IceAddConnectionWatch");
- IceConnectionNumber = (IceConnectionNumberFn)PR_FindFunctionSymbol(iceLib, "IceConnectionNumber");
- IceProcessMessages = (IceProcessMessagesFn)PR_FindFunctionSymbol(iceLib, "IceProcessMessages");
- IceGetConnectionContext = (IceGetConnectionContextFn)PR_FindFunctionSymbol(iceLib, "IceGetConnectionContext");
- if (!IceSetIOErrorHandler || !IceAddConnectionWatch ||
- !IceConnectionNumber || !IceProcessMessages || !IceGetConnectionContext) {
- PR_UnloadLibrary(iceLib);
- PR_UnloadLibrary(smLib);
- return NS_OK;
- }
- SmcInteractDone = (SmcInteractDoneFn)PR_FindFunctionSymbol(smLib, "SmcInteractDone");
- SmcSaveYourselfDone = (SmcSaveYourselfDoneFn)PR_FindFunctionSymbol(smLib, "SmcSaveYourselfDone");
- SmcInteractRequest = (SmcInteractRequestFn)PR_FindFunctionSymbol(smLib, "SmcInteractRequest");
- SmcCloseConnection = (SmcCloseConnectionFn)PR_FindFunctionSymbol(smLib, "SmcCloseConnection");
- SmcOpenConnection = (SmcOpenConnectionFn)PR_FindFunctionSymbol(smLib, "SmcOpenConnection");
- SmcSetProperties = (SmcSetPropertiesFn)PR_FindFunctionSymbol(smLib, "SmcSetProperties");
- if (!SmcInteractDone || !SmcSaveYourselfDone || !SmcInteractRequest ||
- !SmcCloseConnection || !SmcOpenConnection || !SmcSetProperties) {
- PR_UnloadLibrary(iceLib);
- PR_UnloadLibrary(smLib);
- return NS_OK;
- }
- ice_init();
- // all callbacks are mandatory in libSM 1.0, so listen even if we don't care.
- unsigned long mask = SmcSaveYourselfProcMask | SmcDieProcMask |
- SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
- SmcCallbacks callbacks;
- callbacks.save_yourself.callback = nsNativeAppSupportUnix::SaveYourselfCB;
- callbacks.save_yourself.client_data = static_cast<SmPointer>(this);
- callbacks.die.callback = nsNativeAppSupportUnix::DieCB;
- callbacks.die.client_data = static_cast<SmPointer>(this);
- callbacks.save_complete.callback = nsNativeAppSupportUnix::SaveCompleteCB;
- callbacks.save_complete.client_data = nullptr;
- callbacks.shutdown_cancelled.callback =
- nsNativeAppSupportUnix::ShutdownCancelledCB;
- callbacks.shutdown_cancelled.client_data = static_cast<SmPointer>(this);
- char errbuf[256];
- mSessionConnection = SmcOpenConnection(nullptr, this, SmProtoMajor,
- SmProtoMinor, mask, &callbacks,
- prev_client_id.get(), &client_id,
- sizeof(errbuf), errbuf);
- }
- if (!mSessionConnection) {
- return NS_OK;
- }
- LogModule::Init(); // need to make sure initialized before SetClientState
- if (prev_client_id.IsEmpty() ||
- (client_id && !prev_client_id.Equals(client_id))) {
- SetClientState(STATE_REGISTERING);
- } else {
- SetClientState(STATE_IDLE);
- }
- gdk_x11_set_sm_client_id(client_id);
- // Set SM Properties
- // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required
- // properties so must be set, and must have a sensible fallback value.
- // Determine executable path to use for XSMP session restore
- // Is there a request to suppress default binary launcher?
- nsAutoCString path(getenv("MOZ_APP_LAUNCHER"));
- if (path.IsEmpty()) {
- NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
- nsCOMPtr<nsIFile> executablePath;
- nsresult rv;
- bool dummy;
- rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath));
- if (NS_SUCCEEDED(rv)) {
- // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does
- nsAutoCString leafName;
- rv = executablePath->GetNativeLeafName(leafName);
- if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) {
- leafName.SetLength(leafName.Length() - strlen("-bin"));
- executablePath->SetNativeLeafName(leafName);
- }
- executablePath->GetNativePath(path);
- }
- }
- if (path.IsEmpty()) {
- // can't determine executable path. Best fallback is name from
- // application.ini but it might not resolve to the same executable at
- // launch time.
- path = gAppData->name; // will always be set
- ToLowerCase(path);
- MOZ_LOG(sMozSMLog, LogLevel::Warning,
- ("Could not determine executable path. Falling back to %s.", path.get()));
- }
- SmProp propRestart, propClone, propProgram, propUser, *props[4];
- SmPropValue valsRestart[3], valsClone[1], valsProgram[1], valsUser[1];
- int n = 0;
- NS_NAMED_LITERAL_CSTRING(kClientIDParam, "--sm-client-id");
- SetSMValue(valsRestart[0], path);
- SetSMValue(valsRestart[1], kClientIDParam);
- SetSMValue(valsRestart[2], nsDependentCString(client_id));
- SetSMProperty(propRestart, SmRestartCommand, SmLISTofARRAY8, 3, valsRestart);
- props[n++] = &propRestart;
- SetSMValue(valsClone[0], path);
- SetSMProperty(propClone, SmCloneCommand, SmLISTofARRAY8, 1, valsClone);
- props[n++] = &propClone;
- nsAutoCString appName(gAppData->name); // will always be set
- ToLowerCase(appName);
- SetSMValue(valsProgram[0], appName);
- SetSMProperty(propProgram, SmProgram, SmARRAY8, 1, valsProgram);
- props[n++] = &propProgram;
- nsAutoCString userName; // username that started the program
- struct passwd* pw = getpwuid(getuid());
- if (pw && pw->pw_name) {
- userName = pw->pw_name;
- } else {
- userName = NS_LITERAL_CSTRING("nobody");
- MOZ_LOG(sMozSMLog, LogLevel::Warning,
- ("Could not determine user-name. Falling back to %s.", userName.get()));
- }
- SetSMValue(valsUser[0], userName);
- SetSMProperty(propUser, SmUserID, SmARRAY8, 1, valsUser);
- props[n++] = &propUser;
- SmcSetProperties(mSessionConnection, n, props);
- g_free(client_id);
- #endif /* MOZ_X11 */
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNativeAppSupportUnix::Stop(bool *aResult)
- {
- NS_ENSURE_ARG(aResult);
- *aResult = true;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNativeAppSupportUnix::Enable()
- {
- return NS_OK;
- }
- nsresult
- NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
- {
- nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
- if (!native)
- return NS_ERROR_OUT_OF_MEMORY;
- *aResult = native;
- NS_ADDREF(*aResult);
- return NS_OK;
- }
|