aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjbeich <jbeich@FreeBSD.org>2017-11-22 14:25:10 +0800
committerjbeich <jbeich@FreeBSD.org>2017-11-22 14:25:10 +0800
commite85814dc42c7a46021180618f447dfc3ffd57929 (patch)
treea9db90a6bf61c8619e4e9995625a00a88368d9a3
parentb9863b7bce2757f109fe87aff153817972b402c9 (diff)
downloadfreebsd-ports-gnome-e85814dc42c7a46021180618f447dfc3ffd57929.tar.gz
freebsd-ports-gnome-e85814dc42c7a46021180618f447dfc3ffd57929.tar.zst
freebsd-ports-gnome-e85814dc42c7a46021180618f447dfc3ffd57929.zip
gecko: drop GNOMEUI option
-rw-r--r--Mk/bsd.gecko.mk10
-rw-r--r--www/firefox/Makefile1
-rw-r--r--www/firefox/Makefile.options3
-rw-r--r--www/libxul/Makefile2
-rw-r--r--www/libxul/files/patch-bug694570794
5 files changed, 796 insertions, 14 deletions
diff --git a/Mk/bsd.gecko.mk b/Mk/bsd.gecko.mk
index 8ea8e3f06c7b..f65d2dd7d6cc 100644
--- a/Mk/bsd.gecko.mk
+++ b/Mk/bsd.gecko.mk
@@ -333,16 +333,6 @@ MOZ_OPTIONS+= --enable-gconf
MOZ_OPTIONS+= --disable-gconf
.endif
-.if ${MOZILLA_VER:R:R} < 55
-.if ${PORT_OPTIONS:MGNOMEUI}
-BUILD_DEPENDS+= ${libgnomeui_DETECT}:${libgnomeui_LIB_DEPENDS:C/.*://}
-USE_GNOME+= libgnomeui:build
-MOZ_OPTIONS+= --enable-gnomeui
-.else
-MOZ_OPTIONS+= --disable-gnomeui
-.endif
-.endif # Mozilla < 55
-
.if ${PORT_OPTIONS:MLIBPROXY}
LIB_DEPENDS+= libproxy.so:net/libproxy
MOZ_OPTIONS+= --enable-libproxy
diff --git a/www/firefox/Makefile b/www/firefox/Makefile
index c1ff6c2e9b21..dd06465b15a4 100644
--- a/www/firefox/Makefile
+++ b/www/firefox/Makefile
@@ -46,7 +46,6 @@ MOZ_OPTIONS= --enable-application=browser \
--enable-official-branding
OPTIONS_DEFAULT= BUNDLED_CAIRO
-OPTIONS_EXCLUDE= GNOMEUI
.include "${.CURDIR}/../../www/firefox/Makefile.options"
diff --git a/www/firefox/Makefile.options b/www/firefox/Makefile.options
index 2896b871348d..d0ead5d35ec3 100644
--- a/www/firefox/Makefile.options
+++ b/www/firefox/Makefile.options
@@ -1,7 +1,7 @@
# -*- makefile-bsdmake -*-
OPTIONS_DEFINE+= BUNDLED_CAIRO CANBERRA DBUS DEBUG DTRACE FFMPEG GCONF \
- GNOMEUI INTEGER_SAMPLES LIBPROXY \
+ INTEGER_SAMPLES LIBPROXY \
OPTIMIZED_CFLAGS PROFILE TEST
OPTIONS_DEFAULT+= DBUS DTRACE FFMPEG OPTIMIZED_CFLAGS PROFILE \
@@ -26,7 +26,6 @@ OPTIONS_EXCLUDE_aarch64= DTRACE
BUNDLED_CAIRO_DESC?= Use bundled fork of cairo-1.9.5
CANBERRA_DESC?= Sound theme alerts
-GNOMEUI_DESC?= libgnomeui support module
INTEGER_SAMPLES_DESC?= Integer audio sample format
LIBPROXY_DESC?= Proxy support via libproxy
LIGHTNING_DESC?= Calendar extension
diff --git a/www/libxul/Makefile b/www/libxul/Makefile
index 64402110907f..8718ebafc050 100644
--- a/www/libxul/Makefile
+++ b/www/libxul/Makefile
@@ -3,7 +3,7 @@
PORTNAME= libxul
DISTVERSION= 45.9.0
-PORTREVISION= 7
+PORTREVISION= 8
CATEGORIES?= www devel
MASTER_SITES= MOZILLA/firefox/releases/${DISTVERSION}esr/source \
MOZILLA/firefox/candidates/${DISTVERSION}esr-candidates/build3/source
diff --git a/www/libxul/files/patch-bug694570 b/www/libxul/files/patch-bug694570
new file mode 100644
index 000000000000..6a4cb233c6e7
--- /dev/null
+++ b/www/libxul/files/patch-bug694570
@@ -0,0 +1,794 @@
+diff --git toolkit/xre/nsAppRunner.cpp toolkit/xre/nsAppRunner.cpp
+index b4077bc883f1..d088dcb3fa46 100644
+--- toolkit/xre/nsAppRunner.cpp
++++ toolkit/xre/nsAppRunner.cpp
+@@ -275,6 +275,7 @@ SaveToEnv(const char *putenv)
+ if (expr)
+ PR_SetEnv(expr);
+ // We intentionally leak |expr| here since it is required by PR_SetEnv.
++ MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr);
+ }
+
+ // Tests that an environment variable exists and has a value
+diff --git toolkit/xre/nsNativeAppSupportUnix.cpp toolkit/xre/nsNativeAppSupportUnix.cpp
+index 96ee13034f77..75652e38f5db 100644
+--- toolkit/xre/nsNativeAppSupportUnix.cpp
++++ toolkit/xre/nsNativeAppSupportUnix.cpp
+@@ -1,4 +1,5 @@
+-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* 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/. */
+@@ -33,7 +34,12 @@
+
+ #ifdef MOZ_X11
+ #include <gdk/gdkx.h>
+-#include <X11/Xatom.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
+@@ -46,94 +52,398 @@
+ 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."
+
+-typedef struct _GnomeProgram GnomeProgram;
+-typedef struct _GnomeModuleInfo GnomeModuleInfo;
+-typedef struct _GnomeClient GnomeClient;
+-
+-typedef enum {
+- GNOME_SAVE_GLOBAL,
+- GNOME_SAVE_LOCAL,
+- GNOME_SAVE_BOTH
+-} GnomeSaveStyle;
+-
+-typedef enum {
+- GNOME_INTERACT_NONE,
+- GNOME_INTERACT_ERRORS,
+- GNOME_INTERACT_ANY
+-} GnomeInteractStyle;
+-
+-typedef enum {
+- GNOME_DIALOG_ERROR,
+- GNOME_DIALOG_NORMAL
+-} GnomeDialogType;
+-
+-#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
+-typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
+- const GnomeModuleInfo *, int,
+- char **, const char *, ...);
+-typedef GnomeProgram * (*_gnome_program_get_fn)(void);
+-typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
+-typedef GnomeClient * (*_gnome_master_client_fn)(void);
+-typedef void (*_gnome_client_set_restart_command_fn)(GnomeClient*, gint, gchar*[]);
+-
+-static _gnome_client_set_restart_command_fn gnome_client_set_restart_command;
++#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
++};
+
+-gboolean save_yourself_cb(GnomeClient *client, gint phase,
+- GnomeSaveStyle style, gboolean shutdown,
+- GnomeInteractStyle interact, gboolean fast,
+- gpointer user_data)
++#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(NS_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> didSaveSession =
++ nsCOMPtr<nsISupportsPRBool> cancelQuit =
+ do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
+
+- if (!obsServ || !didSaveSession)
+- return TRUE; // OOM
++ bool abortQuit = false;
++ if (cancelQuit) {
++ cancelQuit->SetData(false);
++ obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
+
+- // Notify observers to save the session state
+- didSaveSession->SetData(false);
+- obsServ->NotifyObservers(didSaveSession, "session-save", 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);
++ }
++}
+
+- bool status;
+- didSaveSession->GetData(&status);
++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;
++ }
+
+- // If there was no session saved and the save_yourself request is
+- // caused by upcoming shutdown we like to prepare for it
+- if (!status && shutdown) {
+- nsCOMPtr<nsISupportsPRBool> cancelQuit =
++ bool status = false;
++ if (save_style != SmSaveGlobal) {
++ nsCOMPtr<nsISupportsPRBool> didSaveSession =
+ do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
+
+- cancelQuit->SetData(false);
+- obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
++ if (!didSaveSession) {
++ SmcSaveYourselfDone(smc_conn, True);
++ return;
++ }
+
+- bool abortQuit;
+- cancelQuit->GetData(&abortQuit);
++ // Notify observers to save the session state
++ didSaveSession->SetData(false);
++ obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
++
++ didSaveSession->GetData(&status);
+ }
+
+- return TRUE;
++ // 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 die_cb(GnomeClient *client, gpointer user_data)
++void
++nsNativeAppSupportUnix::DieCB(SmcConn smc_conn, SmPointer client_data)
+ {
+ nsCOMPtr<nsIAppStartup> appService =
+ do_GetService("@mozilla.org/toolkit/app-startup;1");
+
+- if (appService)
++ if (appService) {
+ appService->Quit(nsIAppStartup::eForceQuit);
++ }
++ // Quit causes the shutdown to begin but the shutdown process is asynchronous
++ // so we can't DisconnectFromSM() yet
+ }
+
+-class nsNativeAppSupportUnix : public nsNativeAppSupportBase
++void
++nsNativeAppSupportUnix::ShutdownCancelledCB(SmcConn smc_conn,
++ SmPointer client_data)
+ {
+-public:
+- NS_IMETHOD Start(bool* aRetVal);
+- NS_IMETHOD Stop(bool *aResult);
+- NS_IMETHOD Enable();
++ 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);
++ }
++}
+
+-private:
+-};
++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)
+@@ -168,79 +478,132 @@ nsNativeAppSupportUnix::Start(bool *aRetVal)
+
+ *aRetVal = true;
+
+-#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
++#ifdef MOZ_X11
++ gboolean sm_disable = FALSE;
++ if (!getenv("SESSION_MANAGER")) {
++ sm_disable = TRUE;
++ }
+
+- PRLibrary *gnomeuiLib = PR_LoadLibrary("libgnomeui-2.so.0");
+- if (!gnomeuiLib)
+- return NS_OK;
++ 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;
++ }
++ }
+
+- PRLibrary *gnomeLib = PR_LoadLibrary("libgnome-2.so.0");
+- if (!gnomeLib) {
+- PR_UnloadLibrary(gnomeuiLib);
+- return NS_OK;
++ ++curarg;
+ }
+
+- _gnome_program_init_fn gnome_program_init =
+- (_gnome_program_init_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_init");
+- _gnome_program_get_fn gnome_program_get =
+- (_gnome_program_get_fn)PR_FindFunctionSymbol(gnomeLib, "gnome_program_get");
+- _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)PR_FindFunctionSymbol(gnomeuiLib, "libgnomeui_module_info_get");
+- if (!gnome_program_init || !gnome_program_get || !libgnomeui_module_info_get) {
+- PR_UnloadLibrary(gnomeuiLib);
+- PR_UnloadLibrary(gnomeLib);
+- return NS_OK;
++ if (prev_client_id.IsEmpty()) {
++ prev_client_id = getenv("DESKTOP_AUTOSTART_ID");
+ }
+
+-#endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
++ // We don't want child processes to use the same ID
++ unsetenv("DESKTOP_AUTOSTART_ID");
+
+-#ifdef ACCESSIBILITY
+- // We will load gail, atk-bridge by ourself later
+- // We can't run atk-bridge init here, because gail get the control
+- // Set GNOME_ACCESSIBILITY to 0 can avoid this
+- static const char *accEnv = "GNOME_ACCESSIBILITY";
+- const char *accOldValue = getenv(accEnv);
+- setenv(accEnv, "0", 1);
+-#endif
++ char *client_id = nullptr;
++ if (!sm_disable) {
++ PRLibrary *iceLib = PR_LoadLibrary("libICE.so.6");
++ if (!iceLib) {
++ return NS_OK;
++ }
+
+-#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
+- if (!gnome_program_get()) {
+- gnome_program_init("Gecko", "1.0", libgnomeui_module_info_get(),
+- gArgc, gArgv, nullptr);
+- }
+-#endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
++ PRLibrary *smLib = PR_LoadLibrary("libSM.so.6");
++ if (!smLib) {
++ PR_UnloadLibrary(iceLib);
++ return NS_OK;
++ }
+
+-#ifdef ACCESSIBILITY
+- if (accOldValue) {
+- setenv(accEnv, accOldValue, 1);
+- } else {
+- unsetenv(accEnv);
++ 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);
+ }
+-#endif
+
+- // Careful! These libraries cannot be unloaded after this point because
+- // gnome_program_init causes atexit handlers to be registered. Strange
+- // crashes will occur if these libraries are unloaded.
++ if (!mSessionConnection) {
++ return NS_OK;
++ }
+
+- // TODO GTK3 - see Bug 694570 - Stop using libgnome and libgnomeui on Linux
+-#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
+- gnome_client_set_restart_command = (_gnome_client_set_restart_command_fn)
+- PR_FindFunctionSymbol(gnomeuiLib, "gnome_client_set_restart_command");
++ 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);
++ }
+
+- _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
+- PR_FindFunctionSymbol(gnomeuiLib, "gnome_master_client");
++ gdk_x11_set_sm_client_id(client_id);
+
+- GnomeClient *client = gnome_master_client();
+- g_signal_connect(client, "save-yourself", G_CALLBACK(save_yourself_cb), nullptr);
+- g_signal_connect(client, "die", G_CALLBACK(die_cb), nullptr);
++ // Set SM Properties
++ // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required
++ // properties so must be set, and must have a sensible fallback value.
+
+- // Set the correct/requested restart command in any case.
++ // Determine executable path to use for XSMP session restore
+
+ // Is there a request to suppress default binary launcher?
+- nsAutoCString path;
+- char* argv1 = getenv("MOZ_APP_LAUNCHER");
++ nsAutoCString path(getenv("MOZ_APP_LAUNCHER"));
+
+- if(!argv1) {
+- // Tell the desktop the command for restarting us so that we can be part of XSMP session restore
++ if (path.IsEmpty()) {
+ NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
+ nsCOMPtr<nsIFile> executablePath;
+ nsresult rv;
+@@ -258,14 +621,60 @@ nsNativeAppSupportUnix::Start(bool *aRetVal)
+ }
+
+ executablePath->GetNativePath(path);
+- argv1 = (char*)(path.get());
+ }
+ }
+
+- if (argv1) {
+- gnome_client_set_restart_command(client, 1, &argv1);
++ 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()));
+ }
+-#endif /* MOZ_X11 && (MOZ_WIDGET_GTK == 2) */
++
++ 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;
+ }
+diff --git widget/gtk/compat/gdk/gdkx.h widget/gtk/compat/gdk/gdkx.h
+index 5d59720d2f91..240c12e3013a 100644
+--- widget/gtk/compat/gdk/gdkx.h
++++ widget/gtk/compat/gdk/gdkx.h
+@@ -5,9 +5,14 @@
+ #ifndef GDKX_WRAPPER_H
+ #define GDKX_WRAPPER_H
+
++#include <gtk/gtkversion.h>
++
+ #define gdk_x11_window_foreign_new_for_display gdk_x11_window_foreign_new_for_display_
+ #define gdk_x11_window_lookup_for_display gdk_x11_window_lookup_for_display_
+ #define gdk_x11_window_get_xid gdk_x11_window_get_xid_
++#if !GTK_CHECK_VERSION(2,24,0)
++#define gdk_x11_set_sm_client_id gdk_x11_set_sm_client_id_
++#endif
+ #include_next <gdk/gdkx.h>
+ #undef gdk_x11_window_foreign_new_for_display
+ #undef gdk_x11_window_lookup_for_display
+@@ -35,4 +40,12 @@ gdk_x11_window_get_xid(GdkWindow *window)
+ #define GDK_IS_X11_DISPLAY(a) (true)
+ #endif
+
++#if !GTK_CHECK_VERSION(2,24,0)
++#undef gdk_x11_set_sm_client_id
++static inline void
++gdk_x11_set_sm_client_id (const gchar *sm_client_id)
++{
++ gdk_set_sm_client_id(sm_client_id);
++}
++#endif
+ #endif /* GDKX_WRAPPER_H */
+diff --git widget/gtk/mozgtk/mozgtk.c widget/gtk/mozgtk/mozgtk.c
+index 0bb4dfd04144..17c98fe3dd61 100644
+--- widget/gtk/mozgtk/mozgtk.c
++++ widget/gtk/mozgtk/mozgtk.c
+@@ -132,6 +132,7 @@ STUB(gdk_x11_window_foreign_new_for_display)
+ STUB(gdk_x11_window_lookup_for_display)
+ STUB(gdk_x11_window_set_user_time)
+ STUB(gdk_x11_xatom_to_atom)
++STUB(gdk_x11_set_sm_client_id)
+ STUB(gtk_accel_label_new)
+ STUB(gtk_alignment_get_type)
+ STUB(gtk_alignment_new)