mozilla-kde.patch
changeset 9 bc5dfe5b853a
child 10 1920f0ff04a3
--- /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;