Bug 1839489 [wpt PR 40652] - Revert "Add the Sec-CH-UA-Form-Factor header", a=testonly
[gecko.git] / toolkit / xre / nsNativeAppSupportUnix.cpp
blobbed9e546db2d633b77f02a2f5293d796216ee5d7
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsNativeAppSupportBase.h"
8 #include "nsComponentManagerUtils.h"
9 #include "nsCOMPtr.h"
10 #include "nsXPCOM.h"
11 #include "nsISupportsPrimitives.h"
12 #include "nsIObserverService.h"
13 #include "nsIAppStartup.h"
14 #include "nsServiceManagerUtils.h"
15 #include "prlink.h"
16 #include "nsXREDirProvider.h"
17 #include "nsReadableUtils.h"
19 #include "nsIFile.h"
20 #include "nsDirectoryServiceDefs.h"
21 #include "nsPIDOMWindow.h"
22 #include "nsIWidget.h"
23 #include "mozilla/Logging.h"
24 #include "mozilla/Services.h"
25 #include "mozilla/XREAppData.h"
27 #include <stdlib.h>
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <gtk/gtk.h>
32 #ifdef MOZ_X11
33 # include <gdk/gdkx.h>
34 # include <X11/ICE/ICElib.h>
35 # include <X11/SM/SMlib.h>
36 # include <fcntl.h>
37 # include "nsThreadUtils.h"
39 # include <pwd.h>
40 #endif
42 #ifdef MOZ_ENABLE_DBUS
43 # include <dbus/dbus.h>
44 #endif
46 #define MIN_GTK_MAJOR_VERSION 2
47 #define MIN_GTK_MINOR_VERSION 10
48 #define UNSUPPORTED_GTK_MSG \
49 "We're sorry, this application requires a version of the GTK+ library that is not installed on your computer.\n\n\
50 You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
51 Please upgrade your GTK+ library if you wish to use this application."
53 #if MOZ_X11
54 # undef IceSetIOErrorHandler
55 # undef IceAddConnectionWatch
56 # undef IceConnectionNumber
57 # undef IceProcessMessages
58 # undef IceGetConnectionContext
59 # undef SmcInteractDone
60 # undef SmcSaveYourselfDone
61 # undef SmcInteractRequest
62 # undef SmcCloseConnection
63 # undef SmcOpenConnection
64 # undef SmcSetProperties
66 typedef IceIOErrorHandler (*IceSetIOErrorHandlerFn)(IceIOErrorHandler);
67 typedef int (*IceAddConnectionWatchFn)(IceWatchProc, IcePointer);
68 typedef int (*IceConnectionNumberFn)(IceConn);
69 typedef IceProcessMessagesStatus (*IceProcessMessagesFn)(IceConn,
70 IceReplyWaitInfo*,
71 Bool*);
72 typedef IcePointer (*IceGetConnectionContextFn)(IceConn);
74 typedef void (*SmcInteractDoneFn)(SmcConn, Bool);
75 typedef void (*SmcSaveYourselfDoneFn)(SmcConn, Bool);
76 typedef int (*SmcInteractRequestFn)(SmcConn, int, SmcInteractProc, SmPointer);
77 typedef SmcCloseStatus (*SmcCloseConnectionFn)(SmcConn, int, char**);
78 typedef SmcConn (*SmcOpenConnectionFn)(char*, SmPointer, int, int,
79 unsigned long, SmcCallbacks*,
80 const char*, char**, int, char*);
81 typedef void (*SmcSetPropertiesFn)(SmcConn, int, SmProp**);
83 static IceSetIOErrorHandlerFn IceSetIOErrorHandlerPtr;
84 static IceAddConnectionWatchFn IceAddConnectionWatchPtr;
85 static IceConnectionNumberFn IceConnectionNumberPtr;
86 static IceProcessMessagesFn IceProcessMessagesPtr;
87 static IceGetConnectionContextFn IceGetConnectionContextPtr;
88 static SmcInteractDoneFn SmcInteractDonePtr;
89 static SmcSaveYourselfDoneFn SmcSaveYourselfDonePtr;
90 static SmcInteractRequestFn SmcInteractRequestPtr;
91 static SmcCloseConnectionFn SmcCloseConnectionPtr;
92 static SmcOpenConnectionFn SmcOpenConnectionPtr;
93 static SmcSetPropertiesFn SmcSetPropertiesPtr;
95 # define IceSetIOErrorHandler IceSetIOErrorHandlerPtr
96 # define IceAddConnectionWatch IceAddConnectionWatchPtr
97 # define IceConnectionNumber IceConnectionNumberPtr
98 # define IceProcessMessages IceProcessMessagesPtr
99 # define IceGetConnectionContext IceGetConnectionContextPtr
100 # define SmcInteractDone SmcInteractDonePtr
101 # define SmcSaveYourselfDone SmcSaveYourselfDonePtr
102 # define SmcInteractRequest SmcInteractRequestPtr
103 # define SmcCloseConnection SmcCloseConnectionPtr
104 # define SmcOpenConnection SmcOpenConnectionPtr
105 # define SmcSetProperties SmcSetPropertiesPtr
107 enum ClientState {
108 STATE_DISCONNECTED,
109 STATE_REGISTERING,
110 STATE_IDLE,
111 STATE_INTERACTING,
112 STATE_SHUTDOWN_CANCELLED
115 using namespace mozilla;
117 static const char* gClientStateTable[] = {"DISCONNECTED", "REGISTERING", "IDLE",
118 "INTERACTING", "SHUTDOWN_CANCELLED"};
120 static LazyLogModule sMozSMLog("MozSM");
121 #endif /* MOZ_X11 */
123 class nsNativeAppSupportUnix : public nsNativeAppSupportBase {
124 public:
125 #if MOZ_X11
126 nsNativeAppSupportUnix()
127 : mSessionConnection(nullptr), mClientState(STATE_DISCONNECTED){};
128 ~nsNativeAppSupportUnix() {
129 // this goes out of scope after "web-workers-shutdown" async shutdown phase
130 // so it's safe to disconnect here (i.e. the application won't lose data)
131 DisconnectFromSM();
134 void DisconnectFromSM();
135 #endif
136 NS_IMETHOD Start(bool* aRetVal) override;
137 NS_IMETHOD Enable() override;
139 private:
140 #if MOZ_X11
141 static void SaveYourselfCB(SmcConn smc_conn, SmPointer client_data,
142 int save_style, Bool shutdown, int interact_style,
143 Bool fast);
144 static void DieCB(SmcConn smc_conn, SmPointer client_data);
145 static void InteractCB(SmcConn smc_conn, SmPointer client_data);
146 static void SaveCompleteCB(SmcConn smc_conn, SmPointer client_data){};
147 static void ShutdownCancelledCB(SmcConn smc_conn, SmPointer client_data);
148 void DoInteract();
149 void SetClientState(ClientState aState) {
150 mClientState = aState;
151 MOZ_LOG(sMozSMLog, LogLevel::Debug,
152 ("New state = %s\n", gClientStateTable[aState]));
155 SmcConn mSessionConnection;
156 ClientState mClientState;
157 #endif
160 #if MOZ_X11
161 static gboolean process_ice_messages(IceConn connection) {
162 IceProcessMessagesStatus status;
164 status = IceProcessMessages(connection, nullptr, nullptr);
166 switch (status) {
167 case IceProcessMessagesSuccess:
168 return TRUE;
170 case IceProcessMessagesIOError: {
171 nsNativeAppSupportUnix* native = static_cast<nsNativeAppSupportUnix*>(
172 IceGetConnectionContext(connection));
173 native->DisconnectFromSM();
175 return FALSE;
177 case IceProcessMessagesConnectionClosed:
178 return FALSE;
180 default:
181 g_assert_not_reached();
185 static gboolean ice_iochannel_watch(GIOChannel* channel, GIOCondition condition,
186 gpointer client_data) {
187 return process_ice_messages(static_cast<IceConn>(client_data));
190 static void ice_connection_watch(IceConn connection, IcePointer client_data,
191 Bool opening, IcePointer* watch_data) {
192 guint watch_id;
194 if (opening) {
195 GIOChannel* channel;
196 int fd = IceConnectionNumber(connection);
198 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
199 channel = g_io_channel_unix_new(fd);
200 watch_id =
201 g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_IN | G_IO_ERR),
202 ice_iochannel_watch, connection);
203 g_io_channel_unref(channel);
205 *watch_data = GUINT_TO_POINTER(watch_id);
206 } else {
207 watch_id = GPOINTER_TO_UINT(*watch_data);
208 g_source_remove(watch_id);
212 static void ice_io_error_handler(IceConn connection) {
213 // override the default handler which would exit the application;
214 // do nothing and let ICELib handle the failure of the connection gracefully.
217 static void ice_init(void) {
218 static bool initted = false;
220 if (!initted) {
221 IceSetIOErrorHandler(ice_io_error_handler);
222 IceAddConnectionWatch(ice_connection_watch, nullptr);
223 initted = true;
227 void nsNativeAppSupportUnix::InteractCB(SmcConn smc_conn,
228 SmPointer client_data) {
229 nsNativeAppSupportUnix* self =
230 static_cast<nsNativeAppSupportUnix*>(client_data);
232 self->SetClientState(STATE_INTERACTING);
234 // We do this asynchronously, as we spin the event loop recursively if
235 // a dialog is displayed. If we do this synchronously, we don't finish
236 // processing the current ICE event whilst the dialog is displayed, which
237 // means we won't process any more. libsm hates us if we do the InteractDone
238 // with a pending ShutdownCancelled, and we would certainly like to handle Die
239 // whilst a dialog is displayed
240 NS_DispatchToCurrentThread(
241 NewRunnableMethod("nsNativeAppSupportUnix::DoInteract", self,
242 &nsNativeAppSupportUnix::DoInteract));
245 void nsNativeAppSupportUnix::DoInteract() {
246 nsCOMPtr<nsIObserverService> obsServ =
247 mozilla::services::GetObserverService();
248 if (!obsServ) {
249 SmcInteractDone(mSessionConnection, False);
250 SmcSaveYourselfDone(mSessionConnection, True);
251 SetClientState(STATE_IDLE);
252 return;
255 nsCOMPtr<nsISupportsPRBool> cancelQuit =
256 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
258 bool abortQuit = false;
259 if (cancelQuit) {
260 cancelQuit->SetData(false);
261 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
263 cancelQuit->GetData(&abortQuit);
266 if (!abortQuit && mClientState == STATE_DISCONNECTED) {
267 // The session manager disappeared, whilst we were interacting, so
268 // quit now
269 nsCOMPtr<nsIAppStartup> appService =
270 do_GetService("@mozilla.org/toolkit/app-startup;1");
272 if (appService) {
273 bool userAllowedQuit = true;
274 appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
276 } else {
277 if (mClientState != STATE_SHUTDOWN_CANCELLED) {
278 // Only do this if the shutdown wasn't cancelled
279 SmcInteractDone(mSessionConnection, !!abortQuit);
280 SmcSaveYourselfDone(mSessionConnection, !abortQuit);
283 SetClientState(STATE_IDLE);
287 void nsNativeAppSupportUnix::SaveYourselfCB(SmcConn smc_conn,
288 SmPointer client_data,
289 int save_style, Bool shutdown,
290 int interact_style, Bool fast) {
291 nsNativeAppSupportUnix* self =
292 static_cast<nsNativeAppSupportUnix*>(client_data);
294 // Expect a SaveYourselfCB if we're registering a new client.
295 // All properties are already set in Start() so just reply with
296 // SmcSaveYourselfDone if the callback matches the expected signature.
298 // Ancient versions (?) of xsm do not follow such an early SaveYourself with
299 // SaveComplete. This is a problem if the application freezes interaction
300 // while waiting for a response to SmcSaveYourselfDone. So never freeze
301 // interaction when in STATE_REGISTERING.
303 // That aside, we could treat each combination of flags appropriately and not
304 // special-case this.
305 if (self->mClientState == STATE_REGISTERING) {
306 self->SetClientState(STATE_IDLE);
308 if (save_style == SmSaveLocal && interact_style == SmInteractStyleNone &&
309 !shutdown && !fast) {
310 SmcSaveYourselfDone(self->mSessionConnection, True);
311 return;
315 if (self->mClientState == STATE_SHUTDOWN_CANCELLED) {
316 // The last shutdown request was cancelled whilst we were interacting,
317 // and we haven't finished interacting yet. Switch the state back again
318 self->SetClientState(STATE_INTERACTING);
321 nsCOMPtr<nsIObserverService> obsServ =
322 mozilla::services::GetObserverService();
323 if (!obsServ) {
324 SmcSaveYourselfDone(smc_conn, True);
325 return;
328 bool status = false;
329 nsCOMPtr<nsISupportsPRBool> didSaveSession =
330 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
332 if (!didSaveSession) {
333 SmcSaveYourselfDone(smc_conn, True);
334 return;
337 // Notify observers to save the session state
338 didSaveSession->SetData(false);
339 obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
341 didSaveSession->GetData(&status);
343 // If the interact style permits us to, we are shutting down and we didn't
344 // manage to (or weren't asked to) save the local state, then notify the user
345 // in advance that we are doing to quit (assuming that we aren't already
346 // doing so)
347 if (!status && shutdown && interact_style != SmInteractStyleNone) {
348 if (self->mClientState != STATE_INTERACTING) {
349 SmcInteractRequest(smc_conn, SmDialogNormal,
350 nsNativeAppSupportUnix::InteractCB, client_data);
352 } else {
353 SmcSaveYourselfDone(smc_conn, True);
357 void nsNativeAppSupportUnix::DieCB(SmcConn smc_conn, SmPointer client_data) {
358 nsCOMPtr<nsIAppStartup> appService =
359 do_GetService("@mozilla.org/toolkit/app-startup;1");
361 if (appService) {
362 bool userAllowedQuit = false;
363 appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
365 // Quit causes the shutdown to begin but the shutdown process is asynchronous
366 // so we can't DisconnectFromSM() yet
369 void nsNativeAppSupportUnix::ShutdownCancelledCB(SmcConn smc_conn,
370 SmPointer client_data) {
371 nsNativeAppSupportUnix* self =
372 static_cast<nsNativeAppSupportUnix*>(client_data);
374 // Interacting is the only time when we wouldn't already have called
375 // SmcSaveYourselfDone. Do that now, then set the state to make sure we
376 // don't send it again after finishing interacting
377 if (self->mClientState == STATE_INTERACTING) {
378 SmcSaveYourselfDone(smc_conn, False);
379 self->SetClientState(STATE_SHUTDOWN_CANCELLED);
383 void nsNativeAppSupportUnix::DisconnectFromSM() {
384 // the SM is free to exit any time after we disconnect, so callers must be
385 // sure to have reached a sufficiently advanced phase of shutdown that there
386 // is no risk of data loss:
387 // e.g. all async writes are complete by the end of "profile-before-change"
388 if (mSessionConnection) {
389 SetClientState(STATE_DISCONNECTED);
390 SmcCloseConnection(mSessionConnection, 0, nullptr);
391 mSessionConnection = nullptr;
392 gdk_x11_set_sm_client_id(nullptr); // follow gnome-client behaviour
396 static void SetSMValue(SmPropValue& val, const nsCString& data) {
397 val.value = static_cast<SmPointer>(const_cast<char*>(data.get()));
398 val.length = data.Length();
401 static void SetSMProperty(SmProp& prop, const char* name, const char* type,
402 int numVals, SmPropValue vals[]) {
403 prop.name = const_cast<char*>(name);
404 prop.type = const_cast<char*>(type);
405 prop.num_vals = numVals;
406 prop.vals = vals;
408 #endif /* MOZ_X11 */
410 static void RemoveArg(char** argv) {
411 do {
412 *argv = *(argv + 1);
413 ++argv;
414 } while (*argv);
416 --gArgc;
419 NS_IMETHODIMP
420 nsNativeAppSupportUnix::Start(bool* aRetVal) {
421 NS_ASSERTION(gAppData, "gAppData must not be null.");
423 // The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService,
424 // from diffrent threads. This could lead to race conditions if the dbus is not
425 // initialized before making any other library calls.
426 #ifdef MOZ_ENABLE_DBUS
427 dbus_threads_init_default();
428 #endif
430 *aRetVal = true;
432 #ifdef MOZ_X11
433 gboolean sm_disable = FALSE;
434 if (!getenv("SESSION_MANAGER")) {
435 sm_disable = TRUE;
438 nsAutoCString prev_client_id;
440 char** curarg = gArgv + 1;
441 while (*curarg) {
442 char* arg = *curarg;
443 if (arg[0] == '-' && arg[1] == '-') {
444 arg += 2;
445 if (!strcmp(arg, "sm-disable")) {
446 RemoveArg(curarg);
447 sm_disable = TRUE;
448 continue;
449 } else if (!strcmp(arg, "sm-client-id")) {
450 RemoveArg(curarg);
451 if (*curarg[0] != '-') {
452 prev_client_id = *curarg;
453 RemoveArg(curarg);
455 continue;
459 ++curarg;
462 if (prev_client_id.IsEmpty()) {
463 prev_client_id = getenv("DESKTOP_AUTOSTART_ID");
466 // We don't want child processes to use the same ID
467 unsetenv("DESKTOP_AUTOSTART_ID");
469 char* client_id = nullptr;
470 if (!sm_disable) {
471 PRLibrary* iceLib = PR_LoadLibrary("libICE.so.6");
472 if (!iceLib) {
473 return NS_OK;
476 PRLibrary* smLib = PR_LoadLibrary("libSM.so.6");
477 if (!smLib) {
478 PR_UnloadLibrary(iceLib);
479 return NS_OK;
482 IceSetIOErrorHandler = (IceSetIOErrorHandlerFn)PR_FindFunctionSymbol(
483 iceLib, "IceSetIOErrorHandler");
484 IceAddConnectionWatch = (IceAddConnectionWatchFn)PR_FindFunctionSymbol(
485 iceLib, "IceAddConnectionWatch");
486 IceConnectionNumber = (IceConnectionNumberFn)PR_FindFunctionSymbol(
487 iceLib, "IceConnectionNumber");
488 IceProcessMessages = (IceProcessMessagesFn)PR_FindFunctionSymbol(
489 iceLib, "IceProcessMessages");
490 IceGetConnectionContext = (IceGetConnectionContextFn)PR_FindFunctionSymbol(
491 iceLib, "IceGetConnectionContext");
492 if (!IceSetIOErrorHandler || !IceAddConnectionWatch ||
493 !IceConnectionNumber || !IceProcessMessages ||
494 !IceGetConnectionContext) {
495 PR_UnloadLibrary(iceLib);
496 PR_UnloadLibrary(smLib);
497 return NS_OK;
500 SmcInteractDone =
501 (SmcInteractDoneFn)PR_FindFunctionSymbol(smLib, "SmcInteractDone");
502 SmcSaveYourselfDone = (SmcSaveYourselfDoneFn)PR_FindFunctionSymbol(
503 smLib, "SmcSaveYourselfDone");
504 SmcInteractRequest = (SmcInteractRequestFn)PR_FindFunctionSymbol(
505 smLib, "SmcInteractRequest");
506 SmcCloseConnection = (SmcCloseConnectionFn)PR_FindFunctionSymbol(
507 smLib, "SmcCloseConnection");
508 SmcOpenConnection =
509 (SmcOpenConnectionFn)PR_FindFunctionSymbol(smLib, "SmcOpenConnection");
510 SmcSetProperties =
511 (SmcSetPropertiesFn)PR_FindFunctionSymbol(smLib, "SmcSetProperties");
512 if (!SmcInteractDone || !SmcSaveYourselfDone || !SmcInteractRequest ||
513 !SmcCloseConnection || !SmcOpenConnection || !SmcSetProperties) {
514 PR_UnloadLibrary(iceLib);
515 PR_UnloadLibrary(smLib);
516 return NS_OK;
519 ice_init();
521 // all callbacks are mandatory in libSM 1.0, so listen even if we don't
522 // care.
523 unsigned long mask = SmcSaveYourselfProcMask | SmcDieProcMask |
524 SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
526 SmcCallbacks callbacks;
527 callbacks.save_yourself.callback = nsNativeAppSupportUnix::SaveYourselfCB;
528 callbacks.save_yourself.client_data = static_cast<SmPointer>(this);
530 callbacks.die.callback = nsNativeAppSupportUnix::DieCB;
531 callbacks.die.client_data = static_cast<SmPointer>(this);
533 callbacks.save_complete.callback = nsNativeAppSupportUnix::SaveCompleteCB;
534 callbacks.save_complete.client_data = nullptr;
536 callbacks.shutdown_cancelled.callback =
537 nsNativeAppSupportUnix::ShutdownCancelledCB;
538 callbacks.shutdown_cancelled.client_data = static_cast<SmPointer>(this);
540 char errbuf[256];
541 mSessionConnection = SmcOpenConnection(
542 nullptr, this, SmProtoMajor, SmProtoMinor, mask, &callbacks,
543 prev_client_id.get(), &client_id, sizeof(errbuf), errbuf);
546 if (!mSessionConnection) {
547 return NS_OK;
550 LogModule::Init(
551 gArgc, gArgv); // need to make sure initialized before SetClientState
552 if (prev_client_id.IsEmpty() ||
553 (client_id && !prev_client_id.Equals(client_id))) {
554 SetClientState(STATE_REGISTERING);
555 } else {
556 SetClientState(STATE_IDLE);
559 gdk_x11_set_sm_client_id(client_id);
561 // Set SM Properties
562 // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required
563 // properties so must be set, and must have a sensible fallback value.
565 // Determine executable path to use for XSMP session restore
567 // Is there a request to suppress default binary launcher?
568 nsAutoCString path(getenv("MOZ_APP_LAUNCHER"));
570 if (path.IsEmpty()) {
571 NS_ASSERTION(gDirServiceProvider,
572 "gDirServiceProvider is NULL! This shouldn't happen!");
573 nsCOMPtr<nsIFile> executablePath;
574 nsresult rv;
576 bool dummy;
577 rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy,
578 getter_AddRefs(executablePath));
580 if (NS_SUCCEEDED(rv)) {
581 // Strip off the -bin suffix to get the shell script we should run; this
582 // is what Breakpad does
583 nsAutoCString leafName;
584 rv = executablePath->GetNativeLeafName(leafName);
585 if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, "-bin"_ns)) {
586 leafName.SetLength(leafName.Length() - strlen("-bin"));
587 executablePath->SetNativeLeafName(leafName);
590 executablePath->GetNativePath(path);
594 if (path.IsEmpty()) {
595 // can't determine executable path. Best fallback is name from
596 // application.ini but it might not resolve to the same executable at
597 // launch time.
598 path = gAppData->name; // will always be set
599 ToLowerCase(path);
600 MOZ_LOG(sMozSMLog, LogLevel::Warning,
601 ("Could not determine executable path. Falling back to %s.",
602 path.get()));
605 SmProp propRestart, propClone, propProgram, propUser, *props[4];
606 SmPropValue valsRestart[3], valsClone[1], valsProgram[1], valsUser[1];
607 int n = 0;
609 constexpr auto kClientIDParam = "--sm-client-id"_ns;
611 SetSMValue(valsRestart[0], path);
612 SetSMValue(valsRestart[1], kClientIDParam);
613 SetSMValue(valsRestart[2], nsDependentCString(client_id));
614 SetSMProperty(propRestart, SmRestartCommand, SmLISTofARRAY8, 3, valsRestart);
615 props[n++] = &propRestart;
617 SetSMValue(valsClone[0], path);
618 SetSMProperty(propClone, SmCloneCommand, SmLISTofARRAY8, 1, valsClone);
619 props[n++] = &propClone;
621 nsAutoCString appName(gAppData->name); // will always be set
622 ToLowerCase(appName);
624 SetSMValue(valsProgram[0], appName);
625 SetSMProperty(propProgram, SmProgram, SmARRAY8, 1, valsProgram);
626 props[n++] = &propProgram;
628 nsAutoCString userName; // username that started the program
629 struct passwd* pw = getpwuid(getuid());
630 if (pw && pw->pw_name) {
631 userName = pw->pw_name;
632 } else {
633 userName = "nobody"_ns;
634 MOZ_LOG(
635 sMozSMLog, LogLevel::Warning,
636 ("Could not determine user-name. Falling back to %s.", userName.get()));
639 SetSMValue(valsUser[0], userName);
640 SetSMProperty(propUser, SmUserID, SmARRAY8, 1, valsUser);
641 props[n++] = &propUser;
643 SmcSetProperties(mSessionConnection, n, props);
645 g_free(client_id);
646 #endif /* MOZ_X11 */
648 return NS_OK;
651 NS_IMETHODIMP
652 nsNativeAppSupportUnix::Enable() { return NS_OK; }
654 nsresult NS_CreateNativeAppSupport(nsINativeAppSupport** aResult) {
655 nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
656 if (!native) return NS_ERROR_OUT_OF_MEMORY;
658 *aResult = native;
659 NS_ADDREF(*aResult);
661 return NS_OK;