Search
j0ke.net Open Build Service
>
Projects
>
internetx
:
desktop
>
firefox6
> mozilla-kde.patch
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File mozilla-kde.patch of Package firefox6
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 @@ -87,14 +87,16 @@ GREPREF_FILES = $(topsrcdir)/netwerk/bas # 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 @@ -53,16 +53,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 "prmem.h" #include "pldhash.h" #include "prefapi.h" #include "prefread.h" #include "prefapi_private_data.h" @@ -822,30 +823,48 @@ 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> dirList; dirSvc->Get(listId, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList)); if (dirList) { PRBool hasMore; while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) && hasMore) { nsCOMPtr<nsISupports> elem; dirList->GetNext(getter_AddRefs(elem)); if (elem) { nsCOMPtr<nsIFile> dir = do_QueryInterface(elem); if (dir) { // Do we care if a file provided by this process fails to load? - pref_LoadPrefsInDir(dir, nsnull, 0); + pref_LoadPrefsInDir(dir, specialFiles, NS_ARRAY_LENGTH(specialFiles)); } } } } return NS_OK; } static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name) @@ -938,28 +957,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, NS_ARRAY_LENGTH(specialFiles)); if (NS_FAILED(rv)) NS_WARNING("Error parsing application default preferences."); } // Load jar:$app/omni.jar!/defaults/preferences/*.js nsZipArchive *appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP); if (appJarReader) { 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 @@ -79,8 +79,10 @@ endif ifdef ENABLE_TESTS DIRS += test endif include $(topsrcdir)/config/rules.mk EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp --- a/toolkit/components/downloads/nsDownloadManager.cpp +++ b/toolkit/components/downloads/nsDownloadManager.cpp @@ -71,16 +71,20 @@ #ifdef XP_WIN #include <shlobj.h> #ifdef DOWNLOAD_SCANNER #include "nsDownloadScanner.h" #endif #endif +#if defined(XP_UNIX) && !defined(XP_MACOSX) +#include "nsKDEUtils.h" +#endif + #ifdef XP_MACOSX #include <CoreFoundation/CoreFoundation.h> #endif #ifdef ANDROID #include "AndroidBridge.h" #endif @@ -2192,16 +2196,25 @@ nsDownload::SetState(DownloadState aStat nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID)); // Master pref to control this function. PRBool showTaskbarAlert = PR_TRUE; if (pref) pref->GetBoolPref(PREF_BDM_SHOWALERTONCOMPLETE, &showTaskbarAlert); if (showTaskbarAlert) { + if( nsKDEUtils::kdeSupport()) { + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "DOWNLOADFINISHED" )); + nsAutoString displayName; + GetDisplayName( displayName ); + command.AppendCString( nsCAutoString( ToNewUTF8String( displayName ))); + nsKDEUtils::command( command ); + } else { + // begin non-KDE block PRInt32 alertInterval = 2000; if (pref) pref->GetIntPref(PREF_BDM_SHOWALERTINTERVAL, &alertInterval); PRInt64 alertIntervalUSec = alertInterval * PR_USEC_PER_MSEC; PRInt64 goat = PR_Now() - mStartTime; showTaskbarAlert = goat > alertIntervalUSec; @@ -2225,19 +2238,20 @@ nsDownload::SetState(DownloadState aStat // If downloads are automatically removed per the user's // retention policy, there's no reason to make the text clickable // because if it is, they'll click open the download manager and // the items they downloaded will have been removed. alerts->ShowAlertNotification( NS_LITERAL_STRING(DOWNLOAD_MANAGER_ALERT_ICON), title, message, !removeWhenDone, EmptyString(), mDownloadManager, EmptyString()); - } + } } } + } #if defined(XP_WIN) || defined(XP_MACOSX) || defined(ANDROID) nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget); nsCOMPtr<nsIFile> file; nsAutoString path; if (fileURL && NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) && diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -40,29 +40,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,447 @@ +<?xml version="1.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.getPreventDefault()) + 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.getPreventDefault()) + 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,1371 @@ +<?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 = null; + } + } + + 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. + 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 -*- +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Preferences System. +# +# The Initial Developer of the Original Code is +# Ben Goodger. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ben Goodger <ben@mozilla.org> +# Josh Aas <josh@mozilla.com> +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# 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 @@ -44,32 +44,35 @@ #include "nsIURI.h" #include "nsReadableUtils.h" #include "nsArrayUtils.h" #include "prnetdb.h" #include "prenv.h" #include "nsPrintfCString.h" #include "nsNetUtil.h" #include "nsISupportsPrimitives.h" +#include "nsVoidArray.h" +#include "nsKDEUtils.h" class nsUnixSystemProxySettings : public nsISystemProxySettings { public: NS_DECL_ISUPPORTS NS_DECL_NSISYSTEMPROXYSETTINGS nsUnixSystemProxySettings() {} nsresult Init(); private: ~nsUnixSystemProxySettings() {} nsCOMPtr<nsIGConfService> mGConf; PRBool IsProxyMode(const char* aMode); nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult); nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, PRInt32 aPort, nsACString& aResult); + nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost, PRInt32 aPort, nsACString& aResult); }; NS_IMPL_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings) nsresult nsUnixSystemProxySettings::Init() { // If this is a GNOME session, load gconf and try to use its preferences. @@ -407,16 +410,19 @@ nsUnixSystemProxySettings::GetProxyForUR nsCAutoString host; rv = aURI->GetHost(host); NS_ENSURE_SUCCESS(rv, rv); PRInt32 port; rv = aURI->GetPort(&port); NS_ENSURE_SUCCESS(rv, rv); + if( nsKDEUtils::kdeSupport()) + return GetProxyFromKDE( scheme, host, port, aResult ); + if (!mGConf) return GetProxyFromEnvironment(scheme, host, port, aResult); return GetProxyFromGConf(scheme, host, port, aResult); } #define NS_UNIXSYSTEMPROXYSERVICE_CID /* 0fa3158c-d5a7-43de-9181-a285e74cf1d4 */\ { 0x0fa3158c, 0xd5a7, 0x43de, \ @@ -437,8 +443,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) +{ + nsCAutoString url; + url = aScheme; + url += "://"; + url += aHost; + if( aPort >= 0 ) + { + url += ":"; + url += nsPrintfCString("%d", aPort); + } + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "GETPROXY" )); + command.AppendCString( url ); + nsCStringArray result; + if( !nsKDEUtils::command( command, &result ) || result.Count() != 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 @@ -97,17 +97,18 @@ EXPORTS = nsWindowsDllInterceptor.h else ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) CMMSRCS = nsNativeAppSupportCocoa.mm 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) CPPSRCS += nsNativeAppSupportQt.cpp CPPSRCS += nsQAppInstance.cpp EXPORTS += nsQAppInstance.h else CPPSRCS += nsNativeAppSupportDefault.cpp endif 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,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Unix Native App Support. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsKDEUtils.h" +#include "nsIWidget.h" + +#include <gtk/gtk.h> + +#include <limits.h> +#include <stdio.h> +#include <sys/wait.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() + { + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "CHECK" )); + command.AppendCString( 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; + nsCStringArray* 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 ); + nsCAutoString line( buf ); + line.ReplaceSubstring( "\\n", "\n" ); + line.ReplaceSubstring( "\\" "\\", "\\" ); // \\ -> \ , i.e. unescape + if( p->output && !( command_done || command_failed )) + p->output->AppendCString( 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 nsCStringArray& command, nsCStringArray* output ) + { + return self()->internalCommand( command, NULL, false, output ); + } + +bool nsKDEUtils::commandBlockUi( const nsCStringArray& command, const GtkWindow* parent, nsCStringArray* output ) + { + return self()->internalCommand( command, parent, true, output ); + } + +bool nsKDEUtils::internalCommand( const nsCStringArray& command, const GtkWindow* parent, bool blockUi, + nsCStringArray* 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 nsCStringArray& command ) + { + for( int i = 0; + i < command.Count(); + ++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,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsKDEUtils_h__ +#define nsKDEUtils_h__ + +#include "nsStringGlue.h" +#include "nsVoidArray.h" +#include <stdio.h> + +typedef struct _GtkWindow GtkWindow; + +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 nsCStringArray& command, nsCStringArray* 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 nsCStringArray& command, const GtkWindow* parent, nsCStringArray* output = NULL ); + private: + nsKDEUtils(); + ~nsKDEUtils(); + static nsKDEUtils* self(); + bool startHelper(); + void closeHelper(); + void feedCommand( const nsCStringArray& command ); + bool internalCommand( const nsCStringArray& command, const GtkWindow* parent, bool isParent, + nsCStringArray* 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 @@ -88,18 +88,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,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the GNOME helper app implementation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsCommonRegistry.h" + +#include "nsGNOMERegistry.h" +#include "nsKDERegistry.h" +#include "nsString.h" +#include "nsVoidArray.h" +#include "nsKDEUtils.h" + +/* static */ PRBool +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,56 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the GNOME helper app implementation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIURI.h" +#include "nsCOMPtr.h" + +class nsMIMEInfoBase; + +class nsCommonRegistry +{ + public: + static PRBool 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,119 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the GNOME helper app implementation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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 */ PRBool +nsKDERegistry::HandlerExists(const char *aProtocolScheme) +{ + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "HANDLEREXISTS" )); + command.AppendCString( nsCAutoString( aProtocolScheme )); + return nsKDEUtils::command( command ); +} + +/* static */ nsresult +nsKDERegistry::LoadURL(nsIURI *aURL) +{ + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "OPEN" )); + nsCString url; + aURL->GetSpec( url ); + command.AppendCString( url ); + return nsKDEUtils::command( command ); +} + +/* static */ void +nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme, + nsAString& aDesc) +{ + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "GETAPPDESCFORSCHEME" )); + command.AppendCString( aScheme ); + nsCStringArray output; + if( nsKDEUtils::command( command, &output ) && output.Count() == 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"); + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "GETFROMEXTENSION" )); + command.AppendCString( aFileExt ); + return GetFromHelper( command ); +} + +/* static */ already_AddRefed<nsMIMEInfoBase> +nsKDERegistry::GetFromType(const nsACString& aMIMEType) +{ + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "GETFROMTYPE" )); + command.AppendCString( aMIMEType ); + return GetFromHelper( command ); +} + +/* static */ already_AddRefed<nsMIMEInfoBase> +nsKDERegistry::GetFromHelper(const nsCStringArray& command) +{ + nsCStringArray output; + if( nsKDEUtils::command( command, &output ) && output.Count() == 3 ) + { + nsCString mimetype = *output[ 0 ]; + nsRefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix( mimetype ); + NS_ENSURE_TRUE(mimeInfo, nsnull); + 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 nsnull; +} 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,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the GNOME helper app implementation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIURI.h" +#include "nsCOMPtr.h" + +class nsMIMEInfoBase; +class nsCAutoString; +class nsCStringArray; + +class nsKDERegistry +{ + public: + static PRBool 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 nsCStringArray& 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 @@ -50,30 +50,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(), nsnull); if (action) { nsCAutoString spec; aURI->GetAsciiSpec(spec); if (hildon_uri_open(spec.get(), action, nsnull)) @@ -95,22 +98,22 @@ nsMIMEInfoUnix::LoadUriInternal(nsIURI * return rv; } NS_IMETHODIMP nsMIMEInfoUnix::GetHasDefaultHandler(PRBool *_retval) { *_retval = PR_FALSE; - nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mSchemeOrType); + nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromType(mSchemeOrType); if (!mimeInfo) { nsCAutoString ext; nsresult rv = GetPrimaryExtension(ext); if (NS_SUCCEEDED(rv)) { - mimeInfo = nsGNOMERegistry::GetFromExtension(ext); + mimeInfo = nsCommonRegistry::GetFromExtension(ext); } } if (mimeInfo) *_retval = PR_TRUE; if (*_retval) return NS_OK; @@ -153,16 +156,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()) { + PRBool supports; + if( NS_SUCCEEDED( GetHasDefaultHandler( &supports )) && supports ) { + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "OPEN" )); + command.AppendCString( nativePath ); + command.AppendCString( NS_LITERAL_CSTRING( "MIMETYPE" )); + command.AppendCString( 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); nsCAutoString 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; @@ -180,17 +200,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) { nsCAutoString 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 @@ -44,17 +44,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" @@ -1219,29 +1219,29 @@ nsresult nsOSHelperAppService::OSProtoco ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':'); if (action.isValid()) *aHandlerExists = PR_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) { @@ -1327,17 +1327,17 @@ nsOSHelperAppService::GetFromExtension(c minorType, mime_types_description, PR_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, @@ -1453,17 +1453,17 @@ nsOSHelperAppService::GetFromType(const #ifdef MOZ_WIDGET_GTK2 nsMIMEInfoBase *gnomeInfo = nsnull; 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/src/gtk2/Makefile.in b/widget/src/gtk2/Makefile.in --- a/widget/src/gtk2/Makefile.in +++ b/widget/src/gtk2/Makefile.in @@ -158,11 +158,14 @@ endif DEFINES += -DCAIRO_GFX INCLUDES += \ -I$(srcdir)/../xpwidgets \ -I$(srcdir)/../shared \ -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/src/gtk2/nsFilePicker.cpp b/widget/src/gtk2/nsFilePicker.cpp --- a/widget/src/gtk2/nsFilePicker.cpp +++ b/widget/src/gtk2/nsFilePicker.cpp @@ -31,16 +31,17 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include <gtk/gtk.h> +#include <gdk/gdkx.h> #include "nsIFileURL.h" #include "nsIURI.h" #include "nsIWidget.h" #include "nsILocalFile.h" #include "nsIStringBundle.h" #include "nsArrayEnumerator.h" @@ -50,16 +51,17 @@ #include "nsReadableUtils.h" #include "mozcontainer.h" #include "prmem.h" #include "prlink.h" #include "nsFilePicker.h" #include "nsAccessibilityHelper.h" +#include "nsKDEUtils.h" #if (MOZ_PLATFORM_MAEMO == 5) #include <hildon-fm-2/hildon/hildon-file-chooser-dialog.h> #endif #define MAX_PREVIEW_SIZE 180 nsILocalFile *nsFilePicker::mPrevDisplayDirectory = nsnull; @@ -271,17 +273,19 @@ nsFilePicker::AppendFilters(PRInt32 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; } nsCAutoString filter, name; CopyUTF16toUTF8(aFilter, filter); CopyUTF16toUTF8(aTitle, name); mFilters.AppendElement(filter); mFilterNames.AppendElement(name); @@ -419,16 +423,19 @@ confirm_overwrite_file(GtkWidget *parent gtk_widget_destroy(dialog); return result; } NS_IMETHODIMP nsFilePicker::Show(PRInt16 *aReturn) { + if( nsKDEUtils::kdeSupport()) + return kdeFileDialog( aReturn ); + NS_ENSURE_ARG_POINTER(aReturn); nsXPIDLCString title; title.Adopt(ToNewUTF8String(mTitle)); GtkWindow *parent_widget = get_gtk_window_for_nsiwidget(mParentWidget); GtkFileChooserAction action = GetGtkFileChooserAction(mMode); @@ -569,8 +576,234 @@ nsFilePicker::Show(PRInt16 *aReturn) *aReturn = nsIFilePicker::returnCancel; break; } gtk_widget_destroy(file_chooser); return NS_OK; } + +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 = get_gtk_window_for_nsiwidget( widget ); + 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; + } + } + + nsCAutoString directory; + if (mDisplayDirectory) { + mDisplayDirectory->GetNativePath(directory); + } else if (mPrevDisplayDirectory) { + mPrevDisplayDirectory->GetNativePath(directory); + } + + nsCAutoString 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 = "."; + + nsCAutoString 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 ); + } + } + + nsCStringArray command; + command.AppendCString( nsCAutoString( arg )); + command.AppendCString( startdir ); + if( mMode != nsIFilePicker::modeGetFolder ) + { + command.AppendCString( filters ); + nsCAutoString selected; + selected.AppendInt( mSelectedType ); + command.AppendCString( selected ); + } + command.AppendCString( title ); + if( mMode == nsIFilePicker::modeOpenMultiple ) + command.AppendCString( NS_LITERAL_CSTRING( "MULTIPLE" )); + if( PRInt32 xid = windowToXid( mParentWidget )) + { + command.AppendCString( NS_LITERAL_CSTRING( "PARENT" )); + nsCAutoString parent; + parent.AppendInt( xid ); + command.AppendCString( parent ); + } + + nsCStringArray output; + if( nsKDEUtils::commandBlockUi( command, get_gtk_window_for_nsiwidget( mParentWidget ), &output )) + { + *aReturn = nsIFilePicker::returnOK; + mFiles.Clear(); + if( mMode != nsIFilePicker::modeGetFolder ) + { + mSelectedType = atoi( output[ 0 ]->get()); + output.RemoveCStringAt( 0 ); + } + if (mMode == nsIFilePicker::modeOpenMultiple) + { + mFileURL.Truncate(); + PRUint32 count = output.Count(); + for( PRUint32 i = 0; + i < count; + ++i ) + { + nsCOMPtr<nsILocalFile> localfile; + nsresult rv = NS_NewNativeLocalFile( *output[ i ], + PR_FALSE, + getter_AddRefs(localfile)); + if (NS_SUCCEEDED(rv)) + mFiles.AppendObject(localfile); + } + } + else + { + if( output.Count() == 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<nsILocalFile> file; + GetFile(getter_AddRefs(file)); + if (file) { + nsCOMPtr<nsIFile> dir; + file->GetParent(getter_AddRefs(dir)); + nsCOMPtr<nsILocalFile> localDir(do_QueryInterface(dir)); + if (localDir) { + localDir.swap(mPrevDisplayDirectory); + } + } + if (mMode == nsIFilePicker::modeSave) + { + nsCOMPtr<nsILocalFile> file; + GetFile(getter_AddRefs(file)); + if (file) + { + PRBool exists = PR_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)); + + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "APPSDIALOG" )); + command.AppendCString( title ); + if( PRInt32 xid = windowToXid( mParentWidget )) + { + command.AppendCString( NS_LITERAL_CSTRING( "PARENT" )); + nsCAutoString parent; + parent.AppendInt( xid ); + command.AppendCString( parent ); + } + + nsCStringArray output; + if( nsKDEUtils::commandBlockUi( command, get_gtk_window_for_nsiwidget( mParentWidget ), &output )) + { + *aReturn = nsIFilePicker::returnOK; + mFileURL = output.Count() > 0 ? *output[ 0 ] : nsCString(); + } + else + { + *aReturn = nsIFilePicker::returnCancel; + } + return NS_OK; + } diff --git a/widget/src/gtk2/nsFilePicker.h b/widget/src/gtk2/nsFilePicker.h --- a/widget/src/gtk2/nsFilePicker.h +++ b/widget/src/gtk2/nsFilePicker.h @@ -89,11 +89,17 @@ protected: nsString mDefault; nsString mDefaultExtension; nsTArray<nsCString> mFilters; nsTArray<nsCString> mFilterNames; private: static nsILocalFile *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 @@ -94,10 +94,11 @@ FORCE_STATIC_LIB = 1 # Force use of PIC FORCE_USE_PIC = 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 @@ -59,16 +59,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" struct ManifestDirective { const char* directive; int argc; // Some directives should only be delivered for NS_COMPONENT_LOCATION // manifests. @@ -426,16 +427,17 @@ ParseManifestCommon(NSLocationType aType 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(kOs, "os"); NS_NAMED_LITERAL_STRING(kOsVersion, "osversion"); NS_NAMED_LITERAL_STRING(kABI, "abi"); + NS_NAMED_LITERAL_STRING(kDesktop, "desktop"); // Obsolete NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers"); nsAutoString appID; nsAutoString appVersion; nsAutoString osTarget; nsAutoString abi; @@ -465,39 +467,44 @@ ParseManifestCommon(NSLocationType aType 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(XP_MACOSX) 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(ANDROID) if (mozilla::AndroidBridge::Bridge()) { mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", osVersion); } + 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; @@ -566,24 +573,26 @@ ParseManifestCommon(NSLocationType aType bool ok = true; TriState stAppVersion = eUnspecified; TriState stApp = eUnspecified; TriState stOsVersion = eUnspecified; TriState stOs = eUnspecified; TriState stABI = eUnspecified; 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)) continue; if (directive->contentflags && (CheckFlag(kPlatform, wtoken, platform) || CheckFlag(kContentAccessible, wtoken, contentAccessible))) continue; @@ -602,16 +611,17 @@ ParseManifestCommon(NSLocationType aType ok = false; } if (!ok || stApp == eBad || stAppVersion == eBad || stOs == eBad || stOsVersion == eBad || + stDesktop == eBad || stABI == eBad) continue; if (directive->regfunc) { if (GeckoProcessType_Default != XRE_GetProcessType()) continue; if (!nsChromeRegistry::gChromeRegistry) { diff --git a/xpcom/io/Makefile.in b/xpcom/io/Makefile.in --- a/xpcom/io/Makefile.in +++ b/xpcom/io/Makefile.in @@ -192,17 +192,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 @@ -88,16 +88,17 @@ #include "prproces.h" #include "nsIDirectoryEnumerator.h" #include "nsISimpleEnumerator.h" #include "nsITimelineService.h" #ifdef MOZ_WIDGET_GTK2 #include "nsIGIOService.h" #include "nsIGnomeVFSService.h" +#include "nsKDEUtils.h" #endif #ifdef XP_MACOSX #include <Carbon/Carbon.h> #include "CocoaFileUtils.h" #include "prmem.h" #include "plbase64.h" @@ -1769,44 +1770,50 @@ nsLocalFile::SetPersistentDescriptor(con return InitWithNativePath(aPersistentDescriptor); #endif } NS_IMETHODIMP nsLocalFile::Reveal() { #ifdef MOZ_WIDGET_GTK2 - nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); - nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID); - if (!giovfs && !gnomevfs) - return NS_ERROR_FAILURE; - + nsCAutoString url; PRBool 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; nsCAutoString 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()) { + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "OPEN" )); + command.AppendCString( url ); + 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(XP_MACOSX) CFURLRef url; if (NS_SUCCEEDED(GetCFURL(&url))) { nsresult rv = CocoaFileUtils::RevealFileInFinder(url); ::CFRelease(url); return rv; } return NS_ERROR_FAILURE; @@ -1832,16 +1839,23 @@ nsLocalFile::Launch() if (nsnull == 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()) { + nsCStringArray command; + command.AppendCString( NS_LITERAL_CSTRING( "OPEN" )); + command.AppendCString( 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); }