--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mozilla-kde.patch Mon Nov 30 13:11:31 2009 +0100
@@ -0,0 +1,4038 @@
+diff --git a/chrome/src/Makefile.in b/chrome/src/Makefile.in
+--- a/chrome/src/Makefile.in
++++ b/chrome/src/Makefile.in
+@@ -81,16 +81,17 @@ CPPSRCS = \
+
+ EXTRA_DSO_LDOPTS = \
+ $(MOZ_UNICHARUTIL_LIBS) \
+ $(MOZ_COMPONENT_LIBS) \
+ $(NULL)
+
+ ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
+ EXTRA_DSO_LDOPTS += $(MOZ_GTK2_LIBS)
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
+ endif
+
+ ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
+ EXTRA_DSO_LDOPTS += $(TK_LIBS)
+ endif
+
+ include $(topsrcdir)/config/rules.mk
+
+diff --git a/chrome/src/nsChromeRegistry.cpp b/chrome/src/nsChromeRegistry.cpp
+--- a/chrome/src/nsChromeRegistry.cpp
++++ b/chrome/src/nsChromeRegistry.cpp
+@@ -109,16 +109,17 @@
+ #include "nsIStyleSheet.h"
+ #include "nsISupportsArray.h"
+ #include "nsIVersionComparator.h"
+ #include "nsIWindowMediator.h"
+ #include "nsIXPConnect.h"
+ #include "nsIXULAppInfo.h"
+ #include "nsIXULRuntime.h"
+ #include "nsPresShellIterator.h"
++#include "nsKDEUtils.h"
+
+ #define UILOCALE_CMD_LINE_ARG "UILocale"
+
+ #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
+ #define SELECTED_LOCALE_PREF "general.useragent.locale"
+ #define SELECTED_SKIN_PREF "general.skins.selectedSkin"
+
+ static NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID);
+@@ -1607,16 +1608,17 @@ nsChromeRegistry::ProcessManifestBuffer(
+
+ NS_NAMED_LITERAL_STRING(kPlatform, "platform");
+ NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
+ 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(kDesktop, "desktop");
+
+ nsCOMPtr<nsIIOService> io (do_GetIOService());
+ if (!io) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIProtocolHandler> ph;
+ rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+@@ -1650,35 +1652,39 @@ nsChromeRegistry::ProcessManifestBuffer(
+ if (NS_SUCCEEDED(rv)) {
+ CopyUTF8toUTF16(s, osTarget);
+ ToLowerCase(osTarget);
+ }
+ }
+ }
+
+ 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)
+ long 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"); // TODO others?
+ #endif
+
+ char *token;
+ char *newline = buf;
+ PRUint32 line = 0;
+
+ // outer loop tokenizes by newline
+ while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
+@@ -1712,41 +1718,43 @@ nsChromeRegistry::ProcessManifestBuffer(
+
+ PRBool platform = PR_FALSE;
+ PRBool xpcNativeWrappers = PR_TRUE;
+ PRBool contentAccessible = PR_FALSE;
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOsVersion = eUnspecified;
+ TriState stOs = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckFlag(kPlatform, wtoken, platform) ||
+ CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
+ CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
+ CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsCOMPtr<nsIURI> resolved;
+ rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+ getter_AddRefs(resolved));
+ if (NS_FAILED(rv))
+ continue;
+
+@@ -1797,38 +1805,40 @@ nsChromeRegistry::ProcessManifestBuffer(
+ }
+
+ EnsureLowerCase(package);
+
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOs = eUnspecified;
+ TriState stOsVersion = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsCOMPtr<nsIURI> resolved;
+ rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+ getter_AddRefs(resolved));
+ if (NS_FAILED(rv))
+ continue;
+
+@@ -1859,38 +1869,40 @@ nsChromeRegistry::ProcessManifestBuffer(
+ }
+
+ EnsureLowerCase(package);
+
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOs = eUnspecified;
+ TriState stOsVersion = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsCOMPtr<nsIURI> resolved;
+ rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+ getter_AddRefs(resolved));
+ if (NS_FAILED(rv))
+ continue;
+
+@@ -1923,38 +1935,40 @@ nsChromeRegistry::ProcessManifestBuffer(
+ "Warning: malformed chrome overlay instruction.");
+ continue;
+ }
+
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOs = eUnspecified;
+ TriState stOsVersion = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsCOMPtr<nsIURI> baseuri, overlayuri;
+ rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
+ getter_AddRefs(baseuri));
+ rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
+ getter_AddRefs(overlayuri));
+ if (NS_FAILED(rv)) {
+@@ -1979,38 +1993,40 @@ nsChromeRegistry::ProcessManifestBuffer(
+ "Warning: malformed chrome style instruction.");
+ continue;
+ }
+
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOs = eUnspecified;
+ TriState stOsVersion = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsCOMPtr<nsIURI> baseuri, overlayuri;
+ rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
+ getter_AddRefs(baseuri));
+ rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
+ getter_AddRefs(overlayuri));
+ if (NS_FAILED(rv))
+@@ -2039,38 +2055,40 @@ nsChromeRegistry::ProcessManifestBuffer(
+ "Warning: malformed chrome override instruction.");
+ continue;
+ }
+
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOs = eUnspecified;
+ TriState stOsVersion = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsCOMPtr<nsIURI> chromeuri, resolveduri;
+ rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
+ getter_AddRefs(chromeuri));
+ rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
+ getter_AddRefs(resolveduri));
+ if (NS_FAILED(rv))
+@@ -2101,38 +2119,40 @@ nsChromeRegistry::ProcessManifestBuffer(
+ }
+
+ EnsureLowerCase(package);
+
+ TriState stAppVersion = eUnspecified;
+ TriState stApp = eUnspecified;
+ TriState stOsVersion = eUnspecified;
+ TriState stOs = eUnspecified;
++ TriState stDesktop = eUnspecified;
+
+ PRBool badFlag = PR_FALSE;
+
+ while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+ !badFlag) {
+ NS_ConvertASCIItoUTF16 wtoken(token);
+ ToLowerCase(wtoken);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+ continue;
+
+ LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+ "Warning: Unrecognized chrome registration modifier '%s'.",
+ token);
+ badFlag = PR_TRUE;
+ }
+
+ if (badFlag || stApp == eBad || stAppVersion == eBad ||
+- stOs == eBad || stOsVersion == eBad)
++ stOs == eBad || stOsVersion == eBad || stDesktop == eBad)
+ continue;
+
+ nsDependentCString host(package);
+
+ PRBool exists;
+ rv = rph->HasSubstitution(host, &exists);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (exists) {
+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
+@@ -97,8 +97,10 @@ GARBAGE += $(addprefix $(DIST)/bin/defa
+
+ # 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
+diff --git a/modules/libpref/src/nsPrefService.cpp b/modules/libpref/src/nsPrefService.cpp
+--- a/modules/libpref/src/nsPrefService.cpp
++++ b/modules/libpref/src/nsPrefService.cpp
+@@ -47,16 +47,17 @@
+ #include "nsILocalFile.h"
+ #include "nsIObserverService.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"
+@@ -610,17 +611,18 @@ pref_LoadPrefsInDir(nsIFile* aDir, char
+ rv = rv2;
+ }
+ }
+ }
+
+ return rv;
+ }
+
+-static nsresult pref_LoadPrefsInDirList(const char *listId)
++static nsresult pref_LoadPrefsInDirList(const char *listId,
++ char const *const *aSpecialFiles = NULL, PRUint32 aSpecialFilesCount = 0)
+ {
+ nsresult rv;
+ nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsISimpleEnumerator> dirList;
+ dirSvc->Get(listId,
+ NS_GET_IID(nsISimpleEnumerator),
+@@ -629,17 +631,17 @@ static nsresult pref_LoadPrefsInDirList(
+ 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, aSpecialFiles, aSpecialFilesCount);
+ }
+ }
+ }
+ }
+ return NS_OK;
+ }
+
+ //----------------------------------------------------------------------------------------
+@@ -680,29 +682,41 @@ static nsresult pref_InitInitialObjects(
+ #if defined(VMS)
+ , "openvms.js"
+ #elif defined(_AIX)
+ , "aix.js"
+ #endif
+ #if defined(MOZ_WIDGET_PHOTON)
+ , "photon.js"
+ #endif
++ , "" // placeholder for KDE (empty is otherwise harmless)
+ #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.");
+ }
+
+- rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
++ rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST, specialFiles, NS_ARRAY_LENGTH(specialFiles));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
+ nsnull, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
+
+ nsCOMPtr<nsIObserverService> observerService =
+ do_GetService("@mozilla.org/observer-service;1", &rv);
+
+diff --git a/toolkit/components/downloads/src/Makefile.in b/toolkit/components/downloads/src/Makefile.in
+--- a/toolkit/components/downloads/src/Makefile.in
++++ b/toolkit/components/downloads/src/Makefile.in
+@@ -92,8 +92,9 @@ EXTRA_COMPONENTS = \
+ nsDownloadManagerUI.js \
+ $(NULL)
+ endif
+
+ include $(topsrcdir)/config/rules.mk
+
+ EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS)
+
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
+diff --git a/toolkit/components/downloads/src/nsDownloadManager.cpp b/toolkit/components/downloads/src/nsDownloadManager.cpp
+--- a/toolkit/components/downloads/src/nsDownloadManager.cpp
++++ b/toolkit/components/downloads/src/nsDownloadManager.cpp
+@@ -71,16 +71,20 @@
+
+ #if defined(XP_WIN) && !defined(WINCE)
+ #include <shlobj.h>
+ #ifdef DOWNLOAD_SCANNER
+ #include "nsDownloadScanner.h"
+ #endif
+ #endif
+
++#if defined(XP_UNIX) && !defined(XP_MACOSX)
++#include "nsKDEUtils.h"
++#endif
++
+ #define DOWNLOAD_MANAGER_BUNDLE "chrome://mozapps/locale/downloads/downloads.properties"
+ #define DOWNLOAD_MANAGER_ALERT_ICON "chrome://mozapps/skin/downloads/downloadIcon.png"
+ #define PREF_BDM_SHOWALERTONCOMPLETE "browser.download.manager.showAlertOnComplete"
+ #define PREF_BDM_SHOWALERTINTERVAL "browser.download.manager.showAlertInterval"
+ #define PREF_BDM_RETENTION "browser.download.manager.retention"
+ #define PREF_BDM_QUITBEHAVIOR "browser.download.manager.quitBehavior"
+ #define PREF_BDM_ADDTORECENTDOCS "browser.download.manager.addToRecentDocs"
+ #define PREF_BDM_SCANWHENDONE "browser.download.manager.scanWhenDone"
+@@ -2158,16 +2162,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;
+
+@@ -2193,16 +2206,17 @@ nsDownload::SetState(DownloadState aStat
+ // 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());
+ }
+ }
++ } // end non-KDE block
+ }
+ #if defined(XP_WIN) && !defined(WINCE)
+ 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
+@@ -44,29 +44,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,445 @@
++<?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;
++ 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 "disclosue":
++ 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/Makefile.in b/toolkit/system/unixproxy/Makefile.in
+--- a/toolkit/system/unixproxy/Makefile.in
++++ b/toolkit/system/unixproxy/Makefile.in
+@@ -54,16 +54,18 @@ LIBXUL_LIBRARY = 1
+
+ REQUIRES = \
+ xpcom \
+ string \
+ necko \
+ mozgnome \
+ $(NULL)
+
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
++
+ EXTRA_DSO_LDOPTS += \
+ $(MOZ_LIBPROXY_LIBS) \
+ $(MOZ_COMPONENT_LIBS) \
+ $(NULL)
+
+ ifdef MOZ_ENABLE_LIBPROXY
+
+ CPPSRCS = \
+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, \
+@@ -427,8 +433,33 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUn
+ static const nsModuleComponentInfo components[] = {
+ { "Unix System Proxy Settings Service",
+ NS_UNIXSYSTEMPROXYSERVICE_CID,
+ NS_SYSTEMPROXYSETTINGS_CONTRACTID,
+ nsUnixSystemProxySettingsConstructor }
+ };
+
+ NS_IMPL_NSGETMODULE(nsUnixProxyModule, components)
++
++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
+@@ -131,17 +131,17 @@ CMMSRCS = nsNativeAppSupportCocoa.mm
+ else
+ ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
+ CPPSRCS += nsNativeAppSupportOS2.cpp
+ else
+ ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
+ CPPSRCS += nsNativeAppSupportBeOS.cpp
+ else
+ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+-CPPSRCS += nsNativeAppSupportUnix.cpp
++CPPSRCS += nsNativeAppSupportUnix.cpp nsKDEUtils.cpp
+ else
+ CPPSRCS += nsNativeAppSupportDefault.cpp
+ endif
+ endif
+ endif
+ endif
+ 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,335 @@
++/* -*- 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/gtkwindow.h>
++#include <gtk/gtkmain.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;
++ // if Gtk has meanwhile gotten a grab (bnc#555202, somehow the file dialog
++ // is called with a delay), then do not do anything, as this app would keep
++ // the grabs but block waiting for the helper, which would be unable to do
++ // anything because of the grab
++ if( blockUi && gdk_pointer_is_grabbed())
++ 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
+@@ -102,18 +102,19 @@ CMMSRCS = nsOSHelperAppService.mm \
+ $(NULL)
+ else
+ OSHELPER = nsOSHelperAppService.cpp
+ endif
+
+ LOCAL_INCLUDES = -I$(srcdir)
+
+ 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),qt)
+ OSHELPER += nsGNOMERegistry.cpp
+ OSHELPER += nsMIMEInfoUnix.cpp
+ endif
+
+ ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
+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
+@@ -40,27 +40,30 @@
+ #ifdef MOZ_PLATFORM_HILDON
+ #include <glib.h>
+ #include <hildon-uri.h>
+ #include <hildon-mime.h>
+ #include <libosso.h>
+ #endif
+
+ #include "nsMIMEInfoUnix.h"
+-#include "nsGNOMERegistry.h"
++#include "nsCommonRegistry.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);
+ #ifdef MOZ_PLATFORM_HILDON
+ if (NS_FAILED(rv)){
+ HildonURIAction *action = hildon_uri_get_default_action(mType.get(), nsnull);
+ if (action) {
+ nsCAutoString spec;
+ aURI->GetAsciiSpec(spec);
+ if (hildon_uri_open(spec.get(), action, nsnull))
+ rv = NS_OK;
+@@ -70,21 +73,21 @@ nsMIMEInfoUnix::LoadUriInternal(nsIURI *
+ #endif
+ return rv;
+ }
+
+ NS_IMETHODIMP
+ nsMIMEInfoUnix::GetHasDefaultHandler(PRBool *_retval)
+ {
+ *_retval = PR_FALSE;
+- nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mType);
++ nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromType(mType);
+ if (!mimeInfo) {
+ nsCAutoString ext;
+ GetPrimaryExtension(ext);
+- mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
++ mimeInfo = nsCommonRegistry::GetFromExtension(ext);
+ }
+
+ if (mimeInfo)
+ *_retval = PR_TRUE;
+
+ if (*_retval)
+ return NS_OK;
+
+@@ -101,31 +104,50 @@ nsMIMEInfoUnix::GetHasDefaultHandler(PRB
+ return nsMIMEInfoImpl::GetHasDefaultHandler(_retval);
+ }
+
+ nsresult
+ nsMIMEInfoUnix::LaunchDefaultWithFile(nsIFile *aFile)
+ {
+ nsCAutoString nativePath;
+ aFile->GetNativePath(nativePath);
++
++ 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( mType );
++ if( nsKDEUtils::command( command ))
++ return NS_OK;
++ }
++ if (!mDefaultApplication)
++ return NS_ERROR_FILE_NOT_FOUND;
++
++ return LaunchWithIProcess(mDefaultApplication, nativePath);
++ }
+
+ #ifdef MOZ_PLATFORM_HILDON
+ if(NS_SUCCEEDED(LaunchDefaultWithDBus(PromiseFlatCString(nativePath).get())))
+ return NS_OK;
+ #endif
+
+ nsCOMPtr<nsIGnomeVFSService> vfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
+ if (vfs) {
+ nsCOMPtr<nsIGnomeVFSMimeApp> app;
+ if (NS_SUCCEEDED(vfs->GetAppForMimeType(mType, 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 (NS_SUCCEEDED(vfs->GetAppForMimeType(type, getter_AddRefs(app))) && app)
+ return app->Launch(nativePath);
+ }
+ }
+
+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
+@@ -39,17 +39,17 @@
+ * ***** END LICENSE BLOCK ***** */
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+ #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"
+@@ -1205,29 +1205,29 @@ nsOSHelperAppService::GetHandlerAndDescr
+ nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
+ {
+ LOG(("-- nsOSHelperAppService::OSProtocolHandlerExists for '%s'\n",
+ aProtocolScheme));
+ *aHandlerExists = PR_FALSE;
+
+ #ifdef MOZ_WIDGET_GTK2
+ // Check the GConf registry for a protocol handler
+- *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
++ *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
+ #ifdef MOZ_PLATFORM_HILDON
+ *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)
+ {
+@@ -1313,17 +1313,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,
+@@ -1439,17 +1439,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
+@@ -184,8 +184,11 @@ EXTRA_DSO_LDOPTS += -lgfxpsshar
+ endif
+
+
+ DEFINES +=
+ INCLUDES += \
+ -I$(srcdir)/../xpwidgets \
+ -I$(topsrcdir)/other-licenses/atk-1.0 \
+ $(NULL)
++
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
++
+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
+@@ -50,16 +50,17 @@
+ #include "nsReadableUtils.h"
+ #include "mozcontainer.h"
+
+ #include "prmem.h"
+ #include "prlink.h"
+
+ #include "nsFilePicker.h"
+ #include "nsAccessibilityHelper.h"
++#include "nsKDEUtils.h"
+
+ #ifdef MOZ_PLATFORM_HILDON
+ #include <hildon-fm-2/hildon/hildon-file-chooser-dialog.h>
+ #endif
+
+ #define MAX_PREVIEW_SIZE 180
+
+ nsILocalFile *nsFilePicker::mPrevDisplayDirectory = nsnull;
+@@ -270,17 +271,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);
+@@ -418,16 +421,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);
+@@ -568,8 +574,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.Count() == 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.Count();
++ 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/io/Makefile.in b/xpcom/io/Makefile.in
+--- a/xpcom/io/Makefile.in
++++ b/xpcom/io/Makefile.in
+@@ -195,14 +195,15 @@ 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$(topsrcdir)/toolkit/xre
+
+ ifdef MOZ_PLATFORM_HILDON
+ CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) $(LIBHILDONMIME_CFLAGS)
+ CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) $(LIBHILDONMIME_CFLAGS)
+ endif
+
+diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
+--- a/xpcom/io/nsLocalFileUnix.cpp
++++ b/xpcom/io/nsLocalFileUnix.cpp
+@@ -79,16 +79,17 @@
+ #include "nsXPIDLString.h"
+ #include "prproces.h"
+ #include "nsIDirectoryEnumerator.h"
+ #include "nsISimpleEnumerator.h"
+ #include "nsITimelineService.h"
+
+ #ifdef MOZ_WIDGET_GTK2
+ #include "nsIGnomeVFSService.h"
++#include "nsKDEUtils.h"
+ #endif
+
+ #ifdef MOZ_PLATFORM_HILDON
+ #include <glib.h>
+ #include <hildon-uri.h>
+ #include <hildon-mime.h>
+ #include <libosso.h>
+ #endif
+@@ -1627,36 +1628,46 @@ nsLocalFile::Launch()
+
+ return NS_OK;
+ }
+ #else
+ NS_IMETHODIMP
+ nsLocalFile::Reveal()
+ {
+ #ifdef MOZ_WIDGET_GTK2
+- nsCOMPtr<nsIGnomeVFSService> vfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
+- if (!vfs)
+- return NS_ERROR_FAILURE;
+-
++ nsCAutoString url;
+ PRBool isDirectory;
+ if (NS_FAILED(IsDirectory(&isDirectory)))
+ return NS_ERROR_FAILURE;
+
+ if (isDirectory) {
+- return vfs->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;
+
+- return vfs->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<nsIGnomeVFSService> vfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
++ if (!vfs)
++ return NS_ERROR_FAILURE;
++ return vfs->ShowURIForInput(url);
++
+ #else
+ return NS_ERROR_FAILURE;
+ #endif
+ }
+
+ NS_IMETHODIMP
+ nsLocalFile::Launch()
+ {
+@@ -1674,16 +1685,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<nsIGnomeVFSService> vfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
+ if (!vfs)
+ return NS_ERROR_FAILURE;
+
+ return vfs->ShowURIForInput(mPath);
+ #endif
+ #else
+ return NS_ERROR_FAILURE;