Bug 1728955: part 5) Add missing `// static` comment to `nsClipboard::CreateNativeDat...
[gecko.git] / toolkit / xre / nsNativeAppSupportUnix.cpp
blobe8f7b67c35a05cd84868940502221c48fc47ae76
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 "nsCOMPtr.h"
9 #include "nsXPCOM.h"
10 #include "nsISupportsPrimitives.h"
11 #include "nsIObserverService.h"
12 #include "nsIAppStartup.h"
13 #include "nsServiceManagerUtils.h"
14 #include "prlink.h"
15 #include "nsXREDirProvider.h"
16 #include "nsReadableUtils.h"
18 #include "nsIFile.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsPIDOMWindow.h"
21 #include "nsIWidget.h"
22 #include "mozilla/Logging.h"
23 #include "mozilla/Services.h"
25 #include <stdlib.h>
26 #include <glib.h>
27 #include <glib-object.h>
28 #include <gtk/gtk.h>
30 #ifdef MOZ_X11
31 # include <gdk/gdkx.h>
32 # include <X11/ICE/ICElib.h>
33 # include <X11/SM/SMlib.h>
34 # include <fcntl.h>
35 # include "nsThreadUtils.h"
37 # include <pwd.h>
38 #endif
40 #ifdef MOZ_ENABLE_DBUS
41 # include <dbus/dbus.h>
42 #endif
44 #define MIN_GTK_MAJOR_VERSION 2
45 #define MIN_GTK_MINOR_VERSION 10
46 #define UNSUPPORTED_GTK_MSG \
47 "We're sorry, this application requires a version of the GTK+ library that is not installed on your computer.\n\n\
48 You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
49 Please upgrade your GTK+ library if you wish to use this application."
51 #if MOZ_X11
52 # undef IceSetIOErrorHandler
53 # undef IceAddConnectionWatch
54 # undef IceConnectionNumber
55 # undef IceProcessMessages
56 # undef IceGetConnectionContext
57 # undef SmcInteractDone
58 # undef SmcSaveYourselfDone
59 # undef SmcInteractRequest
60 # undef SmcCloseConnection
61 # undef SmcOpenConnection
62 # undef SmcSetProperties
64 typedef IceIOErrorHandler (*IceSetIOErrorHandlerFn)(IceIOErrorHandler);
65 typedef int (*IceAddConnectionWatchFn)(IceWatchProc, IcePointer);
66 typedef int (*IceConnectionNumberFn)(IceConn);
67 typedef IceProcessMessagesStatus (*IceProcessMessagesFn)(IceConn,
68 IceReplyWaitInfo*,
69 Bool*);
70 typedef IcePointer (*IceGetConnectionContextFn)(IceConn);
72 typedef void (*SmcInteractDoneFn)(SmcConn, Bool);
73 typedef void (*SmcSaveYourselfDoneFn)(SmcConn, Bool);
74 typedef int (*SmcInteractRequestFn)(SmcConn, int, SmcInteractProc, SmPointer);
75 typedef SmcCloseStatus (*SmcCloseConnectionFn)(SmcConn, int, char**);
76 typedef SmcConn (*SmcOpenConnectionFn)(char*, SmPointer, int, int,
77 unsigned long, SmcCallbacks*,
78 const char*, char**, int, char*);
79 typedef void (*SmcSetPropertiesFn)(SmcConn, int, SmProp**);
81 static IceSetIOErrorHandlerFn IceSetIOErrorHandlerPtr;
82 static IceAddConnectionWatchFn IceAddConnectionWatchPtr;
83 static IceConnectionNumberFn IceConnectionNumberPtr;
84 static IceProcessMessagesFn IceProcessMessagesPtr;
85 static IceGetConnectionContextFn IceGetConnectionContextPtr;
86 static SmcInteractDoneFn SmcInteractDonePtr;
87 static SmcSaveYourselfDoneFn SmcSaveYourselfDonePtr;
88 static SmcInteractRequestFn SmcInteractRequestPtr;
89 static SmcCloseConnectionFn SmcCloseConnectionPtr;
90 static SmcOpenConnectionFn SmcOpenConnectionPtr;
91 static SmcSetPropertiesFn SmcSetPropertiesPtr;
93 # define IceSetIOErrorHandler IceSetIOErrorHandlerPtr
94 # define IceAddConnectionWatch IceAddConnectionWatchPtr
95 # define IceConnectionNumber IceConnectionNumberPtr
96 # define IceProcessMessages IceProcessMessagesPtr
97 # define IceGetConnectionContext IceGetConnectionContextPtr
98 # define SmcInteractDone SmcInteractDonePtr
99 # define SmcSaveYourselfDone SmcSaveYourselfDonePtr
100 # define SmcInteractRequest SmcInteractRequestPtr
101 # define SmcCloseConnection SmcCloseConnectionPtr
102 # define SmcOpenConnection SmcOpenConnectionPtr
103 # define SmcSetProperties SmcSetPropertiesPtr
105 enum ClientState {
106 STATE_DISCONNECTED,
107 STATE_REGISTERING,
108 STATE_IDLE,
109 STATE_INTERACTING,
110 STATE_SHUTDOWN_CANCELLED
113 static const char* gClientStateTable[] = {"DISCONNECTED", "REGISTERING", "IDLE",
114 "INTERACTING", "SHUTDOWN_CANCELLED"};
116 static LazyLogModule sMozSMLog("MozSM");
117 #endif /* MOZ_X11 */
119 class nsNativeAppSupportUnix : public nsNativeAppSupportBase {
120 public:
121 #if MOZ_X11
122 nsNativeAppSupportUnix()
123 : mSessionConnection(nullptr), mClientState(STATE_DISCONNECTED){};
124 ~nsNativeAppSupportUnix() {
125 // this goes out of scope after "web-workers-shutdown" async shutdown phase
126 // so it's safe to disconnect here (i.e. the application won't lose data)
127 DisconnectFromSM();
130 void DisconnectFromSM();
131 #endif
132 NS_IMETHOD Start(bool* aRetVal) override;
133 NS_IMETHOD Enable() override;
135 private:
136 #if MOZ_X11
137 static void SaveYourselfCB(SmcConn smc_conn, SmPointer client_data,
138 int save_style, Bool shutdown, int interact_style,
139 Bool fast);
140 static void DieCB(SmcConn smc_conn, SmPointer client_data);
141 static void InteractCB(SmcConn smc_conn, SmPointer client_data);
142 static void SaveCompleteCB(SmcConn smc_conn, SmPointer client_data){};
143 static void ShutdownCancelledCB(SmcConn smc_conn, SmPointer client_data);
144 void DoInteract();
145 void SetClientState(ClientState aState) {
146 mClientState = aState;
147 MOZ_LOG(sMozSMLog, LogLevel::Debug,
148 ("New state = %s\n", gClientStateTable[aState]));
151 SmcConn mSessionConnection;
152 ClientState mClientState;
153 #endif
156 #if MOZ_X11
157 static gboolean process_ice_messages(IceConn connection) {
158 IceProcessMessagesStatus status;
160 status = IceProcessMessages(connection, nullptr, nullptr);
162 switch (status) {
163 case IceProcessMessagesSuccess:
164 return TRUE;
166 case IceProcessMessagesIOError: {
167 nsNativeAppSupportUnix* native = static_cast<nsNativeAppSupportUnix*>(
168 IceGetConnectionContext(connection));
169 native->DisconnectFromSM();
171 return FALSE;
173 case IceProcessMessagesConnectionClosed:
174 return FALSE;
176 default:
177 g_assert_not_reached();
181 static gboolean ice_iochannel_watch(GIOChannel* channel, GIOCondition condition,
182 gpointer client_data) {
183 return process_ice_messages(static_cast<IceConn>(client_data));
186 static void ice_connection_watch(IceConn connection, IcePointer client_data,
187 Bool opening, IcePointer* watch_data) {
188 guint watch_id;
190 if (opening) {
191 GIOChannel* channel;
192 int fd = IceConnectionNumber(connection);
194 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
195 channel = g_io_channel_unix_new(fd);
196 watch_id =
197 g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_IN | G_IO_ERR),
198 ice_iochannel_watch, connection);
199 g_io_channel_unref(channel);
201 *watch_data = GUINT_TO_POINTER(watch_id);
202 } else {
203 watch_id = GPOINTER_TO_UINT(*watch_data);
204 g_source_remove(watch_id);
208 static void ice_io_error_handler(IceConn connection) {
209 // override the default handler which would exit the application;
210 // do nothing and let ICELib handle the failure of the connection gracefully.
213 static void ice_init(void) {
214 static bool initted = false;
216 if (!initted) {
217 IceSetIOErrorHandler(ice_io_error_handler);
218 IceAddConnectionWatch(ice_connection_watch, nullptr);
219 initted = true;
223 void nsNativeAppSupportUnix::InteractCB(SmcConn smc_conn,
224 SmPointer client_data) {
225 nsNativeAppSupportUnix* self =
226 static_cast<nsNativeAppSupportUnix*>(client_data);
228 self->SetClientState(STATE_INTERACTING);
230 // We do this asynchronously, as we spin the event loop recursively if
231 // a dialog is displayed. If we do this synchronously, we don't finish
232 // processing the current ICE event whilst the dialog is displayed, which
233 // means we won't process any more. libsm hates us if we do the InteractDone
234 // with a pending ShutdownCancelled, and we would certainly like to handle Die
235 // whilst a dialog is displayed
236 NS_DispatchToCurrentThread(
237 NewRunnableMethod("nsNativeAppSupportUnix::DoInteract", self,
238 &nsNativeAppSupportUnix::DoInteract));
241 void nsNativeAppSupportUnix::DoInteract() {
242 nsCOMPtr<nsIObserverService> obsServ =
243 mozilla::services::GetObserverService();
244 if (!obsServ) {
245 SmcInteractDone(mSessionConnection, False);
246 SmcSaveYourselfDone(mSessionConnection, True);
247 SetClientState(STATE_IDLE);
248 return;
251 nsCOMPtr<nsISupportsPRBool> cancelQuit =
252 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
254 bool abortQuit = false;
255 if (cancelQuit) {
256 cancelQuit->SetData(false);
257 obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
259 cancelQuit->GetData(&abortQuit);
262 if (!abortQuit && mClientState == STATE_DISCONNECTED) {
263 // The session manager disappeared, whilst we were interacting, so
264 // quit now
265 nsCOMPtr<nsIAppStartup> appService =
266 do_GetService("@mozilla.org/toolkit/app-startup;1");
268 if (appService) {
269 bool userAllowedQuit = true;
270 appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
272 } else {
273 if (mClientState != STATE_SHUTDOWN_CANCELLED) {
274 // Only do this if the shutdown wasn't cancelled
275 SmcInteractDone(mSessionConnection, !!abortQuit);
276 SmcSaveYourselfDone(mSessionConnection, !abortQuit);
279 SetClientState(STATE_IDLE);
283 void nsNativeAppSupportUnix::SaveYourselfCB(SmcConn smc_conn,
284 SmPointer client_data,
285 int save_style, Bool shutdown,
286 int interact_style, Bool fast) {
287 nsNativeAppSupportUnix* self =
288 static_cast<nsNativeAppSupportUnix*>(client_data);
290 // Expect a SaveYourselfCB if we're registering a new client.
291 // All properties are already set in Start() so just reply with
292 // SmcSaveYourselfDone if the callback matches the expected signature.
294 // Ancient versions (?) of xsm do not follow such an early SaveYourself with
295 // SaveComplete. This is a problem if the application freezes interaction
296 // while waiting for a response to SmcSaveYourselfDone. So never freeze
297 // interaction when in STATE_REGISTERING.
299 // That aside, we could treat each combination of flags appropriately and not
300 // special-case this.
301 if (self->mClientState == STATE_REGISTERING) {
302 self->SetClientState(STATE_IDLE);
304 if (save_style == SmSaveLocal && interact_style == SmInteractStyleNone &&
305 !shutdown && !fast) {
306 SmcSaveYourselfDone(self->mSessionConnection, True);
307 return;
311 if (self->mClientState == STATE_SHUTDOWN_CANCELLED) {
312 // The last shutdown request was cancelled whilst we were interacting,
313 // and we haven't finished interacting yet. Switch the state back again
314 self->SetClientState(STATE_INTERACTING);
317 nsCOMPtr<nsIObserverService> obsServ =
318 mozilla::services::GetObserverService();
319 if (!obsServ) {
320 SmcSaveYourselfDone(smc_conn, True);
321 return;
324 bool status = false;
325 nsCOMPtr<nsISupportsPRBool> didSaveSession =
326 do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
328 if (!didSaveSession) {
329 SmcSaveYourselfDone(smc_conn, True);
330 return;
333 // Notify observers to save the session state
334 didSaveSession->SetData(false);
335 obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
337 didSaveSession->GetData(&status);
339 // If the interact style permits us to, we are shutting down and we didn't
340 // manage to (or weren't asked to) save the local state, then notify the user
341 // in advance that we are doing to quit (assuming that we aren't already
342 // doing so)
343 if (!status && shutdown && interact_style != SmInteractStyleNone) {
344 if (self->mClientState != STATE_INTERACTING) {
345 SmcInteractRequest(smc_conn, SmDialogNormal,
346 nsNativeAppSupportUnix::InteractCB, client_data);
348 } else {
349 SmcSaveYourselfDone(smc_conn, True);
353 void nsNativeAppSupportUnix::DieCB(SmcConn smc_conn, SmPointer client_data) {
354 nsCOMPtr<nsIAppStartup> appService =
355 do_GetService("@mozilla.org/toolkit/app-startup;1");
357 if (appService) {
358 bool userAllowedQuit = false;
359 appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
361 // Quit causes the shutdown to begin but the shutdown process is asynchronous
362 // so we can't DisconnectFromSM() yet
365 void nsNativeAppSupportUnix::ShutdownCancelledCB(SmcConn smc_conn,
366 SmPointer client_data) {
367 nsNativeAppSupportUnix* self =
368 static_cast<nsNativeAppSupportUnix*>(client_data);
370 // Interacting is the only time when we wouldn't already have called
371 // SmcSaveYourselfDone. Do that now, then set the state to make sure we
372 // don't send it again after finishing interacting
373 if (self->mClientState == STATE_INTERACTING) {
374 SmcSaveYourselfDone(smc_conn, False);
375 self->SetClientState(STATE_SHUTDOWN_CANCELLED);
379 void nsNativeAppSupportUnix::DisconnectFromSM() {
380 // the SM is free to exit any time after we disconnect, so callers must be
381 // sure to have reached a sufficiently advanced phase of shutdown that there
382 // is no risk of data loss:
383 // e.g. all async writes are complete by the end of "profile-before-change"
384 if (mSessionConnection) {
385 SetClientState(STATE_DISCONNECTED);
386 SmcCloseConnection(mSessionConnection, 0, nullptr);
387 mSessionConnection = nullptr;
388 gdk_x11_set_sm_client_id(nullptr); // follow gnome-client behaviour
392 static void SetSMValue(SmPropValue& val, const nsCString& data) {
393 val.value = static_cast<SmPointer>(const_cast<char*>(data.get()));
394 val.length = data.Length();
397 static void SetSMProperty(SmProp& prop, const char* name, const char* type,
398 int numVals, SmPropValue vals[]) {
399 prop.name = const_cast<char*>(name);
400 prop.type = const_cast<char*>(type);
401 prop.num_vals = numVals;
402 prop.vals = vals;
404 #endif /* MOZ_X11 */
406 static void RemoveArg(char** argv) {
407 do {
408 *argv = *(argv + 1);
409 ++argv;
410 } while (*argv);
412 --gArgc;
415 NS_IMETHODIMP
416 nsNativeAppSupportUnix::Start(bool* aRetVal) {
417 NS_ASSERTION(gAppData, "gAppData must not be null.");
419 // The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService,
420 // from diffrent threads. This could lead to race conditions if the dbus is not
421 // initialized before making any other library calls.
422 #ifdef MOZ_ENABLE_DBUS
423 dbus_threads_init_default();
424 #endif
426 *aRetVal = true;
428 #ifdef MOZ_X11
429 gboolean sm_disable = FALSE;
430 if (!getenv("SESSION_MANAGER")) {
431 sm_disable = TRUE;
434 nsAutoCString prev_client_id;
436 char** curarg = gArgv + 1;
437 while (*curarg) {
438 char* arg = *curarg;
439 if (arg[0] == '-' && arg[1] == '-') {
440 arg += 2;
441 if (!strcmp(arg, "sm-disable")) {
442 RemoveArg(curarg);
443 sm_disable = TRUE;
444 continue;
445 } else if (!strcmp(arg, "sm-client-id")) {
446 RemoveArg(curarg);
447 if (*curarg[0] != '-') {
448 prev_client_id = *curarg;
449 RemoveArg(curarg);
451 continue;
455 ++curarg;
458 if (prev_client_id.IsEmpty()) {
459 prev_client_id = getenv("DESKTOP_AUTOSTART_ID");
462 // We don't want child processes to use the same ID
463 unsetenv("DESKTOP_AUTOSTART_ID");
465 char* client_id = nullptr;
466 if (!sm_disable) {
467 PRLibrary* iceLib = PR_LoadLibrary("libICE.so.6");
468 if (!iceLib) {
469 return NS_OK;
472 PRLibrary* smLib = PR_LoadLibrary("libSM.so.6");
473 if (!smLib) {
474 PR_UnloadLibrary(iceLib);
475 return NS_OK;
478 IceSetIOErrorHandler = (IceSetIOErrorHandlerFn)PR_FindFunctionSymbol(
479 iceLib, "IceSetIOErrorHandler");
480 IceAddConnectionWatch = (IceAddConnectionWatchFn)PR_FindFunctionSymbol(
481 iceLib, "IceAddConnectionWatch");
482 IceConnectionNumber = (IceConnectionNumberFn)PR_FindFunctionSymbol(
483 iceLib, "IceConnectionNumber");
484 IceProcessMessages = (IceProcessMessagesFn)PR_FindFunctionSymbol(
485 iceLib, "IceProcessMessages");
486 IceGetConnectionContext = (IceGetConnectionContextFn)PR_FindFunctionSymbol(
487 iceLib, "IceGetConnectionContext");
488 if (!IceSetIOErrorHandler || !IceAddConnectionWatch ||
489 !IceConnectionNumber || !IceProcessMessages ||
490 !IceGetConnectionContext) {
491 PR_UnloadLibrary(iceLib);
492 PR_UnloadLibrary(smLib);
493 return NS_OK;
496 SmcInteractDone =
497 (SmcInteractDoneFn)PR_FindFunctionSymbol(smLib, "SmcInteractDone");
498 SmcSaveYourselfDone = (SmcSaveYourselfDoneFn)PR_FindFunctionSymbol(
499 smLib, "SmcSaveYourselfDone");
500 SmcInteractRequest = (SmcInteractRequestFn)PR_FindFunctionSymbol(
501 smLib, "SmcInteractRequest");
502 SmcCloseConnection = (SmcCloseConnectionFn)PR_FindFunctionSymbol(
503 smLib, "SmcCloseConnection");
504 SmcOpenConnection =
505 (SmcOpenConnectionFn)PR_FindFunctionSymbol(smLib, "SmcOpenConnection");
506 SmcSetProperties =
507 (SmcSetPropertiesFn)PR_FindFunctionSymbol(smLib, "SmcSetProperties");
508 if (!SmcInteractDone || !SmcSaveYourselfDone || !SmcInteractRequest ||
509 !SmcCloseConnection || !SmcOpenConnection || !SmcSetProperties) {
510 PR_UnloadLibrary(iceLib);
511 PR_UnloadLibrary(smLib);
512 return NS_OK;
515 ice_init();
517 // all callbacks are mandatory in libSM 1.0, so listen even if we don't
518 // care.
519 unsigned long mask = SmcSaveYourselfProcMask | SmcDieProcMask |
520 SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
522 SmcCallbacks callbacks;
523 callbacks.save_yourself.callback = nsNativeAppSupportUnix::SaveYourselfCB;
524 callbacks.save_yourself.client_data = static_cast<SmPointer>(this);
526 callbacks.die.callback = nsNativeAppSupportUnix::DieCB;
527 callbacks.die.client_data = static_cast<SmPointer>(this);
529 callbacks.save_complete.callback = nsNativeAppSupportUnix::SaveCompleteCB;
530 callbacks.save_complete.client_data = nullptr;
532 callbacks.shutdown_cancelled.callback =
533 nsNativeAppSupportUnix::ShutdownCancelledCB;
534 callbacks.shutdown_cancelled.client_data = static_cast<SmPointer>(this);
536 char errbuf[256];
537 mSessionConnection = SmcOpenConnection(
538 nullptr, this, SmProtoMajor, SmProtoMinor, mask, &callbacks,
539 prev_client_id.get(), &client_id, sizeof(errbuf), errbuf);
542 if (!mSessionConnection) {
543 return NS_OK;
546 LogModule::Init(
547 gArgc, gArgv); // need to make sure initialized before SetClientState
548 if (prev_client_id.IsEmpty() ||
549 (client_id && !prev_client_id.Equals(client_id))) {
550 SetClientState(STATE_REGISTERING);
551 } else {
552 SetClientState(STATE_IDLE);
555 gdk_x11_set_sm_client_id(client_id);
557 // Set SM Properties
558 // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required
559 // properties so must be set, and must have a sensible fallback value.
561 // Determine executable path to use for XSMP session restore
563 // Is there a request to suppress default binary launcher?
564 nsAutoCString path(getenv("MOZ_APP_LAUNCHER"));
566 if (path.IsEmpty()) {
567 NS_ASSERTION(gDirServiceProvider,
568 "gDirServiceProvider is NULL! This shouldn't happen!");
569 nsCOMPtr<nsIFile> executablePath;
570 nsresult rv;
572 bool dummy;
573 rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy,
574 getter_AddRefs(executablePath));
576 if (NS_SUCCEEDED(rv)) {
577 // Strip off the -bin suffix to get the shell script we should run; this
578 // is what Breakpad does
579 nsAutoCString leafName;
580 rv = executablePath->GetNativeLeafName(leafName);
581 if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, "-bin"_ns)) {
582 leafName.SetLength(leafName.Length() - strlen("-bin"));
583 executablePath->SetNativeLeafName(leafName);
586 executablePath->GetNativePath(path);
590 if (path.IsEmpty()) {
591 // can't determine executable path. Best fallback is name from
592 // application.ini but it might not resolve to the same executable at
593 // launch time.
594 path = gAppData->name; // will always be set
595 ToLowerCase(path);
596 MOZ_LOG(sMozSMLog, LogLevel::Warning,
597 ("Could not determine executable path. Falling back to %s.",
598 path.get()));
601 SmProp propRestart, propClone, propProgram, propUser, *props[4];
602 SmPropValue valsRestart[3], valsClone[1], valsProgram[1], valsUser[1];
603 int n = 0;
605 constexpr auto kClientIDParam = "--sm-client-id"_ns;
607 SetSMValue(valsRestart[0], path);
608 SetSMValue(valsRestart[1], kClientIDParam);
609 SetSMValue(valsRestart[2], nsDependentCString(client_id));
610 SetSMProperty(propRestart, SmRestartCommand, SmLISTofARRAY8, 3, valsRestart);
611 props[n++] = &propRestart;
613 SetSMValue(valsClone[0], path);
614 SetSMProperty(propClone, SmCloneCommand, SmLISTofARRAY8, 1, valsClone);
615 props[n++] = &propClone;
617 nsAutoCString appName(gAppData->name); // will always be set
618 ToLowerCase(appName);
620 SetSMValue(valsProgram[0], appName);
621 SetSMProperty(propProgram, SmProgram, SmARRAY8, 1, valsProgram);
622 props[n++] = &propProgram;
624 nsAutoCString userName; // username that started the program
625 struct passwd* pw = getpwuid(getuid());
626 if (pw && pw->pw_name) {
627 userName = pw->pw_name;
628 } else {
629 userName = "nobody"_ns;
630 MOZ_LOG(
631 sMozSMLog, LogLevel::Warning,
632 ("Could not determine user-name. Falling back to %s.", userName.get()));
635 SetSMValue(valsUser[0], userName);
636 SetSMProperty(propUser, SmUserID, SmARRAY8, 1, valsUser);
637 props[n++] = &propUser;
639 SmcSetProperties(mSessionConnection, n, props);
641 g_free(client_id);
642 #endif /* MOZ_X11 */
644 return NS_OK;
647 NS_IMETHODIMP
648 nsNativeAppSupportUnix::Enable() { return NS_OK; }
650 nsresult NS_CreateNativeAppSupport(nsINativeAppSupport** aResult) {
651 nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
652 if (!native) return NS_ERROR_OUT_OF_MEMORY;
654 *aResult = native;
655 NS_ADDREF(*aResult);
657 return NS_OK;