forked from pool/MozillaThunderbird
d6fa566d17
* Optionally remove corresponding data files when removing an account * Possibility to copy message filter * Calendar: Event can now be created and edited in a tab * Calendar: Processing of received invitation counter proposals * Chat: Support Twitter Direct Messages * Chat: Liking and favoriting in Twitter * Chat: Removed Yahoo! Messenger support * serveral bugfixes - removed obsolete patches * mozilla-aarch64-48bit-va.patch * mozilla-binutils-visibility.patch * mozilla-flex_buffer_overrun.patch * mozilla-gcc6.patch - added generic mozilla patches * mozilla-aarch64-startup-crash.patch - require newer versions of NSPR and NSS OBS-URL: https://build.opensuse.org/package/show/mozilla:Factory/MozillaThunderbird?expand=0&rev=358
3910 lines
137 KiB
Diff
3910 lines
137 KiB
Diff
# HG changeset patch
|
|
# Parent 5c8ae59424f5318bf7a387257771bf95d3893063
|
|
Description: Add KDE integration to Firefox (toolkit parts)
|
|
Author: Wolfgang Rosenauer <wolfgang@rosenauer.org>
|
|
Author: Lubos Lunak <lunak@suse.com>
|
|
Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751
|
|
https://bugzilla.novell.com/show_bug.cgi?id=170055
|
|
|
|
diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp
|
|
--- a/modules/libpref/Preferences.cpp
|
|
+++ b/modules/libpref/Preferences.cpp
|
|
@@ -31,16 +31,17 @@
|
|
#include "nsIZipReader.h"
|
|
#include "nsPrefBranch.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsCRT.h"
|
|
#include "nsCOMArray.h"
|
|
#include "nsXPCOMCID.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "nsPrintfCString.h"
|
|
+#include "nsKDEUtils.h"
|
|
|
|
#include "nsQuickSort.h"
|
|
#include "PLDHashTable.h"
|
|
|
|
#include "prefapi.h"
|
|
#include "prefread.h"
|
|
#include "prefapi_private_data.h"
|
|
|
|
@@ -1174,16 +1175,34 @@ pref_LoadPrefsInDir(nsIFile* aDir, char
|
|
|
|
static nsresult pref_LoadPrefsInDirList(const char *listId)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
+ // make sure we load these special files after all the others
|
|
+ static const char* specialFiles[] = {
|
|
+#if defined(XP_UNIX)
|
|
+ ""
|
|
+#endif
|
|
+ };
|
|
+
|
|
+ if (nsKDEUtils::kdeSession()) {
|
|
+ for(int i = 0;
|
|
+ i < MOZ_ARRAY_LENGTH(specialFiles);
|
|
+ ++i ) {
|
|
+ if (*specialFiles[ i ] == '\0') {
|
|
+ specialFiles[ i ] = "kde.js";
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
nsCOMPtr<nsISimpleEnumerator> list;
|
|
dirSvc->Get(listId,
|
|
NS_GET_IID(nsISimpleEnumerator),
|
|
getter_AddRefs(list));
|
|
if (!list)
|
|
return NS_OK;
|
|
|
|
bool hasMore;
|
|
@@ -1199,17 +1218,17 @@ static nsresult pref_LoadPrefsInDirList(
|
|
|
|
nsAutoCString leaf;
|
|
path->GetNativeLeafName(leaf);
|
|
|
|
// Do we care if a file provided by this process fails to load?
|
|
if (Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi"))
|
|
ReadExtensionPrefs(path);
|
|
else
|
|
- pref_LoadPrefsInDir(path, nullptr, 0);
|
|
+ pref_LoadPrefsInDir(path, specialFiles, MOZ_ARRAY_LENGTH(specialFiles));
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
|
|
{
|
|
nsZipItemPtr<char> manifest(jarReader, name, true);
|
|
NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
|
|
@@ -1303,24 +1322,36 @@ static nsresult pref_InitInitialObjects(
|
|
/* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
|
|
static const char* specialFiles[] = {
|
|
#if defined(XP_MACOSX)
|
|
"macprefs.js"
|
|
#elif defined(XP_WIN)
|
|
"winpref.js"
|
|
#elif defined(XP_UNIX)
|
|
"unix.js"
|
|
+ , "" // placeholder for KDE (empty is otherwise harmless)
|
|
#if defined(_AIX)
|
|
, "aix.js"
|
|
#endif
|
|
#elif defined(XP_BEOS)
|
|
"beos.js"
|
|
#endif
|
|
};
|
|
|
|
+ if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper?
|
|
+ for(int i = 0;
|
|
+ i < MOZ_ARRAY_LENGTH(specialFiles);
|
|
+ ++i ) {
|
|
+ if( *specialFiles[ i ] == '\0' ) {
|
|
+ specialFiles[ i ] = "kde.js";
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
|
|
if (NS_FAILED(rv))
|
|
NS_WARNING("Error parsing application default preferences.");
|
|
|
|
// Load jar:$app/omni.jar!/defaults/preferences/*.js
|
|
// or jar:$gre/omni.jar!/defaults/preferences/*.js.
|
|
RefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
|
|
// GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
|
|
diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build
|
|
--- a/modules/libpref/moz.build
|
|
+++ b/modules/libpref/moz.build
|
|
@@ -31,16 +31,20 @@ UNIFIED_SOURCES += [
|
|
'prefread.cpp',
|
|
]
|
|
|
|
# prefapi.cpp cannot be built in unified mode because it uses plarena.h
|
|
SOURCES += [
|
|
'prefapi.cpp',
|
|
]
|
|
|
|
+LOCAL_INCLUDES += [
|
|
+ '/toolkit/xre'
|
|
+]
|
|
+
|
|
include('/ipc/chromium/chromium-config.mozbuild')
|
|
|
|
FINAL_LIBRARY = 'xul'
|
|
|
|
DEFINES['OS_ARCH'] = CONFIG['OS_ARCH']
|
|
DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT']
|
|
|
|
FINAL_TARGET_PP_FILES += [
|
|
diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py
|
|
--- a/python/mozbuild/mozpack/chrome/flags.py
|
|
+++ b/python/mozbuild/mozpack/chrome/flags.py
|
|
@@ -211,16 +211,17 @@ class Flags(OrderedDict):
|
|
'contentaccessible': Flag,
|
|
'os': StringFlag,
|
|
'osversion': VersionFlag,
|
|
'abi': StringFlag,
|
|
'platform': Flag,
|
|
'xpcnativewrappers': Flag,
|
|
'tablet': Flag,
|
|
'process': StringFlag,
|
|
+ 'desktop': StringFlag,
|
|
}
|
|
RE = re.compile(r'([!<>=]+)')
|
|
|
|
def __init__(self, *flags):
|
|
'''
|
|
Initialize a set of flags given in string form.
|
|
flags = Flags('contentaccessible=yes', 'appversion>=3.5')
|
|
'''
|
|
diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py
|
|
--- a/python/mozbuild/mozpack/chrome/manifest.py
|
|
+++ b/python/mozbuild/mozpack/chrome/manifest.py
|
|
@@ -33,16 +33,17 @@ class ManifestEntry(object):
|
|
'application',
|
|
'platformversion',
|
|
'os',
|
|
'osversion',
|
|
'abi',
|
|
'xpcnativewrappers',
|
|
'tablet',
|
|
'process',
|
|
+ 'desktop',
|
|
]
|
|
|
|
def __init__(self, base, *flags):
|
|
'''
|
|
Initialize a manifest entry with the given base path and flags.
|
|
'''
|
|
self.base = base
|
|
self.flags = Flags(*flags)
|
|
diff --git a/toolkit/components/downloads/moz.build b/toolkit/components/downloads/moz.build
|
|
--- a/toolkit/components/downloads/moz.build
|
|
+++ b/toolkit/components/downloads/moz.build
|
|
@@ -57,16 +57,17 @@ if not CONFIG['MOZ_SUITE']:
|
|
'nsDownloadManagerUI.manifest',
|
|
]
|
|
|
|
FINAL_LIBRARY = 'xul'
|
|
|
|
LOCAL_INCLUDES += [
|
|
'../protobuf',
|
|
'/ipc/chromium/src',
|
|
+ '/toolkit/xre',
|
|
'chromium'
|
|
]
|
|
|
|
DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
|
|
DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
|
|
|
|
CXXFLAGS += CONFIG['TK_CFLAGS']
|
|
|
|
diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
|
|
--- a/toolkit/components/downloads/nsDownloadManager.cpp
|
|
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
|
|
@@ -52,16 +52,20 @@
|
|
#ifdef XP_WIN
|
|
#include <shlobj.h>
|
|
#include "nsWindowsHelpers.h"
|
|
#ifdef DOWNLOAD_SCANNER
|
|
#include "nsDownloadScanner.h"
|
|
#endif
|
|
#endif
|
|
|
|
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
|
+#include "nsKDEUtils.h"
|
|
+#endif
|
|
+
|
|
#ifdef XP_MACOSX
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
#include "FennecJNIWrappers.h"
|
|
#endif
|
|
|
|
@@ -2723,16 +2727,25 @@ nsDownload::SetState(DownloadState aStat
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
|
|
|
// Master pref to control this function.
|
|
bool showTaskbarAlert = true;
|
|
if (pref)
|
|
pref->GetBoolPref(PREF_BDM_SHOWALERTONCOMPLETE, &showTaskbarAlert);
|
|
|
|
if (showTaskbarAlert) {
|
|
+ if( nsKDEUtils::kdeSupport()) {
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "DOWNLOADFINISHED" ));
|
|
+ nsAutoString displayName;
|
|
+ GetDisplayName( displayName );
|
|
+ command.AppendElement( nsAutoCString( ToNewUTF8String( displayName )));
|
|
+ nsKDEUtils::command( command );
|
|
+ } else {
|
|
+ // begin non-KDE block
|
|
int32_t alertInterval = 2000;
|
|
if (pref)
|
|
pref->GetIntPref(PREF_BDM_SHOWALERTINTERVAL, &alertInterval);
|
|
|
|
int64_t alertIntervalUSec = alertInterval * PR_USEC_PER_MSEC;
|
|
int64_t goat = PR_Now() - mStartTime;
|
|
showTaskbarAlert = goat > alertIntervalUSec;
|
|
|
|
@@ -2764,16 +2777,17 @@ nsDownload::SetState(DownloadState aStat
|
|
message, !removeWhenDone,
|
|
mPrivate ? NS_LITERAL_STRING("private") : NS_LITERAL_STRING("non-private"),
|
|
mDownloadManager, EmptyString(), NS_LITERAL_STRING("auto"),
|
|
EmptyString(), EmptyString(), nullptr, mPrivate,
|
|
false /* requireInteraction */);
|
|
}
|
|
}
|
|
}
|
|
+ }
|
|
|
|
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
|
|
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget);
|
|
nsCOMPtr<nsIFile> file;
|
|
nsAutoString path;
|
|
|
|
if (fileURL &&
|
|
NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) &&
|
|
diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
|
|
--- a/toolkit/content/jar.mn
|
|
+++ b/toolkit/content/jar.mn
|
|
@@ -71,29 +71,33 @@ toolkit.jar:
|
|
content/global/bindings/button.xml (widgets/button.xml)
|
|
content/global/bindings/checkbox.xml (widgets/checkbox.xml)
|
|
content/global/bindings/colorpicker.xml (widgets/colorpicker.xml)
|
|
content/global/bindings/datetimepicker.xml (widgets/datetimepicker.xml)
|
|
content/global/bindings/datetimepopup.xml (widgets/datetimepopup.xml)
|
|
content/global/bindings/datetimebox.xml (widgets/datetimebox.xml)
|
|
content/global/bindings/datetimebox.css (widgets/datetimebox.css)
|
|
* content/global/bindings/dialog.xml (widgets/dialog.xml)
|
|
+* content/global/bindings/dialog-kde.xml (widgets/dialog-kde.xml)
|
|
+% override chrome://global/content/bindings/dialog.xml chrome://global/content/bindings/dialog-kde.xml desktop=kde
|
|
content/global/bindings/editor.xml (widgets/editor.xml)
|
|
content/global/bindings/expander.xml (widgets/expander.xml)
|
|
content/global/bindings/filefield.xml (widgets/filefield.xml)
|
|
* content/global/bindings/findbar.xml (widgets/findbar.xml)
|
|
content/global/bindings/general.xml (widgets/general.xml)
|
|
content/global/bindings/groupbox.xml (widgets/groupbox.xml)
|
|
content/global/bindings/listbox.xml (widgets/listbox.xml)
|
|
content/global/bindings/menu.xml (widgets/menu.xml)
|
|
content/global/bindings/menulist.xml (widgets/menulist.xml)
|
|
content/global/bindings/notification.xml (widgets/notification.xml)
|
|
content/global/bindings/numberbox.xml (widgets/numberbox.xml)
|
|
content/global/bindings/popup.xml (widgets/popup.xml)
|
|
* content/global/bindings/preferences.xml (widgets/preferences.xml)
|
|
+* content/global/bindings/preferences-kde.xml (widgets/preferences-kde.xml)
|
|
+% override chrome://global/content/bindings/preferences.xml chrome://global/content/bindings/preferences-kde.xml desktop=kde
|
|
content/global/bindings/progressmeter.xml (widgets/progressmeter.xml)
|
|
content/global/bindings/radio.xml (widgets/radio.xml)
|
|
content/global/bindings/remote-browser.xml (widgets/remote-browser.xml)
|
|
content/global/bindings/resizer.xml (widgets/resizer.xml)
|
|
content/global/bindings/richlistbox.xml (widgets/richlistbox.xml)
|
|
content/global/bindings/scale.xml (widgets/scale.xml)
|
|
content/global/bindings/scrollbar.xml (widgets/scrollbar.xml)
|
|
content/global/bindings/scrollbox.xml (widgets/scrollbox.xml)
|
|
@@ -113,9 +117,9 @@ toolkit.jar:
|
|
content/global/bindings/videocontrols.css (widgets/videocontrols.css)
|
|
* content/global/bindings/wizard.xml (widgets/wizard.xml)
|
|
#ifdef XP_MACOSX
|
|
content/global/macWindowMenu.js
|
|
#endif
|
|
content/global/svg/svgBindings.xml (/layout/svg/resources/content/svgBindings.xml)
|
|
content/global/gmp-sources/eme-adobe.json (gmp-sources/eme-adobe.json)
|
|
content/global/gmp-sources/openh264.json (gmp-sources/openh264.json)
|
|
- content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)
|
|
\ No newline at end of file
|
|
+ content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)
|
|
diff --git a/toolkit/content/widgets/dialog-kde.xml b/toolkit/content/widgets/dialog-kde.xml
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/toolkit/content/widgets/dialog-kde.xml
|
|
@@ -0,0 +1,457 @@
|
|
+<?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/. -->
|
|
+
|
|
+
|
|
+<bindings id="dialogBindings"
|
|
+ xmlns="http://www.mozilla.org/xbl"
|
|
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
+ xmlns:xbl="http://www.mozilla.org/xbl">
|
|
+
|
|
+ <binding id="dialog" extends="chrome://global/content/bindings/general.xml#root-element">
|
|
+ <resources>
|
|
+ <stylesheet src="chrome://global/skin/dialog.css"/>
|
|
+ </resources>
|
|
+ <content>
|
|
+ <xul:vbox class="box-inherit dialog-content-box" flex="1">
|
|
+ <children/>
|
|
+ </xul:vbox>
|
|
+
|
|
+ <xul:hbox class="dialog-button-box" anonid="buttons"
|
|
+ xbl:inherits="pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient"
|
|
+#ifdef XP_UNIX_GNOME
|
|
+ >
|
|
+ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
+ <xul:spacer anonid="spacer" flex="1"/>
|
|
+ <xul:button dlgtype="cancel" class="dialog-button"/>
|
|
+ <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
|
|
+#elif XP_UNIX
|
|
+ >
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
+ <xul:spacer anonid="spacer" flex="1"/>
|
|
+ <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
|
|
+ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="cancel" class="dialog-button"/>
|
|
+ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
+#else
|
|
+ pack="end">
|
|
+ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
+ <xul:spacer anonid="spacer" flex="1" hidden="true"/>
|
|
+ <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
|
|
+ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="cancel" class="dialog-button"/>
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
+#endif
|
|
+ </xul:hbox>
|
|
+ </content>
|
|
+
|
|
+ <implementation>
|
|
+ <field name="_mStrBundle">null</field>
|
|
+ <field name="_closeHandler">(function(event) {
|
|
+ if (!document.documentElement.cancelDialog())
|
|
+ event.preventDefault();
|
|
+ })</field>
|
|
+
|
|
+ <property name="buttons"
|
|
+ onget="return this.getAttribute('buttons');"
|
|
+ onset="this._configureButtons(val); return val;"/>
|
|
+
|
|
+ <property name="defaultButton">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ if (this.hasAttribute("defaultButton"))
|
|
+ return this.getAttribute("defaultButton");
|
|
+ return "accept"; // default to the accept button
|
|
+ ]]>
|
|
+ </getter>
|
|
+ <setter>
|
|
+ <![CDATA[
|
|
+ this._setDefaultButton(val);
|
|
+ return val;
|
|
+ ]]>
|
|
+ </setter>
|
|
+ </property>
|
|
+
|
|
+ <method name="acceptDialog">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ return this._doButtonCommand("accept");
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="cancelDialog">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ return this._doButtonCommand("cancel");
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="getButton">
|
|
+ <parameter name="aDlgType"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ return this._buttons[aDlgType];
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="moveToAlertPosition">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // hack. we need this so the window has something like its final size
|
|
+ if (window.outerWidth == 1) {
|
|
+ dump("Trying to position a sizeless window; caller should have called sizeToContent() or sizeTo(). See bug 75649.\n");
|
|
+ sizeToContent();
|
|
+ }
|
|
+
|
|
+ if (opener) {
|
|
+ var xOffset = (opener.outerWidth - window.outerWidth) / 2;
|
|
+ var yOffset = opener.outerHeight / 5;
|
|
+
|
|
+ var newX = opener.screenX + xOffset;
|
|
+ var newY = opener.screenY + yOffset;
|
|
+ } else {
|
|
+ newX = (screen.availWidth - window.outerWidth) / 2;
|
|
+ newY = (screen.availHeight - window.outerHeight) / 2;
|
|
+ }
|
|
+
|
|
+ // ensure the window is fully onscreen (if smaller than the screen)
|
|
+ if (newX < screen.availLeft)
|
|
+ newX = screen.availLeft + 20;
|
|
+ if ((newX + window.outerWidth) > (screen.availLeft + screen.availWidth))
|
|
+ newX = (screen.availLeft + screen.availWidth) - window.outerWidth - 20;
|
|
+
|
|
+ if (newY < screen.availTop)
|
|
+ newY = screen.availTop + 20;
|
|
+ if ((newY + window.outerHeight) > (screen.availTop + screen.availHeight))
|
|
+ newY = (screen.availTop + screen.availHeight) - window.outerHeight - 60;
|
|
+
|
|
+ window.moveTo( newX, newY );
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="centerWindowOnScreen">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var xOffset = screen.availWidth/2 - window.outerWidth/2;
|
|
+ var yOffset = screen.availHeight/2 - window.outerHeight/2;
|
|
+
|
|
+ xOffset = xOffset > 0 ? xOffset : 0;
|
|
+ yOffset = yOffset > 0 ? yOffset : 0;
|
|
+ window.moveTo(xOffset, yOffset);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <constructor>
|
|
+ <![CDATA[
|
|
+ this._configureButtons(this.buttons);
|
|
+
|
|
+ // listen for when window is closed via native close buttons
|
|
+ window.addEventListener("close", this._closeHandler, false);
|
|
+
|
|
+ // for things that we need to initialize after onload fires
|
|
+ window.addEventListener("load", this.postLoadInit, false);
|
|
+
|
|
+ window.moveToAlertPosition = this.moveToAlertPosition;
|
|
+ window.centerWindowOnScreen = this.centerWindowOnScreen;
|
|
+ ]]>
|
|
+ </constructor>
|
|
+
|
|
+ <method name="postLoadInit">
|
|
+ <parameter name="aEvent"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ function focusInit() {
|
|
+ const dialog = document.documentElement;
|
|
+ const defaultButton = dialog.getButton(dialog.defaultButton);
|
|
+ // give focus to the first focusable element in the dialog
|
|
+ if (!document.commandDispatcher.focusedElement) {
|
|
+ document.commandDispatcher.advanceFocusIntoSubtree(dialog);
|
|
+
|
|
+ var focusedElt = document.commandDispatcher.focusedElement;
|
|
+ if (focusedElt) {
|
|
+ var initialFocusedElt = focusedElt;
|
|
+ while (focusedElt.localName == "tab" ||
|
|
+ focusedElt.getAttribute("noinitialfocus") == "true") {
|
|
+ document.commandDispatcher.advanceFocusIntoSubtree(focusedElt);
|
|
+ focusedElt = document.commandDispatcher.focusedElement;
|
|
+ if (focusedElt == initialFocusedElt)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (initialFocusedElt.localName == "tab") {
|
|
+ if (focusedElt.hasAttribute("dlgtype")) {
|
|
+ // We don't want to focus on anonymous OK, Cancel, etc. buttons,
|
|
+ // so return focus to the tab itself
|
|
+ initialFocusedElt.focus();
|
|
+ }
|
|
+ }
|
|
+ else if (!/Mac/.test(navigator.platform) &&
|
|
+ focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton) {
|
|
+ defaultButton.focus();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ try {
|
|
+ if (defaultButton)
|
|
+ window.notifyDefaultButtonLoaded(defaultButton);
|
|
+ } catch (e) { }
|
|
+ }
|
|
+
|
|
+ // Give focus after onload completes, see bug 103197.
|
|
+ setTimeout(focusInit, 0);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="mStrBundle">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ if (!this._mStrBundle) {
|
|
+ // need to create string bundle manually instead of using <xul:stringbundle/>
|
|
+ // see bug 63370 for details
|
|
+ this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
|
+ .getService(Components.interfaces.nsIStringBundleService)
|
|
+ .createBundle("chrome://global/locale/dialog.properties");
|
|
+ }
|
|
+ return this._mStrBundle;
|
|
+ ]]></getter>
|
|
+ </property>
|
|
+
|
|
+ <method name="_configureButtons">
|
|
+ <parameter name="aButtons"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // by default, get all the anonymous button elements
|
|
+ var buttons = {};
|
|
+ this._buttons = buttons;
|
|
+ buttons.accept = document.getAnonymousElementByAttribute(this, "dlgtype", "accept");
|
|
+ buttons.cancel = document.getAnonymousElementByAttribute(this, "dlgtype", "cancel");
|
|
+ buttons.extra1 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra1");
|
|
+ buttons.extra2 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra2");
|
|
+ buttons.help = document.getAnonymousElementByAttribute(this, "dlgtype", "help");
|
|
+ buttons.disclosure = document.getAnonymousElementByAttribute(this, "dlgtype", "disclosure");
|
|
+
|
|
+ // look for any overriding explicit button elements
|
|
+ var exBtns = this.getElementsByAttribute("dlgtype", "*");
|
|
+ var dlgtype;
|
|
+ var i;
|
|
+ for (i = 0; i < exBtns.length; ++i) {
|
|
+ dlgtype = exBtns[i].getAttribute("dlgtype");
|
|
+ buttons[dlgtype].hidden = true; // hide the anonymous button
|
|
+ buttons[dlgtype] = exBtns[i];
|
|
+ }
|
|
+
|
|
+ // add the label and oncommand handler to each button
|
|
+ for (dlgtype in buttons) {
|
|
+ var button = buttons[dlgtype];
|
|
+ button.addEventListener("command", this._handleButtonCommand, true);
|
|
+
|
|
+ // don't override custom labels with pre-defined labels on explicit buttons
|
|
+ if (!button.hasAttribute("label")) {
|
|
+ // dialog attributes override the default labels in dialog.properties
|
|
+ if (this.hasAttribute("buttonlabel"+dlgtype)) {
|
|
+ button.setAttribute("label", this.getAttribute("buttonlabel"+dlgtype));
|
|
+ if (this.hasAttribute("buttonaccesskey"+dlgtype))
|
|
+ button.setAttribute("accesskey", this.getAttribute("buttonaccesskey"+dlgtype));
|
|
+ } else if (dlgtype != "extra1" && dlgtype != "extra2") {
|
|
+ button.setAttribute("label", this.mStrBundle.GetStringFromName("button-"+dlgtype));
|
|
+ var accessKey = this.mStrBundle.GetStringFromName("accesskey-"+dlgtype);
|
|
+ if (accessKey)
|
|
+ button.setAttribute("accesskey", accessKey);
|
|
+ }
|
|
+ }
|
|
+ // allow specifying alternate icons in the dialog header
|
|
+ if (!button.hasAttribute("icon")) {
|
|
+ // if there's an icon specified, use that
|
|
+ if (this.hasAttribute("buttonicon"+dlgtype))
|
|
+ button.setAttribute("icon", this.getAttribute("buttonicon"+dlgtype));
|
|
+ // otherwise set defaults
|
|
+ else
|
|
+ switch (dlgtype) {
|
|
+ case "accept":
|
|
+ button.setAttribute("icon", "accept");
|
|
+ break;
|
|
+ case "cancel":
|
|
+ button.setAttribute("icon", "cancel");
|
|
+ break;
|
|
+ case "disclosure":
|
|
+ button.setAttribute("icon", "properties");
|
|
+ break;
|
|
+ case "help":
|
|
+ button.setAttribute("icon", "help");
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // ensure that hitting enter triggers the default button command
|
|
+ this.defaultButton = this.defaultButton;
|
|
+
|
|
+ // if there is a special button configuration, use it
|
|
+ if (aButtons) {
|
|
+ // expect a comma delimited list of dlgtype values
|
|
+ var list = aButtons.split(",");
|
|
+
|
|
+ // mark shown dlgtypes as true
|
|
+ var shown = { accept: false, cancel: false, help: false,
|
|
+ disclosure: false, extra1: false, extra2: false };
|
|
+ for (i = 0; i < list.length; ++i)
|
|
+ shown[list[i].replace(/ /g, "")] = true;
|
|
+
|
|
+ // hide/show the buttons we want
|
|
+ for (dlgtype in buttons)
|
|
+ buttons[dlgtype].hidden = !shown[dlgtype];
|
|
+
|
|
+ // show the spacer on Windows only when the extra2 button is present
|
|
+ if (/Win/.test(navigator.platform)) {
|
|
+ var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer");
|
|
+ spacer.removeAttribute("hidden");
|
|
+ spacer.setAttribute("flex", shown["extra2"]?"1":"0");
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_setDefaultButton">
|
|
+ <parameter name="aNewDefault"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // remove the default attribute from the previous default button, if any
|
|
+ var oldDefaultButton = this.getButton(this.defaultButton);
|
|
+ if (oldDefaultButton)
|
|
+ oldDefaultButton.removeAttribute("default");
|
|
+
|
|
+ var newDefaultButton = this.getButton(aNewDefault);
|
|
+ if (newDefaultButton) {
|
|
+ this.setAttribute("defaultButton", aNewDefault);
|
|
+ newDefaultButton.setAttribute("default", "true");
|
|
+ }
|
|
+ else {
|
|
+ this.setAttribute("defaultButton", "none");
|
|
+ if (aNewDefault != "none")
|
|
+ dump("invalid new default button: " + aNewDefault + ", assuming: none\n");
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_handleButtonCommand">
|
|
+ <parameter name="aEvent"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ return document.documentElement._doButtonCommand(
|
|
+ aEvent.target.getAttribute("dlgtype"));
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_doButtonCommand">
|
|
+ <parameter name="aDlgType"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var button = this.getButton(aDlgType);
|
|
+ if (!button.disabled) {
|
|
+ var noCancel = this._fireButtonEvent(aDlgType);
|
|
+ if (noCancel) {
|
|
+ if (aDlgType == "accept" || aDlgType == "cancel") {
|
|
+ var closingEvent = new CustomEvent("dialogclosing", {
|
|
+ bubbles: true,
|
|
+ detail: { button: aDlgType },
|
|
+ });
|
|
+ this.dispatchEvent(closingEvent);
|
|
+ window.close();
|
|
+ }
|
|
+ }
|
|
+ return noCancel;
|
|
+ }
|
|
+ return true;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_fireButtonEvent">
|
|
+ <parameter name="aDlgType"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var event = document.createEvent("Events");
|
|
+ event.initEvent("dialog"+aDlgType, true, true);
|
|
+
|
|
+ // handle dom event handlers
|
|
+ var noCancel = this.dispatchEvent(event);
|
|
+
|
|
+ // handle any xml attribute event handlers
|
|
+ var handler = this.getAttribute("ondialog"+aDlgType);
|
|
+ if (handler != "") {
|
|
+ var fn = new Function("event", handler);
|
|
+ var returned = fn(event);
|
|
+ if (returned == false)
|
|
+ noCancel = false;
|
|
+ }
|
|
+
|
|
+ return noCancel;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_hitEnter">
|
|
+ <parameter name="evt"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (evt.defaultPrevented)
|
|
+ return;
|
|
+
|
|
+ var btn = this.getButton(this.defaultButton);
|
|
+ if (btn)
|
|
+ this._doButtonCommand(this.defaultButton);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ </implementation>
|
|
+
|
|
+ <handlers>
|
|
+ <handler event="keypress" keycode="VK_RETURN"
|
|
+ group="system" action="this._hitEnter(event);"/>
|
|
+ <handler event="keypress" keycode="VK_ESCAPE" group="system">
|
|
+ if (!event.defaultPrevented)
|
|
+ this.cancelDialog();
|
|
+ </handler>
|
|
+#ifdef XP_MACOSX
|
|
+ <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/>
|
|
+#else
|
|
+ <handler event="focus" phase="capturing">
|
|
+ var btn = this.getButton(this.defaultButton);
|
|
+ if (btn)
|
|
+ btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement));
|
|
+ </handler>
|
|
+#endif
|
|
+ </handlers>
|
|
+
|
|
+ </binding>
|
|
+
|
|
+ <binding id="dialogheader">
|
|
+ <resources>
|
|
+ <stylesheet src="chrome://global/skin/dialog.css"/>
|
|
+ </resources>
|
|
+ <content>
|
|
+ <xul:label class="dialogheader-title" xbl:inherits="value=title,crop" crop="right" flex="1"/>
|
|
+ <xul:label class="dialogheader-description" xbl:inherits="value=description"/>
|
|
+ </content>
|
|
+ </binding>
|
|
+
|
|
+</bindings>
|
|
diff --git a/toolkit/content/widgets/preferences-kde.xml b/toolkit/content/widgets/preferences-kde.xml
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/toolkit/content/widgets/preferences-kde.xml
|
|
@@ -0,0 +1,1411 @@
|
|
+<?xml version="1.0"?>
|
|
+
|
|
+<!DOCTYPE bindings [
|
|
+ <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
|
|
+ %preferencesDTD;
|
|
+ <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
|
|
+ %globalKeysDTD;
|
|
+]>
|
|
+
|
|
+<bindings id="preferencesBindings"
|
|
+ xmlns="http://www.mozilla.org/xbl"
|
|
+ xmlns:xbl="http://www.mozilla.org/xbl"
|
|
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
+
|
|
+#
|
|
+# = Preferences Window Framework
|
|
+#
|
|
+# The syntax for use looks something like:
|
|
+#
|
|
+# <prefwindow>
|
|
+# <prefpane id="prefPaneA">
|
|
+# <preferences>
|
|
+# <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
|
|
+# <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
|
|
+# </preferences>
|
|
+# <checkbox label="Preference" preference="preference1"/>
|
|
+# </prefpane>
|
|
+# </prefwindow>
|
|
+#
|
|
+
|
|
+ <binding id="preferences">
|
|
+ <implementation implements="nsIObserver">
|
|
+ <method name="_constructAfterChildren">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // This method will be called after each one of the child
|
|
+ // <preference> elements is constructed. Its purpose is to propagate
|
|
+ // the values to the associated form elements
|
|
+
|
|
+ var elements = this.getElementsByTagName("preference");
|
|
+ for (let element of elements) {
|
|
+ if (!element._constructed) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ for (let element of elements) {
|
|
+ element.updateElements();
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ <method name="observe">
|
|
+ <parameter name="aSubject"/>
|
|
+ <parameter name="aTopic"/>
|
|
+ <parameter name="aData"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ for (var i = 0; i < this.childNodes.length; ++i) {
|
|
+ var preference = this.childNodes[i];
|
|
+ if (preference.name == aData) {
|
|
+ preference.value = preference.valueFromPreferences;
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="fireChangedEvent">
|
|
+ <parameter name="aPreference"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // Value changed, synthesize an event
|
|
+ try {
|
|
+ var event = document.createEvent("Events");
|
|
+ event.initEvent("change", true, true);
|
|
+ aPreference.dispatchEvent(event);
|
|
+ }
|
|
+ catch (e) {
|
|
+ Components.utils.reportError(e);
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <field name="service">
|
|
+ Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefService);
|
|
+ </field>
|
|
+ <field name="rootBranch">
|
|
+ Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefBranch);
|
|
+ </field>
|
|
+ <field name="defaultBranch">
|
|
+ this.service.getDefaultBranch("");
|
|
+ </field>
|
|
+ <field name="rootBranchInternal">
|
|
+ Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefBranchInternal);
|
|
+ </field>
|
|
+ <property name="type" readonly="true">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ return document.documentElement.type || "";
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+ <property name="instantApply" readonly="true">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ var doc = document.documentElement;
|
|
+ return this.type == "child" ? doc.instantApply
|
|
+ : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+ </implementation>
|
|
+ </binding>
|
|
+
|
|
+ <binding id="preference">
|
|
+ <implementation>
|
|
+ <constructor>
|
|
+ <![CDATA[
|
|
+ this._constructed = true;
|
|
+
|
|
+ // if the element has been inserted without the name attribute set,
|
|
+ // we have nothing to do here
|
|
+ if (!this.name)
|
|
+ return;
|
|
+
|
|
+ this.preferences.rootBranchInternal
|
|
+ .addObserver(this.name, this.preferences, false);
|
|
+ // In non-instant apply mode, we must try and use the last saved state
|
|
+ // from any previous opens of a child dialog instead of the value from
|
|
+ // preferences, to pick up any edits a user may have made.
|
|
+
|
|
+ var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
|
+ .getService(Components.interfaces.nsIScriptSecurityManager);
|
|
+ if (this.preferences.type == "child" &&
|
|
+ !this.instantApply && window.opener &&
|
|
+ secMan.isSystemPrincipal(window.opener.document.nodePrincipal)) {
|
|
+ var pdoc = window.opener.document;
|
|
+
|
|
+ // Try to find a preference element for the same preference.
|
|
+ var preference = null;
|
|
+ var parentPreferences = pdoc.getElementsByTagName("preferences");
|
|
+ for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
|
|
+ var parentPrefs = parentPreferences[k]
|
|
+ .getElementsByAttribute("name", this.name);
|
|
+ for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
|
|
+ if (parentPrefs[l].localName == "preference")
|
|
+ preference = parentPrefs[l];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Don't use the value setter here, we don't want updateElements to be prematurely fired.
|
|
+ this._value = preference ? preference.value : this.valueFromPreferences;
|
|
+ }
|
|
+ else
|
|
+ this._value = this.valueFromPreferences;
|
|
+ this.preferences._constructAfterChildren();
|
|
+ ]]>
|
|
+ </constructor>
|
|
+ <destructor>
|
|
+ this.preferences.rootBranchInternal
|
|
+ .removeObserver(this.name, this.preferences);
|
|
+ </destructor>
|
|
+ <field name="_constructed">false</field>
|
|
+ <property name="instantApply">
|
|
+ <getter>
|
|
+ if (this.getAttribute("instantApply") == "false")
|
|
+ return false;
|
|
+ return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <property name="preferences" onget="return this.parentNode"/>
|
|
+ <property name="name" onget="return this.getAttribute('name');">
|
|
+ <setter>
|
|
+ if (val == this.name)
|
|
+ return val;
|
|
+
|
|
+ this.preferences.rootBranchInternal
|
|
+ .removeObserver(this.name, this.preferences);
|
|
+ this.setAttribute('name', val);
|
|
+ this.preferences.rootBranchInternal
|
|
+ .addObserver(val, this.preferences, false);
|
|
+
|
|
+ return val;
|
|
+ </setter>
|
|
+ </property>
|
|
+ <property name="type" onget="return this.getAttribute('type');"
|
|
+ onset="this.setAttribute('type', val); return val;"/>
|
|
+ <property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
|
|
+ onset="this.setAttribute('inverted', val); return val;"/>
|
|
+ <property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
|
|
+ onset="this.setAttribute('readonly', val); return val;"/>
|
|
+
|
|
+ <field name="_value">null</field>
|
|
+ <method name="_setValue">
|
|
+ <parameter name="aValue"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (this.value !== aValue) {
|
|
+ this._value = aValue;
|
|
+ if (this.instantApply)
|
|
+ this.valueFromPreferences = aValue;
|
|
+ this.preferences.fireChangedEvent(this);
|
|
+ }
|
|
+ return aValue;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ <property name="value" onget="return this._value" onset="return this._setValue(val);"/>
|
|
+
|
|
+ <property name="locked">
|
|
+ <getter>
|
|
+ return this.preferences.rootBranch.prefIsLocked(this.name);
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <property name="disabled">
|
|
+ <getter>
|
|
+ return this.getAttribute("disabled") == "true";
|
|
+ </getter>
|
|
+ <setter>
|
|
+ <![CDATA[
|
|
+ if (val)
|
|
+ this.setAttribute("disabled", "true");
|
|
+ else
|
|
+ this.removeAttribute("disabled");
|
|
+
|
|
+ if (!this.id)
|
|
+ return val;
|
|
+
|
|
+ var elements = document.getElementsByAttribute("preference", this.id);
|
|
+ for (var i = 0; i < elements.length; ++i) {
|
|
+ elements[i].disabled = val;
|
|
+
|
|
+ var labels = document.getElementsByAttribute("control", elements[i].id);
|
|
+ for (var j = 0; j < labels.length; ++j)
|
|
+ labels[j].disabled = val;
|
|
+ }
|
|
+
|
|
+ return val;
|
|
+ ]]>
|
|
+ </setter>
|
|
+ </property>
|
|
+
|
|
+ <property name="tabIndex">
|
|
+ <getter>
|
|
+ return parseInt(this.getAttribute("tabindex"));
|
|
+ </getter>
|
|
+ <setter>
|
|
+ <![CDATA[
|
|
+ if (val)
|
|
+ this.setAttribute("tabindex", val);
|
|
+ else
|
|
+ this.removeAttribute("tabindex");
|
|
+
|
|
+ if (!this.id)
|
|
+ return val;
|
|
+
|
|
+ var elements = document.getElementsByAttribute("preference", this.id);
|
|
+ for (var i = 0; i < elements.length; ++i) {
|
|
+ elements[i].tabIndex = val;
|
|
+
|
|
+ var labels = document.getElementsByAttribute("control", elements[i].id);
|
|
+ for (var j = 0; j < labels.length; ++j)
|
|
+ labels[j].tabIndex = val;
|
|
+ }
|
|
+
|
|
+ return val;
|
|
+ ]]>
|
|
+ </setter>
|
|
+ </property>
|
|
+
|
|
+ <property name="hasUserValue">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ return this.preferences.rootBranch.prefHasUserValue(this.name) &&
|
|
+ this.value !== undefined;
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <method name="reset">
|
|
+ <body>
|
|
+ // defer reset until preference update
|
|
+ this.value = undefined;
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <field name="_useDefault">false</field>
|
|
+ <property name="defaultValue">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ this._useDefault = true;
|
|
+ var val = this.valueFromPreferences;
|
|
+ this._useDefault = false;
|
|
+ return val;
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <property name="_branch">
|
|
+ <getter>
|
|
+ return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <field name="batching">false</field>
|
|
+
|
|
+ <method name="_reportUnknownType">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
|
|
+ .getService(Components.interfaces.nsIConsoleService);
|
|
+ var msg = "<preference> with id='" + this.id + "' and name='" +
|
|
+ this.name + "' has unknown type '" + this.type + "'.";
|
|
+ consoleService.logStringMessage(msg);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="valueFromPreferences">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ try {
|
|
+ // Force a resync of value with preferences.
|
|
+ switch (this.type) {
|
|
+ case "int":
|
|
+ return this._branch.getIntPref(this.name);
|
|
+ case "bool":
|
|
+ var val = this._branch.getBoolPref(this.name);
|
|
+ return this.inverted ? !val : val;
|
|
+ case "wstring":
|
|
+ return this._branch
|
|
+ .getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
|
|
+ .data;
|
|
+ case "string":
|
|
+ case "unichar":
|
|
+ return this._branch
|
|
+ .getComplexValue(this.name, Components.interfaces.nsISupportsString)
|
|
+ .data;
|
|
+ case "fontname":
|
|
+ var family = this._branch
|
|
+ .getComplexValue(this.name, Components.interfaces.nsISupportsString)
|
|
+ .data;
|
|
+ var fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
|
|
+ .createInstance(Components.interfaces.nsIFontEnumerator);
|
|
+ return fontEnumerator.getStandardFamilyName(family);
|
|
+ case "file":
|
|
+ var f = this._branch
|
|
+ .getComplexValue(this.name, Components.interfaces.nsILocalFile);
|
|
+ return f;
|
|
+ default:
|
|
+ this._reportUnknownType();
|
|
+ }
|
|
+ }
|
|
+ catch (e) { }
|
|
+ return null;
|
|
+ ]]>
|
|
+ </getter>
|
|
+ <setter>
|
|
+ <![CDATA[
|
|
+ // Exit early if nothing to do.
|
|
+ if (this.readonly || this.valueFromPreferences == val)
|
|
+ return val;
|
|
+
|
|
+ // The special value undefined means 'reset preference to default'.
|
|
+ if (val === undefined) {
|
|
+ this.preferences.rootBranch.clearUserPref(this.name);
|
|
+ return val;
|
|
+ }
|
|
+
|
|
+ // Force a resync of preferences with value.
|
|
+ switch (this.type) {
|
|
+ case "int":
|
|
+ this.preferences.rootBranch.setIntPref(this.name, val);
|
|
+ break;
|
|
+ case "bool":
|
|
+ this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
|
|
+ break;
|
|
+ case "wstring":
|
|
+ var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
|
|
+ .createInstance(Components.interfaces.nsIPrefLocalizedString);
|
|
+ pls.data = val;
|
|
+ this.preferences.rootBranch
|
|
+ .setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
|
|
+ break;
|
|
+ case "string":
|
|
+ case "unichar":
|
|
+ case "fontname":
|
|
+ var iss = Components.classes["@mozilla.org/supports-string;1"]
|
|
+ .createInstance(Components.interfaces.nsISupportsString);
|
|
+ iss.data = val;
|
|
+ this.preferences.rootBranch
|
|
+ .setComplexValue(this.name, Components.interfaces.nsISupportsString, iss);
|
|
+ break;
|
|
+ case "file":
|
|
+ var lf;
|
|
+ if (typeof(val) == "string") {
|
|
+ lf = Components.classes["@mozilla.org/file/local;1"]
|
|
+ .createInstance(Components.interfaces.nsILocalFile);
|
|
+ lf.persistentDescriptor = val;
|
|
+ if (!lf.exists())
|
|
+ lf.initWithPath(val);
|
|
+ }
|
|
+ else
|
|
+ lf = val.QueryInterface(Components.interfaces.nsILocalFile);
|
|
+ this.preferences.rootBranch
|
|
+ .setComplexValue(this.name, Components.interfaces.nsILocalFile, lf);
|
|
+ break;
|
|
+ default:
|
|
+ this._reportUnknownType();
|
|
+ }
|
|
+ if (!this.batching)
|
|
+ this.preferences.service.savePrefFile(null);
|
|
+ return val;
|
|
+ ]]>
|
|
+ </setter>
|
|
+ </property>
|
|
+
|
|
+ <method name="setElementValue">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (this.locked)
|
|
+ aElement.disabled = true;
|
|
+
|
|
+ if (!this.isElementEditable(aElement))
|
|
+ return;
|
|
+
|
|
+ var rv = undefined;
|
|
+ if (aElement.hasAttribute("onsyncfrompreference")) {
|
|
+ // Value changed, synthesize an event
|
|
+ try {
|
|
+ var event = document.createEvent("Events");
|
|
+ event.initEvent("syncfrompreference", true, true);
|
|
+ var f = new Function ("event",
|
|
+ aElement.getAttribute("onsyncfrompreference"));
|
|
+ rv = f.call(aElement, event);
|
|
+ }
|
|
+ catch (e) {
|
|
+ Components.utils.reportError(e);
|
|
+ }
|
|
+ }
|
|
+ var val = rv;
|
|
+ if (val === undefined)
|
|
+ val = this.instantApply ? this.valueFromPreferences : this.value;
|
|
+ // if the preference is marked for reset, show default value in UI
|
|
+ if (val === undefined)
|
|
+ val = this.defaultValue;
|
|
+
|
|
+ /**
|
|
+ * Initialize a UI element property with a value. Handles the case
|
|
+ * where an element has not yet had a XBL binding attached for it and
|
|
+ * the property setter does not yet exist by setting the same attribute
|
|
+ * on the XUL element using DOM apis and assuming the element's
|
|
+ * constructor or property getters appropriately handle this state.
|
|
+ */
|
|
+ function setValue(element, attribute, value) {
|
|
+ if (attribute in element)
|
|
+ element[attribute] = value;
|
|
+ else
|
|
+ element.setAttribute(attribute, value);
|
|
+ }
|
|
+ if (aElement.localName == "checkbox" ||
|
|
+ aElement.localName == "listitem")
|
|
+ setValue(aElement, "checked", val);
|
|
+ else if (aElement.localName == "colorpicker")
|
|
+ setValue(aElement, "color", val);
|
|
+ else if (aElement.localName == "textbox") {
|
|
+ // XXXmano Bug 303998: Avoid a caret placement issue if either the
|
|
+ // preference observer or its setter calls updateElements as a result
|
|
+ // of the input event handler.
|
|
+ if (aElement.value !== val)
|
|
+ setValue(aElement, "value", val);
|
|
+ }
|
|
+ else
|
|
+ setValue(aElement, "value", val);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="getElementValue">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (aElement.hasAttribute("onsynctopreference")) {
|
|
+ // Value changed, synthesize an event
|
|
+ try {
|
|
+ var event = document.createEvent("Events");
|
|
+ event.initEvent("synctopreference", true, true);
|
|
+ var f = new Function ("event",
|
|
+ aElement.getAttribute("onsynctopreference"));
|
|
+ var rv = f.call(aElement, event);
|
|
+ if (rv !== undefined)
|
|
+ return rv;
|
|
+ }
|
|
+ catch (e) {
|
|
+ Components.utils.reportError(e);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Read the value of an attribute from an element, assuming the
|
|
+ * attribute is a property on the element's node API. If the property
|
|
+ * is not present in the API, then assume its value is contained in
|
|
+ * an attribute, as is the case before a binding has been attached.
|
|
+ */
|
|
+ function getValue(element, attribute) {
|
|
+ if (attribute in element)
|
|
+ return element[attribute];
|
|
+ return element.getAttribute(attribute);
|
|
+ }
|
|
+ if (aElement.localName == "checkbox" ||
|
|
+ aElement.localName == "listitem")
|
|
+ var value = getValue(aElement, "checked");
|
|
+ else if (aElement.localName == "colorpicker")
|
|
+ value = getValue(aElement, "color");
|
|
+ else
|
|
+ value = getValue(aElement, "value");
|
|
+
|
|
+ switch (this.type) {
|
|
+ case "int":
|
|
+ return parseInt(value, 10) || 0;
|
|
+ case "bool":
|
|
+ return typeof(value) == "boolean" ? value : value == "true";
|
|
+ }
|
|
+ return value;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="isElementEditable">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ switch (aElement.localName) {
|
|
+ case "checkbox":
|
|
+ case "colorpicker":
|
|
+ case "radiogroup":
|
|
+ case "textbox":
|
|
+ case "listitem":
|
|
+ case "listbox":
|
|
+ case "menulist":
|
|
+ return true;
|
|
+ }
|
|
+ return aElement.getAttribute("preference-editable") == "true";
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="updateElements">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (!this.id)
|
|
+ return;
|
|
+
|
|
+ // This "change" event handler tracks changes made to preferences by
|
|
+ // sources other than the user in this window.
|
|
+ var elements = document.getElementsByAttribute("preference", this.id);
|
|
+ for (var i = 0; i < elements.length; ++i)
|
|
+ this.setElementValue(elements[i]);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ </implementation>
|
|
+
|
|
+ <handlers>
|
|
+ <handler event="change">
|
|
+ this.updateElements();
|
|
+ </handler>
|
|
+ </handlers>
|
|
+ </binding>
|
|
+
|
|
+ <binding id="prefwindow"
|
|
+ extends="chrome://global/content/bindings/dialog.xml#dialog">
|
|
+ <resources>
|
|
+ <stylesheet src="chrome://global/skin/preferences.css"/>
|
|
+ </resources>
|
|
+ <content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
|
|
+ closebuttonlabel="&preferencesCloseButton.label;"
|
|
+ closebuttonaccesskey="&preferencesCloseButton.accesskey;"
|
|
+ role="dialog"
|
|
+#ifdef XP_WIN
|
|
+ title="&preferencesDefaultTitleWin.title;">
|
|
+#else
|
|
+ title="&preferencesDefaultTitleMac.title;">
|
|
+#endif
|
|
+ <xul:windowdragbox orient="vertical">
|
|
+ <xul:radiogroup anonid="selector" orient="horizontal" class="paneSelector chromeclass-toolbar"
|
|
+ role="listbox"/> <!-- Expose to accessibility APIs as a listbox -->
|
|
+ </xul:windowdragbox>
|
|
+ <xul:hbox flex="1" class="paneDeckContainer">
|
|
+ <xul:deck anonid="paneDeck" flex="1">
|
|
+ <children includes="prefpane"/>
|
|
+ </xul:deck>
|
|
+ </xul:hbox>
|
|
+ <xul:hbox anonid="dlg-buttons" class="prefWindow-dlgbuttons" pack="end">
|
|
+#ifndef XP_UNIX
|
|
+ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
|
|
+ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
+ <xul:spacer anonid="spacer" flex="1"/>
|
|
+ <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
|
|
+ <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
|
|
+#else
|
|
+ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
+ <xul:spacer anonid="spacer" flex="1"/>
|
|
+ <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
|
|
+ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
+ <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
|
|
+ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
+#endif
|
|
+ </xul:hbox>
|
|
+ <xul:hbox>
|
|
+ <children/>
|
|
+ </xul:hbox>
|
|
+ </content>
|
|
+ <implementation implements="nsITimerCallback">
|
|
+ <constructor>
|
|
+ <![CDATA[
|
|
+ if (this.type != "child") {
|
|
+ if (!this._instantApplyInitialized) {
|
|
+ let psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefBranch);
|
|
+ this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
|
|
+ }
|
|
+ if (this.instantApply) {
|
|
+ var docElt = document.documentElement;
|
|
+ var acceptButton = docElt.getButton("accept");
|
|
+ acceptButton.hidden = true;
|
|
+ var cancelButton = docElt.getButton("cancel");
|
|
+ if (/Mac/.test(navigator.platform)) {
|
|
+ // no buttons on Mac except Help
|
|
+ cancelButton.hidden = true;
|
|
+ // Move Help button to the end
|
|
+ document.getAnonymousElementByAttribute(this, "anonid", "spacer").hidden = true;
|
|
+ // Also, don't fire onDialogAccept on enter
|
|
+ acceptButton.disabled = true;
|
|
+ } else {
|
|
+ // morph the Cancel button into the Close button
|
|
+ cancelButton.setAttribute ("icon", "close");
|
|
+ cancelButton.label = docElt.getAttribute("closebuttonlabel");
|
|
+ cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
|
|
+ var panes = this.preferencePanes;
|
|
+
|
|
+ var lastPane = null;
|
|
+ if (this.lastSelected) {
|
|
+ lastPane = document.getElementById(this.lastSelected);
|
|
+ if (!lastPane) {
|
|
+ this.lastSelected = "";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ var paneToLoad;
|
|
+ if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
|
|
+ paneToLoad = document.getElementById(window.arguments[0]);
|
|
+ this.lastSelected = paneToLoad.id;
|
|
+ }
|
|
+ else if (lastPane)
|
|
+ paneToLoad = lastPane;
|
|
+ else
|
|
+ paneToLoad = panes[0];
|
|
+
|
|
+ for (var i = 0; i < panes.length; ++i) {
|
|
+ this._makePaneButton(panes[i]);
|
|
+ if (panes[i].loaded) {
|
|
+ // Inline pane content, fire load event to force initialization.
|
|
+ this._fireEvent("paneload", panes[i]);
|
|
+ }
|
|
+ }
|
|
+ this.showPane(paneToLoad);
|
|
+
|
|
+ if (panes.length == 1)
|
|
+ this._selector.setAttribute("collapsed", "true");
|
|
+ ]]>
|
|
+ </constructor>
|
|
+
|
|
+ <destructor>
|
|
+ <![CDATA[
|
|
+ // Release timers to avoid reference cycles.
|
|
+ if (this._animateTimer) {
|
|
+ this._animateTimer.cancel();
|
|
+ this._animateTimer = null;
|
|
+ }
|
|
+ if (this._fadeTimer) {
|
|
+ this._fadeTimer.cancel();
|
|
+ this._fadeTimer = null;
|
|
+ }
|
|
+ ]]>
|
|
+ </destructor>
|
|
+
|
|
+ <!-- Derived bindings can set this to true to cause us to skip
|
|
+ reading the browser.preferences.instantApply pref in the constructor.
|
|
+ Then they can set instantApply to their wished value. -->
|
|
+ <field name="_instantApplyInitialized">false</field>
|
|
+ <!-- Controls whether changed pref values take effect immediately. -->
|
|
+ <field name="instantApply">false</field>
|
|
+
|
|
+ <property name="preferencePanes"
|
|
+ onget="return this.getElementsByTagName('prefpane');"/>
|
|
+
|
|
+ <property name="type" onget="return this.getAttribute('type');"/>
|
|
+ <property name="_paneDeck"
|
|
+ onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
|
|
+ <property name="_paneDeckContainer"
|
|
+ onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
|
|
+ <property name="_selector"
|
|
+ onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
|
|
+ <property name="lastSelected"
|
|
+ onget="return this.getAttribute('lastSelected');">
|
|
+ <setter>
|
|
+ this.setAttribute("lastSelected", val);
|
|
+ document.persist(this.id, "lastSelected");
|
|
+ return val;
|
|
+ </setter>
|
|
+ </property>
|
|
+ <property name="currentPane"
|
|
+ onset="return this._currentPane = val;">
|
|
+ <getter>
|
|
+ if (!this._currentPane)
|
|
+ this._currentPane = this.preferencePanes[0];
|
|
+
|
|
+ return this._currentPane;
|
|
+ </getter>
|
|
+ </property>
|
|
+ <field name="_currentPane">null</field>
|
|
+
|
|
+
|
|
+ <method name="_makePaneButton">
|
|
+ <parameter name="aPaneElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var radio = document.createElement("radio");
|
|
+ radio.setAttribute("pane", aPaneElement.id);
|
|
+ radio.setAttribute("label", aPaneElement.label);
|
|
+ // Expose preference group choice to accessibility APIs as an unchecked list item
|
|
+ // The parent group is exposed to accessibility APIs as a list
|
|
+ if (aPaneElement.image)
|
|
+ radio.setAttribute("src", aPaneElement.image);
|
|
+ radio.style.listStyleImage = aPaneElement.style.listStyleImage;
|
|
+ this._selector.appendChild(radio);
|
|
+ return radio;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="showPane">
|
|
+ <parameter name="aPaneElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (!aPaneElement)
|
|
+ return;
|
|
+
|
|
+ this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
|
|
+ if (!aPaneElement.loaded) {
|
|
+ let OverlayLoadObserver = function(aPane)
|
|
+ {
|
|
+ this._pane = aPane;
|
|
+ }
|
|
+ OverlayLoadObserver.prototype = {
|
|
+ _outer: this,
|
|
+ observe: function (aSubject, aTopic, aData)
|
|
+ {
|
|
+ this._pane.loaded = true;
|
|
+ this._outer._fireEvent("paneload", this._pane);
|
|
+ this._outer._selectPane(this._pane);
|
|
+ }
|
|
+ };
|
|
+
|
|
+ var obs = new OverlayLoadObserver(aPaneElement);
|
|
+ document.loadOverlay(aPaneElement.src, obs);
|
|
+ }
|
|
+ else
|
|
+ this._selectPane(aPaneElement);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_fireEvent">
|
|
+ <parameter name="aEventName"/>
|
|
+ <parameter name="aTarget"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // Panel loaded, synthesize a load event.
|
|
+ try {
|
|
+ var event = document.createEvent("Events");
|
|
+ event.initEvent(aEventName, true, true);
|
|
+ var cancel = !aTarget.dispatchEvent(event);
|
|
+ if (aTarget.hasAttribute("on" + aEventName)) {
|
|
+ var fn = new Function ("event", aTarget.getAttribute("on" + aEventName));
|
|
+ var rv = fn.call(aTarget, event);
|
|
+ if (rv == false)
|
|
+ cancel = true;
|
|
+ }
|
|
+ return !cancel;
|
|
+ }
|
|
+ catch (e) {
|
|
+ Components.utils.reportError(e);
|
|
+ }
|
|
+ return false;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <field name="_initialized">false</field>
|
|
+ <method name="_selectPane">
|
|
+ <parameter name="aPaneElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (/Mac/.test(navigator.platform)) {
|
|
+ var paneTitle = aPaneElement.label;
|
|
+ if (paneTitle != "")
|
|
+ document.title = paneTitle;
|
|
+ }
|
|
+ var helpButton = document.documentElement.getButton("help");
|
|
+ if (aPaneElement.helpTopic)
|
|
+ helpButton.hidden = false;
|
|
+ else
|
|
+ helpButton.hidden = true;
|
|
+
|
|
+ // Find this pane's index in the deck and set the deck's
|
|
+ // selectedIndex to that value to switch to it.
|
|
+ var prefpanes = this.preferencePanes;
|
|
+ for (var i = 0; i < prefpanes.length; ++i) {
|
|
+ if (prefpanes[i] == aPaneElement) {
|
|
+ this._paneDeck.selectedIndex = i;
|
|
+
|
|
+ if (this.type != "child") {
|
|
+ if (aPaneElement.hasAttribute("flex") && this._shouldAnimate &&
|
|
+ prefpanes.length > 1)
|
|
+ aPaneElement.removeAttribute("flex");
|
|
+ // Calling sizeToContent after the first prefpane is loaded
|
|
+ // will size the windows contents so style information is
|
|
+ // available to calculate correct sizing.
|
|
+ if (!this._initialized && prefpanes.length > 1) {
|
|
+ if (this._shouldAnimate)
|
|
+ this.style.minHeight = 0;
|
|
+ window.sizeToContent();
|
|
+ }
|
|
+
|
|
+ var oldPane = this.lastSelected ? document.getElementById(this.lastSelected) : this.preferencePanes[0];
|
|
+ oldPane.selected = !(aPaneElement.selected = true);
|
|
+ this.lastSelected = aPaneElement.id;
|
|
+ this.currentPane = aPaneElement;
|
|
+ this._initialized = true;
|
|
+
|
|
+ // Only animate if we've switched between prefpanes
|
|
+ if (this._shouldAnimate && oldPane.id != aPaneElement.id) {
|
|
+ aPaneElement.style.opacity = 0.0;
|
|
+ this.animate(oldPane, aPaneElement);
|
|
+ }
|
|
+ else if (!this._shouldAnimate && prefpanes.length > 1) {
|
|
+ var targetHeight = parseInt(window.getComputedStyle(this._paneDeckContainer, "").height);
|
|
+ var verticalPadding = parseInt(window.getComputedStyle(aPaneElement, "").paddingTop);
|
|
+ verticalPadding += parseInt(window.getComputedStyle(aPaneElement, "").paddingBottom);
|
|
+ if (aPaneElement.contentHeight > targetHeight - verticalPadding) {
|
|
+ // To workaround the bottom border of a groupbox from being
|
|
+ // cutoff an hbox with a class of bottomBox may enclose it.
|
|
+ // This needs to include its padding to resize properly.
|
|
+ // See bug 394433
|
|
+ var bottomPadding = 0;
|
|
+ var bottomBox = aPaneElement.getElementsByAttribute("class", "bottomBox")[0];
|
|
+ if (bottomBox)
|
|
+ bottomPadding = parseInt(window.getComputedStyle(bottomBox, "").paddingBottom);
|
|
+ window.innerHeight += bottomPadding + verticalPadding + aPaneElement.contentHeight - targetHeight;
|
|
+ }
|
|
+
|
|
+ // XXX rstrong - extend the contents of the prefpane to
|
|
+ // prevent elements from being cutoff (see bug 349098).
|
|
+ if (aPaneElement.contentHeight + verticalPadding < targetHeight)
|
|
+ aPaneElement._content.style.height = targetHeight - verticalPadding + "px";
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="_shouldAnimate">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefBranch);
|
|
+ var animate = /Mac/.test(navigator.platform);
|
|
+ try {
|
|
+ animate = psvc.getBoolPref("browser.preferences.animateFadeIn");
|
|
+ }
|
|
+ catch (e) { }
|
|
+ return animate;
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <method name="animate">
|
|
+ <parameter name="aOldPane"/>
|
|
+ <parameter name="aNewPane"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // if we are already resizing, use currentHeight
|
|
+ var oldHeight = this._currentHeight ? this._currentHeight : aOldPane.contentHeight;
|
|
+
|
|
+ this._multiplier = aNewPane.contentHeight > oldHeight ? 1 : -1;
|
|
+ var sizeDelta = Math.abs(oldHeight - aNewPane.contentHeight);
|
|
+ this._animateRemainder = sizeDelta % this._animateIncrement;
|
|
+
|
|
+ this._setUpAnimationTimer(oldHeight);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="_sizeIncrement">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ var lastSelectedPane = document.getElementById(this.lastSelected);
|
|
+ var increment = this._animateIncrement * this._multiplier;
|
|
+ var newHeight = this._currentHeight + increment;
|
|
+ if ((this._multiplier > 0 && this._currentHeight >= lastSelectedPane.contentHeight) ||
|
|
+ (this._multiplier < 0 && this._currentHeight <= lastSelectedPane.contentHeight))
|
|
+ return 0;
|
|
+
|
|
+ if ((this._multiplier > 0 && newHeight > lastSelectedPane.contentHeight) ||
|
|
+ (this._multiplier < 0 && newHeight < lastSelectedPane.contentHeight))
|
|
+ increment = this._animateRemainder * this._multiplier;
|
|
+ return increment;
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <method name="notify">
|
|
+ <parameter name="aTimer"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (!document)
|
|
+ aTimer.cancel();
|
|
+
|
|
+ if (aTimer == this._animateTimer) {
|
|
+ var increment = this._sizeIncrement;
|
|
+ if (increment != 0) {
|
|
+ window.innerHeight += increment;
|
|
+ this._currentHeight += increment;
|
|
+ }
|
|
+ else {
|
|
+ aTimer.cancel();
|
|
+ this._setUpFadeTimer();
|
|
+ }
|
|
+ } else if (aTimer == this._fadeTimer) {
|
|
+ var elt = document.getElementById(this.lastSelected);
|
|
+ var newOpacity = parseFloat(window.getComputedStyle(elt, "").opacity) + this._fadeIncrement;
|
|
+ if (newOpacity < 1.0)
|
|
+ elt.style.opacity = newOpacity;
|
|
+ else {
|
|
+ aTimer.cancel();
|
|
+ elt.style.opacity = 1.0;
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_setUpAnimationTimer">
|
|
+ <parameter name="aStartHeight"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (!this._animateTimer)
|
|
+ this._animateTimer = Components.classes["@mozilla.org/timer;1"]
|
|
+ .createInstance(Components.interfaces.nsITimer);
|
|
+ else
|
|
+ this._animateTimer.cancel();
|
|
+ this._currentHeight = aStartHeight;
|
|
+
|
|
+ this._animateTimer.initWithCallback(this, this._animateDelay,
|
|
+ Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="_setUpFadeTimer">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (!this._fadeTimer)
|
|
+ this._fadeTimer = Components.classes["@mozilla.org/timer;1"]
|
|
+ .createInstance(Components.interfaces.nsITimer);
|
|
+ else
|
|
+ this._fadeTimer.cancel();
|
|
+
|
|
+ this._fadeTimer.initWithCallback(this, this._fadeDelay,
|
|
+ Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <field name="_animateTimer">null</field>
|
|
+ <field name="_fadeTimer">null</field>
|
|
+ <field name="_animateDelay">15</field>
|
|
+ <field name="_animateIncrement">40</field>
|
|
+ <field name="_fadeDelay">5</field>
|
|
+ <field name="_fadeIncrement">0.40</field>
|
|
+ <field name="_animateRemainder">0</field>
|
|
+ <field name="_currentHeight">0</field>
|
|
+ <field name="_multiplier">0</field>
|
|
+
|
|
+ <method name="addPane">
|
|
+ <parameter name="aPaneElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ this.appendChild(aPaneElement);
|
|
+
|
|
+ // Set up pane button
|
|
+ this._makePaneButton(aPaneElement);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="openSubDialog">
|
|
+ <parameter name="aURL"/>
|
|
+ <parameter name="aFeatures"/>
|
|
+ <parameter name="aParams"/>
|
|
+ <body>
|
|
+ return openDialog(aURL, "", "modal,centerscreen,resizable=no" + (aFeatures != "" ? ("," + aFeatures) : ""), aParams);
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="openWindow">
|
|
+ <parameter name="aWindowType"/>
|
|
+ <parameter name="aURL"/>
|
|
+ <parameter name="aFeatures"/>
|
|
+ <parameter name="aParams"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
|
+ .getService(Components.interfaces.nsIWindowMediator);
|
|
+ var win = aWindowType ? wm.getMostRecentWindow(aWindowType) : null;
|
|
+ if (win) {
|
|
+ if ("initWithParams" in win)
|
|
+ win.initWithParams(aParams);
|
|
+ win.focus();
|
|
+ }
|
|
+ else {
|
|
+ var features = "resizable,dialog=no,centerscreen" + (aFeatures != "" ? ("," + aFeatures) : "");
|
|
+ var parentWindow = (this.instantApply || !window.opener || window.opener.closed) ? window : window.opener;
|
|
+ win = parentWindow.openDialog(aURL, "_blank", features, aParams);
|
|
+ }
|
|
+ return win;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ </implementation>
|
|
+ <handlers>
|
|
+ <handler event="dialogaccept">
|
|
+ <![CDATA[
|
|
+ if (!this._fireEvent("beforeaccept", this)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
|
+ .getService(Components.interfaces.nsIScriptSecurityManager);
|
|
+ if (this.type == "child" && window.opener &&
|
|
+ secMan.isSystemPrincipal(window.opener.document.nodePrincipal)) {
|
|
+ let psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefBranch);
|
|
+ var pdocEl = window.opener.document.documentElement;
|
|
+ if (pdocEl.instantApply) {
|
|
+ let panes = this.preferencePanes;
|
|
+ for (let i = 0; i < panes.length; ++i)
|
|
+ panes[i].writePreferences(true);
|
|
+ }
|
|
+ else {
|
|
+ // Clone all the preferences elements from the child document and
|
|
+ // insert them into the pane collection of the parent.
|
|
+ var pdoc = window.opener.document;
|
|
+ if (pdoc.documentElement.localName == "prefwindow") {
|
|
+ var currentPane = pdoc.documentElement.currentPane;
|
|
+ var id = window.location.href + "#childprefs";
|
|
+ var childPrefs = pdoc.getElementById(id);
|
|
+ if (!childPrefs) {
|
|
+ childPrefs = pdoc.createElement("preferences");
|
|
+ currentPane.appendChild(childPrefs);
|
|
+ childPrefs.id = id;
|
|
+ }
|
|
+ let panes = this.preferencePanes;
|
|
+ for (let i = 0; i < panes.length; ++i) {
|
|
+ var preferences = panes[i].preferences;
|
|
+ for (var j = 0; j < preferences.length; ++j) {
|
|
+ // Try to find a preference element for the same preference.
|
|
+ var preference = null;
|
|
+ var parentPreferences = pdoc.getElementsByTagName("preferences");
|
|
+ for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
|
|
+ var parentPrefs = parentPreferences[k]
|
|
+ .getElementsByAttribute("name", preferences[j].name);
|
|
+ for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
|
|
+ if (parentPrefs[l].localName == "preference")
|
|
+ preference = parentPrefs[l];
|
|
+ }
|
|
+ }
|
|
+ if (!preference) {
|
|
+ // No matching preference in the parent window.
|
|
+ preference = pdoc.createElement("preference");
|
|
+ childPrefs.appendChild(preference);
|
|
+ preference.name = preferences[j].name;
|
|
+ preference.type = preferences[j].type;
|
|
+ preference.inverted = preferences[j].inverted;
|
|
+ preference.readonly = preferences[j].readonly;
|
|
+ preference.disabled = preferences[j].disabled;
|
|
+ }
|
|
+ preference.value = preferences[j].value;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else {
|
|
+ let panes = this.preferencePanes;
|
|
+ for (var i = 0; i < panes.length; ++i)
|
|
+ panes[i].writePreferences(false);
|
|
+
|
|
+ let psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefService);
|
|
+ psvc.savePrefFile(null);
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ ]]>
|
|
+ </handler>
|
|
+ <handler event="command">
|
|
+ if (event.originalTarget.hasAttribute("pane")) {
|
|
+ var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
|
|
+ this.showPane(pane);
|
|
+ }
|
|
+ </handler>
|
|
+
|
|
+ <handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
|
|
+ <![CDATA[
|
|
+ if (this.instantApply)
|
|
+ window.close();
|
|
+ event.stopPropagation();
|
|
+ event.preventDefault();
|
|
+ ]]>
|
|
+ </handler>
|
|
+
|
|
+ <handler event="keypress"
|
|
+#ifdef XP_MACOSX
|
|
+ key="&openHelpMac.commandkey;" modifiers="accel"
|
|
+#else
|
|
+ keycode="&openHelp.commandkey;"
|
|
+#endif
|
|
+ phase="capturing">
|
|
+ <![CDATA[
|
|
+ var helpButton = this.getButton("help");
|
|
+ if (helpButton.disabled || helpButton.hidden)
|
|
+ return;
|
|
+ this._fireEvent("dialoghelp", this);
|
|
+ event.stopPropagation();
|
|
+ event.preventDefault();
|
|
+ ]]>
|
|
+ </handler>
|
|
+ </handlers>
|
|
+ </binding>
|
|
+
|
|
+ <binding id="prefpane">
|
|
+ <resources>
|
|
+ <stylesheet src="chrome://global/skin/preferences.css"/>
|
|
+ </resources>
|
|
+ <content>
|
|
+ <xul:vbox class="content-box" xbl:inherits="flex">
|
|
+ <children/>
|
|
+ </xul:vbox>
|
|
+ </content>
|
|
+ <implementation>
|
|
+ <method name="writePreferences">
|
|
+ <parameter name="aFlushToDisk"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ // Write all values to preferences.
|
|
+ if (this._deferredValueUpdateElements.size) {
|
|
+ this._finalizeDeferredElements();
|
|
+ }
|
|
+
|
|
+ var preferences = this.preferences;
|
|
+ for (var i = 0; i < preferences.length; ++i) {
|
|
+ var preference = preferences[i];
|
|
+ preference.batching = true;
|
|
+ preference.valueFromPreferences = preference.value;
|
|
+ preference.batching = false;
|
|
+ }
|
|
+ if (aFlushToDisk) {
|
|
+ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefService);
|
|
+ psvc.savePrefFile(null);
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="src"
|
|
+ onget="return this.getAttribute('src');"
|
|
+ onset="this.setAttribute('src', val); return val;"/>
|
|
+ <property name="selected"
|
|
+ onget="return this.getAttribute('selected') == 'true';"
|
|
+ onset="this.setAttribute('selected', val); return val;"/>
|
|
+ <property name="image"
|
|
+ onget="return this.getAttribute('image');"
|
|
+ onset="this.setAttribute('image', val); return val;"/>
|
|
+ <property name="label"
|
|
+ onget="return this.getAttribute('label');"
|
|
+ onset="this.setAttribute('label', val); return val;"/>
|
|
+
|
|
+ <property name="preferenceElements"
|
|
+ onget="return this.getElementsByAttribute('preference', '*');"/>
|
|
+ <property name="preferences"
|
|
+ onget="return this.getElementsByTagName('preference');"/>
|
|
+
|
|
+ <property name="helpTopic">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ // if there are tabs, and the selected tab provides a helpTopic, return that
|
|
+ var box = this.getElementsByTagName("tabbox");
|
|
+ if (box[0]) {
|
|
+ var tab = box[0].selectedTab;
|
|
+ if (tab && tab.hasAttribute("helpTopic"))
|
|
+ return tab.getAttribute("helpTopic");
|
|
+ }
|
|
+
|
|
+ // otherwise, return the helpTopic of the current panel
|
|
+ return this.getAttribute("helpTopic");
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+
|
|
+ <field name="_loaded">false</field>
|
|
+ <property name="loaded"
|
|
+ onget="return !this.src ? true : this._loaded;"
|
|
+ onset="this._loaded = val; return val;"/>
|
|
+
|
|
+ <method name="preferenceForElement">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ return document.getElementById(aElement.getAttribute("preference"));
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <method name="getPreferenceElement">
|
|
+ <parameter name="aStartElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var temp = aStartElement;
|
|
+ while (temp && temp.nodeType == Node.ELEMENT_NODE &&
|
|
+ !temp.hasAttribute("preference"))
|
|
+ temp = temp.parentNode;
|
|
+ return temp.nodeType == Node.ELEMENT_NODE ? temp : aStartElement;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="DeferredTask" readonly="true">
|
|
+ <getter><![CDATA[
|
|
+ let module = {};
|
|
+ Components.utils.import("resource://gre/modules/DeferredTask.jsm", module);
|
|
+ Object.defineProperty(this, "DeferredTask", {
|
|
+ configurable: true,
|
|
+ enumerable: true,
|
|
+ writable: true,
|
|
+ value: module.DeferredTask
|
|
+ });
|
|
+ return module.DeferredTask;
|
|
+ ]]></getter>
|
|
+ </property>
|
|
+ <method name="_deferredValueUpdate">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ delete aElement._deferredValueUpdateTask;
|
|
+ let preference = document.getElementById(aElement.getAttribute("preference"));
|
|
+ let prefVal = preference.getElementValue(aElement);
|
|
+ preference.value = prefVal;
|
|
+ this._deferredValueUpdateElements.delete(aElement);
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ <field name="_deferredValueUpdateElements">
|
|
+ new Set();
|
|
+ </field>
|
|
+ <method name="_finalizeDeferredElements">
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ for (let el of this._deferredValueUpdateElements) {
|
|
+ if (el._deferredValueUpdateTask) {
|
|
+ el._deferredValueUpdateTask.finalize();
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ <method name="userChangedValue">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ let element = this.getPreferenceElement(aElement);
|
|
+ if (element.hasAttribute("preference")) {
|
|
+ if (element.getAttribute("delayprefsave") != "true") {
|
|
+ var preference = document.getElementById(element.getAttribute("preference"));
|
|
+ var prefVal = preference.getElementValue(element);
|
|
+ preference.value = prefVal;
|
|
+ } else {
|
|
+ if (!element._deferredValueUpdateTask) {
|
|
+ element._deferredValueUpdateTask = new this.DeferredTask(this._deferredValueUpdate.bind(this, element), 1000);
|
|
+ this._deferredValueUpdateElements.add(element);
|
|
+ } else {
|
|
+ // Each time the preference is changed, restart the delay.
|
|
+ element._deferredValueUpdateTask.disarm();
|
|
+ }
|
|
+ element._deferredValueUpdateTask.arm();
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+
|
|
+ <property name="contentHeight">
|
|
+ <getter>
|
|
+ var targetHeight = parseInt(window.getComputedStyle(this._content, "").height);
|
|
+ targetHeight += parseInt(window.getComputedStyle(this._content, "").marginTop);
|
|
+ targetHeight += parseInt(window.getComputedStyle(this._content, "").marginBottom);
|
|
+ return targetHeight;
|
|
+ </getter>
|
|
+ </property>
|
|
+ <field name="_content">
|
|
+ document.getAnonymousElementByAttribute(this, "class", "content-box");
|
|
+ </field>
|
|
+ </implementation>
|
|
+ <handlers>
|
|
+ <handler event="command">
|
|
+ // This "command" event handler tracks changes made to preferences by
|
|
+ // the user in this window.
|
|
+ if (event.sourceEvent)
|
|
+ event = event.sourceEvent;
|
|
+ this.userChangedValue(event.target);
|
|
+ </handler>
|
|
+ <handler event="select">
|
|
+ // This "select" event handler tracks changes made to colorpicker
|
|
+ // preferences by the user in this window.
|
|
+ if (event.target.localName == "colorpicker")
|
|
+ this.userChangedValue(event.target);
|
|
+ </handler>
|
|
+ <handler event="change">
|
|
+ // This "change" event handler tracks changes made to preferences by
|
|
+ // the user in this window.
|
|
+ this.userChangedValue(event.target);
|
|
+ </handler>
|
|
+ <handler event="input">
|
|
+ // This "input" event handler tracks changes made to preferences by
|
|
+ // the user in this window.
|
|
+ this.userChangedValue(event.target);
|
|
+ </handler>
|
|
+ <handler event="paneload">
|
|
+ <![CDATA[
|
|
+ // Initialize all values from preferences.
|
|
+ var elements = this.preferenceElements;
|
|
+ for (var i = 0; i < elements.length; ++i) {
|
|
+ try {
|
|
+ var preference = this.preferenceForElement(elements[i]);
|
|
+ preference.setElementValue(elements[i]);
|
|
+ }
|
|
+ catch (e) {
|
|
+ dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
|
|
+ }
|
|
+ }
|
|
+ ]]>
|
|
+ </handler>
|
|
+ </handlers>
|
|
+ </binding>
|
|
+
|
|
+ <binding id="panebutton" role="xul:listitem"
|
|
+ extends="chrome://global/content/bindings/radio.xml#radio">
|
|
+ <resources>
|
|
+ <stylesheet src="chrome://global/skin/preferences.css"/>
|
|
+ </resources>
|
|
+ <content>
|
|
+ <xul:image class="paneButtonIcon" xbl:inherits="src"/>
|
|
+ <xul:label class="paneButtonLabel" xbl:inherits="value=label"/>
|
|
+ </content>
|
|
+ </binding>
|
|
+
|
|
+</bindings>
|
|
+
|
|
+# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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/.
|
|
+
|
|
+#
|
|
+# This is PrefWindow 6. The Code Could Well Be Ready, Are You?
|
|
+#
|
|
+# Historical References:
|
|
+# PrefWindow V (February 1, 2003)
|
|
+# PrefWindow IV (April 24, 2000)
|
|
+# PrefWindow III (January 6, 2000)
|
|
+# PrefWindow II (???)
|
|
+# PrefWindow I (June 4, 1999)
|
|
+#
|
|
diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js
|
|
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
|
|
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
|
|
@@ -627,17 +627,17 @@ nsUnknownContentTypeDialog.prototype = {
|
|
else
|
|
typeString = mimeInfo.MIMEType;
|
|
}
|
|
// When the length is unknown, contentLength would be -1
|
|
if (this.mLauncher.contentLength >= 0) {
|
|
let [size, unit] = DownloadUtils.
|
|
convertByteUnits(this.mLauncher.contentLength);
|
|
type.value = this.dialogElement("strings")
|
|
- .getFormattedString("orderedFileSizeWithType",
|
|
+ .getFormattedString("orderedFileSizeWithType",
|
|
[typeString, size, unit]);
|
|
}
|
|
else {
|
|
type.value = typeString;
|
|
}
|
|
},
|
|
|
|
// Returns true if opening the default application makes sense.
|
|
@@ -801,17 +801,17 @@ nsUnknownContentTypeDialog.prototype = {
|
|
switch (this.dialogElement("openHandler").selectedIndex) {
|
|
case 0:
|
|
// No app need be specified in this case.
|
|
ok = true;
|
|
break;
|
|
case 1:
|
|
// only enable the OK button if we have a default app to use or if
|
|
// the user chose an app....
|
|
- ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path"));
|
|
+ ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Enable Ok button if ok to press.
|
|
this.mDialog.document.documentElement.getButton("accept").disabled = !ok;
|
|
},
|
|
|
|
@@ -1068,30 +1068,56 @@ nsUnknownContentTypeDialog.prototype = {
|
|
params.handlerApp.executable &&
|
|
params.handlerApp.executable.isFile()) {
|
|
// Remember the file they chose to run.
|
|
this.chosenApp = params.handlerApp;
|
|
}
|
|
}
|
|
else {
|
|
#if MOZ_WIDGET_GTK == 3
|
|
- var nsIApplicationChooser = Components.interfaces.nsIApplicationChooser;
|
|
- var appChooser = Components.classes["@mozilla.org/applicationchooser;1"]
|
|
- .createInstance(nsIApplicationChooser);
|
|
- appChooser.init(this.mDialog, this.dialogElement("strings").getString("chooseAppFilePickerTitle"));
|
|
- var contentTypeDialogObj = this;
|
|
- let appChooserCallback = function appChooserCallback_done(aResult) {
|
|
- if (aResult) {
|
|
- contentTypeDialogObj.chosenApp = aResult.QueryInterface(Components.interfaces.nsILocalHandlerApp);
|
|
+ // handle the KDE case which is implemented in the filepicker
|
|
+ // therefore falling back to Gtk2 like behaviour if KDE is running
|
|
+ // FIXME this should be better handled in the nsIApplicationChooser interface
|
|
+ var env = Components.classes["@mozilla.org/process/environment;1"]
|
|
+ .getService(Components.interfaces.nsIEnvironment);
|
|
+ if (env.get('KDE_FULL_SESSION') == "true")
|
|
+ {
|
|
+ var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
|
+ var fp = Components.classes["@mozilla.org/filepicker;1"]
|
|
+ .createInstance(nsIFilePicker);
|
|
+ fp.init(this.mDialog,
|
|
+ this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
|
|
+ nsIFilePicker.modeOpen);
|
|
+
|
|
+ fp.appendFilters(nsIFilePicker.filterApps);
|
|
+
|
|
+ if (fp.show() == nsIFilePicker.returnOK && fp.file) {
|
|
+ // Remember the file they chose to run.
|
|
+ var localHandlerApp =
|
|
+ Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
|
|
+ createInstance(Components.interfaces.nsILocalHandlerApp);
|
|
+ localHandlerApp.executable = fp.file;
|
|
+ this.chosenApp = localHandlerApp;
|
|
}
|
|
- contentTypeDialogObj.finishChooseApp();
|
|
- };
|
|
- appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
|
|
- // The finishChooseApp is called from appChooserCallback
|
|
- return;
|
|
+ } else {
|
|
+ var nsIApplicationChooser = Components.interfaces.nsIApplicationChooser;
|
|
+ var appChooser = Components.classes["@mozilla.org/applicationchooser;1"]
|
|
+ .createInstance(nsIApplicationChooser);
|
|
+ appChooser.init(this.mDialog, this.dialogElement("strings").getString("chooseAppFilePickerTitle"));
|
|
+ var contentTypeDialogObj = this;
|
|
+ let appChooserCallback = function appChooserCallback_done(aResult) {
|
|
+ if (aResult) {
|
|
+ contentTypeDialogObj.chosenApp = aResult.QueryInterface(Components.interfaces.nsILocalHandlerApp);
|
|
+ }
|
|
+ contentTypeDialogObj.finishChooseApp();
|
|
+ };
|
|
+ appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
|
|
+ // The finishChooseApp is called from appChooserCallback
|
|
+ return;
|
|
+ }
|
|
#else
|
|
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
|
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
|
.createInstance(nsIFilePicker);
|
|
fp.init(this.mDialog,
|
|
this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
|
|
nsIFilePicker.modeOpen);
|
|
|
|
diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
|
|
--- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
|
|
+++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
|
|
@@ -15,16 +15,17 @@
|
|
#include "nsPrintfCString.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsIGSettingsService.h"
|
|
#include "nsInterfaceHashtable.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "nsIURI.h"
|
|
+#include "nsKDEUtils.h"
|
|
|
|
class nsUnixSystemProxySettings final : public nsISystemProxySettings {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSISYSTEMPROXYSETTINGS
|
|
|
|
nsUnixSystemProxySettings()
|
|
: mSchemeProxySettings(4)
|
|
@@ -39,16 +40,17 @@ private:
|
|
nsCOMPtr<nsIGSettingsService> mGSettings;
|
|
nsCOMPtr<nsIGSettingsCollection> mProxySettings;
|
|
nsInterfaceHashtable<nsCStringHashKey, nsIGSettingsCollection> mSchemeProxySettings;
|
|
bool IsProxyMode(const char* aMode);
|
|
nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult);
|
|
nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult);
|
|
nsresult GetProxyFromGSettings(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult);
|
|
nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, nsACString& aResult);
|
|
+ nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost, PRInt32 aPort, nsACString& aResult);
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings)
|
|
|
|
NS_IMETHODIMP
|
|
nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
|
|
{
|
|
// dbus prevents us from being threadsafe, but this routine should not block anyhow
|
|
@@ -505,16 +507,19 @@ nsUnixSystemProxySettings::GetProxyFromG
|
|
|
|
nsresult
|
|
nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
|
|
const nsACString & aScheme,
|
|
const nsACString & aHost,
|
|
const int32_t aPort,
|
|
nsACString & aResult)
|
|
{
|
|
+ if (nsKDEUtils::kdeSupport())
|
|
+ return GetProxyFromKDE(aScheme, aHost, aPort, aResult);
|
|
+
|
|
if (mProxySettings) {
|
|
nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult);
|
|
if (NS_SUCCEEDED(rv))
|
|
return rv;
|
|
}
|
|
if (mGConf)
|
|
return GetProxyFromGConf(aScheme, aHost, aPort, aResult);
|
|
|
|
@@ -540,8 +545,34 @@ static const mozilla::Module::ContractID
|
|
|
|
static const mozilla::Module kUnixProxyModule = {
|
|
mozilla::Module::kVersion,
|
|
kUnixProxyCIDs,
|
|
kUnixProxyContracts
|
|
};
|
|
|
|
NSMODULE_DEFN(nsUnixProxyModule) = &kUnixProxyModule;
|
|
+
|
|
+nsresult
|
|
+nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme,
|
|
+ const nsACString& aHost,
|
|
+ PRInt32 aPort,
|
|
+ nsACString& aResult)
|
|
+{
|
|
+ nsAutoCString url;
|
|
+ url = aScheme;
|
|
+ url += "://";
|
|
+ url += aHost;
|
|
+ if( aPort >= 0 )
|
|
+ {
|
|
+ url += ":";
|
|
+ url += nsPrintfCString("%d", aPort);
|
|
+ }
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "GETPROXY" ));
|
|
+ command.AppendElement( url );
|
|
+ nsTArray<nsCString> result;
|
|
+ if( !nsKDEUtils::command( command, &result ) || result.Length() != 1 )
|
|
+ return NS_ERROR_FAILURE;
|
|
+ aResult = result[0];
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build
|
|
--- a/toolkit/xre/moz.build
|
|
+++ b/toolkit/xre/moz.build
|
|
@@ -40,17 +40,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
|
|
'updaterfileutils_osx.mm',
|
|
]
|
|
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
|
|
UNIFIED_SOURCES += [
|
|
'nsNativeAppSupportDefault.cpp',
|
|
'UIKitDirProvider.mm',
|
|
]
|
|
elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|
+ EXPORTS += ['nsKDEUtils.h']
|
|
UNIFIED_SOURCES += [
|
|
+ 'nsKDEUtils.cpp',
|
|
'nsNativeAppSupportUnix.cpp',
|
|
]
|
|
else:
|
|
UNIFIED_SOURCES += [
|
|
'nsNativeAppSupportDefault.cpp',
|
|
]
|
|
|
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
|
|
diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/toolkit/xre/nsKDEUtils.cpp
|
|
@@ -0,0 +1,344 @@
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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 "nsKDEUtils.h"
|
|
+#include "nsIWidget.h"
|
|
+#include "nsISupportsPrimitives.h"
|
|
+#include "nsIMutableArray.h"
|
|
+#include "nsComponentManagerUtils.h"
|
|
+#include "nsArrayUtils.h"
|
|
+
|
|
+#include <gtk/gtk.h>
|
|
+
|
|
+#include <limits.h>
|
|
+#include <stdio.h>
|
|
+#include <sys/wait.h>
|
|
+#include <sys/resource.h>
|
|
+#include <unistd.h>
|
|
+#include <X11/Xlib.h>
|
|
+// copied from X11/X.h as a hack since for an unknown
|
|
+// reason it's not picked up from X11/X.h
|
|
+#ifndef None
|
|
+#define None 0L /* universal null resource or null atom */
|
|
+#endif
|
|
+
|
|
+//#define DEBUG_KDE
|
|
+#ifdef DEBUG_KDE
|
|
+#define KMOZILLAHELPER "kmozillahelper"
|
|
+#else
|
|
+// not need for lib64, it's a binary
|
|
+#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper"
|
|
+#endif
|
|
+
|
|
+#define KMOZILLAHELPER_VERSION 6
|
|
+#define MAKE_STR2( n ) #n
|
|
+#define MAKE_STR( n ) MAKE_STR2( n )
|
|
+
|
|
+static bool getKdeSession()
|
|
+ {
|
|
+ Display* dpy = XOpenDisplay( NULL );
|
|
+ if( dpy == NULL )
|
|
+ return false;
|
|
+ Atom kde_full_session = XInternAtom( dpy, "KDE_FULL_SESSION", True );
|
|
+ bool kde = false;
|
|
+ if( kde_full_session != None )
|
|
+ {
|
|
+ int cnt;
|
|
+ if( Atom* props = XListProperties( dpy, DefaultRootWindow( dpy ), &cnt ))
|
|
+ {
|
|
+ for( int i = 0;
|
|
+ i < cnt;
|
|
+ ++i )
|
|
+ {
|
|
+ if( props[ i ] == kde_full_session )
|
|
+ {
|
|
+ kde = true;
|
|
+#ifdef DEBUG_KDE
|
|
+ fprintf( stderr, "KDE SESSION %d\n", kde );
|
|
+#endif
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ XFree( props );
|
|
+ }
|
|
+ }
|
|
+ XCloseDisplay( dpy );
|
|
+ return kde;
|
|
+ }
|
|
+
|
|
+static bool getKdeSupport()
|
|
+ {
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "CHECK" ));
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( MAKE_STR( KMOZILLAHELPER_VERSION )));
|
|
+ bool kde = nsKDEUtils::command( command );
|
|
+#ifdef DEBUG_KDE
|
|
+ fprintf( stderr, "KDE RUNNING %d\n", kde );
|
|
+#endif
|
|
+ return kde;
|
|
+ }
|
|
+
|
|
+nsKDEUtils::nsKDEUtils()
|
|
+ : commandFile( NULL )
|
|
+ , replyFile( NULL )
|
|
+ {
|
|
+ }
|
|
+
|
|
+nsKDEUtils::~nsKDEUtils()
|
|
+ {
|
|
+// closeHelper(); not actually useful, exiting will close the fd too
|
|
+ }
|
|
+
|
|
+nsKDEUtils* nsKDEUtils::self()
|
|
+ {
|
|
+ static nsKDEUtils s;
|
|
+ return &s;
|
|
+ }
|
|
+
|
|
+static bool helperRunning = false;
|
|
+static bool helperFailed = false;
|
|
+
|
|
+bool nsKDEUtils::kdeSession()
|
|
+ {
|
|
+ static bool session = getKdeSession();
|
|
+ return session;
|
|
+ }
|
|
+
|
|
+bool nsKDEUtils::kdeSupport()
|
|
+ {
|
|
+ static bool support = kdeSession() && getKdeSupport();
|
|
+ return support && helperRunning;
|
|
+ }
|
|
+
|
|
+struct nsKDECommandData
|
|
+ {
|
|
+ FILE* file;
|
|
+ nsTArray<nsCString>* output;
|
|
+ GMainLoop* loop;
|
|
+ bool success;
|
|
+ };
|
|
+
|
|
+static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data )
|
|
+ {
|
|
+ nsKDECommandData* p = static_cast< nsKDECommandData* >( data );
|
|
+ char buf[ 8192 ]; // TODO big enough
|
|
+ bool command_done = false;
|
|
+ bool command_failed = false;
|
|
+ while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL )
|
|
+ { // TODO what if the kernel splits a line into two chunks?
|
|
+//#ifdef DEBUG_KDE
|
|
+// fprintf( stderr, "READ: %s %d\n", buf, feof( p->file ));
|
|
+//#endif
|
|
+ if( char* eol = strchr( buf, '\n' ))
|
|
+ *eol = '\0';
|
|
+ command_done = ( strcmp( buf, "\\1" ) == 0 );
|
|
+ command_failed = ( strcmp( buf, "\\0" ) == 0 );
|
|
+ nsAutoCString line( buf );
|
|
+ line.ReplaceSubstring( "\\n", "\n" );
|
|
+ line.ReplaceSubstring( "\\" "\\", "\\" ); // \\ -> \ , i.e. unescape
|
|
+ if( p->output && !( command_done || command_failed ))
|
|
+ p->output->AppendElement( nsCString( buf )); // TODO utf8?
|
|
+ }
|
|
+ bool quit = false;
|
|
+ if( feof( p->file ) || command_failed )
|
|
+ {
|
|
+ quit = true;
|
|
+ p->success = false;
|
|
+ }
|
|
+ if( command_done )
|
|
+ { // reading one reply finished
|
|
+ quit = true;
|
|
+ p->success = true;
|
|
+ }
|
|
+ if( quit )
|
|
+ {
|
|
+ if( p->loop )
|
|
+ g_main_loop_quit( p->loop );
|
|
+ return FALSE;
|
|
+ }
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+bool nsKDEUtils::command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output )
|
|
+ {
|
|
+ return self()->internalCommand( command, NULL, false, output );
|
|
+ }
|
|
+
|
|
+bool nsKDEUtils::command( nsIArray* command, nsIArray** output)
|
|
+ {
|
|
+ nsTArray<nsCString> in;
|
|
+ PRUint32 length;
|
|
+ command->GetLength( &length );
|
|
+ for ( PRUint32 i = 0; i < length; i++ )
|
|
+ {
|
|
+ nsCOMPtr<nsISupportsCString> str = do_QueryElementAt( command, i );
|
|
+ if( str )
|
|
+ {
|
|
+ nsAutoCString s;
|
|
+ str->GetData( s );
|
|
+ in.AppendElement( s );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nsTArray<nsCString> out;
|
|
+ bool ret = self()->internalCommand( in, NULL, false, &out );
|
|
+
|
|
+ if ( !output ) return ret;
|
|
+
|
|
+ nsCOMPtr<nsIMutableArray> result = do_CreateInstance( NS_ARRAY_CONTRACTID );
|
|
+ if ( !result ) return false;
|
|
+
|
|
+ for ( PRUint32 i = 0; i < out.Length(); i++ )
|
|
+ {
|
|
+ nsCOMPtr<nsISupportsCString> rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
|
|
+ if ( !rstr ) return false;
|
|
+
|
|
+ rstr->SetData( out[i] );
|
|
+ result->AppendElement( rstr, false );
|
|
+ }
|
|
+
|
|
+ NS_ADDREF( *output = result);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+
|
|
+bool nsKDEUtils::commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output )
|
|
+ {
|
|
+ return self()->internalCommand( command, parent, true, output );
|
|
+ }
|
|
+
|
|
+bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool blockUi,
|
|
+ nsTArray<nsCString>* output )
|
|
+ {
|
|
+ if( !startHelper())
|
|
+ return false;
|
|
+ feedCommand( command );
|
|
+ // do not store the data in 'this' but in extra structure, just in case there
|
|
+ // is reentrancy (can there be? the event loop is re-entered)
|
|
+ nsKDECommandData data;
|
|
+ data.file = replyFile;
|
|
+ data.output = output;
|
|
+ data.success = false;
|
|
+ if( blockUi )
|
|
+ {
|
|
+ data.loop = g_main_loop_new( NULL, FALSE );
|
|
+ GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
|
+ if( parent && gtk_window_get_group(parent) )
|
|
+ gtk_window_group_add_window( gtk_window_get_group(parent), GTK_WINDOW( window ));
|
|
+ gtk_widget_realize( window );
|
|
+ gtk_widget_set_sensitive( window, TRUE );
|
|
+ gtk_grab_add( window );
|
|
+ GIOChannel* channel = g_io_channel_unix_new( fileno( data.file ));
|
|
+ g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data );
|
|
+ g_io_channel_unref( channel );
|
|
+ g_main_loop_run( data.loop );
|
|
+ g_main_loop_unref( data.loop );
|
|
+ gtk_grab_remove( window );
|
|
+ gtk_widget_destroy( window );
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ data.loop = NULL;
|
|
+ while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data ))
|
|
+ ;
|
|
+ }
|
|
+ return data.success;
|
|
+ }
|
|
+
|
|
+bool nsKDEUtils::startHelper()
|
|
+ {
|
|
+ if( helperRunning )
|
|
+ return true;
|
|
+ if( helperFailed )
|
|
+ return false;
|
|
+ helperFailed = true;
|
|
+ int fdcommand[ 2 ];
|
|
+ int fdreply[ 2 ];
|
|
+ if( pipe( fdcommand ) < 0 )
|
|
+ return false;
|
|
+ if( pipe( fdreply ) < 0 )
|
|
+ {
|
|
+ close( fdcommand[ 0 ] );
|
|
+ close( fdcommand[ 1 ] );
|
|
+ return false;
|
|
+ }
|
|
+ char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL };
|
|
+ switch( fork())
|
|
+ {
|
|
+ case -1:
|
|
+ {
|
|
+ close( fdcommand[ 0 ] );
|
|
+ close( fdcommand[ 1 ] );
|
|
+ close( fdreply[ 0 ] );
|
|
+ close( fdreply[ 1 ] );
|
|
+ return false;
|
|
+ }
|
|
+ case 0: // child
|
|
+ {
|
|
+ if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 )
|
|
+ _exit( 1 );
|
|
+ if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 )
|
|
+ _exit( 1 );
|
|
+ int maxfd = 1024; // close all other fds
|
|
+ struct rlimit rl;
|
|
+ if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
|
|
+ maxfd = rl.rlim_max;
|
|
+ for( int i = 3;
|
|
+ i < maxfd;
|
|
+ ++i )
|
|
+ close( i );
|
|
+#ifdef DEBUG_KDE
|
|
+ execvp( KMOZILLAHELPER, args );
|
|
+#else
|
|
+ execv( KMOZILLAHELPER, args );
|
|
+#endif
|
|
+ _exit( 1 ); // failed
|
|
+ }
|
|
+ default: // parent
|
|
+ {
|
|
+ commandFile = fdopen( fdcommand[ 1 ], "w" );
|
|
+ replyFile = fdopen( fdreply[ 0 ], "r" );
|
|
+ close( fdcommand[ 0 ] );
|
|
+ close( fdreply[ 1 ] );
|
|
+ if( commandFile == NULL || replyFile == NULL )
|
|
+ {
|
|
+ closeHelper();
|
|
+ return false;
|
|
+ }
|
|
+ // ok, helper ready, getKdeRunning() will check if it works
|
|
+ }
|
|
+ }
|
|
+ helperFailed = false;
|
|
+ helperRunning = true;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+void nsKDEUtils::closeHelper()
|
|
+ {
|
|
+ if( commandFile != NULL )
|
|
+ fclose( commandFile ); // this will also make the helper quit
|
|
+ if( replyFile != NULL )
|
|
+ fclose( replyFile );
|
|
+ helperRunning = false;
|
|
+ }
|
|
+
|
|
+void nsKDEUtils::feedCommand( const nsTArray<nsCString>& command )
|
|
+ {
|
|
+ for( int i = 0;
|
|
+ i < command.Length();
|
|
+ ++i )
|
|
+ {
|
|
+ nsCString line = command[ i ];
|
|
+ line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape
|
|
+ line.ReplaceSubstring( "\n", "\\n" );
|
|
+#ifdef DEBUG_KDE
|
|
+ fprintf( stderr, "COMM: %s\n", line.get());
|
|
+#endif
|
|
+ fputs( line.get(), commandFile );
|
|
+ fputs( "\n", commandFile );
|
|
+ }
|
|
+ fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data
|
|
+ fflush( commandFile );
|
|
+ }
|
|
diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/toolkit/xre/nsKDEUtils.h
|
|
@@ -0,0 +1,48 @@
|
|
+/* -*- 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 nsKDEUtils_h__
|
|
+#define nsKDEUtils_h__
|
|
+
|
|
+#include "nsStringGlue.h"
|
|
+#include "nsTArray.h"
|
|
+#include <stdio.h>
|
|
+
|
|
+typedef struct _GtkWindow GtkWindow;
|
|
+
|
|
+class nsIArray;
|
|
+
|
|
+class NS_EXPORT nsKDEUtils
|
|
+ {
|
|
+ public:
|
|
+ /* Returns true if running inside a KDE session (regardless of whether there is KDE
|
|
+ support available for Firefox). This should be used e.g. when determining
|
|
+ dialog button order but not for code that requires the KDE support. */
|
|
+ static bool kdeSession();
|
|
+ /* Returns true if running inside a KDE session and KDE support is available
|
|
+ for Firefox. This should be used everywhere where the external helper is needed. */
|
|
+ static bool kdeSupport();
|
|
+ /* Executes the given helper command, returns true if helper returned success. */
|
|
+ static bool command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output = NULL );
|
|
+ static bool command( nsIArray* command, nsIArray** output = NULL );
|
|
+ /* Like command(), but additionally blocks the parent widget like if there was
|
|
+ a modal dialog shown and enters the event loop (i.e. there are still paint updates,
|
|
+ this is for commands that take long). */
|
|
+ static bool commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output = NULL );
|
|
+
|
|
+ private:
|
|
+ nsKDEUtils();
|
|
+ ~nsKDEUtils();
|
|
+ static nsKDEUtils* self();
|
|
+ bool startHelper();
|
|
+ void closeHelper();
|
|
+ void feedCommand( const nsTArray<nsCString>& command );
|
|
+ bool internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool isParent,
|
|
+ nsTArray<nsCString>* output );
|
|
+ FILE* commandFile;
|
|
+ FILE* replyFile;
|
|
+ };
|
|
+
|
|
+#endif // nsKDEUtils
|
|
diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
|
|
--- a/uriloader/exthandler/moz.build
|
|
+++ b/uriloader/exthandler/moz.build
|
|
@@ -77,17 +77,19 @@ else:
|
|
SOURCES += [
|
|
osdir + '/nsOSHelperAppService.cpp',
|
|
]
|
|
if CONFIG['GNU_CXX']:
|
|
CXXFLAGS += ['-Wno-error=shadow']
|
|
|
|
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|
UNIFIED_SOURCES += [
|
|
+ 'unix/nsCommonRegistry.cpp',
|
|
'unix/nsGNOMERegistry.cpp',
|
|
+ 'unix/nsKDERegistry.cpp',
|
|
'unix/nsMIMEInfoUnix.cpp',
|
|
]
|
|
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
|
UNIFIED_SOURCES += [
|
|
'android/nsAndroidHandlerApp.cpp',
|
|
'android/nsExternalSharingAppService.cpp',
|
|
'android/nsExternalURLHandlerService.cpp',
|
|
'android/nsMIMEInfoAndroid.cpp',
|
|
@@ -123,16 +125,17 @@ include('/ipc/chromium/chromium-config.m
|
|
|
|
FINAL_LIBRARY = 'xul'
|
|
|
|
LOCAL_INCLUDES += [
|
|
'/dom/base',
|
|
'/dom/ipc',
|
|
'/netwerk/base',
|
|
'/netwerk/protocol/http',
|
|
+ '/toolkit/xre',
|
|
]
|
|
|
|
if CONFIG['MOZ_ENABLE_DBUS']:
|
|
CXXFLAGS += CONFIG['TK_CFLAGS']
|
|
CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
|
|
|
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
|
|
CXXFLAGS += CONFIG['TK_CFLAGS']
|
|
diff --git a/uriloader/exthandler/unix/nsCommonRegistry.cpp b/uriloader/exthandler/unix/nsCommonRegistry.cpp
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/uriloader/exthandler/unix/nsCommonRegistry.cpp
|
|
@@ -0,0 +1,53 @@
|
|
+/* -*- 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 "nsCommonRegistry.h"
|
|
+
|
|
+#include "nsGNOMERegistry.h"
|
|
+#include "nsKDERegistry.h"
|
|
+#include "nsString.h"
|
|
+#include "nsKDEUtils.h"
|
|
+
|
|
+/* static */ bool
|
|
+nsCommonRegistry::HandlerExists(const char *aProtocolScheme)
|
|
+{
|
|
+ if( nsKDEUtils::kdeSupport())
|
|
+ return nsKDERegistry::HandlerExists( aProtocolScheme );
|
|
+ return nsGNOMERegistry::HandlerExists( aProtocolScheme );
|
|
+}
|
|
+
|
|
+/* static */ nsresult
|
|
+nsCommonRegistry::LoadURL(nsIURI *aURL)
|
|
+{
|
|
+ if( nsKDEUtils::kdeSupport())
|
|
+ return nsKDERegistry::LoadURL( aURL );
|
|
+ return nsGNOMERegistry::LoadURL( aURL );
|
|
+}
|
|
+
|
|
+/* static */ void
|
|
+nsCommonRegistry::GetAppDescForScheme(const nsACString& aScheme,
|
|
+ nsAString& aDesc)
|
|
+{
|
|
+ if( nsKDEUtils::kdeSupport())
|
|
+ return nsKDERegistry::GetAppDescForScheme( aScheme, aDesc );
|
|
+ return nsGNOMERegistry::GetAppDescForScheme( aScheme, aDesc );
|
|
+}
|
|
+
|
|
+
|
|
+/* static */ already_AddRefed<nsMIMEInfoBase>
|
|
+nsCommonRegistry::GetFromExtension(const nsACString& aFileExt)
|
|
+{
|
|
+ if( nsKDEUtils::kdeSupport())
|
|
+ return nsKDERegistry::GetFromExtension( aFileExt );
|
|
+ return nsGNOMERegistry::GetFromExtension( aFileExt );
|
|
+}
|
|
+
|
|
+/* static */ already_AddRefed<nsMIMEInfoBase>
|
|
+nsCommonRegistry::GetFromType(const nsACString& aMIMEType)
|
|
+{
|
|
+ if( nsKDEUtils::kdeSupport())
|
|
+ return nsKDERegistry::GetFromType( aMIMEType );
|
|
+ return nsGNOMERegistry::GetFromType( aMIMEType );
|
|
+}
|
|
diff --git a/uriloader/exthandler/unix/nsCommonRegistry.h b/uriloader/exthandler/unix/nsCommonRegistry.h
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/uriloader/exthandler/unix/nsCommonRegistry.h
|
|
@@ -0,0 +1,28 @@
|
|
+/* 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 nsCommonRegistry_h__
|
|
+#define nsCommonRegistry_h__
|
|
+
|
|
+#include "nsIURI.h"
|
|
+#include "nsCOMPtr.h"
|
|
+
|
|
+class nsMIMEInfoBase;
|
|
+
|
|
+class nsCommonRegistry
|
|
+{
|
|
+ public:
|
|
+ static bool HandlerExists(const char *aProtocolScheme);
|
|
+
|
|
+ static nsresult LoadURL(nsIURI *aURL);
|
|
+
|
|
+ static void GetAppDescForScheme(const nsACString& aScheme,
|
|
+ nsAString& aDesc);
|
|
+
|
|
+ static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
|
|
+
|
|
+ static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/uriloader/exthandler/unix/nsKDERegistry.cpp b/uriloader/exthandler/unix/nsKDERegistry.cpp
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/uriloader/exthandler/unix/nsKDERegistry.cpp
|
|
@@ -0,0 +1,88 @@
|
|
+/* -*- 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 "nsKDERegistry.h"
|
|
+#include "prlink.h"
|
|
+#include "prmem.h"
|
|
+#include "nsString.h"
|
|
+#include "nsILocalFile.h"
|
|
+#include "nsMIMEInfoUnix.h"
|
|
+#include "nsAutoPtr.h"
|
|
+#include "nsKDEUtils.h"
|
|
+
|
|
+/* static */ bool
|
|
+nsKDERegistry::HandlerExists(const char *aProtocolScheme)
|
|
+{
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "HANDLEREXISTS" ));
|
|
+ command.AppendElement( nsAutoCString( aProtocolScheme ));
|
|
+ return nsKDEUtils::command( command );
|
|
+}
|
|
+
|
|
+/* static */ nsresult
|
|
+nsKDERegistry::LoadURL(nsIURI *aURL)
|
|
+{
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "OPEN" ));
|
|
+ nsCString url;
|
|
+ aURL->GetSpec( url );
|
|
+ command.AppendElement( url );
|
|
+ bool rv = nsKDEUtils::command( command );
|
|
+ if (!rv)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+/* static */ void
|
|
+nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme,
|
|
+ nsAString& aDesc)
|
|
+{
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "GETAPPDESCFORSCHEME" ));
|
|
+ command.AppendElement( aScheme );
|
|
+ nsTArray<nsCString> output;
|
|
+ if( nsKDEUtils::command( command, &output ) && output.Length() == 1 )
|
|
+ CopyUTF8toUTF16( output[ 0 ], aDesc );
|
|
+}
|
|
+
|
|
+
|
|
+/* static */ already_AddRefed<nsMIMEInfoBase>
|
|
+nsKDERegistry::GetFromExtension(const nsACString& aFileExt)
|
|
+{
|
|
+ NS_ASSERTION(aFileExt[0] != '.', "aFileExt shouldn't start with a dot");
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "GETFROMEXTENSION" ));
|
|
+ command.AppendElement( aFileExt );
|
|
+ return GetFromHelper( command );
|
|
+}
|
|
+
|
|
+/* static */ already_AddRefed<nsMIMEInfoBase>
|
|
+nsKDERegistry::GetFromType(const nsACString& aMIMEType)
|
|
+{
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "GETFROMTYPE" ));
|
|
+ command.AppendElement( aMIMEType );
|
|
+ return GetFromHelper( command );
|
|
+}
|
|
+
|
|
+/* static */ already_AddRefed<nsMIMEInfoBase>
|
|
+nsKDERegistry::GetFromHelper(const nsTArray<nsCString>& command)
|
|
+{
|
|
+ nsTArray<nsCString> output;
|
|
+ if( nsKDEUtils::command( command, &output ) && output.Length() == 3 )
|
|
+ {
|
|
+ nsCString mimetype = output[ 0 ];
|
|
+ RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix( mimetype );
|
|
+ NS_ENSURE_TRUE(mimeInfo, nullptr);
|
|
+ nsCString description = output[ 1 ];
|
|
+ mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
|
|
+ nsCString handlerAppName = output[ 2 ];
|
|
+ mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(handlerAppName));
|
|
+ mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
|
|
+ return mimeInfo.forget();
|
|
+ }
|
|
+ return nullptr;
|
|
+}
|
|
diff --git a/uriloader/exthandler/unix/nsKDERegistry.h b/uriloader/exthandler/unix/nsKDERegistry.h
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/uriloader/exthandler/unix/nsKDERegistry.h
|
|
@@ -0,0 +1,34 @@
|
|
+/* 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 nsKDERegistry_h__
|
|
+#define nsKDERegistry_h__
|
|
+
|
|
+#include "nsIURI.h"
|
|
+#include "nsCOMPtr.h"
|
|
+#include "nsTArray.h"
|
|
+
|
|
+class nsMIMEInfoBase;
|
|
+class nsAutoCString;
|
|
+class nsCString;
|
|
+
|
|
+class nsKDERegistry
|
|
+{
|
|
+ public:
|
|
+ static bool HandlerExists(const char *aProtocolScheme);
|
|
+
|
|
+ static nsresult LoadURL(nsIURI *aURL);
|
|
+
|
|
+ static void GetAppDescForScheme(const nsACString& aScheme,
|
|
+ nsAString& aDesc);
|
|
+
|
|
+ static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
|
|
+
|
|
+ static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
|
|
+ private:
|
|
+ static already_AddRefed<nsMIMEInfoBase> GetFromHelper(const nsTArray<nsCString>& command);
|
|
+
|
|
+};
|
|
+
|
|
+#endif //nsKDERegistry_h__
|
|
diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
|
|
--- a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
|
|
+++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
|
|
@@ -1,50 +1,53 @@
|
|
/* -*- Mode: C++; tab-width: 3; 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 "nsMIMEInfoUnix.h"
|
|
-#include "nsGNOMERegistry.h"
|
|
+#include "nsCommonRegistry.h"
|
|
#include "nsIGIOService.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsIIOService.h"
|
|
#include "nsAutoPtr.h"
|
|
#ifdef MOZ_ENABLE_DBUS
|
|
#include "nsDBusHandlerApp.h"
|
|
#endif
|
|
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
|
+#include "nsKDEUtils.h"
|
|
+#endif
|
|
|
|
nsresult
|
|
nsMIMEInfoUnix::LoadUriInternal(nsIURI * aURI)
|
|
{
|
|
- return nsGNOMERegistry::LoadURL(aURI);
|
|
+ return nsCommonRegistry::LoadURL(aURI);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMIMEInfoUnix::GetHasDefaultHandler(bool *_retval)
|
|
{
|
|
// if mDefaultApplication is set, it means the application has been set from
|
|
// either /etc/mailcap or ${HOME}/.mailcap, in which case we don't want to
|
|
// give the GNOME answer.
|
|
if (mDefaultApplication)
|
|
return nsMIMEInfoImpl::GetHasDefaultHandler(_retval);
|
|
|
|
*_retval = false;
|
|
|
|
if (mClass == eProtocolInfo) {
|
|
- *_retval = nsGNOMERegistry::HandlerExists(mSchemeOrType.get());
|
|
+ *_retval = nsCommonRegistry::HandlerExists(mSchemeOrType.get());
|
|
} else {
|
|
- RefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mSchemeOrType);
|
|
+ RefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromType(mSchemeOrType);
|
|
if (!mimeInfo) {
|
|
nsAutoCString ext;
|
|
nsresult rv = GetPrimaryExtension(ext);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
- mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
|
|
+ mimeInfo = nsCommonRegistry::GetFromExtension(ext);
|
|
}
|
|
}
|
|
if (mimeInfo)
|
|
*_retval = true;
|
|
}
|
|
|
|
if (*_retval)
|
|
return NS_OK;
|
|
@@ -79,16 +82,33 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(ns
|
|
ContentAction::Action::defaultActionForFile(uri, QString(mSchemeOrType.get()));
|
|
if (action.isValid()) {
|
|
action.trigger();
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
|
|
+ if( nsKDEUtils::kdeSupport()) {
|
|
+ bool supports;
|
|
+ if( NS_SUCCEEDED( GetHasDefaultHandler( &supports )) && supports ) {
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "OPEN" ));
|
|
+ command.AppendElement( nativePath );
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "MIMETYPE" ));
|
|
+ command.AppendElement( mSchemeOrType );
|
|
+ if( nsKDEUtils::command( command ))
|
|
+ return NS_OK;
|
|
+ }
|
|
+ if (!mDefaultApplication)
|
|
+ return NS_ERROR_FILE_NOT_FOUND;
|
|
+
|
|
+ return LaunchWithIProcess(mDefaultApplication, nativePath);
|
|
+ }
|
|
+
|
|
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
|
|
if (!giovfs) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// nsGIOMimeApp->Launch wants a URI string instead of local file
|
|
nsresult rv;
|
|
nsCOMPtr<nsIIOService> ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
|
|
diff --git a/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
|
|
--- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp
|
|
+++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
|
|
@@ -10,17 +10,17 @@
|
|
#if defined(MOZ_ENABLE_CONTENTACTION)
|
|
#include <contentaction/contentaction.h>
|
|
#include <QString>
|
|
#endif
|
|
|
|
#include "nsOSHelperAppService.h"
|
|
#include "nsMIMEInfoUnix.h"
|
|
#ifdef MOZ_WIDGET_GTK
|
|
-#include "nsGNOMERegistry.h"
|
|
+#include "nsCommonRegistry.h"
|
|
#endif
|
|
#include "nsISupports.h"
|
|
#include "nsString.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsUnicharUtils.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsIURL.h"
|
|
#include "nsIFileStreams.h"
|
|
@@ -1146,26 +1146,26 @@ nsresult nsOSHelperAppService::OSProtoco
|
|
ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':');
|
|
|
|
if (action.isValid())
|
|
*aHandlerExists = true;
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
// Check the GNOME registry for a protocol handler
|
|
- *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
|
|
+ *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
|
|
{
|
|
#ifdef MOZ_WIDGET_GTK
|
|
- nsGNOMERegistry::GetAppDescForScheme(aScheme, _retval);
|
|
+ nsCommonRegistry::GetAppDescForScheme(aScheme, _retval);
|
|
return _retval.IsEmpty() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
|
|
#else
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
#endif
|
|
}
|
|
|
|
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t * platformAppPath, nsIFile ** aFile)
|
|
{
|
|
@@ -1252,17 +1252,17 @@ nsOSHelperAppService::GetFromExtension(c
|
|
mime_types_description,
|
|
true);
|
|
|
|
if (NS_FAILED(rv) || majorType.IsEmpty()) {
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
LOG(("Looking in GNOME registry\n"));
|
|
RefPtr<nsMIMEInfoBase> gnomeInfo =
|
|
- nsGNOMERegistry::GetFromExtension(aFileExt);
|
|
+ nsCommonRegistry::GetFromExtension(aFileExt);
|
|
if (gnomeInfo) {
|
|
LOG(("Got MIMEInfo from GNOME registry\n"));
|
|
return gnomeInfo.forget();
|
|
}
|
|
#endif
|
|
|
|
rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt),
|
|
majorType,
|
|
@@ -1373,17 +1373,17 @@ nsOSHelperAppService::GetFromType(const
|
|
nsAutoString extensions, mime_types_description;
|
|
LookUpExtensionsAndDescription(majorType,
|
|
minorType,
|
|
extensions,
|
|
mime_types_description);
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
if (handler.IsEmpty()) {
|
|
- RefPtr<nsMIMEInfoBase> gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
|
|
+ RefPtr<nsMIMEInfoBase> gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType);
|
|
if (gnomeInfo) {
|
|
LOG(("Got MIMEInfo from GNOME registry without extensions; setting them "
|
|
"to %s\n", NS_LossyConvertUTF16toASCII(extensions).get()));
|
|
|
|
NS_ASSERTION(!gnomeInfo->HasExtensions(), "How'd that happen?");
|
|
gnomeInfo->SetFileExtensions(NS_ConvertUTF16toUTF8(extensions));
|
|
return gnomeInfo.forget();
|
|
}
|
|
diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build
|
|
--- a/widget/gtk/moz.build
|
|
+++ b/widget/gtk/moz.build
|
|
@@ -101,16 +101,17 @@ else:
|
|
include('/ipc/chromium/chromium-config.mozbuild')
|
|
|
|
FINAL_LIBRARY = 'xul'
|
|
|
|
LOCAL_INCLUDES += [
|
|
'/layout/generic',
|
|
'/layout/xul',
|
|
'/other-licenses/atk-1.0',
|
|
+ '/toolkit/xre',
|
|
'/widget',
|
|
]
|
|
|
|
if CONFIG['MOZ_X11']:
|
|
LOCAL_INCLUDES += [
|
|
'/widget/x11',
|
|
]
|
|
|
|
diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp
|
|
--- a/widget/gtk/nsFilePicker.cpp
|
|
+++ b/widget/gtk/nsFilePicker.cpp
|
|
@@ -4,32 +4,34 @@
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/Types.h"
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
+#include <gdk/gdkx.h>
|
|
|
|
#include "nsGtkUtils.h"
|
|
#include "nsIFileURL.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsIFile.h"
|
|
#include "nsIStringBundle.h"
|
|
|
|
#include "nsArrayEnumerator.h"
|
|
#include "nsMemory.h"
|
|
#include "nsEnumeratorUtils.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "mozcontainer.h"
|
|
|
|
#include "nsFilePicker.h"
|
|
+#include "nsKDEUtils.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
#define MAX_PREVIEW_SIZE 180
|
|
// bug 1184009
|
|
#define MAX_PREVIEW_SOURCE_SIZE 4096
|
|
|
|
nsIFile *nsFilePicker::mPrevDisplayDirectory = nullptr;
|
|
@@ -246,17 +248,19 @@ nsFilePicker::AppendFilters(int32_t aFil
|
|
return nsBaseFilePicker::AppendFilters(aFilterMask);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
|
|
{
|
|
if (aFilter.EqualsLiteral("..apps")) {
|
|
// No platform specific thing we can do here, really....
|
|
- return NS_OK;
|
|
+ // Unless it's KDE.
|
|
+ if( mMode != modeOpen || !nsKDEUtils::kdeSupport())
|
|
+ return NS_OK;
|
|
}
|
|
|
|
nsAutoCString filter, name;
|
|
CopyUTF16toUTF8(aFilter, filter);
|
|
CopyUTF16toUTF8(aTitle, name);
|
|
|
|
mFilters.AppendElement(filter);
|
|
mFilterNames.AppendElement(name);
|
|
@@ -371,16 +375,32 @@ nsFilePicker::Show(int16_t *aReturn)
|
|
|
|
NS_IMETHODIMP
|
|
nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
|
|
{
|
|
// Can't show two dialogs concurrently with the same filepicker
|
|
if (mRunning)
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
+ // KDE file picker is not handled via callback
|
|
+ if( nsKDEUtils::kdeSupport()) {
|
|
+ int16_t result;
|
|
+ mCallback = aCallback;
|
|
+ mRunning = true;
|
|
+ kdeFileDialog(&result);
|
|
+ if (mCallback) {
|
|
+ mCallback->Done(result);
|
|
+ mCallback = nullptr;
|
|
+ } else {
|
|
+ mResult = result;
|
|
+ }
|
|
+ mRunning = false;
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
nsXPIDLCString title;
|
|
title.Adopt(ToNewUTF8String(mTitle));
|
|
|
|
GtkWindow *parent_widget =
|
|
GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
|
|
|
|
GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
|
|
|
|
@@ -603,8 +623,235 @@ nsFilePicker::Done(GtkWidget* file_choos
|
|
if (mCallback) {
|
|
mCallback->Done(result);
|
|
mCallback = nullptr;
|
|
} else {
|
|
mResult = result;
|
|
}
|
|
NS_RELEASE_THIS();
|
|
}
|
|
+
|
|
+nsCString nsFilePicker::kdeMakeFilter( int index )
|
|
+ {
|
|
+ nsCString buf = mFilters[ index ];
|
|
+ for( PRUint32 i = 0;
|
|
+ i < buf.Length();
|
|
+ ++i )
|
|
+ if( buf[ i ] == ';' ) // KDE separates just using spaces
|
|
+ buf.SetCharAt( ' ', i );
|
|
+ if (!mFilterNames[index].IsEmpty())
|
|
+ {
|
|
+ buf += "|";
|
|
+ buf += mFilterNames[index].get();
|
|
+ }
|
|
+ return buf;
|
|
+ }
|
|
+
|
|
+static PRInt32 windowToXid( nsIWidget* widget )
|
|
+ {
|
|
+ GtkWindow *parent_widget = GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
|
|
+ GdkWindow* gdk_window = gtk_widget_get_window( gtk_widget_get_toplevel( GTK_WIDGET( parent_widget )));
|
|
+ return GDK_WINDOW_XID( gdk_window );
|
|
+ }
|
|
+
|
|
+NS_IMETHODIMP nsFilePicker::kdeFileDialog(PRInt16 *aReturn)
|
|
+ {
|
|
+ NS_ENSURE_ARG_POINTER(aReturn);
|
|
+
|
|
+ if( mMode == modeOpen && mFilters.Length() == 1 && mFilters[ 0 ].EqualsLiteral( "..apps" ))
|
|
+ return kdeAppsDialog( aReturn );
|
|
+
|
|
+ nsXPIDLCString title;
|
|
+ title.Adopt(ToNewUTF8String(mTitle));
|
|
+
|
|
+ const char* arg = NULL;
|
|
+ if( mAllowURLs )
|
|
+ {
|
|
+ switch( mMode )
|
|
+ {
|
|
+ case nsIFilePicker::modeOpen:
|
|
+ case nsIFilePicker::modeOpenMultiple:
|
|
+ arg = "GETOPENURL";
|
|
+ break;
|
|
+ case nsIFilePicker::modeSave:
|
|
+ arg = "GETSAVEURL";
|
|
+ break;
|
|
+ case nsIFilePicker::modeGetFolder:
|
|
+ arg = "GETDIRECTORYURL";
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ switch( mMode )
|
|
+ {
|
|
+ case nsIFilePicker::modeOpen:
|
|
+ case nsIFilePicker::modeOpenMultiple:
|
|
+ arg = "GETOPENFILENAME";
|
|
+ break;
|
|
+ case nsIFilePicker::modeSave:
|
|
+ arg = "GETSAVEFILENAME";
|
|
+ break;
|
|
+ case nsIFilePicker::modeGetFolder:
|
|
+ arg = "GETDIRECTORYFILENAME";
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nsAutoCString directory;
|
|
+ if (mDisplayDirectory) {
|
|
+ mDisplayDirectory->GetNativePath(directory);
|
|
+ } else if (mPrevDisplayDirectory) {
|
|
+ mPrevDisplayDirectory->GetNativePath(directory);
|
|
+ }
|
|
+
|
|
+ nsAutoCString startdir;
|
|
+ if (!directory.IsEmpty()) {
|
|
+ startdir = directory;
|
|
+ }
|
|
+ if (mMode == nsIFilePicker::modeSave) {
|
|
+ if( !startdir.IsEmpty())
|
|
+ {
|
|
+ startdir += "/";
|
|
+ startdir += ToNewUTF8String(mDefault);
|
|
+ }
|
|
+ else
|
|
+ startdir = ToNewUTF8String(mDefault);
|
|
+ }
|
|
+ if( startdir.IsEmpty())
|
|
+ startdir = ".";
|
|
+
|
|
+ nsAutoCString filters;
|
|
+ PRInt32 count = mFilters.Length();
|
|
+ if( count == 0 ) //just in case
|
|
+ filters = "*";
|
|
+ else
|
|
+ {
|
|
+ filters = kdeMakeFilter( 0 );
|
|
+ for (PRInt32 i = 1; i < count; ++i)
|
|
+ {
|
|
+ filters += "\n";
|
|
+ filters += kdeMakeFilter( i );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( nsAutoCString( arg ));
|
|
+ command.AppendElement( startdir );
|
|
+ if( mMode != nsIFilePicker::modeGetFolder )
|
|
+ {
|
|
+ command.AppendElement( filters );
|
|
+ nsAutoCString selected;
|
|
+ selected.AppendInt( mSelectedType );
|
|
+ command.AppendElement( selected );
|
|
+ }
|
|
+ command.AppendElement( title );
|
|
+ if( mMode == nsIFilePicker::modeOpenMultiple )
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "MULTIPLE" ));
|
|
+ if( PRInt32 xid = windowToXid( mParentWidget ))
|
|
+ {
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "PARENT" ));
|
|
+ nsAutoCString parent;
|
|
+ parent.AppendInt( xid );
|
|
+ command.AppendElement( parent );
|
|
+ }
|
|
+
|
|
+ nsTArray<nsCString> output;
|
|
+ if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
|
|
+ {
|
|
+ *aReturn = nsIFilePicker::returnOK;
|
|
+ mFiles.Clear();
|
|
+ if( mMode != nsIFilePicker::modeGetFolder )
|
|
+ {
|
|
+ mSelectedType = atoi( output[ 0 ].get());
|
|
+ output.RemoveElementAt( 0 );
|
|
+ }
|
|
+ if (mMode == nsIFilePicker::modeOpenMultiple)
|
|
+ {
|
|
+ mFileURL.Truncate();
|
|
+ PRUint32 count = output.Length();
|
|
+ for( PRUint32 i = 0;
|
|
+ i < count;
|
|
+ ++i )
|
|
+ {
|
|
+ nsCOMPtr<nsIFile> localfile;
|
|
+ nsresult rv = NS_NewNativeLocalFile( output[ i ],
|
|
+ PR_FALSE,
|
|
+ getter_AddRefs(localfile));
|
|
+ if (NS_SUCCEEDED(rv))
|
|
+ mFiles.AppendObject(localfile);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if( output.Length() == 0 )
|
|
+ mFileURL = nsCString();
|
|
+ else if( mAllowURLs )
|
|
+ mFileURL = output[ 0 ];
|
|
+ else // GetFile() actually requires it to be url even for local files :-/
|
|
+ {
|
|
+ mFileURL = nsCString( "file://" );
|
|
+ mFileURL.Append( output[ 0 ] );
|
|
+ }
|
|
+ }
|
|
+ // Remember last used directory.
|
|
+ nsCOMPtr<nsIFile> file;
|
|
+ GetFile(getter_AddRefs(file));
|
|
+ if (file) {
|
|
+ nsCOMPtr<nsIFile> dir;
|
|
+ file->GetParent(getter_AddRefs(dir));
|
|
+ nsCOMPtr<nsIFile> localDir(do_QueryInterface(dir));
|
|
+ if (localDir) {
|
|
+ localDir.swap(mPrevDisplayDirectory);
|
|
+ }
|
|
+ }
|
|
+ if (mMode == nsIFilePicker::modeSave)
|
|
+ {
|
|
+ nsCOMPtr<nsIFile> file;
|
|
+ GetFile(getter_AddRefs(file));
|
|
+ if (file)
|
|
+ {
|
|
+ bool exists = false;
|
|
+ file->Exists(&exists);
|
|
+ if (exists) // TODO do overwrite check in the helper app
|
|
+ *aReturn = nsIFilePicker::returnReplace;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ *aReturn = nsIFilePicker::returnCancel;
|
|
+ }
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
+
|
|
+NS_IMETHODIMP nsFilePicker::kdeAppsDialog(PRInt16 *aReturn)
|
|
+ {
|
|
+ NS_ENSURE_ARG_POINTER(aReturn);
|
|
+
|
|
+ nsXPIDLCString title;
|
|
+ title.Adopt(ToNewUTF8String(mTitle));
|
|
+
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "APPSDIALOG" ));
|
|
+ command.AppendElement( title );
|
|
+ if( PRInt32 xid = windowToXid( mParentWidget ))
|
|
+ {
|
|
+ command.AppendElement( NS_LITERAL_CSTRING( "PARENT" ));
|
|
+ nsAutoCString parent;
|
|
+ parent.AppendInt( xid );
|
|
+ command.AppendElement( parent );
|
|
+ }
|
|
+
|
|
+ nsTArray<nsCString> output;
|
|
+ if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
|
|
+ {
|
|
+ *aReturn = nsIFilePicker::returnOK;
|
|
+ mFileURL = output.Length() > 0 ? output[ 0 ] : nsCString();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ *aReturn = nsIFilePicker::returnCancel;
|
|
+ }
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h
|
|
--- a/widget/gtk/nsFilePicker.h
|
|
+++ b/widget/gtk/nsFilePicker.h
|
|
@@ -69,14 +69,20 @@ protected:
|
|
nsString mDefaultExtension;
|
|
|
|
nsTArray<nsCString> mFilters;
|
|
nsTArray<nsCString> mFilterNames;
|
|
|
|
private:
|
|
static nsIFile *mPrevDisplayDirectory;
|
|
|
|
+ bool kdeRunning();
|
|
+ bool getKdeRunning();
|
|
+ NS_IMETHODIMP kdeFileDialog(PRInt16 *aReturn);
|
|
+ NS_IMETHODIMP kdeAppsDialog(PRInt16 *aReturn);
|
|
+ nsCString kdeMakeFilter( int index );
|
|
+
|
|
#if (MOZ_WIDGET_GTK == 3)
|
|
GtkFileChooserWidget *mFileChooserDelegate;
|
|
#endif
|
|
};
|
|
|
|
#endif
|
|
diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
|
|
--- a/xpcom/components/ManifestParser.cpp
|
|
+++ b/xpcom/components/ManifestParser.cpp
|
|
@@ -32,16 +32,17 @@
|
|
#include "nsTextFormatter.h"
|
|
#include "nsVersionComparator.h"
|
|
#include "nsXPCOMCIDInternal.h"
|
|
|
|
#include "nsIConsoleService.h"
|
|
#include "nsIScriptError.h"
|
|
#include "nsIXULAppInfo.h"
|
|
#include "nsIXULRuntime.h"
|
|
+#include "nsKDEUtils.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
struct ManifestDirective
|
|
{
|
|
const char* directive;
|
|
int argc;
|
|
|
|
@@ -472,16 +473,17 @@ ParseManifest(NSLocationType aType, File
|
|
NS_NAMED_LITERAL_STRING(kRemoteEnabled, "remoteenabled");
|
|
NS_NAMED_LITERAL_STRING(kRemoteRequired, "remoterequired");
|
|
NS_NAMED_LITERAL_STRING(kApplication, "application");
|
|
NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
|
|
NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
|
|
NS_NAMED_LITERAL_STRING(kOs, "os");
|
|
NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
|
|
NS_NAMED_LITERAL_STRING(kABI, "abi");
|
|
+ NS_NAMED_LITERAL_STRING(kDesktop, "desktop");
|
|
NS_NAMED_LITERAL_STRING(kProcess, "process");
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
NS_NAMED_LITERAL_STRING(kTablet, "tablet");
|
|
#endif
|
|
|
|
NS_NAMED_LITERAL_STRING(kMain, "main");
|
|
NS_NAMED_LITERAL_STRING(kContent, "content");
|
|
|
|
@@ -532,44 +534,49 @@ ParseManifest(NSLocationType aType, File
|
|
CopyUTF8toUTF16(s, abi);
|
|
abi.Insert(char16_t('_'), 0);
|
|
abi.Insert(osTarget, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
nsAutoString osVersion;
|
|
+ nsAutoString desktop;
|
|
#if defined(XP_WIN)
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4996) // VC12+ deprecates GetVersionEx
|
|
OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
|
|
if (GetVersionEx(&info)) {
|
|
nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
|
|
info.dwMajorVersion,
|
|
info.dwMinorVersion);
|
|
}
|
|
+ desktop = NS_LITERAL_STRING("win");
|
|
#pragma warning(pop)
|
|
#elif defined(MOZ_WIDGET_COCOA)
|
|
SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
|
|
SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
|
|
nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
|
|
majorVersion,
|
|
minorVersion);
|
|
+ desktop = NS_LITERAL_STRING("macosx");
|
|
#elif defined(MOZ_WIDGET_GTK)
|
|
nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
|
|
gtk_major_version,
|
|
gtk_minor_version);
|
|
+ desktop = nsKDEUtils::kdeSession() ? NS_LITERAL_STRING("kde") : NS_LITERAL_STRING("gnome");
|
|
#elif defined(MOZ_WIDGET_ANDROID)
|
|
bool isTablet = false;
|
|
if (mozilla::AndroidBridge::Bridge()) {
|
|
mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION",
|
|
"RELEASE",
|
|
osVersion);
|
|
isTablet = java::GeckoAppShell::IsTablet();
|
|
}
|
|
+ desktop = NS_LITERAL_STRING("android");
|
|
#endif
|
|
|
|
if (XRE_IsContentProcess()) {
|
|
process = kContent;
|
|
} else {
|
|
process = kMain;
|
|
}
|
|
|
|
@@ -672,25 +679,27 @@ ParseManifest(NSLocationType aType, File
|
|
TriState stOsVersion = eUnspecified;
|
|
TriState stOs = eUnspecified;
|
|
TriState stABI = eUnspecified;
|
|
TriState stProcess = eUnspecified;
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
TriState stTablet = eUnspecified;
|
|
#endif
|
|
int flags = 0;
|
|
+ TriState stDesktop = eUnspecified;
|
|
|
|
while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
|
|
ok) {
|
|
ToLowerCase(token);
|
|
NS_ConvertASCIItoUTF16 wtoken(token);
|
|
|
|
if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
|
|
CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
|
|
CheckStringFlag(kABI, wtoken, abi, stABI) ||
|
|
+ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
|
|
CheckStringFlag(kProcess, wtoken, process, stProcess) ||
|
|
CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
|
|
CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
|
|
CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
|
|
continue;
|
|
}
|
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
@@ -740,16 +749,17 @@ ParseManifest(NSLocationType aType, File
|
|
}
|
|
|
|
if (!ok ||
|
|
stApp == eBad ||
|
|
stAppVersion == eBad ||
|
|
stGeckoVersion == eBad ||
|
|
stOs == eBad ||
|
|
stOsVersion == eBad ||
|
|
+ stDesktop == eBad ||
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
stTablet == eBad ||
|
|
#endif
|
|
stABI == eBad ||
|
|
stProcess == eBad) {
|
|
continue;
|
|
}
|
|
|
|
diff --git a/xpcom/components/moz.build b/xpcom/components/moz.build
|
|
--- a/xpcom/components/moz.build
|
|
+++ b/xpcom/components/moz.build
|
|
@@ -44,12 +44,13 @@ FINAL_LIBRARY = 'xul'
|
|
LOCAL_INCLUDES += [
|
|
'!..',
|
|
'../base',
|
|
'../build',
|
|
'../ds',
|
|
'../reflect/xptinfo',
|
|
'/chrome',
|
|
'/modules/libjar',
|
|
+ '/toolkit/xre'
|
|
]
|
|
|
|
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|
CXXFLAGS += CONFIG['TK_CFLAGS']
|
|
diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
|
|
--- a/xpcom/io/nsLocalFileUnix.cpp
|
|
+++ b/xpcom/io/nsLocalFileUnix.cpp
|
|
@@ -46,16 +46,17 @@
|
|
#include "prproces.h"
|
|
#include "nsIDirectoryEnumerator.h"
|
|
#include "nsISimpleEnumerator.h"
|
|
#include "private/pprio.h"
|
|
#include "prlink.h"
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
#include "nsIGIOService.h"
|
|
+#include "nsKDEUtils.h"
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
#include <Carbon/Carbon.h>
|
|
#include "CocoaFileUtils.h"
|
|
#include "prmem.h"
|
|
#include "plbase64.h"
|
|
|
|
@@ -1948,42 +1949,52 @@ nsLocalFile::SetPersistentDescriptor(con
|
|
return InitWithNativePath(aPersistentDescriptor);
|
|
#endif
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsLocalFile::Reveal()
|
|
{
|
|
#ifdef MOZ_WIDGET_GTK
|
|
- nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
|
|
- if (!giovfs) {
|
|
- return NS_ERROR_FAILURE;
|
|
- }
|
|
+ nsAutoCString url;
|
|
|
|
bool isDirectory;
|
|
if (NS_FAILED(IsDirectory(&isDirectory))) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
+ nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
|
|
if (isDirectory) {
|
|
- return giovfs->ShowURIForInput(mPath);
|
|
+ url = mPath;
|
|
} else if (NS_SUCCEEDED(giovfs->OrgFreedesktopFileManager1ShowItems(mPath))) {
|
|
return NS_OK;
|
|
} else {
|
|
nsCOMPtr<nsIFile> parentDir;
|
|
nsAutoCString dirPath;
|
|
if (NS_FAILED(GetParent(getter_AddRefs(parentDir)))) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
if (NS_FAILED(parentDir->GetNativePath(dirPath))) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
- return giovfs->ShowURIForInput(dirPath);
|
|
+ url = dirPath;
|
|
}
|
|
+
|
|
+ if(nsKDEUtils::kdeSupport()) {
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING("REVEAL") );
|
|
+ command.AppendElement( mPath );
|
|
+ return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
|
|
+ }
|
|
+
|
|
+ if (!giovfs)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ return giovfs->ShowURIForInput(url);
|
|
#elif defined(MOZ_WIDGET_COCOA)
|
|
CFURLRef url;
|
|
if (NS_SUCCEEDED(GetCFURL(&url))) {
|
|
nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
|
|
::CFRelease(url);
|
|
return rv;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
@@ -1991,16 +2002,22 @@ nsLocalFile::Reveal()
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsLocalFile::Launch()
|
|
{
|
|
#ifdef MOZ_WIDGET_GTK
|
|
+ if( nsKDEUtils::kdeSupport()) {
|
|
+ nsTArray<nsCString> command;
|
|
+ command.AppendElement( NS_LITERAL_CSTRING("OPEN") );
|
|
+ command.AppendElement( mPath );
|
|
+ return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
|
|
+ }
|
|
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
|
|
if (!giovfs) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return giovfs->ShowURIForInput(mPath);
|
|
#elif defined(MOZ_ENABLE_CONTENTACTION)
|
|
QUrl uri = QUrl::fromLocalFile(QString::fromUtf8(mPath.get()));
|