mirror of
https://gitdl.cn/https://github.com/chakralinux/gtk.git
synced 2025-02-04 01:07:16 +08:00
409273eb6a
firefox's own notification use libnotify, and provides additional "activate" button comparing with the one provided by kmozillahelper, IMHO integrates better.
3604 lines
126 KiB
Diff
3604 lines
126 KiB
Diff
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/src/Makefile.in b/modules/libpref/src/Makefile.in
|
|
--- a/modules/libpref/src/Makefile.in
|
|
+++ b/modules/libpref/src/Makefile.in
|
|
@@ -54,14 +54,15 @@ endif
|
|
# Optimizer bug with GCC 3.2.2 on OS/2
|
|
ifeq ($(OS_ARCH), OS2)
|
|
nsPrefService.$(OBJ_SUFFIX): nsPrefService.cpp
|
|
$(REPORT_BUILD)
|
|
@$(MAKE_DEPS_AUTO_CXX)
|
|
$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS:-O2=-O1) $(_VPATH_SRCS)
|
|
endif
|
|
|
|
+LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
|
|
|
|
greprefs.js: $(grepref_files)
|
|
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $^ > $@
|
|
|
|
libs:: greprefs.js
|
|
$(INSTALL) $^ $(DIST)/bin/
|
|
diff --git a/modules/libpref/src/Preferences.cpp b/modules/libpref/src/Preferences.cpp
|
|
--- a/modules/libpref/src/Preferences.cpp
|
|
+++ b/modules/libpref/src/Preferences.cpp
|
|
@@ -23,16 +23,17 @@
|
|
#include "nsIStringEnumerator.h"
|
|
#include "nsIZipReader.h"
|
|
#include "nsPrefBranch.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsCRT.h"
|
|
#include "nsCOMArray.h"
|
|
#include "nsXPCOMCID.h"
|
|
#include "nsAutoPtr.h"
|
|
+#include "nsKDEUtils.h"
|
|
|
|
#include "nsQuickSort.h"
|
|
#include "pldhash.h"
|
|
|
|
#include "prefapi.h"
|
|
#include "prefread.h"
|
|
#include "prefapi_private_data.h"
|
|
|
|
@@ -946,16 +947,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 < NS_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;
|
|
@@ -971,17 +990,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).Equals(NS_LITERAL_CSTRING(".xpi")))
|
|
ReadExtensionPrefs(path);
|
|
else
|
|
- pref_LoadPrefsInDir(path, nullptr, 0);
|
|
+ pref_LoadPrefsInDir(path, specialFiles, NS_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);
|
|
@@ -1075,28 +1094,40 @@ 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(VMS)
|
|
, "openvms.js"
|
|
#elif defined(_AIX)
|
|
, "aix.js"
|
|
#endif
|
|
#elif defined(XP_OS2)
|
|
"os2pref.js"
|
|
#elif defined(XP_BEOS)
|
|
"beos.js"
|
|
#endif
|
|
};
|
|
|
|
+ if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper?
|
|
+ for(int i = 0;
|
|
+ i < NS_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.
|
|
nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
|
|
// GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
|
|
diff --git a/toolkit/components/downloads/Makefile.in b/toolkit/components/downloads/Makefile.in
|
|
--- a/toolkit/components/downloads/Makefile.in
|
|
+++ b/toolkit/components/downloads/Makefile.in
|
|
@@ -42,9 +42,12 @@ EXTRA_COMPONENTS = \
|
|
nsDownloadManagerUI.manifest \
|
|
$(NULL)
|
|
endif
|
|
|
|
TEST_DIRS += test
|
|
|
|
include $(topsrcdir)/config/rules.mk
|
|
|
|
+LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
|
|
+
|
|
+
|
|
CXXFLAGS += $(TK_CFLAGS)
|
|
diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
|
|
--- a/toolkit/content/jar.mn
|
|
+++ b/toolkit/content/jar.mn
|
|
@@ -49,29 +49,33 @@ toolkit.jar:
|
|
content/global/viewZoomOverlay.js (viewZoomOverlay.js)
|
|
*+ content/global/bindings/autocomplete.xml (widgets/autocomplete.xml)
|
|
content/global/bindings/browser.xml (widgets/browser.xml)
|
|
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/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/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)
|
|
content/global/bindings/splitter.xml (widgets/splitter.xml)
|
|
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,451 @@
|
|
+<?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
|
|
+ pack="end">
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
|
|
+ <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="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");
|
|
+ else // default to the accept button
|
|
+ return "accept";
|
|
+ ]]>
|
|
+ </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();
|
|
+ }
|
|
+
|
|
+ var xOffset = (opener.outerWidth - window.outerWidth) / 2;
|
|
+ var yOffset = opener.outerHeight / 5;
|
|
+
|
|
+ var newX = opener.screenX + xOffset;
|
|
+ var newY = opener.screenY + yOffset;
|
|
+
|
|
+ // 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; //(opener.outerHeight *2)/10;
|
|
+
|
|
+ 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();
|
|
+ }
|
|
+ }
|
|
+#ifndef XP_MACOSX
|
|
+ else if (focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton) {
|
|
+ defaultButton.focus();
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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];
|
|
+
|
|
+#ifdef XP_WIN
|
|
+# show the spacer on Windows only when the extra2 button is present
|
|
+ var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer");
|
|
+ spacer.removeAttribute("hidden");
|
|
+ spacer.setAttribute("flex", shown["extra2"]?"1":"0");
|
|
+#endif
|
|
+
|
|
+ }
|
|
+ ]]>
|
|
+ </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")
|
|
+ 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_ENTER"
|
|
+ group="system" action="this._hitEnter(event);"/>
|
|
+ <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,1339 @@
|
|
+<?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="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[
|
|
+ // 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.
|
|
+ if (this.preferences.type == "child" &&
|
|
+ !this.instantApply && window.opener) {
|
|
+ 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];
|
|
+ }
|
|
+ }
|
|
+ this._setValue(preference ? preference.value
|
|
+ : this.valueFromPreferences, false);
|
|
+ }
|
|
+ else
|
|
+ this._setValue(this.valueFromPreferences, false);
|
|
+ ]]>
|
|
+ </constructor>
|
|
+ <destructor>
|
|
+ this.preferences.rootBranchInternal
|
|
+ .removeObserver(this.name, this.preferences);
|
|
+ </destructor>
|
|
+
|
|
+ <property name="instantApply">
|
|
+ <getter>
|
|
+ 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"/>
|
|
+ <parameter name="aUpdate"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ if (aUpdate && this.value !== aValue) {
|
|
+ this._value = aValue;
|
|
+ if (this.instantApply)
|
|
+ this.valueFromPreferences = aValue;
|
|
+ this.preferences.fireChangedEvent(this);
|
|
+ }
|
|
+ else if (!aUpdate) {
|
|
+ this._value = aValue;
|
|
+ this.updateElements();
|
|
+ }
|
|
+ return aValue;
|
|
+ ]]>
|
|
+ </body>
|
|
+ </method>
|
|
+ <property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
|
|
+
|
|
+ <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 !== undefined ? rv : (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"
|
|
+#ifdef XP_UNIX_GNOME
|
|
+ >
|
|
+ <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"/>
|
|
+#elif XP_UNIX
|
|
+ pack="end">
|
|
+ <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
|
|
+ <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="disclosure" class="dialog-button" hidden="true"/>
|
|
+#else
|
|
+ pack="end">
|
|
+ <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") {
|
|
+ var 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");
|
|
+#ifdef XP_MACOSX
|
|
+ // no buttons on Mac except Help
|
|
+ cancelButton.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");
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+ 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>
|
|
+
|
|
+ <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) {
|
|
+ function OverlayLoadObserver(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[
|
|
+#ifdef XP_MACOSX
|
|
+ var paneTitle = aPaneElement.label;
|
|
+ if (paneTitle != "")
|
|
+ document.title = paneTitle;
|
|
+#endif
|
|
+ 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);
|
|
+#ifdef XP_MACOSX
|
|
+ var animate = true;
|
|
+#else
|
|
+ var animate = false;
|
|
+#endif
|
|
+ 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;
|
|
+
|
|
+ if (this.type == "child" && window.opener) {
|
|
+ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefBranch);
|
|
+ var instantApply = psvc.getBoolPref("browser.preferences.instantApply");
|
|
+ if (instantApply) {
|
|
+ var panes = this.preferencePanes;
|
|
+ for (var 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) {
|
|
+ var childPrefs = pdoc.createElement("preferences");
|
|
+ currentPane.appendChild(childPrefs);
|
|
+ childPrefs.id = id;
|
|
+ }
|
|
+ var panes = this.preferencePanes;
|
|
+ for (var 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 {
|
|
+ var panes = this.preferencePanes;
|
|
+ for (var i = 0; i < panes.length; ++i)
|
|
+ panes[i].writePreferences(false);
|
|
+
|
|
+ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
+ .getService(Components.interfaces.nsIPrefService);
|
|
+ psvc.savePrefFile(null);
|
|
+ }
|
|
+ ]]>
|
|
+ </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.
|
|
+ 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>
|
|
+
|
|
+ <method name="userChangedValue">
|
|
+ <parameter name="aElement"/>
|
|
+ <body>
|
|
+ <![CDATA[
|
|
+ var element = this.getPreferenceElement(aElement);
|
|
+ if (element.hasAttribute("preference")) {
|
|
+ var preference = document.getElementById(element.getAttribute("preference"));
|
|
+ var prefVal = preference.getElementValue(element);
|
|
+ preference.value = prefVal;
|
|
+ }
|
|
+ ]]>
|
|
+ </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" 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>
|
|
+ <implementation implements="nsIAccessible">
|
|
+ <property name="accessibleType" readonly="true">
|
|
+ <getter>
|
|
+ <![CDATA[
|
|
+ return Components.interfaces.nsIAccessibleProvider.XULListitem;
|
|
+ ]]>
|
|
+ </getter>
|
|
+ </property>
|
|
+ </implementation>
|
|
+ </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/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
|
|
--- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
|
|
+++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
|
|
@@ -14,16 +14,18 @@
|
|
#include "prenv.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsIGSettingsService.h"
|
|
#include "nsInterfaceHashtable.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "nsIURI.h"
|
|
+#include "nsVoidArray.h"
|
|
+#include "nsKDEUtils.h"
|
|
|
|
class nsUnixSystemProxySettings MOZ_FINAL : public nsISystemProxySettings {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSISYSTEMPROXYSETTINGS
|
|
|
|
nsUnixSystemProxySettings() {}
|
|
nsresult Init();
|
|
@@ -35,16 +37,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_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings)
|
|
|
|
NS_IMETHODIMP
|
|
nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
|
|
{
|
|
// dbus prevents us from being threadsafe, but this routine should not block anyhow
|
|
@@ -499,16 +502,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);
|
|
|
|
@@ -534,8 +540,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/Makefile.in b/toolkit/xre/Makefile.in
|
|
--- a/toolkit/xre/Makefile.in
|
|
+++ b/toolkit/xre/Makefile.in
|
|
@@ -69,17 +69,18 @@ else
|
|
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
|
CMMSRCS = nsNativeAppSupportCocoa.mm
|
|
EXPORTS += MacQuirks.h
|
|
else
|
|
ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
|
|
CPPSRCS += nsNativeAppSupportOS2.cpp
|
|
else
|
|
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
|
|
-CPPSRCS += nsNativeAppSupportUnix.cpp
|
|
+CPPSRCS += nsNativeAppSupportUnix.cpp nsKDEUtils.cpp
|
|
+EXPORTS += nsKDEUtils.h
|
|
else
|
|
ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
|
|
MOCSRCS += moc_nsNativeAppSupportQt.cpp
|
|
CPPSRCS += $(MOCSRCS)
|
|
CPPSRCS += nsNativeAppSupportQt.cpp
|
|
CPPSRCS += nsQAppInstance.cpp
|
|
EXPORTS += nsQAppInstance.h
|
|
else
|
|
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,339 @@
|
|
+/* -*- 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>
|
|
+
|
|
+//#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, const GtkWindow* parent, nsTArray<nsCString>* output )
|
|
+ {
|
|
+ return self()->internalCommand( command, parent, true, output );
|
|
+ }
|
|
+
|
|
+bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, const 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 && parent->group )
|
|
+ gtk_window_group_add_window( parent->group, 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, const 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, const GtkWindow* parent, bool isParent,
|
|
+ nsTArray<nsCString>* output );
|
|
+ FILE* commandFile;
|
|
+ FILE* replyFile;
|
|
+ };
|
|
+
|
|
+#endif // nsKDEUtils
|
|
diff --git a/uriloader/exthandler/Makefile.in b/uriloader/exthandler/Makefile.in
|
|
--- a/uriloader/exthandler/Makefile.in
|
|
+++ b/uriloader/exthandler/Makefile.in
|
|
@@ -58,18 +58,19 @@ LOCAL_INCLUDES = -I$(srcdir)
|
|
LOCAL_INCLUDES += -I$(topsrcdir)/dom/base \
|
|
-I$(topsrcdir)/dom/ipc \
|
|
-I$(topsrcdir)/content/base/src \
|
|
-I$(topsrcdir)/content/events/src \
|
|
-I$(topsrcdir)/netwerk/base/src \
|
|
-I$(topsrcdir)/netwerk/protocol/http
|
|
|
|
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
|
|
-OSHELPER += nsGNOMERegistry.cpp
|
|
+OSHELPER += nsCommonRegistry.cpp nsGNOMERegistry.cpp nsKDERegistry.cpp
|
|
OSHELPER += nsMIMEInfoUnix.cpp
|
|
+LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
|
|
endif
|
|
|
|
ifeq ($(MOZ_WIDGET_TOOLKIT),android)
|
|
OSHELPER += nsMIMEInfoAndroid.cpp
|
|
OSHELPER += nsAndroidHandlerApp.cpp
|
|
OSHELPER += nsExternalSharingAppService.cpp
|
|
EXPORTS += nsExternalSharingAppService.h
|
|
OSHELPER += nsExternalURLHandlerService.cpp
|
|
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,54 @@
|
|
+/* -*- 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 "nsVoidArray.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,23 @@
|
|
+/* 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 "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);
|
|
+};
|
|
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,90 @@
|
|
+/* -*- 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 ];
|
|
+ nsRefPtr<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);
|
|
+ nsMIMEInfoBase* retval;
|
|
+ NS_ADDREF((retval = mimeInfo));
|
|
+ return retval;
|
|
+ }
|
|
+ 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,29 @@
|
|
+/* 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 "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);
|
|
+
|
|
+};
|
|
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
|
|
@@ -16,30 +16,33 @@
|
|
#include <QString>
|
|
#if (MOZ_ENABLE_CONTENTACTION)
|
|
#include <contentaction/contentaction.h>
|
|
#include "nsContentHandlerApp.h"
|
|
#endif
|
|
#endif
|
|
|
|
#include "nsMIMEInfoUnix.h"
|
|
-#include "nsGNOMERegistry.h"
|
|
+#include "nsCommonRegistry.h"
|
|
#include "nsIGIOService.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsIIOService.h"
|
|
#include "nsIGnomeVFSService.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)
|
|
{
|
|
- nsresult rv = nsGNOMERegistry::LoadURL(aURI);
|
|
+ nsresult rv = nsCommonRegistry::LoadURL(aURI);
|
|
|
|
#if (MOZ_PLATFORM_MAEMO == 5) && defined (MOZ_ENABLE_GNOMEVFS)
|
|
if (NS_FAILED(rv)){
|
|
HildonURIAction *action = hildon_uri_get_default_action(mSchemeOrType.get(), nullptr);
|
|
if (action) {
|
|
nsAutoCString spec;
|
|
aURI->GetAsciiSpec(spec);
|
|
if (hildon_uri_open(spec.get(), action, nullptr))
|
|
@@ -61,22 +64,22 @@ nsMIMEInfoUnix::LoadUriInternal(nsIURI *
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMIMEInfoUnix::GetHasDefaultHandler(bool *_retval)
|
|
{
|
|
*_retval = false;
|
|
- nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mSchemeOrType);
|
|
+ nsRefPtr<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;
|
|
|
|
@@ -119,16 +122,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);
|
|
nsAutoCString uriSpec;
|
|
if (giovfs) {
|
|
// nsGIOMimeApp->Launch wants a URI string instead of local file
|
|
nsresult rv;
|
|
nsCOMPtr<nsIIOService> ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
nsCOMPtr<nsIURI> uri;
|
|
@@ -146,17 +166,17 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(ns
|
|
/* Fallback to GnomeVFS */
|
|
nsCOMPtr<nsIGnomeVFSMimeApp> app;
|
|
if (NS_SUCCEEDED(gnomevfs->GetAppForMimeType(mSchemeOrType, getter_AddRefs(app))) && app)
|
|
return app->Launch(nativePath);
|
|
}
|
|
|
|
// If we haven't got an app we try to get a valid one by searching for the
|
|
// extension mapped type
|
|
- nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromExtension(nativePath);
|
|
+ nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromExtension(nativePath);
|
|
if (mimeInfo) {
|
|
nsAutoCString type;
|
|
mimeInfo->GetType(type);
|
|
if (giovfs) {
|
|
nsCOMPtr<nsIGIOMimeApp> app;
|
|
if (NS_SUCCEEDED(giovfs->GetAppForMimeType(type, getter_AddRefs(app))) && app)
|
|
return app->Launch(uriSpec);
|
|
} else if (gnomevfs) {
|
|
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_GTK2
|
|
-#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"
|
|
@@ -1157,29 +1157,29 @@ nsresult nsOSHelperAppService::OSProtoco
|
|
ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':');
|
|
|
|
if (action.isValid())
|
|
*aHandlerExists = true;
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_GTK2
|
|
// Check the GConf registry for a protocol handler
|
|
- *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
|
|
+ *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
|
|
#if (MOZ_PLATFORM_MAEMO == 5) && defined (MOZ_ENABLE_GNOMEVFS)
|
|
*aHandlerExists = nsMIMEInfoUnix::HandlerExists(aProtocolScheme);
|
|
#endif
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
|
|
{
|
|
#ifdef MOZ_WIDGET_GTK2
|
|
- 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 PRUnichar * platformAppPath, nsIFile ** aFile)
|
|
{
|
|
@@ -1265,17 +1265,17 @@ nsOSHelperAppService::GetFromExtension(c
|
|
minorType,
|
|
mime_types_description,
|
|
true);
|
|
|
|
if (NS_FAILED(rv) || majorType.IsEmpty()) {
|
|
|
|
#ifdef MOZ_WIDGET_GTK2
|
|
LOG(("Looking in GNOME registry\n"));
|
|
- nsMIMEInfoBase *gnomeInfo = nsGNOMERegistry::GetFromExtension(aFileExt).get();
|
|
+ nsMIMEInfoBase *gnomeInfo = nsCommonRegistry::GetFromExtension(aFileExt).get();
|
|
if (gnomeInfo) {
|
|
LOG(("Got MIMEInfo from GNOME registry\n"));
|
|
return gnomeInfo;
|
|
}
|
|
#endif
|
|
|
|
rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt),
|
|
majorType,
|
|
@@ -1391,17 +1391,17 @@ nsOSHelperAppService::GetFromType(const
|
|
#ifdef MOZ_WIDGET_GTK2
|
|
nsMIMEInfoBase *gnomeInfo = nullptr;
|
|
if (handler.IsEmpty()) {
|
|
// No useful data yet. Check the GNOME registry. Unfortunately, newer
|
|
// GNOME versions no longer have type-to-extension mappings, so we might
|
|
// get back a MIMEInfo without any extensions set. In that case we'll have
|
|
// to look in our mime.types files for the extensions.
|
|
LOG(("Looking in GNOME registry\n"));
|
|
- gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType).get();
|
|
+ gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType).get();
|
|
if (gnomeInfo && gnomeInfo->HasExtensions()) {
|
|
LOG(("Got MIMEInfo from GNOME registry, and it has extensions set\n"));
|
|
return gnomeInfo;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Now look up our extensions
|
|
diff --git a/widget/gtk2/Makefile.in b/widget/gtk2/Makefile.in
|
|
--- a/widget/gtk2/Makefile.in
|
|
+++ b/widget/gtk2/Makefile.in
|
|
@@ -104,11 +104,14 @@ DEFINES += -DCAIRO_GFX -DMOZ_APP_NAME='
|
|
|
|
INCLUDES += \
|
|
-I$(srcdir)/../xpwidgets \
|
|
-I$(srcdir)/../shared \
|
|
-I$(topsrcdir)/layout/generic \
|
|
-I$(topsrcdir)/layout/xul/base/src \
|
|
-I$(topsrcdir)/other-licenses/atk-1.0 \
|
|
$(NULL)
|
|
+
|
|
+LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
|
|
+
|
|
ifdef MOZ_X11
|
|
INCLUDES += -I$(srcdir)/../shared/x11
|
|
endif
|
|
diff --git a/widget/gtk2/nsFilePicker.cpp b/widget/gtk2/nsFilePicker.cpp
|
|
--- a/widget/gtk2/nsFilePicker.cpp
|
|
+++ b/widget/gtk2/nsFilePicker.cpp
|
|
@@ -1,31 +1,33 @@
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/Util.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
+#include <gdk/gdkx.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"
|
|
|
|
#if (MOZ_PLATFORM_MAEMO == 5)
|
|
#include <hildon-fm-2/hildon/hildon-file-chooser-dialog.h>
|
|
#endif
|
|
|
|
using namespace mozilla;
|
|
|
|
#define MAX_PREVIEW_SIZE 180
|
|
@@ -236,17 +238,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);
|
|
@@ -360,16 +364,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);
|
|
const gchar *accept_button = (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
|
@@ -561,8 +581,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/gtk2/nsFilePicker.h b/widget/gtk2/nsFilePicker.h
|
|
--- a/widget/gtk2/nsFilePicker.h
|
|
+++ b/widget/gtk2/nsFilePicker.h
|
|
@@ -67,11 +67,17 @@ protected:
|
|
nsString mDefault;
|
|
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 );
|
|
};
|
|
|
|
#endif
|
|
diff --git a/xpcom/components/Makefile.in b/xpcom/components/Makefile.in
|
|
--- a/xpcom/components/Makefile.in
|
|
+++ b/xpcom/components/Makefile.in
|
|
@@ -59,10 +59,11 @@ LOCAL_INCLUDES = \
|
|
# we don't want the shared lib, but we want to force the creation of a static lib.
|
|
FORCE_STATIC_LIB = 1
|
|
|
|
include $(topsrcdir)/config/rules.mk
|
|
|
|
DEFINES += -D_IMPL_NS_COM
|
|
|
|
ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
|
|
+LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
|
|
CXXFLAGS += $(MOZ_GTK2_CFLAGS)
|
|
endif
|
|
diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
|
|
--- a/xpcom/components/ManifestParser.cpp
|
|
+++ b/xpcom/components/ManifestParser.cpp
|
|
@@ -30,16 +30,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;
|
|
|
|
@@ -397,16 +398,17 @@ ParseManifest(NSLocationType type, FileL
|
|
NS_NAMED_LITERAL_STRING(kPlatform, "platform");
|
|
NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
|
|
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");
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
NS_NAMED_LITERAL_STRING(kTablet, "tablet");
|
|
#endif
|
|
|
|
// Obsolete
|
|
NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
|
|
|
|
nsAutoString appID;
|
|
@@ -444,41 +446,46 @@ ParseManifest(NSLocationType type, FileL
|
|
CopyUTF8toUTF16(s, abi);
|
|
abi.Insert(PRUnichar('_'), 0);
|
|
abi.Insert(osTarget, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
nsAutoString osVersion;
|
|
+ nsAutoString desktop;
|
|
#if defined(XP_WIN)
|
|
OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
|
|
if (GetVersionEx(&info)) {
|
|
nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
|
|
info.dwMajorVersion,
|
|
info.dwMinorVersion);
|
|
}
|
|
+ desktop = NS_LITERAL_STRING("win");
|
|
#elif defined(MOZ_WIDGET_COCOA)
|
|
SInt32 majorVersion, minorVersion;
|
|
if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
|
|
(Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
|
|
nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
|
|
majorVersion,
|
|
minorVersion);
|
|
}
|
|
+ desktop = NS_LITERAL_STRING("macosx");
|
|
#elif defined(MOZ_WIDGET_GTK2)
|
|
nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
|
|
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 = mozilla::AndroidBridge::Bridge()->IsTablet();
|
|
}
|
|
+ desktop = NS_LITERAL_STRING("android");
|
|
#endif
|
|
|
|
// Because contracts must be registered after CIDs, we save and process them
|
|
// at the end.
|
|
nsTArray<CachedDirective> contracts;
|
|
|
|
char *token;
|
|
char *newline = buf;
|
|
@@ -560,24 +567,26 @@ ParseManifest(NSLocationType type, FileL
|
|
TriState stOsVersion = eUnspecified;
|
|
TriState stOs = eUnspecified;
|
|
TriState stABI = eUnspecified;
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
TriState stTablet = eUnspecified;
|
|
#endif
|
|
bool platform = false;
|
|
bool contentAccessible = false;
|
|
+ TriState stDesktop = eUnspecified;
|
|
|
|
while (NULL != (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) ||
|
|
CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
|
|
CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
|
|
CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion))
|
|
continue;
|
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
bool tablet = false;
|
|
if (CheckFlag(kTablet, wtoken, tablet)) {
|
|
@@ -606,16 +615,17 @@ ParseManifest(NSLocationType type, FileL
|
|
}
|
|
|
|
if (!ok ||
|
|
stApp == eBad ||
|
|
stAppVersion == eBad ||
|
|
stGeckoVersion == eBad ||
|
|
stOs == eBad ||
|
|
stOsVersion == eBad ||
|
|
+ stDesktop == eBad ||
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
stTablet == eBad ||
|
|
#endif
|
|
stABI == eBad)
|
|
continue;
|
|
|
|
if (directive->regfunc) {
|
|
if (GeckoProcessType_Default != XRE_GetProcessType())
|
|
diff --git a/xpcom/io/Makefile.in b/xpcom/io/Makefile.in
|
|
--- a/xpcom/io/Makefile.in
|
|
+++ b/xpcom/io/Makefile.in
|
|
@@ -161,17 +161,17 @@ include $(topsrcdir)/ipc/chromium/chromi
|
|
DEFINES += -D_IMPL_NS_COM
|
|
|
|
ifeq ($(OS_ARCH),Linux)
|
|
ifneq (,$(findstring lib64,$(libdir)))
|
|
DEFINES += -DHAVE_USR_LIB64_DIR
|
|
endif
|
|
endif
|
|
|
|
-LOCAL_INCLUDES += -I..
|
|
+LOCAL_INCLUDES += -I.. -I$(topsrcdir)/toolkit/xre
|
|
|
|
ifeq ($(MOZ_PLATFORM_MAEMO),5)
|
|
CFLAGS += $(MOZ_DBUS_CFLAGS)
|
|
CXXFLAGS += $(MOZ_DBUS_CFLAGS)
|
|
endif
|
|
|
|
ifdef MOZ_PLATFORM_MAEMO
|
|
CFLAGS += $(MOZ_PLATFORM_MAEMO_CFLAGS) $(MOZ_QT_CFLAGS)
|
|
diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
|
|
--- a/xpcom/io/nsLocalFileUnix.cpp
|
|
+++ b/xpcom/io/nsLocalFileUnix.cpp
|
|
@@ -50,16 +50,17 @@
|
|
#include "prproces.h"
|
|
#include "nsIDirectoryEnumerator.h"
|
|
#include "nsISimpleEnumerator.h"
|
|
#include "private/pprio.h"
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
#include "nsIGIOService.h"
|
|
#include "nsIGnomeVFSService.h"
|
|
+#include "nsKDEUtils.h"
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
#include <Carbon/Carbon.h>
|
|
#include "CocoaFileUtils.h"
|
|
#include "prmem.h"
|
|
#include "plbase64.h"
|
|
|
|
@@ -1752,44 +1753,51 @@ nsLocalFile::SetPersistentDescriptor(con
|
|
return InitWithNativePath(aPersistentDescriptor);
|
|
#endif
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsLocalFile::Reveal()
|
|
{
|
|
#ifdef MOZ_WIDGET_GTK
|
|
- nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
|
|
- nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
|
|
- if (!giovfs && !gnomevfs)
|
|
- return NS_ERROR_FAILURE;
|
|
-
|
|
+ nsAutoCString url;
|
|
bool isDirectory;
|
|
if (NS_FAILED(IsDirectory(&isDirectory)))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (isDirectory) {
|
|
- if (giovfs)
|
|
- return giovfs->ShowURIForInput(mPath);
|
|
- else
|
|
- /* Fallback to GnomeVFS */
|
|
- return gnomevfs->ShowURIForInput(mPath);
|
|
+ url = mPath;
|
|
} 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;
|
|
|
|
- if (giovfs)
|
|
- return giovfs->ShowURIForInput(dirPath);
|
|
- else
|
|
- return gnomevfs->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;
|
|
+ }
|
|
+
|
|
+ nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
|
|
+ nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
|
|
+ if (!giovfs && !gnomevfs)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ if (giovfs)
|
|
+ return giovfs->ShowURIForInput(url);
|
|
+ else
|
|
+ return gnomevfs->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;
|
|
@@ -1815,16 +1823,23 @@ nsLocalFile::Launch()
|
|
|
|
if (nullptr == connection)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (hildon_mime_open_file(connection, mPath.get()) != kHILDON_SUCCESS)
|
|
return NS_ERROR_FAILURE;
|
|
return NS_OK;
|
|
#else
|
|
+ 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);
|
|
nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
|
|
if (giovfs) {
|
|
return giovfs->ShowURIForInput(mPath);
|
|
} else if (gnomevfs) {
|
|
/* GnomeVFS fallback */
|
|
return gnomevfs->ShowURIForInput(mPath);
|
|
}
|