summaryrefslogtreecommitdiffstats
path: root/comm/suite/components/shell
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/components/shell
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/suite/components/shell')
-rw-r--r--comm/suite/components/shell/ShellService.jsm110
-rw-r--r--comm/suite/components/shell/content/setDesktopBackground.js78
-rw-r--r--comm/suite/components/shell/content/setDesktopBackground.xul49
-rw-r--r--comm/suite/components/shell/jar.mn7
-rw-r--r--comm/suite/components/shell/moz.build49
-rw-r--r--comm/suite/components/shell/nsGNOMEShellService.cpp463
-rw-r--r--comm/suite/components/shell/nsGNOMEShellService.h37
-rw-r--r--comm/suite/components/shell/nsIGNOMEShellService.idl18
-rw-r--r--comm/suite/components/shell/nsIMacShellService.idl14
-rw-r--r--comm/suite/components/shell/nsIShellService.idl98
-rw-r--r--comm/suite/components/shell/nsMacShellService.cpp398
-rw-r--r--comm/suite/components/shell/nsMacShellService.h36
-rw-r--r--comm/suite/components/shell/nsSetDefault.js53
-rw-r--r--comm/suite/components/shell/nsSetDefault.manifest3
-rw-r--r--comm/suite/components/shell/nsShellService.h11
-rw-r--r--comm/suite/components/shell/nsWindowsShellService.cpp793
-rw-r--r--comm/suite/components/shell/nsWindowsShellService.h41
17 files changed, 2258 insertions, 0 deletions
diff --git a/comm/suite/components/shell/ShellService.jsm b/comm/suite/components/shell/ShellService.jsm
new file mode 100644
index 0000000000..2af3e75c6b
--- /dev/null
+++ b/comm/suite/components/shell/ShellService.jsm
@@ -0,0 +1,110 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* 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/. */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["ShellService"];
+
+const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+/**
+ * Internal functionality to save and restore the docShell.allow* properties.
+ */
+var ShellServiceInternal = {
+ /**
+ * Used to determine whether or not to offer "Set as desktop background"
+ * functionality. Even if shell service is available it is not
+ * guaranteed that it is able to set the background for every desktop
+ * which is especially true for Linux with its many different desktop
+ * environments.
+ */
+ get canSetDesktopBackground() {
+ if (AppConstants.platform == "win" ||
+ AppConstants.platform == "macosx") {
+ return true;
+ }
+
+ if (AppConstants.platform == "linux") {
+ if (this.shellService) {
+ let linuxShellService = this.shellService
+ .QueryInterface(Ci.nsIGNOMEShellService);
+ return linuxShellService.canSetDesktopBackground;
+ }
+ }
+
+ return false;
+ },
+
+ /**
+ * Used to determine whether or not to show a "Set Default Client"
+ * query dialog. This attribute is true if the application is starting
+ * up and "shell.checkDefaultClient" is true, otherwise it is false.
+ */
+ _checkedThisSession: false,
+ get shouldCheckDefaultClient() {
+ // If we've already checked, the suite has been started and this is a
+ // new window open, and we don't want to check again.
+ if (this._checkedThisSession) {
+ return false;
+ }
+
+ return Services.prefs.getBoolPref("shell.checkDefaultClient");
+ },
+
+ set shouldCheckDefaultClient(shouldCheck) {
+ Services.prefs.setBoolPref("shell.checkDefaultClient", !!shouldCheck);
+ },
+
+ get shouldBeDefaultClientFor() {
+ return Services.prefs.getIntPref("shell.checkDefaultApps");
+ },
+
+ set shouldBeDefaultClientFor(appTypes) {
+ Services.prefs.setIntPref("shell.checkDefaultApps", appTypes);
+ },
+
+ setDefaultClient(forAllUsers, claimAllTypes, appTypes) {
+ try {
+ this.shellService.setDefaultClient(forAllUsers, claimAllTypes, appTypes);
+ } catch (ex) {
+ Cu.reportError(ex);
+ }
+ },
+
+ isDefaultClient(startupCheck, appTypes) {
+ // If this is the first window, maintain internal state that we've
+ // checked this session (so that subsequent window opens don't show the
+ // default client dialog).
+ if (startupCheck) {
+ this._checkedThisSession = true;
+ }
+ if (this.shellService) {
+ return this.shellService.isDefaultClient(startupCheck, appTypes);
+ }
+ return false;
+ }
+};
+
+XPCOMUtils.defineLazyServiceGetter(ShellServiceInternal, "shellService",
+ "@mozilla.org/suite/shell-service;1", Ci.nsIShellService);
+
+/**
+ * The external API exported by this module.
+ */
+var ShellService = new Proxy(ShellServiceInternal, {
+ get(target, name) {
+ if (name in target) {
+ return target[name];
+ }
+ if (target.shellService) {
+ return target.shellService[name];
+ }
+ Services.console.logStringMessage(`${name} not found in ShellService: ${target.shellService}`);
+ return undefined;
+ }
+});
diff --git a/comm/suite/components/shell/content/setDesktopBackground.js b/comm/suite/components/shell/content/setDesktopBackground.js
new file mode 100644
index 0000000000..efcc5734e4
--- /dev/null
+++ b/comm/suite/components/shell/content/setDesktopBackground.js
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+var {AppConstants} = ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+
+var gShell = Cc["@mozilla.org/suite/shell-service;1"]
+ .getService(Ci.nsIShellService);
+
+var gImage, gImageName, gPosition, gPicker, gDesktop;
+
+function onLoad()
+{
+ document.getElementById("itemsBox").hidden = AppConstants.platform == "macosx";
+ gImage = window.arguments[0];
+ gImageName = window.arguments[1];
+ gPosition = document.getElementById("position");
+ gPicker = document.getElementById("picker");
+ gDesktop = document.getElementById("desktop");
+
+ sizeToContent();
+ window.innerWidth += screen.width / 2 - gDesktop.boxObject.width;
+ window.innerHeight += screen.height / 2 - gDesktop.boxObject.height;
+
+ try {
+ var color = gShell.desktopBackgroundColor;
+ color = (0xF000000 | color).toString(16).toUpperCase().replace("F", "#");
+ gDesktop.style.backgroundColor = color;
+ gPicker.color = color;
+ } catch (e) {
+ gPicker.parentNode.hidden = true;
+ }
+
+ gDesktop.style.backgroundImage = 'url("' + gImage.src + '")';
+
+ updatePosition();
+}
+
+function onApply()
+{
+ if (!gPicker.parentNode.hidden)
+ gShell.desktopBackgroundColor = parseInt(gPicker.color.substr(1), 16);
+
+ gShell.setDesktopBackground(gImage, Ci.nsIShellService[gPosition.value],
+ gImageName);
+}
+
+function updatePosition()
+{
+ gDesktop.style.backgroundPosition = "center";
+ gDesktop.style.backgroundRepeat = "no-repeat";
+ switch (gPosition.value) {
+ case "BACKGROUND_FIT":
+ gDesktop.style.backgroundSize = "contain";
+ return;
+ case "BACKGROUND_FILL":
+ gDesktop.style.backgroundSize = "cover";
+ return;
+ case "BACKGROUND_STRETCH":
+ gDesktop.style.backgroundPosition = "";
+ gDesktop.style.backgroundSize = "100% 100%";
+ return;
+ case "BACKGROUND_TILE":
+ gDesktop.style.backgroundPosition = "";
+ gDesktop.style.backgroundRepeat = "repeat";
+ }
+ gDesktop.style.backgroundSize =
+ (gImage.naturalWidth / 2) + "px " + (gImage.naturalHeight / 2) + "px";
+}
+
+function updateColor()
+{
+ gDesktop.style.backgroundColor = gPicker.color;
+}
diff --git a/comm/suite/components/shell/content/setDesktopBackground.xul b/comm/suite/components/shell/content/setDesktopBackground.xul
new file mode 100644
index 0000000000..16fb384658
--- /dev/null
+++ b/comm/suite/components/shell/content/setDesktopBackground.xul
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+
+<!-- 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/. -->
+
+<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://communicator/locale/setDesktopBackground.dtd">
+
+<dialog id="setDesktopBackground"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="onLoad();"
+ buttons="accept,extra2"
+ buttoniconaccept="close"
+ buttonlabelaccept="&close.label;"
+ buttoniconextra2="apply"
+ buttonlabelextra2="&apply.label;"
+ buttonaccesskeyextra2="&apply.accesskey;"
+ ondialogextra2="onApply();"
+ title="&setDesktopBackground.title;">
+
+ <script src="chrome://communicator/content/setDesktopBackground.js"/>
+
+ <hbox id="itemsBox" align="center">
+ <label value="&position.label;" accesskey="&position.accesskey;"/>
+ <menulist id="position"
+ value="BACKGROUND_STRETCH"
+ persist="value"
+ oncommand="updatePosition();">
+ <menupopup>
+ <menuitem value="BACKGROUND_TILE" label="&position.tile.label;"/>
+ <menuitem value="BACKGROUND_STRETCH" label="&position.stretch.label;"/>
+ <menuitem value="BACKGROUND_CENTER" label="&position.center.label;"/>
+ <menuitem value="BACKGROUND_FILL" label="&position.fill.label;"/>
+ <menuitem value="BACKGROUND_FIT" label="&position.fit.label;"/>
+ </menupopup>
+ </menulist>
+ <hbox flex="1" pack="end">
+ <label value="&picker.label;" accesskey="&picker.accesskey;"/>
+ <colorpicker id="picker" type="button" onchange="updateColor();"/>
+ </hbox>
+ </hbox>
+
+ <groupbox flex="1">
+ <caption label="&preview.caption;"/>
+ <spacer id="desktop" flex="1"/>
+ </groupbox>
+</dialog>
diff --git a/comm/suite/components/shell/jar.mn b/comm/suite/components/shell/jar.mn
new file mode 100644
index 0000000000..c9eb925472
--- /dev/null
+++ b/comm/suite/components/shell/jar.mn
@@ -0,0 +1,7 @@
+# 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/.
+
+comm.jar:
+ content/communicator/setDesktopBackground.js (content/setDesktopBackground.js)
+ content/communicator/setDesktopBackground.xul (content/setDesktopBackground.xul)
diff --git a/comm/suite/components/shell/moz.build b/comm/suite/components/shell/moz.build
new file mode 100644
index 0000000000..e508876c57
--- /dev/null
+++ b/comm/suite/components/shell/moz.build
@@ -0,0 +1,49 @@
+# -*- 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/.
+
+XPIDL_SOURCES += [
+ "nsIShellService.idl",
+]
+
+if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
+ XPIDL_SOURCES += [
+ "nsIMacShellService.idl",
+ ]
+elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
+ XPIDL_SOURCES += [
+ "nsIGNOMEShellService.idl",
+ ]
+
+XPIDL_MODULE = "shellservice"
+
+if CONFIG["OS_ARCH"] == "WINNT":
+ SOURCES += [
+ "nsWindowsShellService.cpp",
+ ]
+ LOCAL_INCLUDES += [
+ "/other-licenses/nsis/Contrib/CityHash/cityhash",
+ ]
+elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
+ SOURCES += ["nsMacShellService.cpp"]
+elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
+ SOURCES += ["nsGNOMEShellService.cpp"]
+
+if SOURCES:
+ EXTRA_COMPONENTS += [
+ "nsSetDefault.js",
+ "nsSetDefault.manifest",
+ ]
+
+EXTRA_JS_MODULES += [
+ "ShellService.jsm",
+]
+
+FINAL_LIBRARY = "suite"
+
+if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
+ CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
+
+JAR_MANIFESTS += ["jar.mn"]
diff --git a/comm/suite/components/shell/nsGNOMEShellService.cpp b/comm/suite/components/shell/nsGNOMEShellService.cpp
new file mode 100644
index 0000000000..15ea0e1131
--- /dev/null
+++ b/comm/suite/components/shell/nsGNOMEShellService.cpp
@@ -0,0 +1,463 @@
+/* -*- Mode: C++; tab-width: 2; 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 "mozilla/ArrayUtils.h"
+
+#include "nsCOMPtr.h"
+#include "nsGNOMEShellService.h"
+#include "nsShellService.h"
+#include "nsIServiceManager.h"
+#include "nsIFile.h"
+#include "nsIProperties.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIPrefService.h"
+#include "prenv.h"
+#include "nsString.h"
+#include "nsIGIOService.h"
+#include "nsIGSettingsService.h"
+#include "nsIStringBundle.h"
+#include "nsIOutputStream.h"
+#include "nsIProcess.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIImageLoadingContent.h"
+#include "imgIRequest.h"
+#include "imgIContainer.h"
+#include "mozilla/GRefPtr.h"
+#include "mozilla/Sprintf.h"
+#include "mozilla/dom/Element.h"
+#if defined(MOZ_WIDGET_GTK)
+#include "nsImageToPixbuf.h"
+#endif
+#include "nsXULAppAPI.h"
+#include "gfxPlatform.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using namespace mozilla;
+
+struct ProtocolAssociation {
+ uint16_t app;
+ const char* protocol;
+ bool essential;
+};
+
+struct MimeTypeAssociation {
+ uint16_t app;
+ const char* mimeType;
+ const char* extensions;
+};
+
+static const ProtocolAssociation gProtocols[] = {
+ { nsIShellService::BROWSER, "http", true },
+ { nsIShellService::BROWSER, "https", true },
+ { nsIShellService::BROWSER, "ftp", false },
+ { nsIShellService::BROWSER, "chrome", false },
+ { nsIShellService::MAIL, "mailto", true },
+ { nsIShellService::NEWS, "news", true },
+ { nsIShellService::NEWS, "snews", true },
+ { nsIShellService::RSS, "feed", true }
+};
+
+static const MimeTypeAssociation gMimeTypes[] = {
+ { nsIShellService::BROWSER, "text/html", "htm html shtml" },
+ { nsIShellService::BROWSER, "application/xhtml+xml", "xhtml xht" },
+ { nsIShellService::MAIL, "message/rfc822", "eml" },
+ { nsIShellService::RSS, "application/rss+xml", "rss" }
+};
+
+#define kDesktopBGSchema "org.gnome.desktop.background"
+#define kDesktopImageGSKey "picture-uri"
+#define kDesktopOptionGSKey "picture-options"
+#define kDesktopDrawBGGSKey "draw-background"
+#define kDesktopColorGSKey "primary-color"
+
+NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService)
+
+nsresult
+GetBrandName(nsACString& aBrandName)
+{
+ // get the product brand name from localized strings
+ nsresult rv;
+ nsCOMPtr<nsIStringBundleService> bundleService(do_GetService("@mozilla.org/intl/stringbundle;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle));
+ NS_ENSURE_TRUE(brandBundle, rv);
+
+ nsAutoString brandName;
+ rv = brandBundle->GetStringFromName("brandShortName", brandName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ CopyUTF16toUTF8(brandName, aBrandName);
+ return rv;
+}
+
+nsresult
+nsGNOMEShellService::Init()
+{
+ nsresult rv;
+
+ if (gfxPlatform::IsHeadless()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ // Check G_BROKEN_FILENAMES. If it's set, then filenames in glib use
+ // the locale encoding. If it's not set, they use UTF-8.
+ mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nullptr;
+
+ if (GetAppPathFromLauncher()) return NS_OK;
+
+ nsCOMPtr<nsIFile> appPath;
+ rv = NS_GetSpecialDirectory(XRE_EXECUTABLE_FILE, getter_AddRefs(appPath));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return appPath->GetNativePath(mAppPath);
+}
+
+bool nsGNOMEShellService::GetAppPathFromLauncher() {
+ gchar *tmp;
+
+ const char* launcher = PR_GetEnv("MOZ_APP_LAUNCHER");
+ if (!launcher) return false;
+
+ if (g_path_is_absolute(launcher)) {
+ mAppPath = launcher;
+ tmp = g_path_get_basename(launcher);
+ gchar* fullpath = g_find_program_in_path(tmp);
+ if (fullpath && mAppPath.Equals(fullpath)) mAppIsInPath = true;
+ g_free(fullpath);
+ } else {
+ tmp = g_find_program_in_path(launcher);
+ if (!tmp) return false;
+ mAppPath = tmp;
+ mAppIsInPath = true;
+ }
+
+ g_free(tmp);
+ return true;
+}
+
+bool
+nsGNOMEShellService::CheckHandlerMatchesAppName(const nsACString &handler) const
+{
+ gint argc;
+ gchar** argv;
+ nsAutoCString command(handler);
+
+ // The string will be something of the form: [/path/to/]application "%s"
+ // We want to remove all of the parameters and get just the binary name.
+
+ if (g_shell_parse_argv(command.get(), &argc, &argv, nullptr) && argc > 0) {
+ command.Assign(argv[0]);
+ g_strfreev(argv);
+ }
+
+ gchar *commandPath;
+ if (mUseLocaleFilenames) {
+ gchar *nativePath =
+ g_filename_from_utf8(command.get(), -1, nullptr, nullptr, nullptr);
+ if (!nativePath) {
+ NS_ERROR("Error converting path to filesystem encoding");
+ return false;
+ }
+
+ commandPath = g_find_program_in_path(nativePath);
+ g_free(nativePath);
+ } else {
+ commandPath = g_find_program_in_path(command.get());
+ }
+
+ if (!commandPath) return false;
+
+ bool matches = mAppPath.Equals(commandPath);
+ g_free(commandPath);
+ return matches;
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::IsDefaultClient(bool aStartupCheck, uint16_t aApps,
+ bool* aIsDefaultClient)
+{
+ *aIsDefaultClient = false;
+
+ nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+ nsAutoCString handler;
+ nsCOMPtr<nsIGIOMimeApp> gioApp;
+
+ for (unsigned int i = 0; i < ArrayLength(gProtocols); i++) {
+ if (aApps & gProtocols[i].app) {
+ if (!gProtocols[i].essential) continue;
+
+ if (giovfs) {
+ handler.Truncate();
+ nsCOMPtr<nsIHandlerApp> handlerApp;
+ nsDependentCString protocol(gProtocols[i].protocol);
+ giovfs->GetAppForURIScheme(protocol, getter_AddRefs(handlerApp));
+ gioApp = do_QueryInterface(handlerApp);
+ if (!gioApp)
+ return NS_OK;
+
+ if (NS_SUCCEEDED(gioApp->GetCommand(handler)) &&
+ !CheckHandlerMatchesAppName(handler))
+ return NS_OK;
+ }
+ }
+ }
+
+ *aIsDefaultClient = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::SetDefaultClient(bool aForAllUsers,
+ bool aClaimAllTypes, uint16_t aApps)
+{
+ nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+ if (giovfs) {
+ nsresult rv;
+ nsCString brandName;
+ rv = GetBrandName(brandName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIGIOMimeApp> appInfo;
+ rv = giovfs->FindAppFromCommand(mAppPath, getter_AddRefs(appInfo));
+ if (NS_FAILED(rv)) {
+ // Application was not found in the list of installed applications
+ // provided by OS. Fallback to create appInfo from command and name.
+ rv = giovfs->CreateAppFromCommand(mAppPath, brandName,
+ getter_AddRefs(appInfo));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // set handler for the protocols
+ for (unsigned int i = 0; i < ArrayLength(gProtocols); ++i) {
+ if (aApps & gProtocols[i].app) {
+ if (appInfo && (gProtocols[i].essential || aClaimAllTypes)) {
+ nsDependentCString protocol(gProtocols[i].protocol);
+ appInfo->SetAsDefaultForURIScheme(protocol);
+ }
+ }
+ }
+
+ if (aClaimAllTypes) {
+ for (unsigned int i = 0; i < ArrayLength(gMimeTypes); i++) {
+ if (aApps & gMimeTypes[i].app) {
+ nsDependentCString type(gMimeTypes[i].mimeType);
+ appInfo->SetAsDefaultForMimeType(type);
+ nsDependentCString extensions(gMimeTypes[i].extensions);
+ appInfo->SetAsDefaultForFileExtensions(extensions);
+ }
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult)
+{
+ // for Gnome or desktops using the same GSettings keys
+ const char *currentDesktop = getenv("XDG_CURRENT_DESKTOP");
+ if (currentDesktop && strstr(currentDesktop, "GNOME") != nullptr) {
+ *aResult = true;
+ return NS_OK;
+ }
+
+ const char *gnomeSession = getenv("GNOME_DESKTOP_SESSION_ID");
+ if (gnomeSession) {
+ *aResult = true;
+ } else {
+ *aResult = false;
+ }
+
+ return NS_OK;
+}
+
+static nsresult WriteImage(const nsCString &aPath, imgIContainer *aImage) {
+#if !defined(MOZ_WIDGET_GTK)
+ return NS_ERROR_NOT_AVAILABLE;
+#else
+ RefPtr<GdkPixbuf> pixbuf = nsImageToPixbuf::ImageToPixbuf(aImage);
+ if (!pixbuf) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", nullptr, nullptr);
+ return res ? NS_OK : NS_ERROR_FAILURE;
+#endif
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::SetDesktopBackground(dom::Element* aElement,
+ int32_t aPosition,
+ const nsACString& aImageName)
+{
+ nsresult rv;
+ nsCOMPtr<nsIImageLoadingContent> imageContent =
+ do_QueryInterface(aElement, &rv);
+ if (!imageContent) return rv;
+
+ // Get the image container.
+ nsCOMPtr<imgIRequest> request;
+ rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+ getter_AddRefs(request));
+ if (!request) return rv;
+ nsCOMPtr<imgIContainer> container;
+ rv = request->GetImage(getter_AddRefs(container));
+ if (!container) return rv;
+
+ // Set desktop wallpaper filling style.
+ nsAutoCString options;
+ switch (aPosition) {
+ case BACKGROUND_TILE:
+ options.AssignLiteral("wallpaper");
+ break;
+ case BACKGROUND_STRETCH:
+ options.AssignLiteral("stretched");
+ break;
+ case BACKGROUND_FILL:
+ options.AssignLiteral("zoom");
+ break;
+ case BACKGROUND_FIT:
+ options.AssignLiteral("scaled");
+ break;
+ default:
+ options.AssignLiteral("centered");
+ break;
+ }
+
+ // Write the background file to the home directory.
+ nsCString filePath(PR_GetEnv("HOME"));
+
+ nsCString brandName;
+ rv = GetBrandName(brandName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Build the file name.
+ filePath.Append('/');
+ filePath.Append(brandName);
+ filePath.AppendLiteral("_wallpaper.png");
+
+ // Write the image to a file in the home dir.
+ rv = WriteImage(filePath, container);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIGSettingsService> gsettings =
+ do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
+ if (gsettings) {
+ nsCOMPtr<nsIGSettingsCollection> background_settings;
+ gsettings->GetCollectionForSchema(nsLiteralCString(kDesktopBGSchema),
+ getter_AddRefs(background_settings));
+ if (background_settings) {
+ gchar *file_uri = g_filename_to_uri(filePath.get(), nullptr, nullptr);
+ if (!file_uri) return NS_ERROR_FAILURE;
+
+ background_settings->SetString(nsLiteralCString(kDesktopOptionGSKey),
+ options);
+ background_settings->SetString(nsLiteralCString(kDesktopImageGSKey),
+ nsDependentCString(file_uri));
+ g_free(file_uri);
+ background_settings->SetBoolean(nsLiteralCString(kDesktopDrawBGGSKey),
+ true);
+ return rv;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+#define COLOR_16_TO_8_BIT(_c) ((_c) >> 8)
+#define COLOR_8_TO_16_BIT(_c) ((_c) << 8 | (_c))
+
+NS_IMETHODIMP
+nsGNOMEShellService::GetDesktopBackgroundColor(uint32_t *aColor)
+{
+ nsCOMPtr<nsIGSettingsService> gsettings =
+ do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
+ nsCOMPtr<nsIGSettingsCollection> background_settings;
+ nsAutoCString background;
+
+ if (gsettings) {
+ gsettings->GetCollectionForSchema(nsLiteralCString(kDesktopBGSchema),
+ getter_AddRefs(background_settings));
+ if (background_settings) {
+ background_settings->GetString(nsLiteralCString(kDesktopColorGSKey),
+ background);
+ }
+ }
+
+ if (background.IsEmpty()) {
+ *aColor = 0;
+ return NS_OK;
+ }
+
+ GdkColor color;
+ NS_ENSURE_TRUE(gdk_color_parse(background.get(), &color), NS_ERROR_FAILURE);
+
+ *aColor = COLOR_16_TO_8_BIT(color.red) << 16 |
+ COLOR_16_TO_8_BIT(color.green) << 8 |
+ COLOR_16_TO_8_BIT(color.blue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::SetDesktopBackgroundColor(uint32_t aColor)
+{
+ NS_ENSURE_ARG_MAX(aColor, 0xFFFFFF);
+
+ uint16_t red = COLOR_8_TO_16_BIT((aColor >> 16) & 0xff);
+ uint16_t green = COLOR_8_TO_16_BIT((aColor >> 8) & 0xff);
+ uint16_t blue = COLOR_8_TO_16_BIT(aColor & 0xff);
+ char colorString[14];
+ sprintf(colorString, "#%04x%04x%04x", red, green, blue);
+
+ nsCOMPtr<nsIGSettingsService> gsettings =
+ do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
+ if (gsettings) {
+ nsCOMPtr<nsIGSettingsCollection> background_settings;
+ gsettings->GetCollectionForSchema(nsLiteralCString(kDesktopBGSchema),
+ getter_AddRefs(background_settings));
+ if (background_settings) {
+ background_settings->SetString(nsLiteralCString(kDesktopColorGSKey),
+ nsDependentCString(colorString));
+ return NS_OK;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI)
+{
+ nsresult rv;
+ nsCOMPtr<nsIProcess> process =
+ do_CreateInstance("@mozilla.org/process/util;1", &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = process->Init(aApplication);
+ if (NS_FAILED(rv))
+ return rv;
+
+ const nsCString& spec = PromiseFlatCString(aURI);
+ const char* specStr = spec.get();
+ return process->Run(false, &specStr, 1);
+}
+
+NS_IMETHODIMP
+nsGNOMEShellService::GetDefaultFeedReader(nsIFile** _retval)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/comm/suite/components/shell/nsGNOMEShellService.h b/comm/suite/components/shell/nsGNOMEShellService.h
new file mode 100644
index 0000000000..558663a2fe
--- /dev/null
+++ b/comm/suite/components/shell/nsGNOMEShellService.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef nsgnomeshellservice_h____
+#define nsgnomeshellservice_h____
+
+#include "nsIGNOMEShellService.h"
+#include "nsString.h"
+#include "mozilla/Attributes.h"
+#include "nsSuiteCID.h"
+
+class nsGNOMEShellService final : public nsIGNOMEShellService
+{
+public:
+ nsGNOMEShellService() : mAppIsInPath(false) {}
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISHELLSERVICE
+ NS_DECL_NSIGNOMESHELLSERVICE
+
+ nsresult Init();
+
+private:
+ ~nsGNOMEShellService() {}
+
+ bool CheckHandlerMatchesAppName(const nsACString& handler) const;
+
+ bool GetAppPathFromLauncher();
+ bool mUseLocaleFilenames;
+ nsCString mAppPath;
+ bool mAppIsInPath;
+};
+
+#endif // nsgnomeshellservice_h____
+
diff --git a/comm/suite/components/shell/nsIGNOMEShellService.idl b/comm/suite/components/shell/nsIGNOMEShellService.idl
new file mode 100644
index 0000000000..64bf823c45
--- /dev/null
+++ b/comm/suite/components/shell/nsIGNOMEShellService.idl
@@ -0,0 +1,18 @@
+/* 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 "nsIShellService.idl"
+
+[scriptable, uuid(26ea117f-f1f1-4d53-8581-1322fcafa0d4)]
+interface nsIGNOMEShellService : nsIShellService
+{
+ /**
+ * Used to determine whether or not to offer "Set as desktop background"
+ * functionality. Even if shell service is available it is not
+ * guaranteed that it is able to set the background for every desktop
+ * which is especially true for Linux with its many different desktop
+ * environments.
+ */
+ readonly attribute boolean canSetDesktopBackground;
+};
diff --git a/comm/suite/components/shell/nsIMacShellService.idl b/comm/suite/components/shell/nsIMacShellService.idl
new file mode 100644
index 0000000000..a8e16c98a1
--- /dev/null
+++ b/comm/suite/components/shell/nsIMacShellService.idl
@@ -0,0 +1,14 @@
+/* -*- Mode: C++; tab-width: 2; 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 "nsIShellService.idl"
+
+[scriptable, uuid(66f4a5cf-8807-43dd-8e65-9954f3c34cf2)]
+interface nsIMacShellService : nsIShellService
+{
+ const long APPLICATION_KEYCHAIN_ACCESS = 2;
+ const long APPLICATION_NETWORK = 3;
+ const long APPLICATION_DESKTOP = 4;
+};
diff --git a/comm/suite/components/shell/nsIShellService.idl b/comm/suite/components/shell/nsIShellService.idl
new file mode 100644
index 0000000000..9320fc6afb
--- /dev/null
+++ b/comm/suite/components/shell/nsIShellService.idl
@@ -0,0 +1,98 @@
+/* -*- Mode: IDL; tab-width: 2; 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 "nsISupports.idl"
+
+interface nsIFile;
+
+webidl Element;
+
+[scriptable, uuid(d7a19d24-9c98-4f88-b11e-52fa8c39ceea)]
+interface nsIShellService : nsISupports
+{
+ /**
+ * app types we can be registered to handle
+ */
+ const unsigned short BROWSER = 0x0001;
+ const unsigned short MAIL = 0x0002;
+ const unsigned short NEWS = 0x0004;
+ const unsigned short RSS = 0x0008;
+
+ /**
+ * Determines whether or not SeaMonkey is the "Default Client" for the
+ * passed in app type.
+ *
+ * This is simply whether or not SeaMonkey is registered to handle
+ * the url schemes associated with the app.
+ *
+ * @param aStartupCheck true if this is the check being performed
+ * by the first window at startup,
+ * false otherwise.
+ * @param aApps the application types being tested (Browser, Mail, News, RSS)
+ */
+ boolean isDefaultClient(in boolean aStartupCheck, in unsigned short aApps);
+
+ /**
+ * Registers SeaMonkey as the "Default Client" for the
+ * passed in app types.
+ *
+ * @param aForAllUsers Whether or not SeaMonkey should attempt
+ * to become the default client for all
+ * users on a multi-user system.
+ * @param aClaimAllTypes Register SeaMonkey as the handler for
+ * additional protocols (ftp, chrome etc)
+ * and web documents (.html, .xhtml etc).
+ * @param aApps the application types being tested (Mail, News, Browser, RSS)
+ */
+ void setDefaultClient(in boolean aForAllUsers, in boolean aClaimAllTypes, in unsigned short aApps);
+
+ /**
+ * Sets the desktop background image using either the HTML <IMG>
+ * element supplied or the background image of the element supplied.
+ *
+ * @param aImageElement Either a HTML <IMG> element or an element with
+ * a background image from which to source the
+ * background image.
+ * @param aPosition How to place the image on the desktop
+ * @param aImageName The image name. Equivalent to the leaf name of the
+ * location.href.
+ */
+
+ void setDesktopBackground(in Element aElement,
+ in long aPosition,
+ in ACString aImageName);
+
+ /**
+ * Flags for positioning/sizing of the Desktop Background image.
+ */
+ const long BACKGROUND_TILE = 1;
+ const long BACKGROUND_STRETCH = 2;
+ const long BACKGROUND_CENTER = 3;
+ const long BACKGROUND_FILL = 4;
+ const long BACKGROUND_FIT = 5;
+
+ /**
+ * The desktop background color, visible when no background image is
+ * used, or if the background image is centered and does not fill the
+ * entire screen. An RGB value (r << 16 | g << 8 | b)
+ */
+ attribute unsigned long desktopBackgroundColor;
+
+ /**
+ * Opens an application with a specific URI to load.
+ * @param application
+ * The application file (or bundle directory, on OS X)
+ * @param uri
+ * The uri to be loaded by the application
+ */
+ void openApplicationWithURI(in nsIFile aApplication, in ACString aURI);
+
+ /**
+ * The default system handler for web feeds
+ */
+ readonly attribute nsIFile defaultFeedReader;
+};
+
diff --git a/comm/suite/components/shell/nsMacShellService.cpp b/comm/suite/components/shell/nsMacShellService.cpp
new file mode 100644
index 0000000000..6aa8aa3088
--- /dev/null
+++ b/comm/suite/components/shell/nsMacShellService.cpp
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 2; 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 "nsDirectoryServiceDefs.h"
+#include "nsIImageLoadingContent.h"
+#include "mozilla/dom/Document.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIContent.h"
+#include "nsICookieJarSettings.h"
+#include "nsILocalFileMac.h"
+#include "nsIObserverService.h"
+#include "nsIPrefService.h"
+#include "nsIServiceManager.h"
+#include "nsIStringBundle.h"
+#include "nsIURL.h"
+#include "nsIWebBrowserPersist.h"
+#include "nsMacShellService.h"
+#include "nsIProperties.h"
+#include "nsServiceManagerUtils.h"
+#include "nsShellService.h"
+#include "nsString.h"
+#include "nsIDocShell.h"
+#include "nsILoadContext.h"
+#include "nsIPrefService.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/ReferrerInfo.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#define SAFARI_BUNDLE_IDENTIFIER "com.apple.Safari"
+
+using mozilla::dom::Element;
+
+NS_IMPL_ISUPPORTS(nsMacShellService, nsIShellService, nsIWebProgressListener)
+
+NS_IMETHODIMP
+nsMacShellService::IsDefaultClient(bool aStartupCheck, uint16_t aApps, bool *aIsDefaultClient)
+{
+ *aIsDefaultClient = false;
+
+ if (aApps & nsIShellService::BROWSER)
+ if(!isDefaultHandlerForProtocol(CFSTR("http")))
+ return NS_OK;
+ if (aApps & nsIShellService::MAIL)
+ if(!isDefaultHandlerForProtocol(CFSTR("mailto")))
+ return NS_OK;
+ if (aApps & nsIShellService::NEWS)
+ if(!isDefaultHandlerForProtocol(CFSTR("news")))
+ return NS_OK;
+ if (aApps & nsIShellService::RSS)
+ if(!isDefaultHandlerForProtocol(CFSTR("feed")))
+ return NS_OK;
+
+ *aIsDefaultClient = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDefaultClient(bool aForAllUsers,
+ bool aClaimAllTypes, uint16_t aApps)
+{
+ // Note: We don't support aForAllUsers on macOS.
+
+ CFStringRef suiteID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (!suiteID)
+ return NS_ERROR_FAILURE;
+
+ if (aApps & nsIShellService::BROWSER)
+ {
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("http"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("https"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (::LSSetDefaultRoleHandlerForContentType(kUTTypeHTML, kLSRolesAll, suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (::LSSetDefaultRoleHandlerForContentType(CFSTR("public.xhtml"), kLSRolesAll, suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ }
+
+ if (aApps & nsIShellService::MAIL)
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("mailto"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (aApps & nsIShellService::NEWS)
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("news"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (aApps & nsIShellService::RSS)
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("feed"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+bool
+nsMacShellService::isDefaultHandlerForProtocol(CFStringRef aScheme)
+{
+ bool isDefault = false;
+
+ CFStringRef suiteID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (!suiteID)
+ {
+ // CFBundleGetIdentifier is expected to return nullptr only if the specified
+ // bundle doesn't have a bundle identifier in its dictionary. In this case,
+ // that means a failure, since our bundle does have an identifier.
+ return isDefault;
+ }
+
+ // Get the default handler's bundle ID for the scheme.
+ CFStringRef defaultHandlerID = ::LSCopyDefaultHandlerForURLScheme(aScheme);
+ if (defaultHandlerID)
+ {
+ // The handler ID in LaunchServices is in all lower case, but the bundle
+ // identifier could have upper case characters. So we're using
+ // CFStringCompare with the kCFCompareCaseInsensitive option here.
+ isDefault = ::CFStringCompare(suiteID, defaultHandlerID,
+ kCFCompareCaseInsensitive) == kCFCompareEqualTo;
+ ::CFRelease(defaultHandlerID);
+ }
+
+ return isDefault;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDesktopBackground(Element* aElement,
+ int32_t aPosition,
+ const nsACString& aImageName)
+{
+ // Note: We don't support aPosition on OS X.
+
+ // Get the image URI:
+ nsresult rv;
+ nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIURI> imageURI;
+ rv = imageContent->GetCurrentURI(getter_AddRefs(imageURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIURI *docURI = aElement->OwnerDoc()->GetDocumentURI();
+ if (!docURI)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIProperties> fileLocator
+ (do_GetService("@mozilla.org/file/directory_service;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Get the current user's "Pictures" folder (That's ~/Pictures):
+ fileLocator->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile),
+ getter_AddRefs(mBackgroundFile));
+ if (!mBackgroundFile)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsAutoString fileNameUnicode;
+ CopyUTF8toUTF16(aImageName, fileNameUnicode);
+
+ // and add the image file name itself:
+ mBackgroundFile->Append(fileNameUnicode);
+
+ // Download the image; the desktop background will be set in OnStateChange():
+ nsCOMPtr<nsIWebBrowserPersist> wbp
+ (do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
+ nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES |
+ nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
+
+ wbp->SetPersistFlags(flags);
+ wbp->SetProgressListener(this);
+
+ nsCOMPtr<nsILoadContext> loadContext;
+ nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetContainer();
+ nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+ if (docShell)
+ {
+ loadContext = do_QueryInterface(docShell);
+ }
+
+ auto referrerInfo = mozilla::MakeRefPtr<mozilla::dom::ReferrerInfo>(*aElement);
+ nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
+ aElement->OwnerDoc()->CookieJarSettings();
+ return wbp->SaveURI(imageURI, aElement->NodePrincipal(), 0, referrerInfo,
+ cookieJarSettings, nullptr, nullptr, mBackgroundFile,
+ nsIContentPolicy::TYPE_IMAGE, loadContext);
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ int32_t aCurSelfProgress,
+ int32_t aMaxSelfProgress,
+ int32_t aCurTotalProgress,
+ int32_t aMaxTotalProgress)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ nsIURI* aLocation,
+ uint32_t aFlags)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ nsresult aStatus,
+ const char16_t* aMessage)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ uint32_t aState)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ uint32_t aEvent) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ uint32_t aStateFlags,
+ nsresult aStatus)
+{
+ if (aStateFlags & STATE_STOP)
+ {
+ bool exists = false;
+ mBackgroundFile->Exists(&exists);
+ if (!exists)
+ return NS_OK;
+
+ nsAutoCString nativePath;
+ mBackgroundFile->GetNativePath(nativePath);
+
+ AEDesc tAEDesc = { typeNull, nil };
+ OSErr err = noErr;
+ AliasHandle aliasHandle = nil;
+ FSRef pictureRef;
+ OSStatus status;
+
+ // Convert the path into a FSRef:
+ status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef,
+ nullptr);
+ if (status == noErr)
+ {
+ err = ::FSNewAlias(nil, &pictureRef, &aliasHandle);
+ if (err == noErr && aliasHandle == nil)
+ err = paramErr;
+
+ if (err == noErr)
+ {
+ // We need the descriptor (based on the picture file reference)
+ // for the 'Set Desktop Picture' apple event.
+ char handleState = ::HGetState((Handle)aliasHandle);
+ ::HLock((Handle)aliasHandle);
+ err = ::AECreateDesc(typeAlias, *aliasHandle,
+ GetHandleSize((Handle)aliasHandle), &tAEDesc);
+ // Unlock the alias handler:
+ ::HSetState((Handle)aliasHandle, handleState);
+ ::DisposeHandle((Handle)aliasHandle);
+ }
+ if (err == noErr)
+ {
+ AppleEvent tAppleEvent;
+ OSType sig = 'MACS';
+ AEBuildError tAEBuildError;
+ // Create a 'Set Desktop Picture' Apple Event:
+ err = ::AEBuildAppleEvent(kAECoreSuite, kAESetData, typeApplSignature,
+ &sig, sizeof(OSType), kAutoGenerateReturnID,
+ kAnyTransactionID, &tAppleEvent, &tAEBuildError,
+ "'----':'obj '{want:type (prop),form:prop" \
+ ",seld:type('dpic'),from:'null'()},data:(@)",
+ &tAEDesc);
+ if (err == noErr)
+ {
+ AppleEvent reply = { typeNull, nil };
+ // Send the event we built, the reply event isn't necessary:
+ err = ::AESend(&tAppleEvent, &reply, kAENoReply, kAENormalPriority,
+ kNoTimeOut, nil, nil);
+ ::AEDisposeDesc(&tAppleEvent);
+ }
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::GetDesktopBackgroundColor(uint32_t *aColor)
+{
+ // This method and |SetDesktopBackgroundColor| has no meaning on macOS.
+ // The mac desktop preferences UI uses pictures for the few solid colors it
+ // supports.
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDesktopBackgroundColor(uint32_t aColor)
+{
+ // This method and |GetDesktopBackgroundColor| has no meaning on macOS.
+ // The mac desktop preferences UI uses pictures for the few solid colors it
+ // supports.
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI)
+{
+ nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(aApplication));
+ CFURLRef appURL;
+ nsresult rv = lfm->GetCFURL(&appURL);
+ if (NS_FAILED(rv))
+ return rv;
+
+ const nsCString& spec = PromiseFlatCString(aURI);
+ const UInt8* uriString = (const UInt8*)spec.get();
+ CFURLRef uri = ::CFURLCreateWithBytes(nullptr, uriString, aURI.Length(),
+ kCFStringEncodingUTF8, nullptr);
+ if (!uri)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ CFArrayRef uris = ::CFArrayCreate(nullptr, (const void**)&uri, 1, nullptr);
+ if (!uris)
+ {
+ ::CFRelease(uri);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ LSLaunchURLSpec launchSpec;
+ launchSpec.appURL = appURL;
+ launchSpec.itemURLs = uris;
+ launchSpec.passThruParams = nullptr;
+ launchSpec.launchFlags = kLSLaunchDefaults;
+ launchSpec.asyncRefCon = nullptr;
+
+ OSErr err = ::LSOpenFromURLSpec(&launchSpec, nullptr);
+
+ ::CFRelease(uris);
+ ::CFRelease(uri);
+
+ return err != noErr ? NS_ERROR_FAILURE : NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::GetDefaultFeedReader(nsIFile** _retval)
+{
+ nsresult rv = NS_ERROR_FAILURE;
+ *_retval = nullptr;
+
+ CFStringRef defaultHandlerID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("feed"));
+ if (!defaultHandlerID)
+ {
+ defaultHandlerID = ::CFStringCreateWithCString(kCFAllocatorDefault,
+ SAFARI_BUNDLE_IDENTIFIER,
+ kCFStringEncodingASCII);
+ }
+
+ CFURLRef defaultHandlerURL = nullptr;
+ OSStatus status = ::LSFindApplicationForInfo(kLSUnknownCreator,
+ defaultHandlerID,
+ nullptr, // inName
+ nullptr, // outAppRef
+ &defaultHandlerURL);
+
+ if (status == noErr && defaultHandlerURL)
+ {
+ nsCOMPtr<nsILocalFileMac> defaultReader =
+ do_CreateInstance("@mozilla.org/file/local;1", &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = defaultReader->InitWithCFURL(defaultHandlerURL);
+ if (NS_SUCCEEDED(rv))
+ {
+ NS_ADDREF(*_retval = defaultReader);
+ }
+ }
+
+ ::CFRelease(defaultHandlerURL);
+ }
+
+ ::CFRelease(defaultHandlerID);
+
+ return rv;
+}
diff --git a/comm/suite/components/shell/nsMacShellService.h b/comm/suite/components/shell/nsMacShellService.h
new file mode 100644
index 0000000000..4fa92513c2
--- /dev/null
+++ b/comm/suite/components/shell/nsMacShellService.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef nsmacshellservice_h____
+#define nsmacshellservice_h____
+
+#include "nsIMacShellService.h"
+#include "nsIWebProgressListener.h"
+#include "nsIFile.h"
+#include "nsCOMPtr.h"
+#include "mozilla/Attributes.h"
+#include "nsSuiteCID.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+class nsMacShellService final : public nsIShellService,
+ public nsIWebProgressListener
+{
+public:
+ nsMacShellService() {};
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISHELLSERVICE
+ NS_DECL_NSIWEBPROGRESSLISTENER
+
+protected:
+ ~nsMacShellService() {}
+ bool isDefaultHandlerForProtocol(CFStringRef aScheme);
+
+private:
+ nsCOMPtr<nsIFile> mBackgroundFile;
+};
+
+#endif
diff --git a/comm/suite/components/shell/nsSetDefault.js b/comm/suite/components/shell/nsSetDefault.js
new file mode 100644
index 0000000000..4d35dc4531
--- /dev/null
+++ b/comm/suite/components/shell/nsSetDefault.js
@@ -0,0 +1,53 @@
+/* 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/. */
+
+/*
+ * This component handles the startup command line arguments of the form:
+ * -setDefaultBrowser
+ * -setDefaultMail
+ * -setDefaultNews
+ * -setDefaultFeed
+ */
+
+const nsICommandLineHandler = Ci.nsICommandLineHandler;
+var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function nsSetDefault() {
+}
+
+nsSetDefault.prototype = {
+ handle: function nsSetDefault_handle(aCmdline) {
+ if (aCmdline.handleFlag("setDefaultBrowser", false)) {
+ var shell = Cc["@mozilla.org/suite/shell-service;1"]
+ .getService(Ci.nsIShellService);
+ shell.setDefaultClient(true, true, Ci.nsIShellService.BROWSER);
+ }
+ else if (aCmdline.handleFlag("setDefaultMail", false)) {
+ var shell = Cc["@mozilla.org/suite/shell-service;1"]
+ .getService(Ci.nsIShellService);
+ shell.setDefaultClient(true, true, Ci.nsIShellService.MAIL);
+ }
+ else if (aCmdline.handleFlag("setDefaultNews", false)) {
+ var shell = Cc["@mozilla.org/suite/shell-service;1"]
+ .getService(Ci.nsIShellService);
+ shell.setDefaultClient(true, true, Ci.nsIShellService.NEWS);
+ }
+ else if (aCmdline.handleFlag("setDefaultFeed", false)) {
+ var shell = Cc["@mozilla.org/suite/shell-service;1"]
+ .getService(Ci.nsIShellService);
+ shell.setDefaultClient(true, true, Ci.nsIShellService.RSS);
+ }
+ },
+
+ helpInfo: " -setDefaultBrowser Set this app as the default browser client.\n" +
+ " -setDefaultMail Set this app as the default mail client.\n" +
+ " -setDefaultNews Set this app as the default newsreader.\n" +
+ " -setDefaultFeed Set this app as the default feedreader.\n",
+
+ classID: Components.ID("{a3d5b950-690a-491f-a881-2c2cdcd241cb}"),
+ QueryInterface: XPCOMUtils.generateQI([nsICommandLineHandler])
+}
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSetDefault]);
+
diff --git a/comm/suite/components/shell/nsSetDefault.manifest b/comm/suite/components/shell/nsSetDefault.manifest
new file mode 100644
index 0000000000..7d4a585bc7
--- /dev/null
+++ b/comm/suite/components/shell/nsSetDefault.manifest
@@ -0,0 +1,3 @@
+component {a3d5b950-690a-491f-a881-2c2cdcd241cb} nsSetDefault.js
+contract @mozilla.org/suite/default-browser-clh;1 {a3d5b950-690a-491f-a881-2c2cdcd241cb}
+category command-line-handler m-setdefault @mozilla.org/suite/default-browser-clh;1
diff --git a/comm/suite/components/shell/nsShellService.h b/comm/suite/components/shell/nsShellService.h
new file mode 100644
index 0000000000..f5275a6556
--- /dev/null
+++ b/comm/suite/components/shell/nsShellService.h
@@ -0,0 +1,11 @@
+/* -*- Mode: C++; tab-width: 2; 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 "nsIShellService.h"
+
+#define PREF_CHECKDEFAULTCLIENT "shell.checkDefaultClient"
+
+#define SHELLSERVICE_PROPERTIES "chrome://communicator/locale/shellservice.properties"
+#define BRAND_PROPERTIES "chrome://branding/locale/brand.properties"
diff --git a/comm/suite/components/shell/nsWindowsShellService.cpp b/comm/suite/components/shell/nsWindowsShellService.cpp
new file mode 100644
index 0000000000..7cdf1cbd88
--- /dev/null
+++ b/comm/suite/components/shell/nsWindowsShellService.cpp
@@ -0,0 +1,793 @@
+/* -*- Mode: C++; tab-width: 2; 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 "nsWindowsShellService.h"
+
+#include "imgIContainer.h"
+#include "imgIRequest.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
+#include "nsIContent.h"
+#include "nsIImageLoadingContent.h"
+#include "nsIOutputStream.h"
+#include "nsIPrefService.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsIServiceManager.h"
+#include "nsIStringBundle.h"
+#include "nsNetUtil.h"
+#include "nsServiceManagerUtils.h"
+#include "nsShellService.h"
+#include "nsIProcess.h"
+#include "nsICategoryManager.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIWindowsRegKey.h"
+#include "nsUnicharUtils.h"
+#include "nsIURLFormatter.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/WindowsVersion.h"
+#include "mozilla/dom/Element.h"
+
+#include "windows.h"
+#include "shellapi.h"
+
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0600
+#define INITGUID
+#include <shlobj.h>
+
+#ifndef MAX_BUF
+#define MAX_BUF 4096
+#endif
+
+#define REG_SUCCEEDED(val) \
+ (val == ERROR_SUCCESS)
+
+#define REG_FAILED(val) \
+ (val != ERROR_SUCCESS)
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+NS_IMPL_ISUPPORTS(nsWindowsShellService, nsIShellService)
+
+static nsresult
+OpenKeyForReading(HKEY aKeyRoot, const wchar_t* aKeyName, HKEY* aKey)
+{
+ DWORD res = ::RegOpenKeyExW(aKeyRoot, aKeyName, 0, KEY_READ, aKey);
+ switch (res) {
+ case ERROR_SUCCESS:
+ break;
+ case ERROR_ACCESS_DENIED:
+ return NS_ERROR_FILE_ACCESS_DENIED;
+ case ERROR_FILE_NOT_FOUND:
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ return NS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Default SeaMonkey OS integration Registry Settings
+// Note: Some settings only exist when using the installer!
+// The setting of SeaMonkey as default application is made by a helper
+// application since writing those values may require elevation.
+//
+// Default Browser settings:
+// - File Extension Mappings
+// -----------------------
+// The following file extensions:
+// .htm .html .shtml .xht .xhtml
+// are mapped like so:
+//
+// HKCU\SOFTWARE\Classes\.<ext>\ (default) REG_SZ SeaMonkeyHTML
+//
+// as aliases to the class:
+//
+// HKCU\SOFTWARE\Classes\SeaMonkeyHTML\
+// DefaultIcon (default) REG_SZ <appfolder>\chrome\icons\default\html-file.ico
+// shell\open\command (default) REG_SZ <apppath> -url "%1"
+//
+// - Windows Vista Protocol Handler
+//
+// HKCU\SOFTWARE\Classes\SeaMonkeyURL\(default) REG_SZ <appname> URL
+// EditFlags REG_DWORD 2
+// FriendlyTypeName REG_SZ <appname> URL
+// DefaultIcon (default) REG_SZ <apppath>,1
+// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
+// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
+// shell\open\ddeexec NoActivateHandler REG_SZ
+// \Application (default) REG_SZ SeaMonkey
+// \Topic (default) REG_SZ WWW_OpenURL
+//
+// - Protocol Mappings
+// -----------------
+// The following protocols:
+// HTTP, HTTPS, FTP
+// are mapped like so:
+//
+// HKCU\SOFTWARE\Classes\<protocol>\
+// DefaultIcon (default) REG_SZ <apppath>,0
+// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
+// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
+// shell\open\ddeexec NoActivateHandler REG_SZ
+// \Application (default) REG_SZ SeaMonkey
+// \Topic (default) REG_SZ WWW_OpenURL
+//
+// - Windows Start Menu (Win2K SP2, XP SP1, and newer)
+// -------------------------------------------------
+// The following keys are set to make SeaMonkey appear in the Start Menu as the
+// browser:
+//
+// HKCU\SOFTWARE\Clients\StartMenuInternet\SEAMONKEY.EXE\
+// (default) REG_SZ <appname>
+// DefaultIcon (default) REG_SZ <apppath>,0
+// InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
+// InstallInfo IconsVisible REG_DWORD 1
+// InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
+// InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
+// shell\open\command (default) REG_SZ <apppath>
+// shell\properties (default) REG_SZ <appname> &Preferences
+// shell\properties\command (default) REG_SZ <apppath> -preferences
+// shell\safemode (default) REG_SZ <appname> &Safe Mode
+// shell\safemode\command (default) REG_SZ <apppath> -safe-mode
+//
+//
+//
+// Default Mail&News settings
+//
+// - File Extension Mappings
+// -----------------------
+// The following file extension:
+// .eml
+// is mapped like this:
+//
+// HKCU\SOFTWARE\Classes\.eml (default) REG_SZ SeaMonkeyEML
+//
+// That aliases to this class:
+// HKCU\SOFTWARE\Classes\SeaMonkeyEML\ (default) REG_SZ SeaMonkey (Mail) Document
+// FriendlyTypeName REG_SZ SeaMonkey (Mail) Document
+// DefaultIcon (default) REG_SZ <appfolder>\chrome\icons\default\html-file.ico
+// shell\open\command (default) REG_SZ <apppath> "%1"
+//
+// - Windows Vista Protocol Handler
+//
+// HKCU\SOFTWARE\Classes\SeaMonkeyCOMPOSE (default) REG_SZ SeaMonkey (Mail) URL
+// DefaultIcon REG_SZ <apppath>,0
+// EditFlags REG_DWORD 2
+// shell\open\command (default) REG_SZ <apppath> -osint -compose "%1"
+//
+// HKCU\SOFTWARE\Classes\SeaMonkeyNEWS (default) REG_SZ SeaMonkey (News) URL
+// DefaultIcon REG_SZ <apppath>,0
+// EditFlags REG_DWORD 2
+// shell\open\command (default) REG_SZ <apppath> -osint -news "%1"
+//
+//
+// - Protocol Mappings
+// -----------------
+// The following protocol:
+// mailto
+// is mapped like this:
+//
+// HKCU\SOFTWARE\Classes\mailto\ (default) REG_SZ SeaMonkey (Mail) URL
+// EditFlags REG_DWORD 2
+// URL Protocol REG_SZ
+// DefaultIcon (default) REG_SZ <apppath>,0
+// shell\open\command (default) REG_SZ <apppath> -osint -compose "%1"
+//
+// The following protocols:
+// news,nntp,snews
+// are mapped like this:
+//
+// HKCU\SOFTWARE\Classes\<protocol>\ (default) REG_SZ SeaMonkey (News) URL
+// EditFlags REG_DWORD 2
+// URL Protocol REG_SZ
+// DefaultIcon (default) REG_SZ <appath>,0
+// shell\open\command (default) REG_SZ <appath> -osint -news "%1"
+//
+// - Windows Start Menu (Win2K SP2, XP SP1, and newer)
+// -------------------------------------------------
+// The following keys are set to make SeaMonkey appear in the Start Menu as
+// the default mail program:
+//
+// HKCU\SOFTWARE\Clients\Mail\SeaMonkey
+// (default) REG_SZ <appname>
+// DLLPath REG_SZ <appfolder>\mozMapi32.dll
+// DefaultIcon (default) REG_SZ <apppath>,0
+// InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
+// InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
+// InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
+// shell\open\command (default) REG_SZ <apppath> -mail
+// shell\properties (default) REG_SZ <appname> &Preferences
+// shell\properties\command (default) REG_SZ <apppath> -preferences
+//
+// Also set SeaMonkey as News reader (Usenet), though Windows does currently
+// not expose a default news reader to UI. Applications like Outlook
+// also add themselves to this registry key
+//
+// HKCU\SOFTWARE\Clients\News\SeaMonkey
+// (default) REG_SZ <appname>
+// DLLPath REG_SZ <appfolder>\mozMapi32.dll
+// DefaultIcon (default) REG_SZ <apppath>,0
+// shell\open\command (default) REG_SZ <apppath> -news
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+typedef enum {
+ NO_SUBSTITUTION = 0x00,
+ APP_PATH_SUBSTITUTION = 0x01
+} SettingFlags;
+
+#define APP_REG_NAME L"SeaMonkey"
+// APP_REG_NAME_MAIL and APP_REG_NAME_NEWS should be kept in synch with
+// AppRegNameMail and AppRegNameNews in the installer file: defines.nsi.in
+#define APP_REG_NAME_MAIL L"SeaMonkey (Mail)"
+#define APP_REG_NAME_NEWS L"SeaMonkey (News)"
+#define CLS_HTML "SeaMonkeyHTML"
+#define CLS_URL "SeaMonkeyURL"
+#define CLS_EML "SeaMonkeyEML"
+#define CLS_MAILTOURL "SeaMonkeyCOMPOSE"
+#define CLS_NEWSURL "SeaMonkeyNEWS"
+#define CLS_FEEDURL "SeaMonkeyFEED"
+#define SMI "SOFTWARE\\Clients\\StartMenuInternet\\"
+#define DI "\\DefaultIcon"
+#define II "\\InstallInfo"
+#define SOP "\\shell\\open\\command"
+
+#define VAL_ICON "%APPPATH%,0"
+#define VAL_HTML_OPEN "\"%APPPATH%\" -url \"%1\""
+#define VAL_URL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
+#define VAL_MAIL_OPEN "\"%APPPATH%\" \"%1\""
+
+#define MAKE_KEY_NAME1(PREFIX, MID) \
+ PREFIX MID
+
+// The DefaultIcon registry key value should never be used (e.g. NON_ESSENTIAL)
+// when checking if SeaMonkey is the default browser since other applications
+// (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
+// Handlers.
+// see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for more info.
+static SETTING gBrowserSettings[] = {
+ // File Extension Class - as of 1.8.1.2 the value for VAL_URL_OPEN is also
+ // checked for CLS_HTML since SeaMonkey should also own opening local files
+ // when set as the default browser.
+ { MAKE_KEY_NAME1(CLS_HTML, SOP), "", VAL_HTML_OPEN, APP_PATH_SUBSTITUTION },
+
+ // Protocol Handler Class - for Vista and above
+ { MAKE_KEY_NAME1(CLS_URL, SOP), "", VAL_URL_OPEN, APP_PATH_SUBSTITUTION },
+
+ // Protocol Handlers
+ { MAKE_KEY_NAME1("HTTP", DI), "", VAL_ICON, APP_PATH_SUBSTITUTION },
+ { MAKE_KEY_NAME1("HTTP", SOP), "", VAL_URL_OPEN, APP_PATH_SUBSTITUTION },
+ { MAKE_KEY_NAME1("HTTPS", DI), "", VAL_ICON, APP_PATH_SUBSTITUTION },
+ { MAKE_KEY_NAME1("HTTPS", SOP), "", VAL_URL_OPEN, APP_PATH_SUBSTITUTION }
+
+ // These values must be set by hand, since they contain localized strings.
+ // seamonkey.exe\shell\properties (default) REG_SZ SeaMonkey &Preferences
+ // seamonkey.exe\shell\safemode (default) REG_SZ SeaMonkey &Safe Mode
+};
+
+ static SETTING gMailSettings[] = {
+ // File Extension Aliases
+ { ".eml", "", CLS_EML, NO_SUBSTITUTION },
+ // File Extension Class
+ { MAKE_KEY_NAME1(CLS_EML, SOP), "", VAL_MAIL_OPEN, APP_PATH_SUBSTITUTION},
+
+ // Protocol Handler Class - for Vista and above
+ { MAKE_KEY_NAME1(CLS_MAILTOURL, SOP), "", "\"%APPPATH%\" -osint -compose \"%1\"", APP_PATH_SUBSTITUTION },
+
+ // Protocol Handlers
+ { MAKE_KEY_NAME1("mailto", SOP), "", "\"%APPPATH%\" -osint -compose \"%1\"", APP_PATH_SUBSTITUTION }
+ };
+
+ static SETTING gNewsSettings[] = {
+ // Protocol Handler Class - for Vista and above
+ { MAKE_KEY_NAME1(CLS_NEWSURL, SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
+
+ // Protocol Handlers
+ { MAKE_KEY_NAME1("news", SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
+ { MAKE_KEY_NAME1("nntp", SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
+};
+
+ static SETTING gFeedSettings[] = {
+ // Protocol Handler Class - for Vista and above
+ { MAKE_KEY_NAME1(CLS_FEEDURL, SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
+
+ // Protocol Handlers
+ { MAKE_KEY_NAME1("feed", SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
+};
+
+nsresult
+GetHelperPath(nsString& aPath)
+{
+ nsresult rv;
+ nsCOMPtr<nsIProperties> directoryService =
+ do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIFile> appHelper;
+ rv = directoryService->Get(XRE_EXECUTABLE_FILE,
+ NS_GET_IID(nsIFile),
+ getter_AddRefs(appHelper));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appHelper->SetNativeLeafName("uninstall"_ns);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appHelper->AppendNative("helper.exe"_ns);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appHelper->GetPath(aPath);
+
+ aPath.Insert('"', 0);
+ aPath.Append('"');
+
+ return rv;
+}
+
+nsresult
+LaunchHelper(const nsString& aPath)
+{
+ STARTUPINFOW si = {sizeof(si), 0};
+ PROCESS_INFORMATION pi = {0};
+
+ BOOL ok = CreateProcessW(nullptr, (LPWSTR)aPath.get(), nullptr, nullptr,
+ FALSE, 0, nullptr, nullptr, &si, &pi);
+
+ if (!ok)
+ return NS_ERROR_FAILURE;
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return NS_OK;
+}
+
+/* helper routine. Iterate over the passed in settings object,
+ testing each key to see if we are handling it.
+*/
+bool
+nsWindowsShellService::TestForDefault(SETTING aSettings[], int32_t aSize)
+{
+ wchar_t currValue[MAX_BUF];
+ SETTING* end = aSettings + aSize;
+ for (SETTING * settings = aSettings; settings < end; ++settings) {
+ NS_ConvertUTF8toUTF16 dataLongPath(settings->valueData);
+ NS_ConvertUTF8toUTF16 dataShortPath(settings->valueData);
+ NS_ConvertUTF8toUTF16 key(settings->keyName);
+ NS_ConvertUTF8toUTF16 value(settings->valueName);
+ if (settings->flags & APP_PATH_SUBSTITUTION) {
+ int32_t offset = dataLongPath.Find(u"%APPPATH%");
+ dataLongPath.Replace(offset, 9, mAppLongPath);
+ // Remove the quotes around %APPPATH% in VAL_OPEN for short paths
+ int32_t offsetQuoted = dataShortPath.Find(u"\"%APPPATH%\"");
+ if (offsetQuoted != -1)
+ dataShortPath.Replace(offsetQuoted, 11, mAppShortPath);
+ else
+ dataShortPath.Replace(offset, 9, mAppShortPath);
+ }
+
+ ::ZeroMemory(currValue, sizeof(currValue));
+ HKEY theKey;
+ nsresult rv = OpenKeyForReading(HKEY_CLASSES_ROOT, key.get(), &theKey);
+ if (NS_FAILED(rv))
+ // Key does not exist
+ return false;
+
+ DWORD len = sizeof currValue;
+ DWORD res = ::RegQueryValueExW(theKey, value.get(),
+ nullptr, nullptr, (LPBYTE)currValue, &len);
+ // Close the key we opened.
+ ::RegCloseKey(theKey);
+ if (REG_FAILED(res) ||
+ _wcsicmp(dataLongPath.get(), currValue) &&
+ _wcsicmp(dataShortPath.get(), currValue)) {
+ // Key wasn't set, or was set to something else (something else became the default client)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+nsresult nsWindowsShellService::Init()
+{
+ wchar_t appPath[MAX_BUF];
+ if (!::GetModuleFileNameW(0, appPath, MAX_BUF))
+ return NS_ERROR_FAILURE;
+
+ mAppLongPath.Assign(appPath);
+
+ // Support short path to the exe so if it is already set the user is not
+ // prompted to set the default mail client again.
+ if (!::GetShortPathNameW(appPath, appPath, MAX_BUF))
+ return NS_ERROR_FAILURE;
+
+ mAppShortPath.Assign(appPath);
+
+ return NS_OK;
+}
+
+bool
+nsWindowsShellService::IsDefaultClientVista(uint16_t aApps, bool* aIsDefaultClient)
+{
+ IApplicationAssociationRegistration* pAAR;
+
+ HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
+ nullptr,
+ CLSCTX_INPROC,
+ IID_IApplicationAssociationRegistration,
+ (void**)&pAAR);
+
+ if (SUCCEEDED(hr)) {
+ BOOL isDefaultBrowser = true;
+ BOOL isDefaultMail = true;
+ BOOL isDefaultNews = true;
+ if (aApps & nsIShellService::BROWSER)
+ pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, APP_REG_NAME, &isDefaultBrowser);
+ if (aApps & nsIShellService::MAIL)
+ pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, APP_REG_NAME_MAIL, &isDefaultMail);
+ if (aApps & nsIShellService::NEWS)
+ pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, APP_REG_NAME_NEWS, &isDefaultNews);
+
+ *aIsDefaultClient = isDefaultBrowser && isDefaultNews && isDefaultMail;
+
+ pAAR->Release();
+ return true;
+ }
+ return false;
+}
+
+NS_IMETHODIMP
+nsWindowsShellService::IsDefaultClient(bool aStartupCheck, uint16_t aApps, bool *aIsDefaultClient)
+{
+ *aIsDefaultClient = true;
+
+ // for each type, check if it is the default app
+ // browser check needs to be at the top
+ if (aApps & nsIShellService::BROWSER) {
+ *aIsDefaultClient &= TestForDefault(gBrowserSettings, sizeof(gBrowserSettings)/sizeof(SETTING));
+ // Only check if this app is default on Vista if the previous checks
+ // indicate that this app is the default.
+ if (*aIsDefaultClient)
+ IsDefaultClientVista(nsIShellService::BROWSER, aIsDefaultClient);
+ }
+ if (aApps & nsIShellService::MAIL) {
+ *aIsDefaultClient &= TestForDefault(gMailSettings, sizeof(gMailSettings)/sizeof(SETTING));
+ // Only check if this app is default on Vista if the previous checks
+ // indicate that this app is the default.
+ if (*aIsDefaultClient)
+ IsDefaultClientVista(nsIShellService::MAIL, aIsDefaultClient);
+ }
+ if (aApps & nsIShellService::NEWS) {
+ *aIsDefaultClient &= TestForDefault(gNewsSettings, sizeof(gNewsSettings)/sizeof(SETTING));
+ // Only check if this app is default on Vista if the previous checks
+ // indicate that this app is the default.
+ if (*aIsDefaultClient)
+ IsDefaultClientVista(nsIShellService::NEWS, aIsDefaultClient);
+ }
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsWindowsShellService::SetDefaultClient(bool aForAllUsers,
+ bool aClaimAllTypes, uint16_t aApps)
+{
+ nsAutoString appHelperPath;
+ if (NS_FAILED(GetHelperPath(appHelperPath)))
+ return NS_ERROR_FAILURE;
+
+ if (aForAllUsers)
+ appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
+ else {
+ appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
+ if (aApps & nsIShellService::BROWSER)
+ appHelperPath.AppendLiteral(" Browser");
+
+ if (aApps & nsIShellService::MAIL)
+ appHelperPath.AppendLiteral(" Mail");
+
+ if (aApps & nsIShellService::NEWS)
+ appHelperPath.AppendLiteral(" News");
+ }
+
+ return LaunchHelper(appHelperPath);
+}
+
+static nsresult
+WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
+{
+ nsresult rv;
+
+ RefPtr<SourceSurface> surface =
+ aImage->GetFrame(imgIContainer::FRAME_CURRENT,
+ imgIContainer::FLAG_SYNC_DECODE);
+ NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
+
+ // For either of the following formats we want to set the biBitCount member
+ // of the BITMAPINFOHEADER struct to 32, below. For that value the bitmap
+ // format defines that the A8/X8 WORDs in the bitmap byte stream be ignored
+ // for the BI_RGB value we use for the biCompression member.
+ MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
+ surface->GetFormat() == SurfaceFormat::B8G8R8X8);
+
+ RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
+ NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
+
+ int32_t width = dataSurface->GetSize().width;
+ int32_t height = dataSurface->GetSize().height;
+ int32_t bytesPerPixel = 4 * sizeof(uint8_t);
+ int32_t bytesPerRow = bytesPerPixel * width;
+
+ // initialize these bitmap structs which we will later
+ // serialize directly to the head of the bitmap file
+ BITMAPINFOHEADER bmi;
+ bmi.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.biWidth = width;
+ bmi.biHeight = height;
+ bmi.biPlanes = 1;
+ bmi.biBitCount = (WORD)bytesPerPixel*8;
+ bmi.biCompression = BI_RGB;
+ bmi.biSizeImage = bytesPerRow * height;
+ bmi.biXPelsPerMeter = 0;
+ bmi.biYPelsPerMeter = 0;
+ bmi.biClrUsed = 0;
+ bmi.biClrImportant = 0;
+
+ BITMAPFILEHEADER bf;
+ bf.bfType = 0x4D42; // 'BM'
+ bf.bfReserved1 = 0;
+ bf.bfReserved2 = 0;
+ bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+ bf.bfSize = bf.bfOffBits + bmi.biSizeImage;
+
+ // get a file output stream
+ nsCOMPtr<nsIOutputStream> stream;
+ rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ DataSourceSurface::MappedSurface map;
+ if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // write the bitmap headers and rgb pixel data to the file
+ rv = NS_ERROR_FAILURE;
+ if (stream) {
+ uint32_t written;
+ stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
+ if (written == sizeof(BITMAPFILEHEADER)) {
+ stream->Write((const char*)&bmi, sizeof(BITMAPINFOHEADER), &written);
+ if (written == sizeof(BITMAPINFOHEADER)) {
+ // write out the image data backwards because the desktop won't
+ // show bitmaps with negative heights for top-to-bottom
+ uint32_t i = map.mStride * height;
+ rv = NS_OK;
+ do {
+ i -= map.mStride;
+ stream->Write(((const char*)map.mData) + i, bytesPerRow, &written);
+ if (written != bytesPerRow) {
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
+ } while (i != 0);
+ }
+ }
+
+ stream->Close();
+ }
+
+ dataSurface->Unmap();
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWindowsShellService::SetDesktopBackground(dom::Element* aElement,
+ int32_t aPosition,
+ const nsACString& aImageName)
+{
+ if (!aElement || !aElement->IsHTMLElement(nsGkAtoms::img)) {
+ // XXX write background loading stuff!
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIImageLoadingContent> imageContent =
+ do_QueryInterface(aElement, &rv);
+ if (!imageContent)
+ return rv;
+
+ // get the image container
+ nsCOMPtr<imgIRequest> request;
+ rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+ getter_AddRefs(request));
+ if (!request)
+ return rv;
+
+ nsCOMPtr<imgIContainer> container;
+ rv = request->GetImage(getter_AddRefs(container));
+ if (!container)
+ return NS_ERROR_FAILURE;
+
+ // get the file name from localized strings
+ nsCOMPtr<nsIStringBundleService> bundleService(
+ do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIStringBundle> shellBundle;
+ rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
+ getter_AddRefs(shellBundle));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // e.g. "Desktop Background.bmp"
+ nsAutoString fileLeafName;
+ rv = shellBundle->GetStringFromName("desktopBackgroundLeafNameWin",
+ fileLeafName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // get the profile root directory
+ nsCOMPtr<nsIFile> file;
+ rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
+ getter_AddRefs(file));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // eventually, the path is "%APPDATA%\Mozilla\SeaMonkey\Desktop Background.bmp"
+ rv = file->Append(fileLeafName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString path;
+ rv = file->GetPath(path);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // write the bitmap to a file in the profile directory
+ rv = WriteBitmap(file, container);
+
+ // if the file was written successfully, set it as the system wallpaper
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIWindowsRegKey> key(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ u"Control Panel\\Desktop"_ns,
+ nsIWindowsRegKey::ACCESS_SET_VALUE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ int style = 0;
+ switch (aPosition) {
+ case BACKGROUND_STRETCH:
+ style = 2;
+ break;
+ case BACKGROUND_FILL:
+ style = 10;
+ break;
+ case BACKGROUND_FIT:
+ style = 6;
+ break;
+ }
+
+ nsString value;
+ value.AppendInt(style);
+ rv = key->WriteStringValue(u"WallpaperStyle"_ns, value);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ value.Assign(aPosition == BACKGROUND_TILE ? '1' : '0');
+ rv = key->WriteStringValue(u"TileWallpaper"_ns, value);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Close();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
+ SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWindowsShellService::GetDesktopBackgroundColor(uint32_t* aColor)
+{
+ uint32_t color = ::GetSysColor(COLOR_DESKTOP);
+ *aColor = (GetRValue(color) << 16) | (GetGValue(color) << 8) | GetBValue(color);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWindowsShellService::SetDesktopBackgroundColor(uint32_t aColor)
+{
+ int parameter = COLOR_DESKTOP;
+ BYTE r = (aColor >> 16);
+ BYTE g = (aColor << 16) >> 24;
+ BYTE b = (aColor << 24) >> 24;
+ COLORREF color = RGB(r,g,b);
+
+ ::SetSysColors(1, &parameter, &color);
+
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ u"Control Panel\\Colors"_ns,
+ nsIWindowsRegKey::ACCESS_SET_VALUE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ wchar_t rgb[12];
+ _snwprintf(rgb, 12, L"%u %u %u", r, g, b);
+ rv = key->WriteStringValue(u"Background"_ns,
+ nsDependentString(rgb));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return key->Close();
+}
+
+NS_IMETHODIMP
+nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
+ const nsACString& aURI)
+{
+ nsresult rv;
+ nsCOMPtr<nsIProcess> process =
+ do_CreateInstance("@mozilla.org/process/util;1", &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = process->Init(aApplication);
+ if (NS_FAILED(rv))
+ return rv;
+
+ const nsCString& spec = PromiseFlatCString(aURI);
+ const char* specStr = spec.get();
+ return process->Run(false, &specStr, 1);
+}
+
+NS_IMETHODIMP
+nsWindowsShellService::GetDefaultFeedReader(nsIFile** _retval)
+{
+ *_retval = nullptr;
+
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
+ u"feed\\shell\\open\\command"_ns,
+ nsIWindowsRegKey::ACCESS_READ);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsString path;
+ rv = key->ReadStringValue(EmptyString(), path);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (path.IsEmpty())
+ return NS_ERROR_FAILURE;
+
+ if (path.First() == '"') {
+ // Everything inside the quotes
+ path = Substring(path, 1, path.FindChar('"', 1) - 1);
+ } else {
+ // Everything up to the first space
+ path = Substring(path, 0, path.FindChar(' '));
+ }
+
+ nsCOMPtr<nsIFile> defaultReader =
+ do_CreateInstance("@mozilla.org/file/local;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = defaultReader->InitWithPath(path);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool exists;
+ rv = defaultReader->Exists(&exists);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!exists)
+ return NS_ERROR_FAILURE;
+
+ NS_ADDREF(*_retval = defaultReader);
+ return NS_OK;
+}
diff --git a/comm/suite/components/shell/nsWindowsShellService.h b/comm/suite/components/shell/nsWindowsShellService.h
new file mode 100644
index 0000000000..a29dff2e5d
--- /dev/null
+++ b/comm/suite/components/shell/nsWindowsShellService.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; 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 "nscore.h"
+#include "nsShellService.h"
+#include "nsString.h"
+#include "nsIShellService.h"
+#include "mozilla/Attributes.h"
+#include "nsSuiteCID.h"
+
+#include <windows.h>
+
+typedef struct {
+ const char* keyName;
+ const char* valueName;
+ const char* valueData;
+
+ int32_t flags;
+} SETTING;
+
+class nsWindowsShellService final : public nsIShellService
+{
+public:
+ nsWindowsShellService() {};
+ nsresult Init();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISHELLSERVICE
+
+protected:
+ ~nsWindowsShellService() {}
+ bool IsDefaultClientVista(uint16_t aApps, bool* aIsDefaultClient);
+ bool TestForDefault(SETTING aSettings[], int32_t aSize);
+
+private:
+ nsString mAppLongPath;
+ nsString mAppShortPath;
+};
+