Backed out 11 changesets (bug 1518639, bug 513742) for chrome failures at browser/components/shell/test/test_headless_screenshot.html
authorCoroiu Cristina <ccoroiu@mozilla.com>
Wed, 06 Mar 2019 21:28:49 +0200
changeset 462750 3d8dd3615c4589c9cafe613a471152323078b5d9
parent 462749 84e8066625fd72fdb1eb6eab85621ae842fe91b4
child 462751 2a58c63890ccdbbeb846c45dea03cf35b566ebdc
push id35658
push userccoroiu@mozilla.com
push dateThu, 07 Mar 2019 04:34:33 +0000
treeherdermozilla-central@a6f8093bf1a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1518639, 513742
milestone67.0a1
backs out84e8066625fd72fdb1eb6eab85621ae842fe91b4
4ef3cc37f719d02443a2058192fdb4c61d3e3dca
276ca640adc8ff16ff3ff7252e8aa5016205b1e0
73ca9a68d7714e9bfc4d4ed59c8dda5ffdc3cd86
967993505a3d00a79cd81dccf66ffa0612a58ad4
fc466857ab39e3d2371f13ddae553c921fb727d2
28404f97bb22b726afee8df04184da81138497a2
5373c5bb9ad5bb7c3af1cae390c3612be51176b5
a7490cdfb635f95c1eb8c33283064842bc490cbd
28c7186745e3d5de5f44a72a81e0068cb23ce547
35287afd3acea1602bed159dc879aa666e64b9c8
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 11 changesets (bug 1518639, bug 513742) for chrome failures at browser/components/shell/test/test_headless_screenshot.html Backed out changeset 84e8066625fd (bug 1518639) Backed out changeset 4ef3cc37f719 (bug 513742) Backed out changeset 276ca640adc8 (bug 1518639) Backed out changeset 73ca9a68d771 (bug 1518639) Backed out changeset 967993505a3d (bug 1518639) Backed out changeset fc466857ab39 (bug 1518639) Backed out changeset 28404f97bb22 (bug 1518639) Backed out changeset 5373c5bb9ad5 (bug 1518639) Backed out changeset a7490cdfb635 (bug 1518639) Backed out changeset 28c7186745e3 (bug 1518639) Backed out changeset 35287afd3ace (bug 1518639)
ipc/glue/WindowsMessageLoop.cpp
toolkit/components/moz.build
toolkit/components/remote/RemoteUtils.cpp
toolkit/components/remote/RemoteUtils.h
toolkit/components/remote/components.conf
toolkit/components/remote/moz.build
toolkit/components/remote/nsDBusRemoteClient.cpp
toolkit/components/remote/nsDBusRemoteClient.h
toolkit/components/remote/nsDBusRemoteServer.cpp
toolkit/components/remote/nsDBusRemoteServer.h
toolkit/components/remote/nsDBusRemoteService.cpp
toolkit/components/remote/nsDBusRemoteService.h
toolkit/components/remote/nsGTKRemoteServer.cpp
toolkit/components/remote/nsGTKRemoteServer.h
toolkit/components/remote/nsGTKRemoteService.cpp
toolkit/components/remote/nsGTKRemoteService.h
toolkit/components/remote/nsIRemoteService.idl
toolkit/components/remote/nsRemoteClient.h
toolkit/components/remote/nsRemoteServer.h
toolkit/components/remote/nsRemoteService.cpp
toolkit/components/remote/nsRemoteService.h
toolkit/components/remote/nsUnixRemoteServer.cpp
toolkit/components/remote/nsUnixRemoteServer.h
toolkit/components/remote/nsWinRemoteClient.cpp
toolkit/components/remote/nsWinRemoteClient.h
toolkit/components/remote/nsWinRemoteServer.cpp
toolkit/components/remote/nsWinRemoteServer.h
toolkit/components/remote/nsWinRemoteUtils.h
toolkit/components/remote/nsXRemoteClient.cpp
toolkit/components/remote/nsXRemoteClient.h
toolkit/components/remote/nsXRemoteServer.cpp
toolkit/components/remote/nsXRemoteServer.h
toolkit/components/remote/nsXRemoteService.cpp
toolkit/components/remote/nsXRemoteService.h
toolkit/moz.configure
toolkit/toolkit.mozbuild
toolkit/xre/moz.build
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsINativeAppSupport.idl
toolkit/xre/nsNativeAppSupportBase.cpp
toolkit/xre/nsNativeAppSupportUnix.cpp
toolkit/xre/nsNativeAppSupportWin.cpp
toolkit/xre/nsNativeAppSupportWin.h
uriloader/exthandler/DBusHelpers.h
widget/xremoteclient/DBusRemoteClient.cpp
widget/xremoteclient/DBusRemoteClient.h
widget/xremoteclient/RemoteUtils.cpp
widget/xremoteclient/RemoteUtils.h
widget/xremoteclient/XRemoteClient.cpp
widget/xremoteclient/XRemoteClient.h
widget/xremoteclient/moz.build
widget/xremoteclient/nsRemoteClient.h
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -86,16 +86,19 @@ extern UINT sAppShellGeckoMsgId;
 namespace {
 
 const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc";
 const wchar_t k3rdPartyWindowProp[] = L"Mozilla3rdPartyWindow";
 
 // This isn't defined before Windows XP.
 enum { WM_XP_THEMECHANGED = 0x031A };
 
+char16_t gAppMessageWindowName[256] = {0};
+int32_t gAppMessageWindowNameLength = 0;
+
 nsTArray<HWND>* gNeuteredWindows = nullptr;
 
 typedef nsTArray<nsAutoPtr<DeferredMessage> > DeferredMessageArray;
 DeferredMessageArray* gDeferredMessages = nullptr;
 
 HHOOK gDeferredGetMsgHook = nullptr;
 HHOOK gDeferredCallWndProcHook = nullptr;
 
@@ -466,16 +469,44 @@ static bool WindowIsDeferredWindow(HWND 
 
   // Plugin windows that can trigger ipc calls in child:
   // 'ShockwaveFlashFullScreen' - flash fullscreen window
   if (className.EqualsLiteral("ShockwaveFlashFullScreen")) {
     SetPropW(hWnd, k3rdPartyWindowProp, (HANDLE)1);
     return true;
   }
 
+  // nsNativeAppSupport makes a window like "FirefoxMessageWindow" based on the
+  // toolkit app's name. It's pretty expensive to calculate this so we only try
+  // once.
+  if (gAppMessageWindowNameLength == 0) {
+    nsCOMPtr<nsIXULAppInfo> appInfo =
+        do_GetService("@mozilla.org/xre/app-info;1");
+    if (appInfo) {
+      nsAutoCString appName;
+      if (NS_SUCCEEDED(appInfo->GetName(appName))) {
+        appName.AppendLiteral("MessageWindow");
+        nsDependentString windowName(gAppMessageWindowName);
+        CopyUTF8toUTF16(appName, windowName);
+        gAppMessageWindowNameLength = windowName.Length();
+      }
+    }
+
+    // Don't try again if that failed.
+    if (gAppMessageWindowNameLength == 0) {
+      gAppMessageWindowNameLength = -1;
+    }
+  }
+
+  if (gAppMessageWindowNameLength != -1 &&
+      className.Equals(nsDependentString(gAppMessageWindowName,
+                                         gAppMessageWindowNameLength))) {
+    return true;
+  }
+
   return false;
 }
 
 bool NeuterWindowProcedure(HWND hWnd) {
   if (!WindowIsDeferredWindow(hWnd)) {
     // Some other kind of window, skip.
     return false;
   }
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -3,17 +3,17 @@
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'General')
 
 # These component dirs are built for all apps (including suite)
-if CONFIG['MOZ_HAS_REMOTE']:
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     DIRS += ['remote']
 
 DIRS += [
     'aboutcache',
     'aboutcheckerboard',
     'aboutmemory',
     'aboutperformance',
     'alerts',
new file mode 100644
--- /dev/null
+++ b/toolkit/components/remote/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+Classes = [
+    {
+        'cid': '{c0773e90-5799-4eff-ad03-3ebcd85624ac}',
+        'contract_ids': ['@mozilla.org/toolkit/remote-service;1'],
+        'type': 'nsRemoteService',
+        'headers': ['/toolkit/components/remote/nsRemoteService.h'],
+    },
+]
--- a/toolkit/components/remote/moz.build
+++ b/toolkit/components/remote/moz.build
@@ -2,38 +2,36 @@
 # vim: set filetype=python:
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'Startup and Profile System')
 
+XPIDL_SOURCES += [
+    'nsIRemoteService.idl',
+]
+
+XPIDL_MODULE = 'toolkitremote'
+
 SOURCES += [
-    'nsRemoteService.cpp',
+    'nsXRemoteService.cpp',
 ]
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     SOURCES += [
-        'nsGTKRemoteServer.cpp',
-        'nsUnixRemoteServer.cpp',
-        'nsXRemoteClient.cpp',
-        'nsXRemoteServer.cpp',
-        'RemoteUtils.cpp',
+        'nsGTKRemoteService.cpp',
+        'nsRemoteService.cpp',
     ]
     if CONFIG['MOZ_ENABLE_DBUS']:
         SOURCES += [
-            'nsDBusRemoteClient.cpp',
-            'nsDBusRemoteServer.cpp',
+            'nsDBusRemoteService.cpp',
         ]
         CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
-    CXXFLAGS += CONFIG['TK_CFLAGS']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
-    SOURCES += [
-        'nsWinRemoteClient.cpp',
-        'nsWinRemoteServer.cpp',
+    XPCOM_MANIFESTS += [
+        'components.conf',
     ]
 
-LOCAL_INCLUDES += [
-    '../../profile',
-]
 FINAL_LIBRARY = 'xul'
+
+CXXFLAGS += CONFIG['TK_CFLAGS']
rename from toolkit/components/remote/nsDBusRemoteServer.cpp
rename to toolkit/components/remote/nsDBusRemoteService.cpp
--- a/toolkit/components/remote/nsDBusRemoteServer.cpp
+++ b/toolkit/components/remote/nsDBusRemoteService.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=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 "nsDBusRemoteServer.h"
+#include "nsDBusRemoteService.h"
+#include "nsRemoteService.h"
 
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/Base64.h"
 #include "nsIServiceManager.h"
 #include "nsIWidget.h"
@@ -22,16 +23,18 @@
 
 #include "nsGTKToolkit.h"
 
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
 #include <dlfcn.h>
 
+NS_IMPL_ISUPPORTS(nsDBusRemoteService, nsIRemoteService)
+
 const char *introspect_template =
     "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection "
     "1.0//EN\"\n"
     "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\";>\n"
     "<node>\n"
     " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
     "   <method name=\"Introspect\">\n"
     "     <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
@@ -39,17 +42,17 @@ const char *introspect_template =
     " </interface>\n"
     " <interface name=\"org.mozilla.%s\">\n"
     "   <method name=\"OpenURL\">\n"
     "     <arg name=\"url\" direction=\"in\" type=\"s\"/>\n"
     "   </method>\n"
     " </interface>\n"
     "</node>\n";
 
-DBusHandlerResult nsDBusRemoteServer::Introspect(DBusMessage *msg) {
+DBusHandlerResult nsDBusRemoteService::Introspect(DBusMessage *msg) {
   DBusMessage *reply;
 
   reply = dbus_message_new_method_return(msg);
   if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
   nsAutoCString introspect_xml;
   introspect_xml = nsPrintfCString(introspect_template, mAppName.get());
 
@@ -58,43 +61,43 @@ DBusHandlerResult nsDBusRemoteServer::In
                            DBUS_TYPE_INVALID);
 
   dbus_connection_send(mConnection, reply, nullptr);
   dbus_message_unref(reply);
 
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-DBusHandlerResult nsDBusRemoteServer::OpenURL(DBusMessage *msg) {
+DBusHandlerResult nsDBusRemoteService::OpenURL(DBusMessage *msg) {
   DBusMessage *reply = nullptr;
   const char *commandLine;
   int length;
 
   if (!dbus_message_get_args(msg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
                              &commandLine, &length, DBUS_TYPE_INVALID) ||
       length == 0) {
     nsAutoCString errorMsg;
     errorMsg = nsPrintfCString("org.mozilla.%s.Error", mAppName.get());
     reply = dbus_message_new_error(msg, errorMsg.get(), "Wrong argument");
   } else {
     guint32 timestamp = gtk_get_current_event_time();
     if (timestamp == GDK_CURRENT_TIME) {
       timestamp = guint32(g_get_monotonic_time() / 1000);
     }
-    HandleCommandLine(commandLine, timestamp);
+    nsRemoteService::HandleCommandLine(commandLine, timestamp);
     reply = dbus_message_new_method_return(msg);
   }
 
   dbus_connection_send(mConnection, reply, nullptr);
   dbus_message_unref(reply);
 
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-DBusHandlerResult nsDBusRemoteServer::HandleDBusMessage(
+DBusHandlerResult nsDBusRemoteService::HandleDBusMessage(
     DBusConnection *aConnection, DBusMessage *msg) {
   NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection.");
 
   const char *method = dbus_message_get_member(msg);
   const char *iface = dbus_message_get_interface(msg);
 
   if ((strcmp("Introspect", method) == 0) &&
       (strcmp("org.freedesktop.DBus.Introspectable", iface) == 0)) {
@@ -107,39 +110,39 @@ DBusHandlerResult nsDBusRemoteServer::Ha
   if ((strcmp("OpenURL", method) == 0) &&
       (strcmp(ourInterfaceName.get(), iface) == 0)) {
     return OpenURL(msg);
   }
 
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
-void nsDBusRemoteServer::UnregisterDBusInterface(DBusConnection *aConnection) {
+void nsDBusRemoteService::UnregisterDBusInterface(DBusConnection *aConnection) {
   NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection.");
   // Not implemented
 }
 
 static DBusHandlerResult message_handler(DBusConnection *conn, DBusMessage *msg,
                                          void *user_data) {
-  auto interface = static_cast<nsDBusRemoteServer *>(user_data);
+  auto interface = static_cast<nsDBusRemoteService *>(user_data);
   return interface->HandleDBusMessage(conn, msg);
 }
 
 static void unregister(DBusConnection *conn, void *user_data) {
-  auto interface = static_cast<nsDBusRemoteServer *>(user_data);
+  auto interface = static_cast<nsDBusRemoteService *>(user_data);
   interface->UnregisterDBusInterface(conn);
 }
 
 static DBusObjectPathVTable remoteHandlersTable = {
     .unregister_function = unregister,
     .message_function = message_handler,
 };
 
-nsresult nsDBusRemoteServer::Startup(const char *aAppName,
-                                     const char *aProfileName) {
+NS_IMETHODIMP
+nsDBusRemoteService::Startup(const char *aAppName, const char *aProfileName) {
   if (mConnection && dbus_connection_get_is_connected(mConnection)) {
     // We're already connected so we don't need to reconnect
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
   // Don't even try to start without any application/profile name
   if (!aAppName || aAppName[0] == '\0' || !aProfileName ||
       aProfileName[0] == '\0')
@@ -202,18 +205,16 @@ nsresult nsDBusRemoteServer::Startup(con
                                             &remoteHandlersTable, this)) {
     mConnection = nullptr;
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-void nsDBusRemoteServer::Shutdown() {
-  if (!mConnection) {
-    return;
-  }
-
+NS_IMETHODIMP
+nsDBusRemoteService::Shutdown() {
   dbus_connection_unregister_object_path(mConnection, mPathName.get());
 
   // dbus_connection_unref() will be called by RefPtr here.
   mConnection = nullptr;
+  return NS_OK;
 }
rename from toolkit/components/remote/nsDBusRemoteServer.h
rename to toolkit/components/remote/nsDBusRemoteService.h
--- a/toolkit/components/remote/nsDBusRemoteServer.h
+++ b/toolkit/components/remote/nsDBusRemoteService.h
@@ -1,38 +1,39 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=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/. */
 
-#ifndef __nsDBusRemoteServer_h__
-#define __nsDBusRemoteServer_h__
+#ifndef __nsDBusRemoteService_h__
+#define __nsDBusRemoteService_h__
 
-#include "nsRemoteServer.h"
-#include "nsUnixRemoteServer.h"
+#include "nsIRemoteService.h"
 #include "mozilla/DBusHelpers.h"
+#include "nsString.h"
 
-class nsDBusRemoteServer final : public nsRemoteServer,
-                                 public nsUnixRemoteServer {
+class nsDBusRemoteService final : public nsIRemoteService {
  public:
-  nsDBusRemoteServer() : mConnection(nullptr), mAppName(nullptr) {}
-  ~nsDBusRemoteServer() override { Shutdown(); }
+  // We will be a static singleton, so don't use the ordinary methods.
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREMOTESERVICE
 
-  nsresult Startup(const char *aAppName, const char *aProfileName) override;
-  void Shutdown() override;
+  nsDBusRemoteService() : mConnection(nullptr), mAppName(nullptr) {}
 
   DBusHandlerResult HandleDBusMessage(DBusConnection *aConnection,
                                       DBusMessage *msg);
   void UnregisterDBusInterface(DBusConnection *aConnection);
 
  private:
+  ~nsDBusRemoteService() {}
+
   DBusHandlerResult OpenURL(DBusMessage *msg);
   DBusHandlerResult Introspect(DBusMessage *msg);
 
   // The connection is owned by DBus library
   RefPtr<DBusConnection> mConnection;
   nsCString mAppName;
   nsCString mPathName;
 };
 
-#endif  // __nsDBusRemoteServer_h__
+#endif  // __nsDBusRemoteService_h__
rename from toolkit/components/remote/nsGTKRemoteServer.cpp
rename to toolkit/components/remote/nsGTKRemoteService.cpp
--- a/toolkit/components/remote/nsGTKRemoteServer.cpp
+++ b/toolkit/components/remote/nsGTKRemoteService.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=8:
  */
 /* 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 "nsGTKRemoteServer.h"
+#include "nsGTKRemoteService.h"
 
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
 #include "nsPIDOMWindow.h"
@@ -18,57 +18,58 @@
 #include "nsIServiceManager.h"
 #include "nsIAppShellService.h"
 #include "nsAppShellCID.h"
 
 #include "nsCOMPtr.h"
 
 #include "nsGTKToolkit.h"
 
-nsresult nsGTKRemoteServer::Startup(const char* aAppName,
-                                    const char* aProfileName) {
+NS_IMPL_ISUPPORTS(nsGTKRemoteService, nsIRemoteService)
+
+NS_IMETHODIMP
+nsGTKRemoteService::Startup(const char* aAppName, const char* aProfileName) {
   NS_ASSERTION(aAppName, "Don't pass a null appname!");
 
-  if (mServerWindow) {
-    return NS_ERROR_ALREADY_INITIALIZED;
-  }
+  if (mServerWindow) return NS_ERROR_ALREADY_INITIALIZED;
 
   XRemoteBaseStartup(aAppName, aProfileName);
 
   mServerWindow = gtk_invisible_new();
   gtk_widget_realize(mServerWindow);
   HandleCommandsFor(mServerWindow);
 
   return NS_OK;
 }
 
-void nsGTKRemoteServer::Shutdown() {
-  if (!mServerWindow) {
-    return;
-  }
+NS_IMETHODIMP
+nsGTKRemoteService::Shutdown() {
+  if (!mServerWindow) return NS_ERROR_NOT_INITIALIZED;
 
   gtk_widget_destroy(mServerWindow);
   mServerWindow = nullptr;
+
+  return NS_OK;
 }
 
-void nsGTKRemoteServer::HandleCommandsFor(GtkWidget* widget) {
+void nsGTKRemoteService::HandleCommandsFor(GtkWidget* widget) {
   g_signal_connect(G_OBJECT(widget), "property_notify_event",
-                   G_CALLBACK(HandlePropertyChange), this);
+                   G_CALLBACK(HandlePropertyChange), nullptr);
 
   gtk_widget_add_events(widget, GDK_PROPERTY_CHANGE_MASK);
 
   Window window = gdk_x11_window_get_xid(gtk_widget_get_window(widget));
-  nsXRemoteServer::HandleCommandsFor(window);
+  nsXRemoteService::HandleCommandsFor(window);
 }
 
-gboolean nsGTKRemoteServer::HandlePropertyChange(GtkWidget* aWidget,
-                                                 GdkEventProperty* pevent,
-                                                 nsGTKRemoteServer* aThis) {
+gboolean nsGTKRemoteService::HandlePropertyChange(GtkWidget* aWidget,
+                                                  GdkEventProperty* pevent,
+                                                  void* aData) {
   if (pevent->state == GDK_PROPERTY_NEW_VALUE) {
     Atom changedAtom = gdk_x11_atom_to_xatom(pevent->atom);
 
     XID window = gdk_x11_window_get_xid(gtk_widget_get_window(aWidget));
-    return aThis->HandleNewProperty(
-        window, GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), pevent->time,
-        changedAtom);
+    return HandleNewProperty(window,
+                             GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
+                             pevent->time, changedAtom);
   }
   return FALSE;
 }
rename from toolkit/components/remote/nsGTKRemoteServer.h
rename to toolkit/components/remote/nsGTKRemoteService.h
--- a/toolkit/components/remote/nsGTKRemoteServer.h
+++ b/toolkit/components/remote/nsGTKRemoteService.h
@@ -1,37 +1,38 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=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/. */
 
-#ifndef __nsGTKRemoteServer_h__
-#define __nsGTKRemoteServer_h__
+#ifndef __nsGTKRemoteService_h__
+#define __nsGTKRemoteService_h__
 
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 
-#include "nsRemoteServer.h"
-#include "nsXRemoteServer.h"
+#include "nsIRemoteService.h"
+#include "nsXRemoteService.h"
 #include "mozilla/Attributes.h"
 
-class nsGTKRemoteServer final : public nsXRemoteServer {
+class nsGTKRemoteService final : public nsIRemoteService,
+                                 public nsXRemoteService {
  public:
-  nsGTKRemoteServer() : mServerWindow(nullptr) {}
-  ~nsGTKRemoteServer() override { Shutdown(); }
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREMOTESERVICE
 
-  nsresult Startup(const char* aAppName, const char* aProfileName) override;
-  void Shutdown() override;
+  nsGTKRemoteService() : mServerWindow(nullptr) {}
 
   static gboolean HandlePropertyChange(GtkWidget* widget,
-                                       GdkEventProperty* event,
-                                       nsGTKRemoteServer* aData);
+                                       GdkEventProperty* event, void* aData);
 
  private:
+  ~nsGTKRemoteService() {}
+
   void HandleCommandsFor(GtkWidget* aWidget);
 
   GtkWidget* mServerWindow;
 };
 
 #endif  // __nsGTKRemoteService_h__
new file mode 100644
--- /dev/null
+++ b/toolkit/components/remote/nsIRemoteService.idl
@@ -0,0 +1,38 @@
+/* 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 "nsISupports.idl"
+
+interface mozIDOMWindow;
+
+/**
+ * Start and stop the remote service (xremote/phremote), and register
+ * windows with the service for backwards compatibility with old xremote
+ * clients.
+ *
+ * @status FLUID This interface is not frozen and is not intended for embedders
+ *               who want a frozen API. If you are an embedder and need this
+ *               functionality, contact Benjamin Smedberg about the possibility
+ *               of freezing the functionality you need.
+ */
+
+[scriptable, uuid(bf23f1c3-7012-42dd-b0bb-a84060ccc52e)]
+interface nsIRemoteService : nsISupports
+{
+  /**
+   * Start the remote service. This should not be done until app startup
+   * appears to have been successful.
+   *
+   * @param appName     (Required) Sets a window property identifying the
+   *                    application.
+   * @param profileName (May be null) Sets a window property identifying the
+   *                    profile name.
+   */
+  void startup(in string appName, in string profileName);
+
+  /**
+   * Stop the remote service from accepting additional requests.
+   */
+  void shutdown();
+};
deleted file mode 100644
--- a/toolkit/components/remote/nsRemoteServer.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=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/. */
-
-#ifndef __nsRemoteServer_h__
-#define __nsRemoteServer_h__
-
-#include "nsString.h"
-
-class nsRemoteServer {
- public:
-  virtual ~nsRemoteServer() = default;
-
-  virtual nsresult Startup(const char* aAppName, const char* aProfileName) = 0;
-  virtual void Shutdown() = 0;
-};
-
-#endif  // __nsRemoteServer_h__
--- a/toolkit/components/remote/nsRemoteService.cpp
+++ b/toolkit/components/remote/nsRemoteService.cpp
@@ -1,187 +1,183 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=8:
  */
 /* 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/. */
 
-#ifdef XP_UNIX
-#  include <sys/types.h>
-#  include <pwd.h>
-#endif
-
-#ifdef MOZ_WIDGET_GTK
-#  include "nsGTKRemoteServer.h"
-#  include "nsXRemoteClient.h"
-#  ifdef MOZ_ENABLE_DBUS
-#    include "nsDBusRemoteServer.h"
-#    include "nsDBusRemoteClient.h"
-#  endif
-#elif defined(XP_WIN)
-#  include "nsWinRemoteServer.h"
-#  include "nsWinRemoteClient.h"
+#include "nsGTKRemoteService.h"
+#ifdef MOZ_ENABLE_DBUS
+#  include "nsDBusRemoteService.h"
 #endif
 #include "nsRemoteService.h"
 
-#include "nsString.h"
-#include "nsServiceManagerUtils.h"
-#include "mozilla/ModuleUtils.h"
-#include "SpecialSystemDirectory.h"
-#include "mozilla/CmdLineAndEnvUtils.h"
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
 
-// Time to wait for the remoting service to start
-#define START_TIMEOUT_SEC 5
-#define START_SLEEP_MSEC 100
-
-using namespace mozilla;
-
-extern int gArgc;
-extern char** gArgv;
-
-using namespace mozilla;
-
-NS_IMPL_ISUPPORTS(nsRemoteService, nsIObserver)
+#include "nsIServiceManager.h"
+#include "nsIAppShellService.h"
+#include "nsAppShellCID.h"
+#include "nsInterfaceHashtable.h"
+#include "nsGTKToolkit.h"
+#include "nsICommandLineRunner.h"
+#include "nsCommandLine.h"
+#include "nsString.h"
+#include "nsIFile.h"
 
-nsRemoteService::nsRemoteService(const char* aProgram) : mProgram(aProgram) {
-  ToLowerCase(mProgram);
-}
+NS_IMPL_ISUPPORTS(nsRemoteService, nsIRemoteService, nsIObserver)
 
-void nsRemoteService::SetProfile(nsACString& aProfile) {
-  mProfile = aProfile;
-}
+NS_IMETHODIMP
+nsRemoteService::Startup(const char* aAppName, const char* aProfileName) {
+  bool useX11Remote = GDK_IS_X11_DISPLAY(gdk_display_get_default());
 
-void nsRemoteService::LockStartup() {
-  nsCOMPtr<nsIFile> mutexDir;
-  nsresult rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
-                                          getter_AddRefs(mutexDir));
-  if (NS_SUCCEEDED(rv)) {
-    mutexDir->AppendNative(mProgram);
-
-    rv = mutexDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
-    if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
-      mRemoteLockDir = mutexDir;
+#if defined(MOZ_ENABLE_DBUS)
+  if (!useX11Remote) {
+    nsresult rv;
+    mDBusRemoteService = new nsDBusRemoteService();
+    rv = mDBusRemoteService->Startup(aAppName, aProfileName);
+    if (NS_FAILED(rv)) {
+      mDBusRemoteService = nullptr;
     }
   }
-
-  if (mRemoteLockDir) {
-    const mozilla::TimeStamp epoch = mozilla::TimeStamp::Now();
-    do {
-      rv = mRemoteLock.Lock(mRemoteLockDir, nullptr);
-      if (NS_SUCCEEDED(rv)) break;
-      PR_Sleep(START_SLEEP_MSEC);
-    } while ((mozilla::TimeStamp::Now() - epoch) <
-             mozilla::TimeDuration::FromSeconds(START_TIMEOUT_SEC));
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Cannot lock remote start mutex");
-    }
-  }
-}
-
-void nsRemoteService::UnlockStartup() {
-  mRemoteLock.Unlock();
-  mRemoteLock.Cleanup();
-
-  if (mRemoteLockDir) {
-    mRemoteLockDir->Remove(false);
-    mRemoteLockDir = nullptr;
-  }
-}
-
-RemoteResult nsRemoteService::StartClient(const char* aDesktopStartupID) {
-  if (mProfile.IsEmpty()) {
-    return REMOTE_NOT_FOUND;
+#endif
+  if (useX11Remote) {
+    mGtkRemoteService = new nsGTKRemoteService();
+    mGtkRemoteService->Startup(aAppName, aProfileName);
   }
 
-  nsAutoPtr<nsRemoteClient> client;
-
-#ifdef MOZ_WIDGET_GTK
-  bool useX11Remote = GDK_IS_X11_DISPLAY(gdk_display_get_default());
-
-#  if defined(MOZ_ENABLE_DBUS)
-  if (!useX11Remote) {
-    client = new nsDBusRemoteClient();
-  }
-#  endif
-  if (useX11Remote) {
-    client = new nsXRemoteClient();
-  }
-#elif defined(XP_WIN)
-  client = new nsWinRemoteClient();
-#else
-  return REMOTE_NOT_FOUND;
-#endif
-
-  nsresult rv = client ? client->Init() : NS_ERROR_FAILURE;
-  if (NS_FAILED(rv)) return REMOTE_NOT_FOUND;
-
-  nsCString response;
-  bool success = false;
-  rv = client->SendCommandLine(mProgram.get(), mProfile.get(), gArgc, gArgv,
-                               aDesktopStartupID, getter_Copies(response),
-                               &success);
-  // did the command fail?
-  if (!success) return REMOTE_NOT_FOUND;
-
-  // The "command not parseable" error is returned when the
-  // nsICommandLineHandler throws a NS_ERROR_ABORT.
-  if (response.EqualsLiteral("500 command not parseable"))
-    return REMOTE_ARG_BAD;
-
-  if (NS_FAILED(rv)) return REMOTE_NOT_FOUND;
-
-  return REMOTE_FOUND;
-}
-
-void nsRemoteService::StartupServer() {
-  if (mRemoteServer) {
-    return;
-  }
-
-  if (mProfile.IsEmpty()) {
-    return;
-  }
-
-#ifdef MOZ_WIDGET_GTK
-  bool useX11Remote = GDK_IS_X11_DISPLAY(gdk_display_get_default());
-
-#  if defined(MOZ_ENABLE_DBUS)
-  if (!useX11Remote) {
-    mRemoteServer = MakeUnique<nsDBusRemoteServer>();
-  }
-#  endif
-  if (useX11Remote) {
-    mRemoteServer = MakeUnique<nsGTKRemoteServer>();
-  }
-#elif defined(XP_WIN)
-  mRemoteServer = MakeUnique<nsWinRemoteServer>();
-#else
-  return;
-#endif
-
-  nsresult rv = mRemoteServer->Startup(mProgram.get(), mProfile.get());
-
-  if (NS_FAILED(rv)) {
-    mRemoteServer = nullptr;
-    return;
-  }
+  if (!mDBusRemoteService && !mGtkRemoteService) return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIObserverService> obs(
       do_GetService("@mozilla.org/observer-service;1"));
   if (obs) {
     obs->AddObserver(this, "xpcom-shutdown", false);
     obs->AddObserver(this, "quit-application", false);
   }
+
+  return NS_OK;
 }
 
-void nsRemoteService::ShutdownServer() { mRemoteServer = nullptr; }
+NS_IMETHODIMP
+nsRemoteService::Shutdown() {
+#if defined(MOZ_ENABLE_DBUS)
+  if (mDBusRemoteService) {
+    mDBusRemoteService->Shutdown();
+    mDBusRemoteService = nullptr;
+  }
+#endif
+  if (mGtkRemoteService) {
+    mGtkRemoteService->Shutdown();
+    mGtkRemoteService = nullptr;
+  }
+  return NS_OK;
+}
 
-nsRemoteService::~nsRemoteService() { ShutdownServer(); }
+nsRemoteService::~nsRemoteService() { Shutdown(); }
 
 NS_IMETHODIMP
 nsRemoteService::Observe(nsISupports* aSubject, const char* aTopic,
                          const char16_t* aData) {
   // This can be xpcom-shutdown or quit-application, but it's the same either
   // way.
-  ShutdownServer();
+  Shutdown();
   return NS_OK;
 }
+
+// Set desktop startup ID to the passed ID, if there is one, so that any created
+// windows get created with the right window manager metadata, and any windows
+// that get new tabs and are activated also get the right WM metadata.
+// The timestamp will be used if there is no desktop startup ID, or if we're
+// raising an existing window rather than showing a new window for the first
+// time.
+void nsRemoteService::SetDesktopStartupIDOrTimestamp(
+    const nsACString& aDesktopStartupID, uint32_t aTimestamp) {
+  nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
+  if (!toolkit) return;
+
+  if (!aDesktopStartupID.IsEmpty()) {
+    toolkit->SetDesktopStartupID(aDesktopStartupID);
+  }
+
+  toolkit->SetFocusTimestamp(aTimestamp);
+}
+
+static bool FindExtensionParameterInCommand(const char* aParameterName,
+                                            const nsACString& aCommand,
+                                            char aSeparator,
+                                            nsACString* aValue) {
+  nsAutoCString searchFor;
+  searchFor.Append(aSeparator);
+  searchFor.Append(aParameterName);
+  searchFor.Append('=');
+
+  nsACString::const_iterator start, end;
+  aCommand.BeginReading(start);
+  aCommand.EndReading(end);
+  if (!FindInReadable(searchFor, start, end)) return false;
+
+  nsACString::const_iterator charStart, charEnd;
+  charStart = end;
+  aCommand.EndReading(charEnd);
+  nsACString::const_iterator idStart = charStart, idEnd;
+  if (FindCharInReadable(aSeparator, charStart, charEnd)) {
+    idEnd = charStart;
+  } else {
+    idEnd = charEnd;
+  }
+  *aValue = nsDependentCSubstring(idStart, idEnd);
+  return true;
+}
+
+const char* nsRemoteService::HandleCommandLine(const char* aBuffer,
+                                               uint32_t aTimestamp) {
+  nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
+
+  // the commandline property is constructed as an array of int32_t
+  // followed by a series of null-terminated strings:
+  //
+  // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
+  // (offset is from the beginning of the buffer)
+
+  int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer));
+  const char* wd = aBuffer + ((argc + 1) * sizeof(int32_t));
+
+  nsCOMPtr<nsIFile> lf;
+  nsresult rv =
+      NS_NewNativeLocalFile(nsDependentCString(wd), true, getter_AddRefs(lf));
+  if (NS_FAILED(rv)) return "509 internal error";
+
+  nsAutoCString desktopStartupID;
+
+  const char** argv = (const char**)malloc(sizeof(char*) * argc);
+  if (!argv) return "509 internal error";
+
+  const int32_t* offset = reinterpret_cast<const int32_t*>(aBuffer) + 1;
+
+  for (int i = 0; i < argc; ++i) {
+    argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
+
+    if (i == 0) {
+      nsDependentCString cmd(argv[0]);
+      FindExtensionParameterInCommand("DESKTOP_STARTUP_ID", cmd, ' ',
+                                      &desktopStartupID);
+    }
+  }
+
+  rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
+
+  free(argv);
+  if (NS_FAILED(rv)) {
+    return "509 internal error";
+  }
+
+  SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
+
+  rv = cmdline->Run();
+
+  if (NS_ERROR_ABORT == rv) return "500 command not parseable";
+
+  if (NS_FAILED(rv)) return "509 internal error";
+
+  return "200 executed command";
+}
--- a/toolkit/components/remote/nsRemoteService.h
+++ b/toolkit/components/remote/nsRemoteService.h
@@ -3,49 +3,36 @@
  */
 /* 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/. */
 
 #ifndef __nsRemoteService_h__
 #define __nsRemoteService_h__
 
-#include "nsRemoteServer.h"
+#include "nsIRemoteService.h"
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
 #include "nsPIDOMWindow.h"
-#include "mozilla/UniquePtr.h"
-#include "nsIFile.h"
-#include "nsProfileLock.h"
 
-enum RemoteResult {
-  REMOTE_NOT_FOUND = 0,
-  REMOTE_FOUND = 1,
-  REMOTE_ARG_BAD = 2
-};
-
-class nsRemoteService final : public nsIObserver {
+class nsRemoteService final : public nsIRemoteService, public nsIObserver {
  public:
   // We will be a static singleton, so don't use the ordinary methods.
   NS_DECL_ISUPPORTS
+  NS_DECL_NSIREMOTESERVICE
   NS_DECL_NSIOBSERVER
 
-  explicit nsRemoteService(const char* aProgram);
-  void SetProfile(nsACString& aProfile);
+  static const char* HandleCommandLine(const char* aBuffer,
+                                       uint32_t aTimestamp);
 
-  void LockStartup();
-  void UnlockStartup();
+  nsCOMPtr<nsIRemoteService> mDBusRemoteService;
+  nsCOMPtr<nsIRemoteService> mGtkRemoteService;
 
-  RemoteResult StartClient(const char* aDesktopStartupID);
-  void StartupServer();
-  void ShutdownServer();
+  nsRemoteService() {}
 
  private:
   ~nsRemoteService();
 
-  mozilla::UniquePtr<nsRemoteServer> mRemoteServer;
-  nsProfileLock mRemoteLock;
-  nsCOMPtr<nsIFile> mRemoteLockDir;
-  nsCString mProgram;
-  nsCString mProfile;
+  static void SetDesktopStartupIDOrTimestamp(
+      const nsACString& aDesktopStartupID, uint32_t aTimestamp);
 };
 
 #endif  // __nsRemoteService_h__
deleted file mode 100644
--- a/toolkit/components/remote/nsUnixRemoteServer.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=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 "nsUnixRemoteServer.h"
-#include "nsGTKToolkit.h"
-#include "nsCOMPtr.h"
-#include "nsICommandLineRunner.h"
-#include "nsCommandLine.h"
-#include "nsIFile.h"
-
-// Set desktop startup ID to the passed ID, if there is one, so that any created
-// windows get created with the right window manager metadata, and any windows
-// that get new tabs and are activated also get the right WM metadata.
-// The timestamp will be used if there is no desktop startup ID, or if we're
-// raising an existing window rather than showing a new window for the first
-// time.
-void nsUnixRemoteServer::SetDesktopStartupIDOrTimestamp(
-    const nsACString& aDesktopStartupID, uint32_t aTimestamp) {
-  nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
-  if (!toolkit) return;
-
-  if (!aDesktopStartupID.IsEmpty()) {
-    toolkit->SetDesktopStartupID(aDesktopStartupID);
-  }
-
-  toolkit->SetFocusTimestamp(aTimestamp);
-}
-
-static bool FindExtensionParameterInCommand(const char* aParameterName,
-                                            const nsACString& aCommand,
-                                            char aSeparator,
-                                            nsACString* aValue) {
-  nsAutoCString searchFor;
-  searchFor.Append(aSeparator);
-  searchFor.Append(aParameterName);
-  searchFor.Append('=');
-
-  nsACString::const_iterator start, end;
-  aCommand.BeginReading(start);
-  aCommand.EndReading(end);
-  if (!FindInReadable(searchFor, start, end)) return false;
-
-  nsACString::const_iterator charStart, charEnd;
-  charStart = end;
-  aCommand.EndReading(charEnd);
-  nsACString::const_iterator idStart = charStart, idEnd;
-  if (FindCharInReadable(aSeparator, charStart, charEnd)) {
-    idEnd = charStart;
-  } else {
-    idEnd = charEnd;
-  }
-  *aValue = nsDependentCSubstring(idStart, idEnd);
-  return true;
-}
-
-const char* nsUnixRemoteServer::HandleCommandLine(const char* aBuffer,
-                                                  uint32_t aTimestamp) {
-  nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
-
-  // the commandline property is constructed as an array of int32_t
-  // followed by a series of null-terminated strings:
-  //
-  // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
-  // (offset is from the beginning of the buffer)
-
-  int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer));
-  const char* wd = aBuffer + ((argc + 1) * sizeof(int32_t));
-
-  nsCOMPtr<nsIFile> lf;
-  nsresult rv =
-      NS_NewNativeLocalFile(nsDependentCString(wd), true, getter_AddRefs(lf));
-  if (NS_FAILED(rv)) return "509 internal error";
-
-  nsAutoCString desktopStartupID;
-
-  const char** argv = (const char**)malloc(sizeof(char*) * argc);
-  if (!argv) return "509 internal error";
-
-  const int32_t* offset = reinterpret_cast<const int32_t*>(aBuffer) + 1;
-
-  for (int i = 0; i < argc; ++i) {
-    argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
-
-    if (i == 0) {
-      nsDependentCString cmd(argv[0]);
-      FindExtensionParameterInCommand("DESKTOP_STARTUP_ID", cmd, ' ',
-                                      &desktopStartupID);
-    }
-  }
-
-  rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
-
-  free(argv);
-  if (NS_FAILED(rv)) {
-    return "509 internal error";
-  }
-
-  SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
-
-  rv = cmdline->Run();
-
-  if (NS_ERROR_ABORT == rv) return "500 command not parseable";
-
-  if (NS_FAILED(rv)) return "509 internal error";
-
-  return "200 executed command";
-}
deleted file mode 100644
--- a/toolkit/components/remote/nsUnixRemoteServer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=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/. */
-
-#ifndef __nsUnixRemoteServer_h__
-#define __nsUnixRemoteServer_h__
-
-#include "nsString.h"
-
-#ifdef IS_BIG_ENDIAN
-#  define TO_LITTLE_ENDIAN32(x)                           \
-    ((((x)&0xff000000) >> 24) | (((x)&0x00ff0000) >> 8) | \
-     (((x)&0x0000ff00) << 8) | (((x)&0x000000ff) << 24))
-#else
-#  define TO_LITTLE_ENDIAN32(x) (x)
-#endif
-
-class nsUnixRemoteServer {
- protected:
-  void SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID,
-                                      uint32_t aTimestamp);
-  const char* HandleCommandLine(const char* aBuffer, uint32_t aTimestamp);
-};
-
-#endif  // __nsGTKRemoteService_h__
deleted file mode 100644
--- a/toolkit/components/remote/nsWinRemoteClient.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=4:tabstop=4:
- */
-/* 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 "nsWinRemoteClient.h"
-#include "nsWinRemoteUtils.h"
-
-#include <windows.h>
-
-using namespace mozilla;
-
-nsresult nsWinRemoteClient::Init() {
-  return NS_OK;
-}
-
-nsresult nsWinRemoteClient::SendCommandLine(const char *aProgram, const char *aProfile,
-                                            int32_t argc, char **argv,
-                                            const char *aDesktopStartupID,
-                                            char **aResponse, bool *aSucceeded) {
-  *aSucceeded = false;
-
-  nsString className;
-  BuildClassName(aProgram, aProfile, className);
-
-  HWND handle = ::FindWindowW(className.get(), 0);
-
-  if (!handle) {
-    return NS_OK;
-  }
-
-  WCHAR *cmd = ::GetCommandLineW();
-  WCHAR cwd[MAX_PATH];
-  _wgetcwd(cwd, MAX_PATH);
-
-  // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
-  NS_ConvertUTF16toUTF8 utf8buffer(cmd);
-  utf8buffer.Append('\0');
-  WCHAR *cwdPtr = cwd;
-  AppendUTF16toUTF8(MakeStringSpan(reinterpret_cast<char16_t *>(cwdPtr)),
-                    utf8buffer);
-  utf8buffer.Append('\0');
-
-  // We used to set dwData to zero, when we didn't send the working dir.
-  // Now we're using it as a version number.
-  COPYDATASTRUCT cds = {1, utf8buffer.Length(), (void *)utf8buffer.get()};
-  // Bring the already running Mozilla process to the foreground.
-  // nsWindow will restore the window (if minimized) and raise it.
-  ::SetForegroundWindow(handle);
-  ::SendMessage(handle, WM_COPYDATA, 0, (LPARAM)&cds);
-
-  *aSucceeded = true;
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/toolkit/components/remote/nsWinRemoteClient.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=4:tabstop=4:
- */
-/* 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/. */
-
-#ifndef nsWinRemoteClient_h__
-#define nsWinRemoteClient_h__
-
-#include "nscore.h"
-#include "nsRemoteClient.h"
-
-/**
- * Pure-virtual common base class for remoting implementations.
- */
-
-class nsWinRemoteClient : public nsRemoteClient {
- public:
-  virtual ~nsWinRemoteClient() = default;
-
-  nsresult Init() override;
-
-  nsresult SendCommandLine(const char *aProgram, const char *aProfile,
-                           int32_t argc, char **argv,
-                           const char *aDesktopStartupID,
-                           char **aResponse, bool *aSucceeded) override;
-};
-
-#endif  // nsWinRemoteClient_h__
deleted file mode 100644
--- a/toolkit/components/remote/nsWinRemoteServer.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=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 "nsWinRemoteServer.h"
-#include "nsWinRemoteUtils.h"
-#include "nsCOMPtr.h"
-#include "nsIComponentManager.h"
-#include "nsIServiceManager.h"
-#include "nsIDOMChromeWindow.h"
-#include "nsXPCOM.h"
-#include "nsPIDOMWindow.h"
-#include "nsIWindowMediator.h"
-#include "nsIBaseWindow.h"
-#include "nsIWidget.h"
-#include "nsICommandLineRunner.h"
-#include "nsICommandLine.h"
-#include "nsCommandLine.h"
-#include "nsIDocShell.h"
-
-HWND hwndForDOMWindow(mozIDOMWindowProxy *window) {
-  if (!window) {
-    return 0;
-  }
-  nsCOMPtr<nsPIDOMWindowOuter> pidomwindow = nsPIDOMWindowOuter::From(window);
-
-  nsCOMPtr<nsIBaseWindow> ppBaseWindow =
-      do_QueryInterface(pidomwindow->GetDocShell());
-  if (!ppBaseWindow) {
-    return 0;
-  }
-
-  nsCOMPtr<nsIWidget> ppWidget;
-  ppBaseWindow->GetMainWidget(getter_AddRefs(ppWidget));
-
-  return (HWND)(ppWidget->GetNativeData(NS_NATIVE_WIDGET));
-}
-
-static nsresult GetMostRecentWindow(mozIDOMWindowProxy **aWindow) {
-  nsresult rv;
-  nsCOMPtr<nsIWindowMediator> med(
-      do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
-  if (NS_FAILED(rv)) return rv;
-
-  if (med) return med->GetMostRecentWindow(nullptr, aWindow);
-
-  return NS_ERROR_FAILURE;
-}
-
-void HandleCommandLine(const char *aCmdLineString, nsIFile *aWorkingDir,
-                       uint32_t aState) {
-  nsresult rv;
-
-  int justCounting = 1;
-  char **argv = 0;
-  // Flags, etc.
-  int init = 1;
-  int between, quoted, bSlashCount;
-  int argc;
-  const char *p;
-  nsAutoCString arg;
-
-  nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
-
-  // Parse command line args according to MS spec
-  // (see "Parsing C++ Command-Line Arguments" at
-  // http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
-  // We loop if we've not finished the second pass through.
-  while (1) {
-    // Initialize if required.
-    if (init) {
-      p = aCmdLineString;
-      between = 1;
-      argc = quoted = bSlashCount = 0;
-
-      init = 0;
-    }
-    if (between) {
-      // We are traversing whitespace between args.
-      // Check for start of next arg.
-      if (*p != 0 && !isspace(*p)) {
-        // Start of another arg.
-        between = 0;
-        arg = "";
-        switch (*p) {
-          case '\\':
-            // Count the backslash.
-            bSlashCount = 1;
-            break;
-          case '"':
-            // Remember we're inside quotes.
-            quoted = 1;
-            break;
-          default:
-            // Add character to arg.
-            arg += *p;
-            break;
-        }
-      } else {
-        // Another space between args, ignore it.
-      }
-    } else {
-      // We are processing the contents of an argument.
-      // Check for whitespace or end.
-      if (*p == 0 || (!quoted && isspace(*p))) {
-        // Process pending backslashes (interpret them
-        // literally since they're not followed by a ").
-        while (bSlashCount) {
-          arg += '\\';
-          bSlashCount--;
-        }
-        // End current arg.
-        if (!justCounting) {
-          argv[argc] = new char[arg.Length() + 1];
-          strcpy(argv[argc], arg.get());
-        }
-        argc++;
-        // We're now between args.
-        between = 1;
-      } else {
-        // Still inside argument, process the character.
-        switch (*p) {
-          case '"':
-            // First, digest preceding backslashes (if any).
-            while (bSlashCount > 1) {
-              // Put one backsplash in arg for each pair.
-              arg += '\\';
-              bSlashCount -= 2;
-            }
-            if (bSlashCount) {
-              // Quote is literal.
-              arg += '"';
-              bSlashCount = 0;
-            } else {
-              // Quote starts or ends a quoted section.
-              if (quoted) {
-                // Check for special case of consecutive double
-                // quotes inside a quoted section.
-                if (*(p + 1) == '"') {
-                  // This implies a literal double-quote.  Fake that
-                  // out by causing next double-quote to look as
-                  // if it was preceded by a backslash.
-                  bSlashCount = 1;
-                } else {
-                  quoted = 0;
-                }
-              } else {
-                quoted = 1;
-              }
-            }
-            break;
-          case '\\':
-            // Add to count.
-            bSlashCount++;
-            break;
-          default:
-            // Accept any preceding backslashes literally.
-            while (bSlashCount) {
-              arg += '\\';
-              bSlashCount--;
-            }
-            // Just add next char to the current arg.
-            arg += *p;
-            break;
-        }
-      }
-    }
-    // Check for end of input.
-    if (*p) {
-      // Go to next character.
-      p++;
-    } else {
-      // If on first pass, go on to second.
-      if (justCounting) {
-        // Allocate argv array.
-        argv = new char *[argc];
-
-        // Start second pass
-        justCounting = 0;
-        init = 1;
-      } else {
-        // Quit.
-        break;
-      }
-    }
-  }
-
-  rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
-
-  // Cleanup.
-  while (argc) {
-    delete[] argv[--argc];
-  }
-  delete[] argv;
-
-  if (NS_FAILED(rv)) {
-    NS_ERROR("Error initializing command line.");
-    return;
-  }
-
-  cmdLine->Run();
-}
-
-LRESULT CALLBACK WindowProc(HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp) {
-  if (msg == WM_COPYDATA) {
-    // This is an incoming request.
-    COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lp;
-    nsCOMPtr<nsIFile> workingDir;
-
-    if (1 >= cds->dwData) {
-      char *wdpath = (char *)cds->lpData;
-      // skip the command line, and get the working dir of the
-      // other process, which is after the first null char
-      while (*wdpath) ++wdpath;
-
-      ++wdpath;
-
-      NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath), false,
-                      getter_AddRefs(workingDir));
-    }
-    HandleCommandLine((char *)cds->lpData, workingDir,
-                      nsICommandLine::STATE_REMOTE_AUTO);
-
-    // Get current window and return its window handle.
-    nsCOMPtr<mozIDOMWindowProxy> win;
-    GetMostRecentWindow(getter_AddRefs(win));
-    return win ? (LRESULT)hwndForDOMWindow(win) : 0;
-  }
-  return DefWindowProc(msgWindow, msg, wp, lp);
-}
-
-nsresult nsWinRemoteServer::Startup(const char* aAppName,
-    const char* aProfileName) {
-
-  nsString className;
-  BuildClassName(aAppName, aProfileName, className);
-
-  WNDCLASSW classStruct = {0,                           // style
-                           &WindowProc,                 // lpfnWndProc
-                           0,                           // cbClsExtra
-                           0,                           // cbWndExtra
-                           0,                           // hInstance
-                           0,                           // hIcon
-                           0,                           // hCursor
-                           0,                           // hbrBackground
-                           0,                           // lpszMenuName
-                           className.get()};            // lpszClassName
-
-  // Register the window class.
-  NS_ENSURE_TRUE(::RegisterClassW(&classStruct), NS_ERROR_FAILURE);
-
-  // Create the window.
-  mHandle = ::CreateWindowW(className.get(),
-                            0,           // title
-                            WS_CAPTION,  // style
-                            0, 0, 0, 0,  // x, y, cx, cy
-                            0,           // parent
-                            0,           // menu
-                            0,           // instance
-                            0);          // create struct
-
-  return mHandle ? NS_OK : NS_ERROR_FAILURE;
-}
-
-void nsWinRemoteServer::Shutdown() {
-  DestroyWindow(mHandle);
-  mHandle = nullptr;
-}
deleted file mode 100644
--- a/toolkit/components/remote/nsWinRemoteServer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=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/. */
-
-#ifndef __nsWinRemoteServer_h__
-#define __nsWinRemoteServer_h__
-
-#include "nsRemoteServer.h"
-
-#include <windows.h>
-
-class nsWinRemoteServer final : public nsRemoteServer {
- public:
-  nsWinRemoteServer() = default;
-  ~nsWinRemoteServer() override = default;
-
-  nsresult Startup(const char* aAppName, const char* aProfileName) override;
-  void Shutdown() override;
-
- private:
-  HWND mHandle;
-};
-
-#endif  // __nsWinRemoteService_h__
deleted file mode 100644
--- a/toolkit/components/remote/nsWinRemoteUtils.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=4:tabstop=4:
- */
-/* 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/. */
-
-#ifndef nsWinRemoteUtils_h__
-#define nsWinRemoteUtils_h__
-
-#include "nsString.h"
-
-static void BuildClassName(const char *aProgram, const char *aProfile,
-                           nsString& aClassName) {
-  aClassName.AppendPrintf("Mozilla_%s_%s_RemoteWindow", aProgram, aProfile);
-}
-
-#endif  // nsWinRemoteUtils_h__
rename from toolkit/components/remote/nsXRemoteServer.cpp
rename to toolkit/components/remote/nsXRemoteService.cpp
--- a/toolkit/components/remote/nsXRemoteServer.cpp
+++ b/toolkit/components/remote/nsXRemoteService.cpp
@@ -2,17 +2,18 @@
 /* vim:expandtab:shiftwidth=2:tabstop=8:
  */
 /* 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 "mozilla/ArrayUtils.h"
 
-#include "nsXRemoteServer.h"
+#include "nsXRemoteService.h"
+#include "nsRemoteService.h"
 #include "nsIObserverService.h"
 #include "nsCOMPtr.h"
 #include "nsIServiceManager.h"
 #include "nsICommandLineRunner.h"
 #include "nsICommandLine.h"
 
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
@@ -48,37 +49,37 @@ const unsigned char kRemoteVersion[] = "
 
 // Minimize the roundtrips to the X server by getting all the atoms at once
 static const char *XAtomNames[] = {
     MOZILLA_VERSION_PROP,    MOZILLA_LOCK_PROP,    MOZILLA_RESPONSE_PROP,
     MOZILLA_USER_PROP,       MOZILLA_PROFILE_PROP, MOZILLA_PROGRAM_PROP,
     MOZILLA_COMMANDLINE_PROP};
 static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
 
-Atom nsXRemoteServer::sMozVersionAtom;
-Atom nsXRemoteServer::sMozLockAtom;
-Atom nsXRemoteServer::sMozResponseAtom;
-Atom nsXRemoteServer::sMozUserAtom;
-Atom nsXRemoteServer::sMozProfileAtom;
-Atom nsXRemoteServer::sMozProgramAtom;
-Atom nsXRemoteServer::sMozCommandLineAtom;
+Atom nsXRemoteService::sMozVersionAtom;
+Atom nsXRemoteService::sMozLockAtom;
+Atom nsXRemoteService::sMozResponseAtom;
+Atom nsXRemoteService::sMozUserAtom;
+Atom nsXRemoteService::sMozProfileAtom;
+Atom nsXRemoteService::sMozProgramAtom;
+Atom nsXRemoteService::sMozCommandLineAtom;
 
-nsXRemoteServer::nsXRemoteServer() = default;
+nsXRemoteService::nsXRemoteService() = default;
 
-void nsXRemoteServer::XRemoteBaseStartup(const char *aAppName,
-                                         const char *aProfileName) {
+void nsXRemoteService::XRemoteBaseStartup(const char *aAppName,
+                                          const char *aProfileName) {
   EnsureAtoms();
 
   mAppName = aAppName;
   ToLowerCase(mAppName);
 
   mProfileName = aProfileName;
 }
 
-void nsXRemoteServer::HandleCommandsFor(Window aWindowId) {
+void nsXRemoteService::HandleCommandsFor(Window aWindowId) {
   // set our version
   XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozVersionAtom,
                   XA_STRING, 8, PropModeReplace, kRemoteVersion,
                   sizeof(kRemoteVersion) - 1);
 
   // get our username
   unsigned char *logname;
   logname = (unsigned char *)PR_GetEnv("LOGNAME");
@@ -88,23 +89,25 @@ void nsXRemoteServer::HandleCommandsFor(
                     XA_STRING, 8, PropModeReplace, logname,
                     strlen((char *)logname));
   }
 
   XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozProgramAtom,
                   XA_STRING, 8, PropModeReplace,
                   (unsigned char *)mAppName.get(), mAppName.Length());
 
-  XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozProfileAtom,
-                  XA_STRING, 8, PropModeReplace,
-                  (unsigned char *)mProfileName.get(), mProfileName.Length());
+  if (!mProfileName.IsEmpty()) {
+    XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozProfileAtom,
+                    XA_STRING, 8, PropModeReplace,
+                    (unsigned char *)mProfileName.get(), mProfileName.Length());
+  }
 }
 
-bool nsXRemoteServer::HandleNewProperty(XID aWindowId, Display *aDisplay,
-                                        Time aEventTime, Atom aChangedAtom) {
+bool nsXRemoteService::HandleNewProperty(XID aWindowId, Display *aDisplay,
+                                         Time aEventTime, Atom aChangedAtom) {
   if (aChangedAtom == sMozCommandLineAtom) {
     // We got a new command atom.
     int result;
     Atom actual_type;
     int actual_format;
     unsigned long nitems, bytes_after;
     char *data = 0;
 
@@ -124,17 +127,17 @@ bool nsXRemoteServer::HandleNewProperty(
     // Failed to get property off the window?
     if (result != Success) return false;
 
     // Failed to get the data off the window or it was the wrong type?
     if (!data || !TO_LITTLE_ENDIAN32(*reinterpret_cast<int32_t *>(data)))
       return false;
 
     // cool, we got the property data.
-    const char *response = HandleCommandLine(data, aEventTime);
+    const char *response = nsRemoteService::HandleCommandLine(data, aEventTime);
 
     // put the property onto the window as the response
     XChangeProperty(aDisplay, aWindowId, sMozResponseAtom, XA_STRING, 8,
                     PropModeReplace, (const unsigned char *)response,
                     strlen(response));
     XFree(data);
     return true;
   }
@@ -147,17 +150,17 @@ bool nsXRemoteServer::HandleNewProperty(
   else if (aChangedAtom == sMozLockAtom) {
     // someone locked the window
     return true;
   }
 
   return false;
 }
 
-void nsXRemoteServer::EnsureAtoms(void) {
+void nsXRemoteService::EnsureAtoms(void) {
   if (sMozVersionAtom) return;
 
   XInternAtoms(mozilla::DefaultXDisplay(), const_cast<char **>(XAtomNames),
                ArrayLength(XAtomNames), False, XAtoms);
 
   int i = 0;
   sMozVersionAtom = XAtoms[i++];
   sMozLockAtom = XAtoms[i++];
rename from toolkit/components/remote/nsXRemoteServer.h
rename to toolkit/components/remote/nsXRemoteService.h
--- a/toolkit/components/remote/nsXRemoteServer.h
+++ b/toolkit/components/remote/nsXRemoteService.h
@@ -1,33 +1,41 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=8:
  */
 /* 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/. */
 
-#ifndef NSXREMOTESERVER_H
-#define NSXREMOTESERVER_H
+#ifndef NSXREMOTESERVICE_H
+#define NSXREMOTESERVICE_H
 
 #include "nsString.h"
-#include "nsRemoteServer.h"
-#include "nsUnixRemoteServer.h"
 
 #include <X11/Xlib.h>
 #include <X11/X.h>
 
+class nsIDOMWindow;
+
+#ifdef IS_BIG_ENDIAN
+#  define TO_LITTLE_ENDIAN32(x)                           \
+    ((((x)&0xff000000) >> 24) | (((x)&0x00ff0000) >> 8) | \
+     (((x)&0x0000ff00) << 8) | (((x)&0x000000ff) << 24))
+#else
+#  define TO_LITTLE_ENDIAN32(x) (x)
+#endif
+
 /**
   Base class for GTK/Qt remote service
 */
-class nsXRemoteServer : public nsRemoteServer, public nsUnixRemoteServer {
+class nsXRemoteService {
  protected:
-  nsXRemoteServer();
-  bool HandleNewProperty(Window aWindowId, Display* aDisplay, Time aEventTime,
-                         Atom aChangedAtom);
+  nsXRemoteService();
+  static bool HandleNewProperty(Window aWindowId, Display* aDisplay,
+                                Time aEventTime, Atom aChangedAtom);
   void XRemoteBaseStartup(const char* aAppName, const char* aProfileName);
   void HandleCommandsFor(Window aWindowId);
 
  private:
   void EnsureAtoms();
 
   nsCString mAppName;
   nsCString mProfileName;
@@ -36,9 +44,9 @@ class nsXRemoteServer : public nsRemoteS
   static Atom sMozLockAtom;
   static Atom sMozResponseAtom;
   static Atom sMozUserAtom;
   static Atom sMozProfileAtom;
   static Atom sMozProgramAtom;
   static Atom sMozCommandLineAtom;
 };
 
-#endif  // NSXREMOTESERVER_H
+#endif  // NSXREMOTESERVICE_H
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -1647,19 +1647,8 @@ with only_when(compile_environment & tar
             return namespace(name=name, path=path)
         die('Could not find {} {}'.format(name, error_extra))
 
 
     set_config('MOZ_ANGLE_RENDERER', True)
     set_config('MOZ_D3DCOMPILER_VISTA_DLL', d3d_compiler_dll.name,
                when=d3d_compiler_dll.path)
     set_config('MOZ_D3DCOMPILER_VISTA_DLL_PATH', d3d_compiler_dll.path)
-
-# Remoting protocol support
-# ==============================================================
-
-@depends(toolkit)
-def has_remote(toolkit):
-    if 'gtk' in toolkit or toolkit == 'windows':
-        return True
-
-set_config('MOZ_HAS_REMOTE', has_remote)
-set_define('MOZ_HAS_REMOTE', has_remote)
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -154,16 +154,17 @@ DIRS += [
     '/startupcache',
     '/js/ductwork/debugger',
     '/other-licenses/snappy',
 ]
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     DIRS += [
         '/toolkit/system/gnome',
+        '/widget/xremoteclient',
     ]
 
 if CONFIG['ENABLE_MARIONETTE']:
     DIRS += [
         '/testing/firefox-ui',
         '/testing/marionette',
     ]
 
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -91,21 +91,16 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT
     UNIFIED_SOURCES += [
         'nsNativeAppSupportUnix.cpp',
     ]
 else:
     UNIFIED_SOURCES += [
         'nsNativeAppSupportDefault.cpp',
     ]
 
-if CONFIG['MOZ_HAS_REMOTE']:
-    LOCAL_INCLUDES += [
-        '../components/remote',
-    ]
-
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
     UNIFIED_SOURCES += [
         'nsGDKErrorHandler.cpp',
     ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS += ['nsX11ErrorHandler.h']
     UNIFIED_SOURCES += [
@@ -241,16 +236,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     ]
 
 CXXFLAGS += CONFIG['TK_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
+    LOCAL_INCLUDES += [
+        '/widget/xremoteclient',
+    ]
 
 DEFINES['TOPOBJDIR'] = TOPOBJDIR
 FINAL_TARGET_PP_FILES += [
     'platform.ini'
 ]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -182,18 +182,27 @@
 #endif
 
 #ifdef XP_MACOSX
 #  include "nsILocalFileMac.h"
 #  include "nsCommandLineServiceMac.h"
 #endif
 
 // for X remote support
-#if defined(MOZ_HAS_REMOTE)
-#  include "nsRemoteService.h"
+#if defined(MOZ_WIDGET_GTK)
+#  include "XRemoteClient.h"
+#  include "nsIRemoteService.h"
+#  include "nsProfileLock.h"
+#  include "SpecialSystemDirectory.h"
+#  include <sched.h>
+#  ifdef MOZ_ENABLE_DBUS
+#    include "DBusRemoteClient.h"
+#  endif
+// Time to wait for the remoting service to start
+#  define MOZ_XREMOTE_START_TIMEOUT_SEC 5
 #endif
 
 #if defined(DEBUG) && defined(XP_WIN32)
 #  include <malloc.h>
 #endif
 
 #if defined(XP_MACOSX)
 #  include <Carbon/Carbon.h>
@@ -298,19 +307,16 @@ FuzzerRunner* fuzzerRunner = 0;
 
 #  ifdef LIBFUZZER
 void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
   mozilla::fuzzerRunner->setParams(aDriver);
 }
 #  endif
 #endif  // FUZZING
 
-// Undo X11/X.h's definition of None
-#undef None
-
 namespace mozilla {
 int (*RunGTest)(int*, char**) = 0;
 }  // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::startup;
 using mozilla::Unused;
 using mozilla::dom::ContentChild;
@@ -393,16 +399,22 @@ static MOZ_FORMAT_PRINTF(2, 3) void Outp
   }
 #else
   vfprintf(stderr, fmt, ap);
 #endif
 
   va_end(ap);
 }
 
+enum RemoteResult {
+  REMOTE_NOT_FOUND = 0,
+  REMOTE_FOUND = 1,
+  REMOTE_ARG_BAD = 2
+};
+
 /**
  * Check for a commandline flag. If the flag takes a parameter, the
  * parameter is returned in aParam. Flags may be in the form -arg or
  * --arg (or /arg on win32).
  *
  * @param aArg the parameter to check. Must be lowercase.
  * @param aParam if non-null, the -arg <data> will be stored in this pointer.
  *        This is *not* allocated, but rather a pointer to the argv data.
@@ -420,16 +432,80 @@ static ArgResult CheckArg(const char* aA
  * Will not remove flag if found.
  *
  * @param aArg the parameter to check. Must be lowercase.
  */
 static ArgResult CheckArgExists(const char* aArg) {
   return CheckArg(aArg, nullptr, CheckArgFlag::None);
 }
 
+#if defined(XP_WIN)
+/**
+ * Check for a commandline flag from the windows shell and remove it from the
+ * argv used when restarting. Flags MUST be in the form -arg.
+ *
+ * @param aArg the parameter to check. Must be lowercase.
+ */
+static ArgResult CheckArgShell(const char* aArg) {
+  char** curarg = gRestartArgv + 1;  // skip argv[0]
+
+  while (*curarg) {
+    char* arg = curarg[0];
+
+    if (arg[0] == '-') {
+      ++arg;
+
+      if (strimatch(aArg, arg)) {
+        do {
+          *curarg = *(curarg + 1);
+          ++curarg;
+        } while (*curarg);
+
+        --gRestartArgc;
+
+        return ARG_FOUND;
+      }
+    }
+
+    ++curarg;
+  }
+
+  return ARG_NONE;
+}
+
+/**
+ * Enabled Native App Support to process DDE messages when the app needs to
+ * restart and the app has been launched by the Windows shell to open an url.
+ * When aWait is false this will process the DDE events manually. This prevents
+ * Windows from displaying an error message due to the DDE message not being
+ * acknowledged.
+ */
+static void ProcessDDE(nsINativeAppSupport* aNative, bool aWait) {
+  // When the app is launched by the windows shell the windows shell
+  // expects the app to be available for DDE messages and if it isn't
+  // windows displays an error dialog. To prevent the error the DDE server
+  // is enabled and pending events are processed when the app needs to
+  // restart after it was launched by the shell with the requestpending
+  // argument. The requestpending pending argument is removed to
+  // differentiate it from being launched when an app restart is not
+  // required.
+  ArgResult ar;
+  ar = CheckArgShell("requestpending");
+  if (ar == ARG_FOUND) {
+    aNative->Enable();  // enable win32 DDE responses
+    if (aWait) {
+      // This is just a guesstimate based on testing different values.
+      // If count is 8 or less windows will display an error dialog.
+      int32_t count = 20;
+      SpinEventLoopUntil([&]() { return --count < 0; });
+    }
+  }
+}
+#endif
+
 bool gSafeMode = false;
 
 /**
  * The nsXULAppInfo object implements nsIFactory so that it can be its own
  * singleton.
  */
 class nsXULAppInfo : public nsIXULAppInfo,
                      public nsIObserver,
@@ -1411,22 +1487,20 @@ static void DumpHelp() {
 
   printf(
       "  -h or --help       Print this message.\n"
       "  -v or --version    Print %s version.\n"
       "  -P <profile>       Start with <profile>.\n"
       "  --profile <path>   Start with profile at <path>.\n"
       "  --migration        Start with migration wizard.\n"
       "  --ProfileManager   Start with ProfileManager.\n"
-#ifdef MOZ_HAS_REMOTE
       "  --no-remote        Do not accept or send remote commands; implies\n"
       "                     --new-instance.\n"
       "  --new-instance     Open new instance, not a new window in running "
       "instance.\n"
-#endif
       "  --UILocale <locale> Start with <locale> resources as UI Locale.\n"
       "  --safe-mode        Disables extensions and themes for this session.\n"
 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
       "  --allow-downgrade  Allows downgrading a profile.\n"
 #endif
       "  -MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment variable, "
       "overrides it.\n"
       "  -MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
@@ -1466,16 +1540,86 @@ static inline void DumpVersion() {
   printf("%s", NS_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
 
   if (gAppData->copyright) {
     printf(", %s", (const char*)gAppData->copyright);
   }
   printf("\n");
 }
 
+#if defined(MOZ_WIDGET_GTK)
+static RemoteResult ParseRemoteCommandLine(nsCString& program,
+                                           const char** profile,
+                                           const char** username) {
+  ArgResult ar;
+
+  ar = CheckArg("p", profile, CheckArgFlag::None);
+  if (ar == ARG_BAD) {
+    // Leave it to the normal command line handling to handle this situation.
+    return REMOTE_NOT_FOUND;
+  }
+
+  const char* temp = nullptr;
+  ar = CheckArg("a", &temp, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
+  if (ar == ARG_BAD) {
+    PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
+    return REMOTE_ARG_BAD;
+  }
+  if (ar == ARG_FOUND) {
+    program.Assign(temp);
+  }
+
+  ar = CheckArg("u", username,
+                CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
+  if (ar == ARG_BAD) {
+    PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
+    return REMOTE_ARG_BAD;
+  }
+
+  return REMOTE_FOUND;
+}
+
+static RemoteResult StartRemoteClient(const char* aDesktopStartupID,
+                                      nsCString& program, const char* profile,
+                                      const char* username) {
+  nsAutoPtr<nsRemoteClient> client;
+
+  bool useX11Remote = GDK_IS_X11_DISPLAY(gdk_display_get_default());
+
+#  if defined(MOZ_ENABLE_DBUS)
+  if (!useX11Remote) {
+    client = new DBusRemoteClient();
+  }
+#  endif
+  if (useX11Remote) {
+    client = new XRemoteClient();
+  }
+
+  nsresult rv = client ? client->Init() : NS_ERROR_FAILURE;
+  if (NS_FAILED(rv)) return REMOTE_NOT_FOUND;
+
+  nsCString response;
+  bool success = false;
+  rv = client->SendCommandLine(program.get(), username, profile, gArgc, gArgv,
+                               aDesktopStartupID, getter_Copies(response),
+                               &success);
+  // did the command fail?
+  if (!success) return REMOTE_NOT_FOUND;
+
+  // The "command not parseable" error is returned when the
+  // nsICommandLineHandler throws a NS_ERROR_ABORT.
+  if (response.EqualsLiteral("500 command not parseable"))
+    return REMOTE_ARG_BAD;
+
+  if (NS_FAILED(rv)) return REMOTE_NOT_FOUND;
+
+  return REMOTE_FOUND;
+}
+#endif  // MOZ_WIDGET_GTK
+
 void XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) {
   mozilla::Omnijar::Init(greOmni, appOmni);
 }
 
 nsresult XRE_GetBinaryPath(nsIFile** aResult) {
   return mozilla::BinaryPath::GetFile(aResult);
 }
 
@@ -1577,17 +1721,17 @@ static void SetupLauncherProcessPref() {
 
 #endif  // XP_WIN
 
 // If aBlankCommandLine is true, then the application will be launched with a
 // blank command line instead of being launched with the same command line that
 // it was initially started with.
 static nsresult LaunchChild(nsINativeAppSupport* aNative,
                             bool aBlankCommandLine = false) {
-  aNative->Quit();  // destroy message window
+  aNative->Quit();  // release DDE mutex, if we're holding it
 
   // Restart this process by exec'ing it into the current process
   // if supported by the platform.  Otherwise, use NSPR.
 
 #ifdef MOZ_JPROF
   // make sure JPROF doesn't think we're E10s
   unsetenv("JPROF_SLAVE");
 #endif
@@ -1846,16 +1990,22 @@ static ReturnAbortOnError ShowProfileMan
     rv = xpcom.SetWindowCreator(aNative);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
 #ifdef XP_MACOSX
     CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv,
                                                true);
 #endif
 
+#ifdef XP_WIN
+    // we don't have to wait here because profile manager window will pump
+    // and DDE message will be handled
+    ProcessDDE(aNative, false);
+#endif
+
     {  // extra scoping is needed so we release these components before xpcom
        // shutdown
       nsCOMPtr<nsIWindowWatcher> windowWatcher(
           do_GetService(NS_WINDOWWATCHER_CONTRACTID));
       nsCOMPtr<nsIDialogParamBlock> ioParamBlock(
           do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
       nsCOMPtr<nsIMutableArray> dlgArray(
           do_CreateInstance(NS_ARRAY_CONTRACTID));
@@ -2777,22 +2927,19 @@ bool fire_glxtest_process();
 #include "GeckoProfiler.h"
 
 // Encapsulates startup and shutdown state for XRE_main
 class XREMain {
  public:
   XREMain()
       : mStartOffline(false),
         mShuttingDown(false)
-#ifdef MOZ_HAS_REMOTE
-        ,
-        mDisableRemote(false)
-#endif
 #if defined(MOZ_WIDGET_GTK)
         ,
+        mDisableRemote(false),
         mGdkDisplay(nullptr)
 #endif
             {};
 
   ~XREMain() {
     mScopedXPCOM = nullptr;
     mAppData = nullptr;
   }
@@ -2804,29 +2951,32 @@ class XREMain {
 
   Result<bool, nsresult> CheckLastStartupWasCrash();
 
   nsCOMPtr<nsINativeAppSupport> mNativeApp;
   RefPtr<nsToolkitProfileService> mProfileSvc;
   nsCOMPtr<nsIFile> mProfD;
   nsCOMPtr<nsIFile> mProfLD;
   nsCOMPtr<nsIProfileLock> mProfileLock;
-#if defined(MOZ_HAS_REMOTE)
-  RefPtr<nsRemoteService> mRemoteService;
+#if defined(MOZ_WIDGET_GTK)
+  nsCOMPtr<nsIRemoteService> mRemoteService;
+  nsProfileLock mRemoteLock;
+  nsCOMPtr<nsIFile> mRemoteLockDir;
 #endif
 
   UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
   UniquePtr<XREAppData> mAppData;
 
   nsXREDirProvider mDirProvider;
+  nsAutoCString mProfileName;
   nsAutoCString mDesktopStartupID;
 
   bool mStartOffline;
   bool mShuttingDown;
-#if defined(MOZ_HAS_REMOTE)
+#if defined(MOZ_WIDGET_GTK)
   bool mDisableRemote;
 #endif
 
 #if defined(MOZ_WIDGET_GTK)
   GdkDisplay* mGdkDisplay;
 #endif
 };
 
@@ -3319,47 +3469,42 @@ int XREMain::XRE_mainInit(bool* aExitFla
           nsPrintfCString("0x%x", cpuUpdateRevision));
     }
   }
 #endif
 
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode,
                                      gSafeMode);
 
-#if defined(MOZ_HAS_REMOTE)
   // Handle --no-remote and --new-instance command line arguments. Setup
   // the environment to better accommodate other components and various
   // restart scenarios.
   ar = CheckArg("no-remote", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --no-remote is invalid when argument --osint "
                "is specified\n");
     return 1;
   }
   if (ar == ARG_FOUND) {
     SaveToEnv("MOZ_NO_REMOTE=1");
-    mDisableRemote = true;
-  } else if (EnvHasValue("MOZ_NO_REMOTE")) {
-    mDisableRemote = true;
   }
 
   ar = CheckArg("new-instance", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --new-instance is invalid when argument "
                "--osint is specified\n");
     return 1;
   }
-  if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
-    mDisableRemote = true;
-  }
-#endif
+  if (ar == ARG_FOUND) {
+    SaveToEnv("MOZ_NEW_INSTANCE=1");
+  }
 
   ar = CheckArg("offline", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --offline is invalid when argument --osint is "
                "specified\n");
     return 1;
@@ -3746,22 +3891,16 @@ int XREMain::XRE_mainStartup(bool* aExit
     } else {
       result = 1;
       printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
     }
     *aExitFlag = true;
     return result;
   }
 
-#ifdef MOZ_HAS_REMOTE
-  if (gfxPlatform::IsHeadless()) {
-    mDisableRemote = true;
-  }
-#endif
-
 #ifdef MOZ_X11
   // Init X11 in thread-safe mode. Must be called prior to the first call to
   // XOpenDisplay (called inside gdk_display_open). This is a requirement for
   // off main tread compositing.
   if (!gfxPlatform::IsHeadless()) {
     XInitThreads();
   }
 #endif
@@ -3822,24 +3961,103 @@ int XREMain::XRE_mainStartup(bool* aExit
       }
     }
 #  ifdef MOZ_WIDGET_GTK
     else {
       mGdkDisplay =
           gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
     }
 #  endif
+  } else {
+    mDisableRemote = true;
   }
 #endif
-#if defined(MOZ_HAS_REMOTE)
+#if defined(MOZ_WIDGET_GTK)
   // handle --remote now that xpcom is fired up
-  if (!mDisableRemote) {
-    mRemoteService = new nsRemoteService(gAppData->remotingName);
-    if (mRemoteService) {
-      mRemoteService->LockStartup();
+  bool newInstance;
+  {
+    char* e = PR_GetEnv("MOZ_NO_REMOTE");
+    mDisableRemote = (mDisableRemote || (e && *e));
+    if (mDisableRemote) {
+      newInstance = true;
+    } else {
+      e = PR_GetEnv("MOZ_NEW_INSTANCE");
+      newInstance = (e && *e);
+    }
+  }
+
+  if (!newInstance) {
+    nsAutoCString program(gAppData->remotingName);
+    ToLowerCase(program);
+
+    const char* username = getenv("LOGNAME");
+    const char* profile = nullptr;
+
+    RemoteResult rr = ParseRemoteCommandLine(program, &profile, &username);
+    if (rr == REMOTE_ARG_BAD) {
+      return 1;
+    }
+
+    if (!username) {
+      struct passwd* pw = getpwuid(geteuid());
+      if (pw && pw->pw_name) {
+        // Beware that another call to getpwent/getpwname/getpwuid will
+        // overwrite pw, but we don't have such another call between here and
+        // when username is used last.
+        username = pw->pw_name;
+      }
+    }
+
+    nsCOMPtr<nsIFile> mutexDir;
+    rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
+                                   getter_AddRefs(mutexDir));
+    if (NS_SUCCEEDED(rv)) {
+      nsAutoCString mutexPath = program + NS_LITERAL_CSTRING("_");
+      // In the unlikely even that LOGNAME is not set and getpwuid failed, just
+      // don't put the username in the mutex directory. It will conflict with
+      // other users mutex, but the worst that can happen is that they wait for
+      // MOZ_XREMOTE_START_TIMEOUT_SEC during startup in that case.
+      if (username) {
+        mutexPath.Append(username);
+      }
+      if (profile) {
+        mutexPath.Append(NS_LITERAL_CSTRING("_") + nsDependentCString(profile));
+      }
+      mutexDir->AppendNative(mutexPath);
+
+      rv = mutexDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
+      if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
+        mRemoteLockDir = mutexDir;
+      }
+    }
+
+    if (mRemoteLockDir) {
+      const TimeStamp epoch = mozilla::TimeStamp::Now();
+      do {
+        rv = mRemoteLock.Lock(mRemoteLockDir, nullptr);
+        if (NS_SUCCEEDED(rv)) break;
+        sched_yield();
+      } while ((TimeStamp::Now() - epoch) <
+               TimeDuration::FromSeconds(MOZ_XREMOTE_START_TIMEOUT_SEC));
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Cannot lock XRemote start mutex");
+      }
+    }
+
+    // Try to remote the entire command line. If this fails, start up normally.
+    const char* desktopStartupIDPtr =
+        mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
+
+    rr = StartRemoteClient(desktopStartupIDPtr, program, profile, username);
+    if (rr == REMOTE_FOUND) {
+      *aExitFlag = true;
+      return 0;
+    }
+    if (rr == REMOTE_ARG_BAD) {
+      return 1;
     }
   }
 #endif
 #if defined(MOZ_WIDGET_GTK)
   g_set_application_name(mAppData->name);
   gtk_window_set_auto_startup_notification(false);
 
 #endif /* defined(MOZ_WIDGET_GTK) */
@@ -3953,50 +4171,16 @@ int XREMain::XRE_mainStartup(bool* aExit
   }
 
   if (NS_FAILED(rv)) {
     // We failed to choose or create profile - notify user and quit
     ProfileMissingDialog(mNativeApp);
     return 1;
   }
 
-#if defined(MOZ_HAS_REMOTE)
-  if (mRemoteService) {
-    // We want a unique profile name to identify the remote instance.
-    nsCString profileName;
-    if (profile) {
-      rv = profile->GetName(profileName);
-    }
-    if (!profile || NS_FAILED(rv) || profileName.IsEmpty()) {
-      // Couldn't get a name from the profile. Use the directory name?
-      nsString leafName;
-      rv = mProfD->GetLeafName(leafName);
-      if (NS_SUCCEEDED(rv)) {
-        profileName = NS_ConvertUTF16toUTF8(leafName);
-      }
-    }
-
-    mRemoteService->SetProfile(profileName);
-
-    // Try to remote the entire command line. If this fails, start up
-    // normally.
-    const char* desktopStartupIDPtr =
-        mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
-
-    RemoteResult rr = mRemoteService->StartClient(desktopStartupIDPtr);
-    if (rr == REMOTE_FOUND) {
-      *aExitFlag = true;
-      return 0;
-    }
-    if (rr == REMOTE_ARG_BAD) {
-      return 1;
-    }
-  }
-#endif
-
   // We always want to lock the profile even if we're actually going to reset
   // it later.
   rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
                    getter_AddRefs(mProfileLock));
   if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
     *aExitFlag = true;
     return 0;
   } else if (NS_FAILED(rv)) {
@@ -4029,16 +4213,23 @@ int XREMain::XRE_mainStartup(bool* aExit
         return 1;
       }
     } else {
       NS_WARNING("Profile reset failed.");
       return 1;
     }
   }
 
+  if (profile) {
+    rv = profile->GetName(mProfileName);
+    if (NS_FAILED(rv)) {
+      mProfileName.Truncate(0);
+    }
+  }
+
   gProfileLock = mProfileLock;
 
   nsAutoCString version;
   BuildVersion(version);
 
 #ifdef TARGET_OS_ABI
   NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
 #else
@@ -4481,22 +4672,27 @@ nsresult XREMain::XRE_mainRun() {
   if (!mShuttingDown) {
     rv = cmdLine->Run();
     NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
 
     appStartup->GetShuttingDown(&mShuttingDown);
   }
 
   if (!mShuttingDown) {
-#if defined(MOZ_HAS_REMOTE)
+#if defined(MOZ_WIDGET_GTK)
     // if we have X remote support, start listening for requests on the
     // proxy window.
-    if (mRemoteService) {
-      mRemoteService->StartupServer();
-      mRemoteService->UnlockStartup();
+    if (!mDisableRemote)
+      mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
+    if (mRemoteService)
+      mRemoteService->Startup(mAppData->remotingName, mProfileName.get());
+    if (mRemoteLockDir) {
+      mRemoteLock.Unlock();
+      mRemoteLock.Cleanup();
+      mRemoteLockDir->Remove(false);
     }
 #endif /* MOZ_WIDGET_GTK */
 
     mNativeApp->Enable();
   }
 
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
   if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
@@ -4689,20 +4885,20 @@ int XREMain::XRE_main(int argc, char* ar
     appInitiatedRestart = true;
 
     // We have an application restart don't do any shutdown checks here
     // In particular we don't want to poison IO for checking late-writes.
     gShutdownChecks = SCM_NOTHING;
   }
 
   if (!mShuttingDown) {
-#if defined(MOZ_HAS_REMOTE)
+#if defined(MOZ_WIDGET_GTK)
     // shut down the x remote proxy window
     if (mRemoteService) {
-      mRemoteService->ShutdownServer();
+      mRemoteService->Shutdown();
     }
 #endif /* MOZ_WIDGET_GTK */
   }
 
   mScopedXPCOM = nullptr;
 
 #if defined(XP_WIN)
   mozilla::widget::StopAudioSession();
--- a/toolkit/xre/nsINativeAppSupport.idl
+++ b/toolkit/xre/nsINativeAppSupport.idl
@@ -3,17 +3,20 @@
  * 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 "nsISupports.idl"
 
 /* nsINativeAppSupport
  *
  * This "pseudo" (in the XPCOM sense) interface provides for
- * platform-specific general application support
+ * platform-specific general application support:
+ *  o It manages the details of the simple DDE communication 
+ *    supported on the Win32 platform (it is the addition of this 
+ *    item that prompted the creation of this interface.
  *
  * Due to the nature of the beast, this interface is not a full-blown
  * XPCOM component.  The primary reason is that objects that implement
  * this interface generally must be operational *before* XPCOM (or any
  * of the rest of Mozilla) are initialized.  As a result, this 
  * interface is instantiated by somewhat unconventional means.
  *
  * To create the implementor of this interface, you call the function
@@ -31,28 +34,70 @@
  *          such cases, the returned nsresult indicates whether the
  *          reason to exit is due to an error or not.
  *
  *          Win32 Note: In the case of starting a second instance
  *                      of this executable, this function will return
  *                      PR_FALSE and nsresult==NS_OK.  This means that
  *                      the command line arguments have been
  *                      successfully passed to the instance of the
- *                      application acting as a remote server.
- *  quit - Informs the native app support that the application is stopping. The
- *         app support should disable any functionality enabled by start.
+ *                      application acting as a DDE server.
+ *
+ *  stop - You call this to inform the native app support that the
+ *         application *wishes* to terminate.  If the returned boolean
+ *         value is PR_FALSE, then the application should continue
+ *         (as if there were still additional top-level windows open).
+ *         
+ *         Win32 Note: If this is the instance of the application
+ *                     acting as the DDE server, and there are current
+ *                     DDE conversations active with other instances
+ *                     acting as DDE clients, then this function will
+ *                     return PR_FALSE.
+ * 
+ *  quit - Like Stop, but this method *forces* termination (or more 
+ *         precisely, indicates that the application is about to be
+ *         terminated regardless of what a call to Stop might have
+ *         returned.
+ *
+ *         This method is intended to be called when the user selects
+ *         the "Quit" option (close all windows and exit).
+ *
+ *         Win32 Note: Stop is problematic in the case of "Quit" (close
+ *                     all windows and exit the application) because
+ *                     either we don't Quit or (potentially) we lose
+ *                     requests coming from other instances of the
+ *                     application.  The strategy is to give preference
+ *                     to the user's explicit Quit request.  In the
+ *                     unlikely event that a request is pending from
+ *                     another instance of the application, then such
+ *                     requests are essentially ignored.  This is
+ *                     roughly equivalent to handling that request by
+ *                     opening a new window, followed by immediately
+ *                     closing it.  Since this is the same as if the
+ *                     request came in immediately before the Quit
+ *                     call (versus immediately after it), no harm.
+ *
+ *                     There is an exposure here: Upon return from this
+ *                     function, any DDE connect request (for Mozilla)
+ *                     will fail and other instances of the application
+ *                     will start up as a DDE server.  In that case,
+ *                     those instances may do things that conflict with
+ *                     the subsequent shutting down of the instance that
+ *                     is quitting.  For this reason, the call to Quit
+ *                     should be deferred as long as possible.
  *
  *  onLastWindowClosing -  Called when the last window is closed. Used as a
  *                         "soft" shutdown, passwords are flushed.
  */
 
 interface nsIXULWindow;
 
 [scriptable, uuid(5fdf8480-1f98-11d4-8077-00600811a9c3)]
 interface nsINativeAppSupport : nsISupports {
     // Startup/shutdown.
     boolean start();
     void    enable();
+    boolean stop();
     void    quit();
 
     void onLastWindowClosing();
     void ReOpen();
 };
--- a/toolkit/xre/nsNativeAppSupportBase.cpp
+++ b/toolkit/xre/nsNativeAppSupportBase.cpp
@@ -16,16 +16,23 @@ NS_IMETHODIMP
 nsNativeAppSupportBase::Start(bool *result) {
   *result = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNativeAppSupportBase::Enable() { return NS_OK; }
 
+// Stop answer defaults to OK.
+NS_IMETHODIMP
+nsNativeAppSupportBase::Stop(bool *result) {
+  *result = true;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsNativeAppSupportBase::Quit() { return NS_OK; }
 
 NS_IMETHODIMP
 nsNativeAppSupportBase::ReOpen() { return NS_OK; }
 
 NS_IMETHODIMP
 nsNativeAppSupportBase::OnLastWindowClosing() { return NS_OK; }
--- a/toolkit/xre/nsNativeAppSupportUnix.cpp
+++ b/toolkit/xre/nsNativeAppSupportUnix.cpp
@@ -130,16 +130,17 @@ class nsNativeAppSupportUnix : public ns
     // 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) override;
+  NS_IMETHOD Stop(bool *aResult) override;
   NS_IMETHOD Enable() override;
 
  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);
@@ -646,16 +647,23 @@ nsNativeAppSupportUnix::Start(bool *aRet
 
   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);
--- a/toolkit/xre/nsNativeAppSupportWin.cpp
+++ b/toolkit/xre/nsNativeAppSupportWin.cpp
@@ -1,36 +1,338 @@
 /* -*- Mode: C++; tab-width: 4; 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 "nsNativeAppSupportWin.h"
+#include "nsAppRunner.h"
+#include "nsContentUtils.h"
+#include "nsXULAppAPI.h"
+#include "nsString.h"
+#include "nsIBrowserDOMWindow.h"
+#include "nsCommandLine.h"
+#include "nsCOMPtr.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsIDOMChromeWindow.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIWindowWatcher.h"
+#include "nsPIDOMWindow.h"
+#include "nsGlobalWindow.h"
+#include "nsIDocShell.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsIBaseWindow.h"
+#include "nsIWidget.h"
+#include "nsIAppShellService.h"
+#include "nsIXULWindow.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIPromptService.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "mozilla/Services.h"
+#include "nsIFile.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsIWebNavigation.h"
+#include "nsIWindowMediator.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsIAppStartup.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/Location.h"
 
 #include <windows.h>
+#include <shellapi.h>
+#include <ddeml.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <io.h>
+#include <direct.h>
 #include <fcntl.h>
 
 using namespace mozilla;
 
-/*
- * This code attaches the process to the appropriate console.
+static HWND hwndForDOMWindow(mozIDOMWindowProxy *);
+
+static nsresult GetMostRecentWindow(const char16_t *aType,
+                                    mozIDOMWindowProxy **aWindow) {
+  nsresult rv;
+  nsCOMPtr<nsIWindowMediator> med(
+      do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
+  if (NS_FAILED(rv)) return rv;
+
+  if (med) return med->GetMostRecentWindow(aType, aWindow);
+
+  return NS_ERROR_FAILURE;
+}
+
+static void activateWindow(mozIDOMWindowProxy *win) {
+  // Try to get native window handle.
+  HWND hwnd = hwndForDOMWindow(win);
+  if (hwnd) {
+    // Restore the window if it is minimized.
+    if (::IsIconic(hwnd)) {
+      ::ShowWindow(hwnd, SW_RESTORE);
+    }
+    // Use the OS call, if possible.
+    ::SetForegroundWindow(hwnd);
+  } else {
+    // Use internal method.
+    nsCOMPtr<nsPIDOMWindowOuter> piWin = nsPIDOMWindowOuter::From(win);
+    piWin->Focus();
+  }
+}
+
+#ifdef DEBUG_law
+#  undef MOZ_DEBUG_DDE
+#  define MOZ_DEBUG_DDE 1
+#endif
+
+// Simple Win32 mutex wrapper.
+struct Win32Mutex {
+  explicit Win32Mutex(const char16_t *name)
+      : mName(name), mHandle(0), mState(-1) {
+    mHandle = CreateMutexW(0, FALSE, mName.get());
+#if MOZ_DEBUG_DDE
+    printf("CreateMutex error = 0x%08X\n", (int)GetLastError());
+#endif
+  }
+  ~Win32Mutex() {
+    if (mHandle) {
+      // Make sure we release it if we own it.
+      Unlock();
+
+      BOOL rc MOZ_MAYBE_UNUSED = CloseHandle(mHandle);
+#if MOZ_DEBUG_DDE
+      if (!rc) {
+        printf("CloseHandle error = 0x%08X\n", (int)GetLastError());
+      }
+#endif
+    }
+  }
+  BOOL Lock(DWORD timeout) {
+    if (mHandle) {
+#if MOZ_DEBUG_DDE
+      printf("Waiting (%d msec) for DDE mutex...\n", (int)timeout);
+#endif
+      mState = WaitForSingleObject(mHandle, timeout);
+#if MOZ_DEBUG_DDE
+      printf("...wait complete, result = 0x%08X, GetLastError=0x%08X\n",
+             (int)mState, (int)::GetLastError());
+#endif
+      return mState == WAIT_OBJECT_0 || mState == WAIT_ABANDONED;
+    } else {
+      return FALSE;
+    }
+  }
+  void Unlock() {
+    if (mHandle && mState == WAIT_OBJECT_0) {
+#if MOZ_DEBUG_DDE
+      printf("Releasing DDE mutex\n");
+#endif
+      ReleaseMutex(mHandle);
+      mState = -1;
+    }
+  }
+
+ private:
+  nsString mName;
+  HANDLE mHandle;
+  DWORD mState;
+};
+
+/* DDE Notes
+ *
+ * This section describes the Win32 DDE service implementation for
+ * Mozilla.  DDE is used on Win32 platforms to communicate between
+ * separate instances of mozilla.exe (or other Mozilla-based
+ * executables), or, between the Win32 desktop shell and Mozilla.
+ *
+ * The first instance of Mozilla will become the "server" and
+ * subsequent executables (and the shell) will use DDE to send
+ * requests to that process.  The requests are DDE "execute" requests
+ * that pass the command line arguments.
+ *
+ * Mozilla registers the DDE application "Mozilla" and currently
+ * supports only the "WWW_OpenURL" topic.  This should be reasonably
+ * compatible with applications that interfaced with Netscape
+ * Communicator (and its predecessors?).  Note that even that topic
+ * may not be supported in a compatible fashion as the command-line
+ * options for Mozilla are different than for Communiator.
+ *
+ * It is imperative that at most one instance of Mozilla execute in
+ * "server mode" at any one time.  The "native app support" in Mozilla
+ * on Win32 ensures that only the server process performs XPCOM
+ * initialization (that is not required for subsequent client processes
+ * to communicate with the server process).
+ *
+ * To guarantee that only one server starts up, a Win32 "mutex" is used
+ * to ensure only one process executes the server-detection code.  That
+ * code consists of initializing DDE and doing a DdeConnect to Mozilla's
+ * application/topic.  If that connection succeeds, then a server process
+ * must be running already.
+ *
+ * Otherwise, no server has started.  In that case, the current process
+ * calls DdeNameService to register that application/topic.  Only at that
+ * point does the mutex get released.
+ *
+ * There are a couple of subtleties that one should be aware of:
+ *
+ * 1. It is imperative that DdeInitialize be called only after the mutex
+ *    lock has been obtained.  The reason is that at shutdown, DDE
+ *    notifications go out to all initialized DDE processes.  Thus, if
+ *    the mutex is owned by a terminating intance of Mozilla, then
+ *    calling DdeInitialize and then WaitForSingleObject will cause the
+ *    DdeUninitialize from the terminating process to "hang" until the
+ *    process waiting for the mutex times out (and can then service the
+ *    notification that the DDE server is terminating).  So, don't mess
+ *    with the sequence of things in the startup/shutdown logic.
+ *
+ * 2. All mutex requests are made with a reasonably long timeout value and
+ *    are designed to "fail safe" (i.e., a timeout is treated as failure).
+ *
+ * 3. An attempt has been made to minimize the degree to which the main
+ *    Mozilla application logic needs to be aware of the DDE mechanisms
+ *    implemented herein.  As a result, this module surfaces a very
+ *    large-grained interface, consisting of simple start/stop methods.
+ *    As a consequence, details of certain scenarios can be "lost."
+ *    Particularly, incoming DDE requests can arrive after this module
+ *    initiates the DDE server, but before Mozilla is initialized to the
+ *    point where those requests can be serviced (e.g., open a browser
+ *    window to a particular URL).  Since the client process sends the
+ *    request early on, it may not be prepared to respond to that error.
+ *    Thus, such situations may fail silently.  The design goal is that
+ *    they fail harmlessly.  Refinements on this point will be made as
+ *    details emerge (and time permits).
  */
 
-class nsNativeAppSupportWin : public nsNativeAppSupportBase {
+/* Update 2001 March
+ *
+ * A significant DDE bug in Windows is causing Mozilla to get wedged at
+ * startup.  This is detailed in Bugzill bug 53952
+ * (http://bugzilla.mozilla.org/show_bug.cgi?id=53952).
+ *
+ * To resolve this, we are using a new strategy:
+ *   o Use a "message window" to detect that Mozilla is already running and
+ *     to pass requests from a second instance back to the first;
+ *   o Run only as a "DDE server" (not as DDE client); this avoids the
+ *     problematic call to DDEConnect().
+ *
+ * We still use the mutex semaphore to protect the code that detects
+ * whether Mozilla is already running.
+ */
+
+/* Update 2007 January
+ *
+ * A change in behavior was implemented in July 2004 which made the
+ * application on launch to add and on quit to remove the ddexec registry key.
+ * See bug 246078.
+ * Windows Vista has changed the methods used to set an application as default
+ * and the new methods are incompatible with removing the ddeexec registry key.
+ * See bug 353089.
+ *
+ * OS DDE Sequence:
+ * 1. OS checks if the dde name is registered.
+ * 2. If it is registered the OS sends a DDE request with the WWW_OpenURL topic
+ *    and the params as specified in the default value of the ddeexec registry
+ *    key for the verb (e.g. open).
+ * 3. If it isn't registered the OS launches the executable defined in the
+ *    verb's (e.g. open) command registry key.
+ * 4. If the ifexec registry key is not present the OS sends a DDE request with
+ *    the WWW_OpenURL topic and the params as specified in the default value of
+ *    the ddeexec registry key for the verb (e.g. open).
+ * 5. If the ifexec registry key is present the OS sends a DDE request with the
+ *    WWW_OpenURL topic and the params as specified in the ifexec registry key
+ *    for the verb (e.g. open).
+ *
+ * Application DDE Sequence:
+ * 1. If the application is running a DDE request is received with the
+ *    WWW_OpenURL topic and the params as specified in the default value of the
+ *    ddeexec registry key (e.g. "%1",,0,0,,,, where '%1' is the url to open)
+ *    for the verb (e.g. open).
+ * 2. If the application is not running it is launched with the --requestPending
+ *    and the --url argument.
+ * 2.1  If the application does not need to restart and the --requestPending
+ *      argument is present the accompanying url will not be used. Instead the
+ *      application will wait for the DDE message to open the url.
+ * 2.2  If the application needs to restart the --requestPending argument is
+ *      removed from the arguments used to restart the application and the url
+ *      will be handled normally.
+ *
+ * Note: Due to a bug in IE the ifexec key should not be used (see bug 355650).
+ */
+
+class nsNativeAppSupportWin : public nsNativeAppSupportBase,
+                              public nsIObserver {
  public:
+  NS_DECL_NSIOBSERVER
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // Overrides of base implementation.
+  NS_IMETHOD Start(bool *aResult) override;
+  NS_IMETHOD Stop(bool *aResult) override;
+  NS_IMETHOD Quit() override;
+  NS_IMETHOD Enable() override;
+  // The "old" Start method (renamed).
+  NS_IMETHOD StartDDE();
   // Utility function to handle a Win32-specific command line
   // option: "--console", which dynamically creates a Windows
   // console.
   void CheckConsole();
 
  private:
   ~nsNativeAppSupportWin() {}
+  static void HandleCommandLine(const char *aCmdLineString,
+                                nsIFile *aWorkingDir, uint32_t aState);
+  static HDDEDATA CALLBACK HandleDDENotification(UINT uType, UINT uFmt,
+                                                 HCONV hconv, HSZ hsz1,
+                                                 HSZ hsz2, HDDEDATA hdata,
+                                                 ULONG_PTR dwData1,
+                                                 ULONG_PTR dwData2);
+  static void ParseDDEArg(HSZ args, int index, nsString &string);
+  static void ParseDDEArg(const WCHAR *args, int index, nsString &aString);
+  static HDDEDATA CreateDDEData(DWORD value);
+  static HDDEDATA CreateDDEData(LPBYTE value, DWORD len);
+  static bool InitTopicStrings();
+  static int FindTopic(HSZ topic);
+  static void ActivateLastWindow();
+  static nsresult OpenWindow(const char *urlstr, const char *args);
+  static nsresult OpenBrowserWindow();
+  static void SetupSysTrayIcon();
+  static void RemoveSysTrayIcon();
+
+  static int mConversations;
+  enum {
+    topicOpenURL,
+    topicActivate,
+    topicCancelProgress,
+    topicVersion,
+    topicRegisterViewer,
+    topicUnRegisterViewer,
+    topicGetWindowInfo,
+    // Note: Insert new values above this line!!!!!
+    topicCount  // Count of the number of real topics
+  };
+  static HSZ mApplication, mTopics[topicCount];
+  static DWORD mInstance;
+  static bool mCanHandleRequests;
+  static char16_t mMutexName[];
+  friend struct MessageWindow;
 };  // nsNativeAppSupportWin
 
+NS_INTERFACE_MAP_BEGIN(nsNativeAppSupportWin)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END_INHERITING(nsNativeAppSupportBase)
+
+NS_IMPL_ADDREF_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
+NS_IMPL_RELEASE_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
+
 void UseParentConsole() {
   if (AttachConsole(ATTACH_PARENT_PROCESS)) {
     // Redirect the standard streams to the existing console, but
     // only if they haven't been redirected to a valid file.
     // Visual Studio's _fileno() returns -2 for the standard
     // streams if they aren't associated with an output stream.
     if (_fileno(stdout) == -2) {
       freopen("CONOUT$", "w", stdout);
@@ -82,8 +384,1057 @@ nsresult NS_CreateNativeAppSupport(nsINa
   // Check for dynamic console creation request.
   pNative->CheckConsole();
 
   *aResult = pNative;
   NS_ADDREF(*aResult);
 
   return NS_OK;
 }
+
+// Constants
+#define MOZ_DDE_APPLICATION "Mozilla"
+#define MOZ_MUTEX_NAMESPACE L"Local\\"
+#define MOZ_STARTUP_MUTEX_NAME L"StartupMutex"
+#define MOZ_DDE_START_TIMEOUT 30000
+#define MOZ_DDE_STOP_TIMEOUT 15000
+#define MOZ_DDE_EXEC_TIMEOUT 15000
+
+// The array entries must match the enum ordering!
+const char *const topicNames[] = {"WWW_OpenURL",        "WWW_Activate",
+                                  "WWW_CancelProgress", "WWW_Version",
+                                  "WWW_RegisterViewer", "WWW_UnRegisterViewer",
+                                  "WWW_GetWindowInfo"};
+
+// Static member definitions.
+int nsNativeAppSupportWin::mConversations = 0;
+HSZ nsNativeAppSupportWin::mApplication = 0;
+HSZ nsNativeAppSupportWin::mTopics[nsNativeAppSupportWin::topicCount] = {0};
+DWORD nsNativeAppSupportWin::mInstance = 0;
+bool nsNativeAppSupportWin::mCanHandleRequests = false;
+
+char16_t nsNativeAppSupportWin::mMutexName[128] = {0};
+
+// Message window encapsulation.
+struct MessageWindow {
+  // ctor/dtor are simplistic
+  MessageWindow() {
+    // Try to find window.
+    mHandle = ::FindWindowW(className(), 0);
+  }
+
+  // Act like an HWND.
+  operator HWND() { return mHandle; }
+
+  // Class name: appName + "MessageWindow"
+  static const wchar_t *className() {
+    static wchar_t classNameBuffer[128];
+    static wchar_t *mClassName = 0;
+    if (!mClassName) {
+      ::_snwprintf(classNameBuffer,
+                   128,  // size of classNameBuffer in PRUnichars
+                   L"%s%s",
+                   static_cast<const wchar_t *>(
+                       NS_ConvertUTF8toUTF16(gAppData->remotingName).get()),
+                   L"MessageWindow");
+      mClassName = classNameBuffer;
+    }
+    return mClassName;
+  }
+
+  // Create: Register class and create window.
+  NS_IMETHOD Create() {
+    WNDCLASSW classStruct = {0,                           // style
+                             &MessageWindow::WindowProc,  // lpfnWndProc
+                             0,                           // cbClsExtra
+                             0,                           // cbWndExtra
+                             0,                           // hInstance
+                             0,                           // hIcon
+                             0,                           // hCursor
+                             0,                           // hbrBackground
+                             0,                           // lpszMenuName
+                             className()};                // lpszClassName
+
+    // Register the window class.
+    NS_ENSURE_TRUE(::RegisterClassW(&classStruct), NS_ERROR_FAILURE);
+
+    // Create the window.
+    NS_ENSURE_TRUE((mHandle = ::CreateWindowW(className(),
+                                              0,           // title
+                                              WS_CAPTION,  // style
+                                              0, 0, 0, 0,  // x, y, cx, cy
+                                              0,           // parent
+                                              0,           // menu
+                                              0,           // instance
+                                              0)),         // create struct
+                   NS_ERROR_FAILURE);
+
+#if MOZ_DEBUG_DDE
+    printf("Message window = 0x%08X\n", (int)mHandle);
+#endif
+
+    return NS_OK;
+  }
+
+  // Destory:  Get rid of window and reset mHandle.
+  NS_IMETHOD Destroy() {
+    nsresult retval = NS_OK;
+
+    if (mHandle) {
+      // DestroyWindow can only destroy windows created from
+      //  the same thread.
+      BOOL desRes = DestroyWindow(mHandle);
+      if (FALSE != desRes) {
+        mHandle = nullptr;
+      } else {
+        retval = NS_ERROR_FAILURE;
+      }
+    }
+
+    return retval;
+  }
+
+  // SendRequest: Pass the command line via WM_COPYDATA to message window.
+  NS_IMETHOD SendRequest() {
+    WCHAR *cmd = ::GetCommandLineW();
+    WCHAR cwd[MAX_PATH];
+    _wgetcwd(cwd, MAX_PATH);
+
+    // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
+    NS_ConvertUTF16toUTF8 utf8buffer(cmd);
+    utf8buffer.Append('\0');
+    WCHAR *cwdPtr = cwd;
+    AppendUTF16toUTF8(MakeStringSpan(reinterpret_cast<char16_t *>(cwdPtr)),
+                      utf8buffer);
+    utf8buffer.Append('\0');
+
+    // We used to set dwData to zero, when we didn't send the working dir.
+    // Now we're using it as a version number.
+    COPYDATASTRUCT cds = {1, utf8buffer.Length(), (void *)utf8buffer.get()};
+    // Bring the already running Mozilla process to the foreground.
+    // nsWindow will restore the window (if minimized) and raise it.
+    ::SetForegroundWindow(mHandle);
+    ::SendMessage(mHandle, WM_COPYDATA, 0, (LPARAM)&cds);
+    return NS_OK;
+  }
+
+  // Window proc.
+  static LRESULT CALLBACK WindowProc(HWND msgWindow, UINT msg, WPARAM wp,
+                                     LPARAM lp) {
+    if (msg == WM_COPYDATA) {
+      if (!nsNativeAppSupportWin::mCanHandleRequests) return FALSE;
+
+      // This is an incoming request.
+      COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lp;
+#if MOZ_DEBUG_DDE
+      printf("Incoming request: %s\n", (const char *)cds->lpData);
+#endif
+      nsCOMPtr<nsIFile> workingDir;
+
+      if (1 >= cds->dwData) {
+        char *wdpath = (char *)cds->lpData;
+        // skip the command line, and get the working dir of the
+        // other process, which is after the first null char
+        while (*wdpath) ++wdpath;
+
+        ++wdpath;
+
+#ifdef MOZ_DEBUG_DDE
+        printf("Working dir: %s\n", wdpath);
+#endif
+
+        NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath), false,
+                        getter_AddRefs(workingDir));
+      }
+      (void)nsNativeAppSupportWin::HandleCommandLine(
+          (char *)cds->lpData, workingDir, nsICommandLine::STATE_REMOTE_AUTO);
+
+      // Get current window and return its window handle.
+      nsCOMPtr<mozIDOMWindowProxy> win;
+      GetMostRecentWindow(0, getter_AddRefs(win));
+      return win ? (LRESULT)hwndForDOMWindow(win) : 0;
+    }
+    return DefWindowProc(msgWindow, msg, wp, lp);
+  }
+
+ private:
+  HWND mHandle;
+};  // struct MessageWindow
+
+/* Start: Tries to find the "message window" to determine if it
+ *        exists.  If so, then Mozilla is already running.  In that
+ *        case, we use the handle to the "message" window and send
+ *        a request corresponding to this process's command line
+ *        options.
+ *
+ *        If not, then this is the first instance of Mozilla.  In
+ *        that case, we create and set up the message window.
+ *
+ *        The checking for existence of the message window must
+ *        be protected by use of a mutex semaphore.
+ */
+NS_IMETHODIMP
+nsNativeAppSupportWin::Start(bool *aResult) {
+  NS_ENSURE_ARG(aResult);
+  NS_ENSURE_TRUE(mInstance == 0, NS_ERROR_NOT_INITIALIZED);
+  NS_ENSURE_STATE(gAppData);
+
+  if (getenv("MOZ_NO_REMOTE")) {
+    *aResult = true;
+    return NS_OK;
+  }
+
+  nsresult rv = NS_ERROR_FAILURE;
+  *aResult = false;
+
+  // Grab mutex first.
+
+  // Build mutex name from app name.
+  ::_snwprintf(
+      reinterpret_cast<wchar_t *>(mMutexName),
+      sizeof mMutexName / sizeof(char16_t), L"%s%s%s", MOZ_MUTEX_NAMESPACE,
+      static_cast<const wchar_t *>(NS_ConvertUTF8toUTF16(gAppData->name).get()),
+      MOZ_STARTUP_MUTEX_NAME);
+  Win32Mutex startupLock = Win32Mutex(mMutexName);
+
+  NS_ENSURE_TRUE(startupLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE);
+
+  // Search for existing message window.
+  MessageWindow msgWindow;
+  if ((HWND)msgWindow) {
+    // We are a client process.  Pass request to message window.
+    rv = msgWindow.SendRequest();
+  } else {
+    // We will be server.
+    rv = msgWindow.Create();
+    if (NS_SUCCEEDED(rv)) {
+      // Start up DDE server.
+      this->StartDDE();
+      // Tell caller to spin message loop.
+      *aResult = true;
+    }
+  }
+
+  startupLock.Unlock();
+
+  return rv;
+}
+
+bool nsNativeAppSupportWin::InitTopicStrings() {
+  for (int i = 0; i < topicCount; i++) {
+    if (!(mTopics[i] = DdeCreateStringHandleA(
+              mInstance, const_cast<char *>(topicNames[i]), CP_WINANSI))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+int nsNativeAppSupportWin::FindTopic(HSZ topic) {
+  for (int i = 0; i < topicCount; i++) {
+    if (DdeCmpStringHandles(topic, mTopics[i]) == 0) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+// Start DDE server.
+//
+// This used to be the Start() method when we were using DDE as the
+// primary IPC mechanism between secondary Mozilla processes and the
+// initial "server" process.
+//
+// Now, it simply initializes the DDE server.  The caller must check
+// that this process is to be the server, and, must acquire the DDE
+// startup mutex semaphore prior to calling this routine.  See ::Start(),
+// above.
+NS_IMETHODIMP
+nsNativeAppSupportWin::StartDDE() {
+  NS_ENSURE_TRUE(mInstance == 0, NS_ERROR_NOT_INITIALIZED);
+
+  // Initialize DDE.
+  NS_ENSURE_TRUE(DMLERR_NO_ERROR ==
+                     DdeInitialize(&mInstance,
+                                   nsNativeAppSupportWin::HandleDDENotification,
+                                   APPCLASS_STANDARD, 0),
+                 NS_ERROR_FAILURE);
+
+  // Allocate DDE strings.
+  NS_ENSURE_TRUE(
+      (mApplication = DdeCreateStringHandleA(
+           mInstance, (char *)(const char *)gAppData->name, CP_WINANSI)) &&
+          InitTopicStrings(),
+      NS_ERROR_FAILURE);
+
+  // Next step is to register a DDE service.
+  NS_ENSURE_TRUE(DdeNameService(mInstance, mApplication, 0, DNS_REGISTER),
+                 NS_ERROR_FAILURE);
+
+#if MOZ_DEBUG_DDE
+  printf("DDE server started\n");
+#endif
+
+  return NS_OK;
+}
+
+// If no DDE conversations are pending, terminate DDE.
+NS_IMETHODIMP
+nsNativeAppSupportWin::Stop(bool *aResult) {
+  NS_ENSURE_ARG(aResult);
+  NS_ENSURE_TRUE(mInstance, NS_ERROR_NOT_INITIALIZED);
+
+  nsresult rv = NS_OK;
+  *aResult = true;
+
+  Win32Mutex ddeLock(mMutexName);
+
+  if (ddeLock.Lock(MOZ_DDE_STOP_TIMEOUT)) {
+    if (mConversations == 0) {
+      this->Quit();
+    } else {
+      *aResult = false;
+    }
+
+    ddeLock.Unlock();
+  } else {
+    // No DDE application name specified, but that's OK.  Just
+    // forge ahead.
+    *aResult = true;
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsNativeAppSupportWin::Observe(nsISupports *aSubject, const char *aTopic,
+                               const char16_t *aData) {
+  if (strcmp(aTopic, "quit-application") == 0) {
+    Quit();
+  } else {
+    NS_ERROR("Unexpected observer topic.");
+  }
+
+  return NS_OK;
+}
+
+// Terminate DDE regardless.
+NS_IMETHODIMP
+nsNativeAppSupportWin::Quit() {
+  // If another process wants to look for the message window, they need
+  // to wait to hold the lock, in which case they will not find the
+  // window as we will destroy ours under our lock.
+  // When the mutex goes off the stack, it is unlocked via destructor.
+  Win32Mutex mutexLock(mMutexName);
+  NS_ENSURE_TRUE(mutexLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE);
+
+  // If we've got a message window to receive IPC or new window requests,
+  // get rid of it as we are shutting down.
+  // Note:  Destroy calls DestroyWindow, which will only work on a window
+  //  created by the same thread.
+  MessageWindow mw;
+  mw.Destroy();
+
+  if (mInstance) {
+    // Unregister application name.
+    DdeNameService(mInstance, mApplication, 0, DNS_UNREGISTER);
+    // Clean up strings.
+    if (mApplication) {
+      DdeFreeStringHandle(mInstance, mApplication);
+      mApplication = 0;
+    }
+    for (int i = 0; i < topicCount; i++) {
+      if (mTopics[i]) {
+        DdeFreeStringHandle(mInstance, mTopics[i]);
+        mTopics[i] = 0;
+      }
+    }
+    DdeUninitialize(mInstance);
+    mInstance = 0;
+#if MOZ_DEBUG_DDE
+    printf("DDE server stopped\n");
+#endif
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNativeAppSupportWin::Enable() {
+  mCanHandleRequests = true;
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->AddObserver(this, "quit-application", false);
+  } else {
+    NS_ERROR("No observer service?");
+  }
+
+  return NS_OK;
+}
+
+#if MOZ_DEBUG_DDE
+// Macro to generate case statement for a given XTYP value.
+#  define XTYP_CASE(t) \
+    case t:            \
+      result = #t;     \
+      break
+
+static nsCString uTypeDesc(UINT uType) {
+  nsCString result;
+  switch (uType) {
+    XTYP_CASE(XTYP_ADVSTART);
+    XTYP_CASE(XTYP_CONNECT);
+    XTYP_CASE(XTYP_ADVREQ);
+    XTYP_CASE(XTYP_REQUEST);
+    XTYP_CASE(XTYP_WILDCONNECT);
+    XTYP_CASE(XTYP_ADVDATA);
+    XTYP_CASE(XTYP_EXECUTE);
+    XTYP_CASE(XTYP_POKE);
+    XTYP_CASE(XTYP_ADVSTOP);
+    XTYP_CASE(XTYP_CONNECT_CONFIRM);
+    XTYP_CASE(XTYP_DISCONNECT);
+    XTYP_CASE(XTYP_ERROR);
+    XTYP_CASE(XTYP_MONITOR);
+    XTYP_CASE(XTYP_REGISTER);
+    XTYP_CASE(XTYP_XACT_COMPLETE);
+    XTYP_CASE(XTYP_UNREGISTER);
+    default:
+      result = "XTYP_?????";
+  }
+  return result;
+}
+
+static nsCString hszValue(DWORD instance, HSZ hsz) {
+  // Extract string from HSZ.
+  nsCString result("[");
+  DWORD len = DdeQueryString(instance, hsz, nullptr, nullptr, CP_WINANSI);
+  if (len) {
+    char buffer[256];
+    DdeQueryString(instance, hsz, buffer, sizeof buffer, CP_WINANSI);
+    result += buffer;
+  }
+  result += "]";
+  return result;
+}
+#endif
+
+// Utility function to escape double-quotes within a string.
+static void escapeQuotes(nsAString &aString) {
+  int32_t offset = -1;
+  while (1) {
+    // Find next '"'.
+    offset = aString.FindChar('"', ++offset);
+    if (offset == kNotFound) {
+      // No more quotes, exit.
+      break;
+    } else {
+      // Insert back-slash ahead of the '"'.
+      aString.Insert(char16_t('\\'), offset);
+      // Increment offset because we just inserted a slash
+      offset++;
+    }
+  }
+  return;
+}
+
+HDDEDATA CALLBACK nsNativeAppSupportWin::HandleDDENotification(
+    UINT uType,           // transaction type
+    UINT uFmt,            // clipboard data format
+    HCONV hconv,          // handle to the conversation
+    HSZ hsz1,             // handle to a string
+    HSZ hsz2,             // handle to a string
+    HDDEDATA hdata,       // handle to a global memory object
+    ULONG_PTR dwData1,    // transaction-specific data
+    ULONG_PTR dwData2) {  // transaction-specific data
+
+  if (!mCanHandleRequests) return 0;
+
+#if MOZ_DEBUG_DDE
+  printf("DDE: uType  =%s\n", uTypeDesc(uType).get());
+  printf("     uFmt   =%u\n", (unsigned)uFmt);
+  printf("     hconv  =%08x\n", (int)hconv);
+  printf("     hsz1   =%08x:%s\n", (int)hsz1, hszValue(mInstance, hsz1).get());
+  printf("     hsz2   =%08x:%s\n", (int)hsz2, hszValue(mInstance, hsz2).get());
+  printf("     hdata  =%08x\n", (int)hdata);
+  printf("     dwData1=%08x\n", (int)dwData1);
+  printf("     dwData2=%08x\n", (int)dwData2);
+#endif
+
+  HDDEDATA result = 0;
+  if (uType & XCLASS_BOOL) {
+    switch (uType) {
+      case XTYP_CONNECT:
+        // Make sure its for our service/topic.
+        if (FindTopic(hsz1) != -1) {
+          // We support this connection.
+          result = (HDDEDATA)1;
+        }
+        break;
+      case XTYP_CONNECT_CONFIRM:
+        // We don't care about the conversation handle, at this point.
+        result = (HDDEDATA)1;
+        break;
+    }
+  } else if (uType & XCLASS_DATA) {
+    if (uType == XTYP_REQUEST) {
+      switch (FindTopic(hsz1)) {
+        case topicOpenURL: {
+          // Open a given URL...
+
+          // Get the URL from the first argument in the command.
+          nsAutoString url;
+          ParseDDEArg(hsz2, 0, url);
+
+          // Read the 3rd argument in the command to determine if a
+          // new window is to be used.
+          nsAutoString windowID;
+          ParseDDEArg(hsz2, 2, windowID);
+          // "" means to open the URL in a new window.
+          if (windowID.IsEmpty()) {
+            url.InsertLiteral(u"mozilla -new-window ", 0);
+          } else {
+            url.InsertLiteral(u"mozilla -url ", 0);
+          }
+
+#if MOZ_DEBUG_DDE
+          printf("Handling dde XTYP_REQUEST request: [%s]...\n",
+                 NS_ConvertUTF16toUTF8(url).get());
+#endif
+          // Now handle it.
+          HandleCommandLine(NS_ConvertUTF16toUTF8(url).get(), nullptr,
+                            nsICommandLine::STATE_REMOTE_EXPLICIT);
+
+          // Return pseudo window ID.
+          result = CreateDDEData(1);
+          break;
+        }
+        case topicGetWindowInfo: {
+          // This topic has to get the current URL, get the current
+          // page title and then format the output into the DDE
+          // return string.  The return value is "URL","Page Title",
+          // "Window ID" however the window ID is not used for this
+          // command, therefore it is returned as a null string
+
+          // This isn't really a loop.  We just use "break"
+          // statements to bypass the remaining steps when
+          // something goes wrong.
+          do {
+            // Get most recently used Nav window.
+            nsCOMPtr<mozIDOMWindowProxy> navWin;
+            GetMostRecentWindow(u"navigator:browser", getter_AddRefs(navWin));
+            nsCOMPtr<nsPIDOMWindowOuter> piNavWin = do_QueryInterface(navWin);
+            if (!piNavWin) {
+              // There is not a window open
+              break;
+            }
+
+            // Get content window.
+            nsCOMPtr<nsPIDOMWindowOuter> internalContent =
+                nsGlobalWindowOuter::Cast(piNavWin)->GetContent();
+            if (!internalContent) {
+              break;
+            }
+            // Get location.
+            RefPtr<dom::Location> location = internalContent->GetLocation();
+            if (!location) {
+              break;
+            }
+            // Get href for URL.
+            nsAutoString url;
+            if (NS_FAILED(location->GetHref(url))) {
+              break;
+            }
+            // Escape any double-quotes.
+            escapeQuotes(url);
+
+            // Now for the title...
+
+            // Get the base window from the doc shell...
+            nsCOMPtr<nsIBaseWindow> baseWindow =
+                do_QueryInterface(internalContent->GetDocShell());
+            if (!baseWindow) {
+              break;
+            }
+            // And from the base window we can get the title.
+            nsString title;
+            if (!baseWindow) {
+              break;
+            }
+            baseWindow->GetTitle(title);
+            // Escape any double-quotes in the title.
+            escapeQuotes(title);
+
+            // Use a string buffer for the output data, first
+            // save a quote.
+            nsAutoCString outpt(NS_LITERAL_CSTRING("\""));
+            // Now copy the URL converting the Unicode string
+            // to a single-byte ASCII string
+            nsAutoCString tmpNativeStr;
+            NS_CopyUnicodeToNative(url, tmpNativeStr);
+            outpt.Append(tmpNativeStr);
+            // Add the "," used to separate the URL and the page
+            // title
+            outpt.Append(NS_LITERAL_CSTRING("\",\""));
+            // Now copy the current page title to the return string
+            NS_CopyUnicodeToNative(title, tmpNativeStr);
+            outpt.Append(tmpNativeStr);
+            // Fill out the return string with the remainin ",""
+            outpt.Append(NS_LITERAL_CSTRING("\",\"\""));
+
+            // Create a DDE handle to a char string for the data
+            // being returned, this copies and creates a "shared"
+            // copy of the DDE response until the calling APP
+            // reads it and says it can be freed.
+            result = CreateDDEData((LPBYTE)(const char *)outpt.get(),
+                                   outpt.Length() + 1);
+#if MOZ_DEBUG_DDE
+            printf("WWW_GetWindowInfo->%s\n", outpt.get());
+#endif
+          } while (false);
+          break;
+        }
+        case topicActivate: {
+          // Activate a Nav window...
+          nsAutoString windowID;
+          ParseDDEArg(hsz2, 0, windowID);
+          // 4294967295 is decimal for 0xFFFFFFFF which is also a
+          //   correct value to do that Activate last window stuff
+          if (windowID.EqualsLiteral("-1") ||
+              windowID.EqualsLiteral("4294967295")) {
+            // We only support activating the most recent window (or a new one).
+            ActivateLastWindow();
+            // Return pseudo window ID.
+            result = CreateDDEData(1);
+          }
+          break;
+        }
+        case topicVersion: {
+          // Return version.  We're restarting at 1.0!
+          DWORD version = 1 << 16;  // "1.0"
+          result = CreateDDEData(version);
+          break;
+        }
+        case topicRegisterViewer: {
+          // Register new viewer (not implemented).
+          result = CreateDDEData(false);
+          break;
+        }
+        case topicUnRegisterViewer: {
+          // Unregister new viewer (not implemented).
+          result = CreateDDEData(false);
+          break;
+        }
+        default:
+          break;
+      }
+    } else if (uType & XTYP_POKE) {
+      switch (FindTopic(hsz1)) {
+        case topicCancelProgress: {
+          // "Handle" progress cancel (actually, pretty much ignored).
+          result = (HDDEDATA)DDE_FACK;
+          break;
+        }
+        default:
+          break;
+      }
+    }
+  } else if (uType & XCLASS_FLAGS) {
+    if (uType == XTYP_EXECUTE) {
+      // Prove that we received the request.
+      DWORD bytes;
+      LPBYTE request = DdeAccessData(hdata, &bytes);
+#if MOZ_DEBUG_DDE
+      printf("Handling dde request: [%s]...\n", (char *)request);
+#endif
+
+      nsAutoString url;
+      ParseDDEArg((const WCHAR *)request, 0, url);
+
+      // Read the 3rd argument in the command to determine if a
+      // new window is to be used.
+      nsAutoString windowID;
+      ParseDDEArg((const WCHAR *)request, 2, windowID);
+
+      // "" means to open the URL in a new window.
+      if (windowID.IsEmpty()) {
+        url.InsertLiteral(u"mozilla -new-window ", 0);
+      } else {
+        url.InsertLiteral(u"mozilla -url ", 0);
+      }
+#if MOZ_DEBUG_DDE
+      printf("Handling dde XTYP_REQUEST request: [%s]...\n",
+             NS_ConvertUTF16toUTF8(url).get());
+#endif
+      // Now handle it.
+      HandleCommandLine(NS_ConvertUTF16toUTF8(url).get(), nullptr,
+                        nsICommandLine::STATE_REMOTE_EXPLICIT);
+
+      // Release the data.
+      DdeUnaccessData(hdata);
+      result = (HDDEDATA)DDE_FACK;
+    } else {
+      result = (HDDEDATA)DDE_FNOTPROCESSED;
+    }
+  } else if (uType & XCLASS_NOTIFICATION) {
+  }
+#if MOZ_DEBUG_DDE
+  printf("DDE result=%d (0x%08X)\n", (int)result, (int)result);
+#endif
+  return result;
+}
+
+// Utility function to advance to end of quoted string.
+// p+offset must point to the comma preceding the arg on entry.
+// On return, p+result points to the closing '"' (or end of the string
+// if the closing '"' is missing) if the arg is quoted.  If the arg
+// is not quoted, then p+result will point to the first character
+// of the arg.
+static int32_t advanceToEndOfQuotedArg(const WCHAR *p, int32_t offset,
+                                       int32_t len) {
+  // Check whether the current arg is quoted.
+  if (p[++offset] == '"') {
+    // Advance past the closing quote.
+    while (offset < len && p[++offset] != '"') {
+      // If the current character is a backslash, then the
+      // next character can't be a *real* '"', so skip it.
+      if (p[offset] == '\\') {
+        offset++;
+      }
+    }
+  }
+  return offset;
+}
+
+void nsNativeAppSupportWin::ParseDDEArg(const WCHAR *args, int index,
+                                        nsString &aString) {
+  if (args) {
+    nsDependentString temp(args);
+
+    // offset points to the comma preceding the desired arg.
+    int32_t offset = -1;
+    // Skip commas till we get to the arg we want.
+    while (index--) {
+      // If this arg is quoted, then go to closing quote.
+      offset = advanceToEndOfQuotedArg(args, offset, temp.Length());
+      // Find next comma.
+      offset = temp.FindChar(',', offset);
+      if (offset == kNotFound) {
+        // No more commas, give up.
+        aString = args;
+        return;
+      }
+    }
+    // The desired argument starts just past the preceding comma,
+    // which offset points to, and extends until the following
+    // comma (or the end of the string).
+    //
+    // Since the argument might be enclosed in quotes, we need to
+    // deal with that before searching for the terminating comma.
+    // We advance offset so it ends up pointing to the start of
+    // the argument we want.
+    int32_t end = advanceToEndOfQuotedArg(args, offset++, temp.Length());
+    // Find next comma (or end of string).
+    end = temp.FindChar(',', end);
+    if (end == kNotFound) {
+      // Arg is the rest of the string.
+      end = temp.Length();
+    }
+    // Extract result.
+    aString.Assign(args + offset, end - offset);
+  }
+  return;
+}
+
+// Utility to parse out argument from a DDE item string.
+void nsNativeAppSupportWin::ParseDDEArg(HSZ args, int index,
+                                        nsString &aString) {
+  DWORD argLen = DdeQueryStringW(mInstance, args, nullptr, 0, CP_WINUNICODE);
+  // there wasn't any string, so return empty string
+  if (!argLen) return;
+  nsAutoString temp;
+  // Ensure result's buffer is sufficiently big.
+  temp.SetLength(argLen);
+  // Now get the string contents.
+  DdeQueryString(mInstance, args,
+                 reinterpret_cast<wchar_t *>(temp.BeginWriting()),
+                 temp.Length(), CP_WINUNICODE);
+  // Parse out the given arg.
+  ParseDDEArg(temp.get(), index, aString);
+  return;
+}
+
+HDDEDATA nsNativeAppSupportWin::CreateDDEData(DWORD value) {
+  return CreateDDEData((LPBYTE)&value, sizeof value);
+}
+
+HDDEDATA nsNativeAppSupportWin::CreateDDEData(LPBYTE value, DWORD len) {
+  HDDEDATA result =
+      DdeCreateDataHandle(mInstance, value, len, 0, mApplication, CF_TEXT, 0);
+  return result;
+}
+
+void nsNativeAppSupportWin::ActivateLastWindow() {
+  nsCOMPtr<mozIDOMWindowProxy> navWin;
+  GetMostRecentWindow(u"navigator:browser", getter_AddRefs(navWin));
+  if (navWin) {
+    // Activate that window.
+    activateWindow(navWin);
+  } else {
+    // Need to create a Navigator window, then.
+    OpenBrowserWindow();
+  }
+}
+
+void nsNativeAppSupportWin::HandleCommandLine(const char *aCmdLineString,
+                                              nsIFile *aWorkingDir,
+                                              uint32_t aState) {
+  nsresult rv;
+
+  int justCounting = 1;
+  char **argv = 0;
+  // Flags, etc.
+  int init = 1;
+  int between, quoted, bSlashCount;
+  int argc;
+  const char *p;
+  nsAutoCString arg;
+
+  nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
+
+  // Parse command line args according to MS spec
+  // (see "Parsing C++ Command-Line Arguments" at
+  // http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
+  // We loop if we've not finished the second pass through.
+  while (1) {
+    // Initialize if required.
+    if (init) {
+      p = aCmdLineString;
+      between = 1;
+      argc = quoted = bSlashCount = 0;
+
+      init = 0;
+    }
+    if (between) {
+      // We are traversing whitespace between args.
+      // Check for start of next arg.
+      if (*p != 0 && !isspace(*p)) {
+        // Start of another arg.
+        between = 0;
+        arg = "";
+        switch (*p) {
+          case '\\':
+            // Count the backslash.
+            bSlashCount = 1;
+            break;
+          case '"':
+            // Remember we're inside quotes.
+            quoted = 1;
+            break;
+          default:
+            // Add character to arg.
+            arg += *p;
+            break;
+        }
+      } else {
+        // Another space between args, ignore it.
+      }
+    } else {
+      // We are processing the contents of an argument.
+      // Check for whitespace or end.
+      if (*p == 0 || (!quoted && isspace(*p))) {
+        // Process pending backslashes (interpret them
+        // literally since they're not followed by a ").
+        while (bSlashCount) {
+          arg += '\\';
+          bSlashCount--;
+        }
+        // End current arg.
+        if (!justCounting) {
+          argv[argc] = new char[arg.Length() + 1];
+          strcpy(argv[argc], arg.get());
+        }
+        argc++;
+        // We're now between args.
+        between = 1;
+      } else {
+        // Still inside argument, process the character.
+        switch (*p) {
+          case '"':
+            // First, digest preceding backslashes (if any).
+            while (bSlashCount > 1) {
+              // Put one backsplash in arg for each pair.
+              arg += '\\';
+              bSlashCount -= 2;
+            }
+            if (bSlashCount) {
+              // Quote is literal.
+              arg += '"';
+              bSlashCount = 0;
+            } else {
+              // Quote starts or ends a quoted section.
+              if (quoted) {
+                // Check for special case of consecutive double
+                // quotes inside a quoted section.
+                if (*(p + 1) == '"') {
+                  // This implies a literal double-quote.  Fake that
+                  // out by causing next double-quote to look as
+                  // if it was preceded by a backslash.
+                  bSlashCount = 1;
+                } else {
+                  quoted = 0;
+                }
+              } else {
+                quoted = 1;
+              }
+            }
+            break;
+          case '\\':
+            // Add to count.
+            bSlashCount++;
+            break;
+          default:
+            // Accept any preceding backslashes literally.
+            while (bSlashCount) {
+              arg += '\\';
+              bSlashCount--;
+            }
+            // Just add next char to the current arg.
+            arg += *p;
+            break;
+        }
+      }
+    }
+    // Check for end of input.
+    if (*p) {
+      // Go to next character.
+      p++;
+    } else {
+      // If on first pass, go on to second.
+      if (justCounting) {
+        // Allocate argv array.
+        argv = new char *[argc];
+
+        // Start second pass
+        justCounting = 0;
+        init = 1;
+      } else {
+        // Quit.
+        break;
+      }
+    }
+  }
+
+  rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
+
+  // Cleanup.
+  while (argc) {
+    delete[] argv[--argc];
+  }
+  delete[] argv;
+
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Error initializing command line.");
+    return;
+  }
+
+  cmdLine->Run();
+}
+
+nsresult nsNativeAppSupportWin::OpenWindow(const char *urlstr,
+                                           const char *args) {
+  nsresult rv = NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
+  nsCOMPtr<nsISupportsCString> sarg(
+      do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
+  if (sarg) sarg->SetData(nsDependentCString(args));
+
+  if (wwatch && sarg) {
+    nsCOMPtr<mozIDOMWindowProxy> newWindow;
+    rv = wwatch->OpenWindow(0, urlstr, "_blank", "chrome,dialog=no,all", sarg,
+                            getter_AddRefs(newWindow));
+#if MOZ_DEBUG_DDE
+  } else {
+    printf("Get WindowWatcher (or create string) failed\n");
+#endif
+  }
+  return rv;
+}
+
+HWND hwndForDOMWindow(mozIDOMWindowProxy *window) {
+  if (!window) {
+    return 0;
+  }
+  nsCOMPtr<nsPIDOMWindowOuter> pidomwindow = nsPIDOMWindowOuter::From(window);
+
+  nsCOMPtr<nsIBaseWindow> ppBaseWindow =
+      do_QueryInterface(pidomwindow->GetDocShell());
+  if (!ppBaseWindow) {
+    return 0;
+  }
+
+  nsCOMPtr<nsIWidget> ppWidget;
+  ppBaseWindow->GetMainWidget(getter_AddRefs(ppWidget));
+
+  return (HWND)(ppWidget->GetNativeData(NS_NATIVE_WIDGET));
+}
+
+nsresult nsNativeAppSupportWin::OpenBrowserWindow() {
+  nsresult rv = NS_OK;
+
+  // Open the argument URL in the most recently used Navigator window.
+  // If there is no Nav window, open a new one.
+
+  // If at all possible, hand the request off to the most recent
+  // browser window.
+
+  nsCOMPtr<mozIDOMWindowProxy> navWin;
+  GetMostRecentWindow(u"navigator:browser", getter_AddRefs(navWin));
+
+  // This isn't really a loop.  We just use "break" statements to fall
+  // out to the OpenWindow call when things go awry.
+  do {
+    // If caller requires a new window, then don't use an existing one.
+    if (!navWin) {
+      // Have to open a new one.
+      break;
+    }
+
+    nsCOMPtr<nsIBrowserDOMWindow> bwin;
+    {  // scope a bunch of temporary cruft used to generate bwin
+      nsCOMPtr<nsIWebNavigation> navNav(do_GetInterface(navWin));
+      nsCOMPtr<nsIDocShellTreeItem> navItem(do_QueryInterface(navNav));
+      if (navItem) {
+        nsCOMPtr<nsIDocShellTreeItem> rootItem;
+        navItem->GetRootTreeItem(getter_AddRefs(rootItem));
+        nsCOMPtr<nsPIDOMWindowOuter> rootWin =
+            rootItem ? rootItem->GetWindow() : nullptr;
+        nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
+        if (chromeWin) chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
+      }
+    }
+    if (bwin) {
+      nsCOMPtr<nsIURI> uri;
+      NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank"), 0, 0);
+      if (uri) {
+        nsCOMPtr<mozIDOMWindowProxy> container;
+        rv = bwin->OpenURI(uri, 0, nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
+                           nsIBrowserDOMWindow::OPEN_EXTERNAL,
+                           nsContentUtils::GetSystemPrincipal(),
+                           getter_AddRefs(container));
+        if (NS_SUCCEEDED(rv)) return NS_OK;
+      }
+    }
+
+    NS_ERROR("failed to hand off external URL to extant window");
+  } while (false);
+
+  // open a new window if caller requested it or if anything above failed
+
+  char *argv[] = {0};
+  nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
+
+  rv = cmdLine->Init(0, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return cmdLine->Run();
+}
--- a/toolkit/xre/nsNativeAppSupportWin.h
+++ b/toolkit/xre/nsNativeAppSupportWin.h
@@ -10,16 +10,25 @@
  *
  * This file, and the generated .h, are only needed on Win32 platforms.
  */
 
 // Constants identifying Win32 "native" resources.
 
 #ifdef MOZ_PHOENIX
 
+// Splash screen dialog ID.
+#  define IDD_SPLASH 100
+
+// Splash screen bitmap ID.
+#  define IDB_SPLASH 101
+
+// DDE application name
+#  define ID_DDE_APPLICATION_NAME 102
+
 #  define IDI_APPICON 1
 #  define IDI_DOCUMENT 2
 #  define IDI_NEWWINDOW 3
 #  define IDI_NEWTAB 4
 #  define IDI_PBMODE 5
 #  ifndef IDI_APPLICATION
 #    define IDI_APPLICATION 32512
 #  endif
--- a/uriloader/exthandler/DBusHelpers.h
+++ b/uriloader/exthandler/DBusHelpers.h
@@ -4,17 +4,16 @@
  * 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/. */
 
 #ifndef mozilla_DBusHelpers_h
 #define mozilla_DBusHelpers_h
 
 #include <dbus/dbus.h>
 #include "mozilla/UniquePtr.h"
-#include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
 template <>
 struct RefPtrTraits<DBusMessage> {
   static void AddRef(DBusMessage* aMessage) {
     MOZ_ASSERT(aMessage);
     dbus_message_ref(aMessage);
rename from toolkit/components/remote/nsDBusRemoteClient.cpp
rename to widget/xremoteclient/DBusRemoteClient.cpp
--- a/toolkit/components/remote/nsDBusRemoteClient.cpp
+++ b/widget/xremoteclient/DBusRemoteClient.cpp
@@ -1,67 +1,64 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=8:
  */
 /* vim:set ts=8 sw=2 et cindent: */
 /* 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 "nsDBusRemoteClient.h"
+#include "DBusRemoteClient.h"
 #include "RemoteUtils.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Base64.h"
 #include "nsPrintfCString.h"
 
 #include <dlfcn.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
 using mozilla::LogLevel;
-static mozilla::LazyLogModule sRemoteLm("nsDBusRemoteClient");
+static mozilla::LazyLogModule sRemoteLm("DBusRemoteClient");
 
-nsDBusRemoteClient::nsDBusRemoteClient() {
+DBusRemoteClient::DBusRemoteClient() {
   mConnection = nullptr;
-  MOZ_LOG(sRemoteLm, LogLevel::Debug,
-          ("nsDBusRemoteClient::nsDBusRemoteClient"));
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("DBusRemoteClient::DBusRemoteClient"));
 }
 
-nsDBusRemoteClient::~nsDBusRemoteClient() {
-  MOZ_LOG(sRemoteLm, LogLevel::Debug,
-          ("nsDBusRemoteClient::~nsDBusRemoteClient"));
+DBusRemoteClient::~DBusRemoteClient() {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("DBusRemoteClient::~DBusRemoteClient"));
   Shutdown();
 }
 
-nsresult nsDBusRemoteClient::Init() {
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsDBusRemoteClient::Init"));
+nsresult DBusRemoteClient::Init() {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("DBusRemoteClient::Init"));
 
   if (mConnection) return NS_OK;
 
   mConnection =
       already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SESSION, nullptr));
   if (!mConnection) return NS_ERROR_FAILURE;
 
   dbus_connection_set_exit_on_disconnect(mConnection, false);
   dbus_connection_setup_with_g_main(mConnection, nullptr);
 
   return NS_OK;
 }
 
-void nsDBusRemoteClient::Shutdown(void) {
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsDBusRemoteClient::Shutdown"));
+void DBusRemoteClient::Shutdown(void) {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("DBusRemoteClient::Shutdown"));
   // This connection is owned by libdbus and we don't need to close it
   mConnection = nullptr;
 }
 
-nsresult nsDBusRemoteClient::SendCommandLine(
-    const char *aProgram, const char *aProfile, int32_t argc, char **argv,
-    const char *aDesktopStartupID, char **aResponse, bool *aWindowFound) {
-  NS_ENSURE_TRUE(aProgram, NS_ERROR_INVALID_ARG);
-
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsDBusRemoteClient::SendCommandLine"));
+nsresult DBusRemoteClient::SendCommandLine(
+    const char *aProgram, const char *aUsername, const char *aProfile,
+    int32_t argc, char **argv, const char *aDesktopStartupID, char **aResponse,
+    bool *aWindowFound) {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("DBusRemoteClient::SendCommandLine"));
 
   int commandLineLength;
   char *commandLine =
       ConstructCommandLine(argc, argv, aDesktopStartupID, &commandLineLength);
   if (!commandLine) return NS_ERROR_FAILURE;
 
   nsresult rv =
       DoSendDBusCommandLine(aProgram, aProfile, commandLine, commandLineLength);
@@ -69,57 +66,98 @@ nsresult nsDBusRemoteClient::SendCommand
   *aWindowFound = NS_SUCCEEDED(rv);
 
   MOZ_LOG(sRemoteLm, LogLevel::Debug,
           ("DoSendDBusCommandLine returning 0x%" PRIx32 "\n",
            static_cast<uint32_t>(rv)));
   return rv;
 }
 
-bool nsDBusRemoteClient::GetRemoteDestinationName(const char *aProgram,
-                                                  const char *aProfile,
-                                                  nsCString &aDestinationName) {
-  // We have a profile name - just create the destination.
-  // D-Bus names can contain only [a-z][A-Z][0-9]_
-  // characters so adjust the profile string properly.
-  nsAutoCString profileName;
-  nsresult rv = mozilla::Base64Encode(nsAutoCString(aProfile), profileName);
-  NS_ENSURE_SUCCESS(rv, false);
-  profileName.ReplaceChar("+/=", '_');
+bool DBusRemoteClient::GetRemoteDestinationName(const char *aProgram,
+                                                const char *aProfile,
+                                                nsCString &aDestinationName) {
+  if (!aProfile || aProfile[0] == '\0') {
+    // We don't have a profile name - search for active mozilla instances.
+    RefPtr<DBusMessage> msg =
+        already_AddRefed<DBusMessage>(dbus_message_new_method_call(
+            "org.freedesktop.DBus", "/org/freedesktop/DBus",
+            "org.freedesktop.DBus", "ListNames"));
+    if (!msg) {
+      return false;
+    }
 
-  aDestinationName =
-      nsPrintfCString("org.mozilla.%s.%s", aProgram, profileName.get());
-  if (aDestinationName.Length() > DBUS_MAXIMUM_NAME_LENGTH)
-    aDestinationName.Truncate(DBUS_MAXIMUM_NAME_LENGTH);
+    // send message and get a handle for a reply
+    RefPtr<DBusMessage> reply =
+        already_AddRefed<DBusMessage>(dbus_connection_send_with_reply_and_block(
+            mConnection, msg, -1, nullptr));
+    if (!reply) {
+      return false;
+    }
 
-  static auto sDBusValidateBusName =
-      (bool (*)(const char *, DBusError *))dlsym(RTLD_DEFAULT,
-                                                  "dbus_validate_bus_name");
-  if (!sDBusValidateBusName) {
-    return false;
-  }
-
-  if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
-    // We don't have a valid busName yet - try to create a default one.
-    aDestinationName =
-        nsPrintfCString("org.mozilla.%s.%s", aProgram, "default");
-    if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
-      // We failed completelly to get a valid bus name - just quit
-      // to prevent crash at dbus_bus_request_name().
+    char **interfaces;
+    dbus_int32_t interfaceNums;
+    if (!dbus_message_get_args(reply, nullptr, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING, &interfaces, &interfaceNums,
+                               DBUS_TYPE_INVALID)) {
       return false;
     }
-  }
+
+    nsAutoCString destinationTemplate;
+    destinationTemplate = nsPrintfCString("org.mozilla.%s", aProgram);
+
+    aDestinationName.SetLength(0);
+    for (int i = 0; i < interfaceNums; i++) {
+      if (strstr(interfaces[i], destinationTemplate.get())) {
+        aDestinationName = interfaces[i];
+        break;
+      }
+    }
+    dbus_free_string_array(interfaces);
+
+    return (!aDestinationName.IsEmpty());
+  } else {
+    // We have a profile name - just create the destination.
+    // D-Bus names can contain only [a-z][A-Z][0-9]_
+    // characters so adjust the profile string properly.
+    nsAutoCString profileName;
+    nsresult rv = mozilla::Base64Encode(nsAutoCString(aProfile), profileName);
+    NS_ENSURE_SUCCESS(rv, false);
+    profileName.ReplaceChar("+/=", '_');
 
-  return true;
+    aDestinationName =
+        nsPrintfCString("org.mozilla.%s.%s", aProgram, profileName.get());
+    if (aDestinationName.Length() > DBUS_MAXIMUM_NAME_LENGTH)
+      aDestinationName.Truncate(DBUS_MAXIMUM_NAME_LENGTH);
+
+    static auto sDBusValidateBusName =
+        (bool (*)(const char *, DBusError *))dlsym(RTLD_DEFAULT,
+                                                   "dbus_validate_bus_name");
+    if (!sDBusValidateBusName) {
+      return false;
+    }
+
+    if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
+      // We don't have a valid busName yet - try to create a default one.
+      aDestinationName =
+          nsPrintfCString("org.mozilla.%s.%s", aProgram, "default");
+      if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
+        // We failed completelly to get a valid bus name - just quit
+        // to prevent crash at dbus_bus_request_name().
+        return false;
+      }
+    }
+
+    return true;
+  }
 }
 
-nsresult nsDBusRemoteClient::DoSendDBusCommandLine(const char *aProgram,
-                                                   const char *aProfile,
-                                                   const char *aBuffer,
-                                                   int aLength) {
+nsresult DBusRemoteClient::DoSendDBusCommandLine(const char *aProgram,
+                                                 const char *aProfile,
+                                                 const char *aBuffer,
+                                                 int aLength) {
   nsAutoCString destinationName;
   if (!GetRemoteDestinationName(aProgram, aProfile, destinationName))
     return NS_ERROR_FAILURE;
 
   nsAutoCString pathName;
   pathName = nsPrintfCString("/org/mozilla/%s/Remote", aProgram);
 
   nsAutoCString remoteInterfaceName;
rename from toolkit/components/remote/nsDBusRemoteClient.h
rename to widget/xremoteclient/DBusRemoteClient.h
--- a/toolkit/components/remote/nsDBusRemoteClient.h
+++ b/widget/xremoteclient/DBusRemoteClient.h
@@ -6,25 +6,25 @@
 #ifndef DBusRemoteClient_h__
 #define DBusRemoteClient_h__
 
 #include "nsRemoteClient.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/DBusHelpers.h"
 #include "nsString.h"
 
-class nsDBusRemoteClient : public nsRemoteClient {
+class DBusRemoteClient : public nsRemoteClient {
  public:
-  nsDBusRemoteClient();
-  ~nsDBusRemoteClient();
+  DBusRemoteClient();
+  ~DBusRemoteClient();
 
   virtual nsresult Init() override;
-  virtual nsresult SendCommandLine(const char *aProgram, const char *aProfile,
-                                   int32_t argc, char **argv,
-                                   const char *aDesktopStartupID,
+  virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
+                                   const char *aProfile, int32_t argc,
+                                   char **argv, const char *aDesktopStartupID,
                                    char **aResponse, bool *aSucceeded) override;
   void Shutdown();
 
  private:
   bool GetRemoteDestinationName(const char *aProgram, const char *aProfile,
                                 nsCString &aDestinationName);
   nsresult DoSendDBusCommandLine(const char *aProgram, const char *aProfile,
                                  const char *aBuffer, int aLength);
rename from toolkit/components/remote/RemoteUtils.cpp
rename to widget/xremoteclient/RemoteUtils.cpp
rename from toolkit/components/remote/RemoteUtils.h
rename to widget/xremoteclient/RemoteUtils.h
rename from toolkit/components/remote/nsXRemoteClient.cpp
rename to widget/xremoteclient/XRemoteClient.cpp
--- a/toolkit/components/remote/nsXRemoteClient.cpp
+++ b/widget/xremoteclient/XRemoteClient.cpp
@@ -1,22 +1,21 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=8:
  */
 /* vim:set ts=8 sw=2 et cindent: */
 /* 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 "nsDebug.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Unused.h"
-#include "nsXRemoteClient.h"
+#include "XRemoteClient.h"
 #include "RemoteUtils.h"
 #include "plstr.h"
 #include "prsystem.h"
 #include "mozilla/Logging.h"
 #include "prenv.h"
 #include "prdtoa.h"
 #include <stdlib.h>
 #include <unistd.h>
@@ -50,50 +49,50 @@
 #  else
 #    define MAX_PATH 1024
 #  endif
 #endif
 
 using mozilla::LogLevel;
 using mozilla::Unused;
 
-static mozilla::LazyLogModule sRemoteLm("nsXRemoteClient");
+static mozilla::LazyLogModule sRemoteLm("XRemoteClient");
 
 static int (*sOldHandler)(Display *, XErrorEvent *);
 static bool sGotBadWindow;
 
-nsXRemoteClient::nsXRemoteClient() {
+XRemoteClient::XRemoteClient() {
   mDisplay = 0;
   mInitialized = false;
   mMozVersionAtom = 0;
   mMozLockAtom = 0;
   mMozCommandLineAtom = 0;
   mMozResponseAtom = 0;
   mMozWMStateAtom = 0;
   mMozUserAtom = 0;
   mMozProfileAtom = 0;
   mMozProgramAtom = 0;
   mLockData = 0;
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsXRemoteClient::nsXRemoteClient"));
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::XRemoteClient"));
 }
 
-nsXRemoteClient::~nsXRemoteClient() {
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsXRemoteClient::~nsXRemoteClient"));
+XRemoteClient::~XRemoteClient() {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::~XRemoteClient"));
   if (mInitialized) Shutdown();
 }
 
 // Minimize the roundtrips to the X-server
 static const char *XAtomNames[] = {
     MOZILLA_VERSION_PROP, MOZILLA_LOCK_PROP,       MOZILLA_RESPONSE_PROP,
     "WM_STATE",           MOZILLA_USER_PROP,       MOZILLA_PROFILE_PROP,
     MOZILLA_PROGRAM_PROP, MOZILLA_COMMANDLINE_PROP};
 static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
 
-nsresult nsXRemoteClient::Init() {
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsXRemoteClient::Init"));
+nsresult XRemoteClient::Init() {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Init"));
 
   if (mInitialized) return NS_OK;
 
   // try to open the display
   mDisplay = XOpenDisplay(0);
   if (!mDisplay) return NS_ERROR_FAILURE;
 
   // get our atoms
@@ -110,18 +109,18 @@ nsresult nsXRemoteClient::Init() {
   mMozProgramAtom = XAtoms[i++];
   mMozCommandLineAtom = XAtoms[i];
 
   mInitialized = true;
 
   return NS_OK;
 }
 
-void nsXRemoteClient::Shutdown(void) {
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsXRemoteClient::Shutdown"));
+void XRemoteClient::Shutdown(void) {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Shutdown"));
 
   if (!mInitialized) return;
 
   // shut everything down
   XCloseDisplay(mDisplay);
   mDisplay = 0;
   mInitialized = false;
   if (mLockData) {
@@ -134,30 +133,31 @@ static int HandleBadWindow(Display *disp
   if (event->error_code == BadWindow) {
     sGotBadWindow = true;
     return 0;  // ignored
   }
 
   return (*sOldHandler)(display, event);
 }
 
-nsresult nsXRemoteClient::SendCommandLine(
-    const char *aProgram, const char *aProfile, int32_t argc, char **argv,
-    const char *aDesktopStartupID, char **aResponse, bool *aWindowFound) {
-  NS_ENSURE_TRUE(aProgram, NS_ERROR_INVALID_ARG);
-
-  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("nsXRemoteClient::SendCommandLine"));
+nsresult XRemoteClient::SendCommandLine(const char *aProgram,
+                                        const char *aUsername,
+                                        const char *aProfile, int32_t argc,
+                                        char **argv,
+                                        const char *aDesktopStartupID,
+                                        char **aResponse, bool *aWindowFound) {
+  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::SendCommandLine"));
 
   *aWindowFound = false;
 
   // FindBestWindow() iterates down the window hierarchy, so catch X errors
   // when windows get destroyed before being accessed.
   sOldHandler = XSetErrorHandler(HandleBadWindow);
 
-  Window w = FindBestWindow(aProgram, aProfile);
+  Window w = FindBestWindow(aProgram, aUsername, aProfile);
 
   nsresult rv = NS_OK;
 
   if (w) {
     // ok, let the caller know that we at least found a window.
     *aWindowFound = true;
 
     // Ignore BadWindow errors up to this point.  The last request from
@@ -188,17 +188,17 @@ nsresult nsXRemoteClient::SendCommandLin
 
   MOZ_LOG(sRemoteLm, LogLevel::Debug,
           ("SendCommandInternal returning 0x%" PRIx32 "\n",
            static_cast<uint32_t>(rv)));
 
   return rv;
 }
 
-Window nsXRemoteClient::CheckWindow(Window aWindow) {
+Window XRemoteClient::CheckWindow(Window aWindow) {
   Atom type = None;
   int format;
   unsigned long nitems, bytesafter;
   unsigned char *data;
   Window innerWindow;
 
   XGetWindowProperty(mDisplay, aWindow, mMozWMStateAtom, 0, 0, False,
                      AnyPropertyType, &type, &format, &nitems, &bytesafter,
@@ -212,17 +212,17 @@ Window nsXRemoteClient::CheckWindow(Wind
   // didn't find it here so check the children of this window
   innerWindow = CheckChildren(aWindow);
 
   if (innerWindow) return innerWindow;
 
   return aWindow;
 }
 
-Window nsXRemoteClient::CheckChildren(Window aWindow) {
+Window XRemoteClient::CheckChildren(Window aWindow) {
   Window root, parent;
   Window *children;
   unsigned int nchildren;
   unsigned int i;
   Atom type = None;
   int format;
   unsigned long nitems, after;
   unsigned char *data;
@@ -247,17 +247,17 @@ Window nsXRemoteClient::CheckChildren(Wi
     retval = CheckChildren(children[i]);
   }
 
   if (children) XFree((char *)children);
 
   return retval;
 }
 
-nsresult nsXRemoteClient::GetLock(Window aWindow, bool *aDestroyed) {
+nsresult XRemoteClient::GetLock(Window aWindow, bool *aDestroyed) {
   bool locked = false;
   bool waited = false;
   *aDestroyed = false;
 
   nsresult rv = NS_OK;
 
   if (!mLockData) {
     char pidstr[32];
@@ -368,28 +368,29 @@ nsresult nsXRemoteClient::GetLock(Window
   } else if (*aDestroyed) {
     MOZ_LOG(sRemoteLm, LogLevel::Debug,
             ("window 0x%x unexpectedly destroyed.\n", (unsigned int)aWindow));
   }
 
   return rv;
 }
 
-Window nsXRemoteClient::FindBestWindow(const char *aProgram,
-                                       const char *aProfile) {
+Window XRemoteClient::FindBestWindow(const char *aProgram,
+                                     const char *aUsername,
+                                     const char *aProfile) {
   Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
   Window bestWindow = 0;
   Window root2, parent, *kids;
   unsigned int nkids;
 
   // Get a list of the children of the root window, walk the list
   // looking for the best window that fits the criteria.
   if (!XQueryTree(mDisplay, root, &root2, &parent, &kids, &nkids)) {
     MOZ_LOG(sRemoteLm, LogLevel::Debug,
-            ("XQueryTree failed in nsXRemoteClient::FindBestWindow"));
+            ("XQueryTree failed in XRemoteClient::FindBestWindow"));
     return 0;
   }
 
   if (!(kids && nkids)) {
     MOZ_LOG(sRemoteLm, LogLevel::Debug, ("root window has no children"));
     return 0;
   }
 
@@ -416,40 +417,50 @@ Window nsXRemoteClient::FindBestWindow(c
     XFree(data_return);
 
     if (!(version >= 5.1 && version < 6)) continue;
 
     data_return = 0;
 
     if (status != Success || type == None) continue;
 
-    // Check that this window is from the right program.
-    Unused << XGetWindowProperty(
-        mDisplay, w, mMozProgramAtom, 0, (65536 / sizeof(long)), False,
-        XA_STRING, &type, &format, &nitems, &bytesafter, &data_return);
+    // If someone passed in a program name, check it against this one
+    // unless it's "any" in which case, we don't care.  If someone did
+    // pass in a program name and this window doesn't support that
+    // protocol, we don't include it in our list.
+    if (aProgram && strcmp(aProgram, "any")) {
+      Unused << XGetWindowProperty(
+          mDisplay, w, mMozProgramAtom, 0, (65536 / sizeof(long)), False,
+          XA_STRING, &type, &format, &nitems, &bytesafter, &data_return);
 
-    // If the return name is not the same as this program name, we don't want
-    // this window.
-    if (data_return) {
-      if (strcmp(aProgram, (const char *)data_return)) {
+      // If the return name is not the same as what someone passed in,
+      // we don't want this window.
+      if (data_return) {
+        if (strcmp(aProgram, (const char *)data_return)) {
+          XFree(data_return);
+          continue;
+        }
+
+        // This is actually the success condition.
         XFree(data_return);
+      } else {
+        // Doesn't support the protocol, even though the user
+        // requested it.  So we're not going to use this window.
         continue;
       }
-
-      // This is actually the success condition.
-      XFree(data_return);
-    } else {
-      // Doesn't support the protocol, even though the user
-      // requested it.  So we're not going to use this window.
-      continue;
     }
 
     // Check to see if it has the user atom on that window.  If there
     // is then we need to make sure that it matches what we have.
-    const char *username = PR_GetEnv("LOGNAME");
+    const char *username;
+    if (aUsername) {
+      username = aUsername;
+    } else {
+      username = PR_GetEnv("LOGNAME");
+    }
 
     if (username) {
       Unused << XGetWindowProperty(
           mDisplay, w, mMozUserAtom, 0, (65536 / sizeof(long)), False,
           XA_STRING, &type, &format, &nitems, &bytesafter, &data_return);
 
       // if there's a username compare it with what we have
       if (data_return) {
@@ -461,49 +472,48 @@ Window nsXRemoteClient::FindBestWindow(c
 
         XFree(data_return);
       }
     }
 
     // Check to see if there's a profile name on this window.  If
     // there is, then we need to make sure it matches what someone
     // passed in.
-    Unused << XGetWindowProperty(
-        mDisplay, w, mMozProfileAtom, 0, (65536 / sizeof(long)), False,
-        XA_STRING, &type, &format, &nitems, &bytesafter, &data_return);
+    if (aProfile) {
+      Unused << XGetWindowProperty(
+          mDisplay, w, mMozProfileAtom, 0, (65536 / sizeof(long)), False,
+          XA_STRING, &type, &format, &nitems, &bytesafter, &data_return);
 
-    // If there's a profile compare it with what we have
-    if (data_return) {
-      // If the profiles aren't equal, we don't want this window.
-      if (strcmp(aProfile, (const char *)data_return)) {
+      // If there's a profile compare it with what we have
+      if (data_return) {
+        // If the profiles aren't equal, we don't want this window.
+        if (strcmp(aProfile, (const char *)data_return)) {
+          XFree(data_return);
+          continue;
+        }
+
         XFree(data_return);
-        continue;
       }
-
-      XFree(data_return);
-    } else {
-      // This isn't the window for this profile.
-      continue;
     }
 
     // Check to see if the window supports the new command-line passing
     // protocol, if that is requested.
 
     // If we got this far, this is the best window.  It passed
     // all the tests.
     bestWindow = w;
     break;
   }
 
   if (kids) XFree((char *)kids);
 
   return bestWindow;
 }
 
-nsresult nsXRemoteClient::FreeLock(Window aWindow) {
+nsresult XRemoteClient::FreeLock(Window aWindow) {
   int result;
   Atom actual_type;
   int actual_format;
   unsigned long nitems, bytes_after;
   unsigned char *data = 0;
 
   result = XGetWindowProperty(
       mDisplay, aWindow, mMozLockAtom, 0, (65536 / sizeof(long)),
@@ -525,39 +535,38 @@ nsresult nsXRemoteClient::FreeLock(Windo
              mLockData, data));
     return NS_ERROR_FAILURE;
   }
 
   if (data) XFree(data);
   return NS_OK;
 }
 
-nsresult nsXRemoteClient::DoSendCommandLine(Window aWindow, int32_t argc,
-                                            char **argv,
-                                            const char *aDesktopStartupID,
-                                            char **aResponse,
-                                            bool *aDestroyed) {
+nsresult XRemoteClient::DoSendCommandLine(Window aWindow, int32_t argc,
+                                          char **argv,
+                                          const char *aDesktopStartupID,
+                                          char **aResponse, bool *aDestroyed) {
   *aDestroyed = false;
 
   int commandLineLength;
   char *commandLine =
       ConstructCommandLine(argc, argv, aDesktopStartupID, &commandLineLength);
   XChangeProperty(mDisplay, aWindow, mMozCommandLineAtom, XA_STRING, 8,
                   PropModeReplace, (unsigned char *)commandLine,
                   commandLineLength);
   free(commandLine);
 
   if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandLineAtom))
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
 
-bool nsXRemoteClient::WaitForResponse(Window aWindow, char **aResponse,
-                                      bool *aDestroyed, Atom aCommandAtom) {
+bool XRemoteClient::WaitForResponse(Window aWindow, char **aResponse,
+                                    bool *aDestroyed, Atom aCommandAtom) {
   bool done = false;
   bool accepted = false;
 
   while (!done) {
     XEvent event;
     XNextEvent(mDisplay, &event);
     if (event.xany.type == DestroyNotify &&
         event.xdestroywindow.window == aWindow) {
rename from toolkit/components/remote/nsXRemoteClient.h
rename to widget/xremoteclient/XRemoteClient.h
--- a/toolkit/components/remote/nsXRemoteClient.h
+++ b/widget/xremoteclient/XRemoteClient.h
@@ -3,34 +3,35 @@
  * 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 <X11/X.h>
 #include <X11/Xlib.h>
 
 #include "nsRemoteClient.h"
 
-class nsXRemoteClient : public nsRemoteClient {
+class XRemoteClient : public nsRemoteClient {
  public:
-  nsXRemoteClient();
-  ~nsXRemoteClient();
+  XRemoteClient();
+  ~XRemoteClient();
 
   virtual nsresult Init() override;
-  virtual nsresult SendCommandLine(const char *aProgram, const char *aProfile,
-                                   int32_t argc, char **argv,
-                                   const char *aDesktopStartupID,
+  virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
+                                   const char *aProfile, int32_t argc,
+                                   char **argv, const char *aDesktopStartupID,
                                    char **aResponse, bool *aSucceeded) override;
   void Shutdown();
 
  private:
   Window CheckWindow(Window aWindow);
   Window CheckChildren(Window aWindow);
   nsresult GetLock(Window aWindow, bool *aDestroyed);
   nsresult FreeLock(Window aWindow);
-  Window FindBestWindow(const char *aProgram, const char *aProfile);
+  Window FindBestWindow(const char *aProgram, const char *aUsername,
+                        const char *aProfile);
   nsresult DoSendCommandLine(Window aWindow, int32_t argc, char **argv,
                              const char *aDesktopStartupID, char **aResponse,
                              bool *aDestroyed);
   bool WaitForResponse(Window aWindow, char **aResponse, bool *aDestroyed,
                        Atom aCommandAtom);
 
   Display *mDisplay;
 
new file mode 100644
--- /dev/null
+++ b/widget/xremoteclient/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+with Files("**"):
+    BUG_COMPONENT = ("Core", "Widget")
+
+FINAL_LIBRARY = 'xul'
+
+SOURCES += [
+    'RemoteUtils.cpp',
+    'XRemoteClient.cpp',
+]
+
+if CONFIG['MOZ_ENABLE_DBUS']:
+    SOURCES += [
+        'DBusRemoteClient.cpp',
+    ]
+    CXXFLAGS += CONFIG['TK_CFLAGS']
+    CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
rename from toolkit/components/remote/nsRemoteClient.h
rename to widget/xremoteclient/nsRemoteClient.h
--- a/toolkit/components/remote/nsRemoteClient.h
+++ b/widget/xremoteclient/nsRemoteClient.h
@@ -48,15 +48,15 @@ class nsRemoteClient {
    *
    * @param aResponse If there is a response, it will be here.  This
    * includes error messages.  The string is allocated using stdlib
    * string functions, so free it with free().
    *
    * @return true if succeeded, false if no running instance was found.
    *
    */
-  virtual nsresult SendCommandLine(const char *aProgram, const char *aProfile,
-                                   int32_t argc, char **argv,
-                                   const char *aDesktopStartupID,
+  virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
+                                   const char *aProfile, int32_t argc,
+                                   char **argv, const char *aDesktopStartupID,
                                    char **aResponse, bool *aSucceeded) = 0;
 };
 
 #endif  // nsRemoteClient_h__