From d950524fffac89cff7eb85d0500e4df5d1d1628a Mon Sep 17 00:00:00 2001
From: Legimet <legimet.calc@gmail.com>
Date: Sat, 6 Feb 2016 15:26:57 -0500
Subject: [PATCH] Add KDE integration patches for Abrowser 44

---
 helpers/DATA/firefox/firefox-kde.patch | 1815 ++++++++++++
 helpers/DATA/firefox/mozilla-kde.patch | 3780 ++++++++++++++++++++++++
 2 files changed, 5595 insertions(+)
 create mode 100644 helpers/DATA/firefox/firefox-kde.patch
 create mode 100644 helpers/DATA/firefox/mozilla-kde.patch

diff --git a/helpers/DATA/firefox/firefox-kde.patch b/helpers/DATA/firefox/firefox-kde.patch
new file mode 100644
index 00000000..40302144
--- /dev/null
+++ b/helpers/DATA/firefox/firefox-kde.patch
@@ -0,0 +1,1815 @@
+# HG changeset patch
+# Parent  77c3bdc27160dfa96aa4b3288c7f12a72f273967
+
+diff --git a/browser/base/content/browser-kde.xul b/browser/base/content/browser-kde.xul
+new file mode 100644
+--- /dev/null
++++ b/browser/base/content/browser-kde.xul
+@@ -0,0 +1,1250 @@
++#filter substitution
++<?xml version="1.0"?>
++# -*- Mode: HTML -*-
++#
++# This Source Code Form is subject to the terms of the Mozilla Public
++# License, v. 2.0. If a copy of the MPL was not distributed with this
++# file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
++<?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
++<?xml-stylesheet href="chrome://devtools/skin/common.css" type="text/css"?>
++<?xml-stylesheet href="chrome://browser/skin/controlcenter/panel.css" type="text/css"?>
++<?xml-stylesheet href="chrome://browser/skin/customizableui/panelUIOverlay.css" type="text/css"?>
++<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
++<?xml-stylesheet href="chrome://browser/skin/browser-lightweightTheme.css" type="text/css"?>
++
++<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
++<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
++<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
++
++# All DTD information is stored in a separate file so that it can be shared by
++# hiddenWindow.xul.
++#include browser-doctype.inc
++
++<window id="main-window"
++        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++        xmlns:svg="http://www.w3.org/2000/svg"
++        xmlns:html="http://www.w3.org/1999/xhtml"
++        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
++        onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
++        title="&mainWindow.title;"
++        title_normal="&mainWindow.title;"
++#ifdef XP_MACOSX
++        title_privatebrowsing="&mainWindow.title;&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
++        titledefault="&mainWindow.title;"
++        titlemodifier=""
++        titlemodifier_normal=""
++        titlemodifier_privatebrowsing="&mainWindow.titlePrivateBrowsingSuffix;"
++#else
++        title_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
++        titlemodifier="&mainWindow.titlemodifier;"
++        titlemodifier_normal="&mainWindow.titlemodifier;"
++        titlemodifier_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
++#endif
++#ifdef CAN_DRAW_IN_TITLEBAR
++#ifdef XP_WIN
++        chromemargin="0,2,2,2"
++#else
++        chromemargin="0,-1,-1,-1"
++#endif
++        tabsintitlebar="true"
++#endif
++        titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
++        lightweightthemes="true"
++        lightweightthemesfooter="browser-bottombox"
++        windowtype="navigator:browser"
++        macanimationtype="document"
++        screenX="4" screenY="4"
++        fullscreenbutton="true"
++        sizemode="normal"
++        retargetdocumentfocus="urlbar"
++        persist="screenX screenY width height sizemode">
++
++# All JS files which are not content (only) dependent that browser.xul
++# wishes to include *must* go into the global-scripts.inc file
++# so that they can be shared by macBrowserOverlay.xul.
++#include global-scripts.inc
++<script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
++
++<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
++
++<script type="application/javascript" src="chrome://browser/content/places/editBookmarkOverlay.js"/>
++
++# All sets except for popupsets (commands, keys, stringbundles and broadcasters) *must* go into the
++# browser-sets.inc file for sharing with hiddenWindow.xul.
++#define FULL_BROWSER_WINDOW
++#include browser-sets.inc
++#undef FULL_BROWSER_WINDOW
++
++  <popupset id="mainPopupSet">
++    <menupopup id="tabContextMenu"
++               onpopupshowing="if (event.target == this) TabContextMenu.updateContextMenu(this);"
++               onpopuphidden="if (event.target == this) TabContextMenu.contextTab = null;">
++      <menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
++                oncommand="gBrowser.reloadTab(TabContextMenu.contextTab);"/>
++      <menuitem id="context_toggleMuteTab" oncommand="TabContextMenu.contextTab.toggleMuteAudio();"/>
++      <menuseparator/>
++      <menuitem id="context_pinTab" label="&pinTab.label;"
++                accesskey="&pinTab.accesskey;"
++                oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
++      <menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
++                accesskey="&unpinTab.accesskey;"
++                oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
++      <menu id="context_tabViewMenu" label="&moveToGroup.label;"
++            accesskey="&moveToGroup.accesskey;">
++        <menupopup id="context_tabViewMenuPopup"
++                   onpopupshowing="if (event.target == this) TabView.moveToGroupPopupShowing(event);">
++          <menuseparator id="context_tabViewNamedGroups" hidden="true"/>
++          <menuitem id="context_tabViewNewGroup" label="&moveToNewGroup.label;"
++                    oncommand="TabView.moveTabTo(TabContextMenu.contextTab, null);"/>
++        </menupopup>
++      </menu>
++      <menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
++                accesskey="&moveToNewWindow.accesskey;"
++                tbattr="tabbrowser-multiple"
++                oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
++#ifdef E10S_TESTING_ONLY
++      <menuitem id="context_openNonRemoteWindow" label="Open in new non-e10s window"
++                tbattr="tabbrowser-remote"
++                hidden="true"
++                oncommand="gBrowser.openNonRemoteWindow(TabContextMenu.contextTab);"/>
++#endif
++      <menuseparator/>
++      <menuitem id="context_reloadAllTabs" label="&reloadAllTabs.label;" accesskey="&reloadAllTabs.accesskey;"
++                tbattr="tabbrowser-multiple-visible"
++                oncommand="gBrowser.reloadAllTabs();"/>
++      <menuitem id="context_bookmarkAllTabs"
++                label="&bookmarkAllTabs.label;"
++                accesskey="&bookmarkAllTabs.accesskey;"
++                command="Browser:BookmarkAllTabs"/>
++      <menuitem id="context_closeTabsToTheEnd" label="&closeTabsToTheEnd.label;" accesskey="&closeTabsToTheEnd.accesskey;"
++                oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab);"/>
++      <menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
++                oncommand="gBrowser.removeAllTabsBut(TabContextMenu.contextTab);"/>
++      <menuseparator/>
++      <menuitem id="context_undoCloseTab"
++                label="&undoCloseTab.label;"
++                accesskey="&undoCloseTab.accesskey;"
++                observes="History:UndoCloseTab"/>
++      <menuitem id="context_closeTab" label="&closeTab.label;" accesskey="&closeTab.accesskey;"
++                oncommand="gBrowser.removeTab(TabContextMenu.contextTab, { animate: true });"/>
++    </menupopup>
++
++    <!-- bug 415444/582485: event.stopPropagation is here for the cloned version
++         of this menupopup -->
++    <menupopup id="backForwardMenu"
++               onpopupshowing="return FillHistoryMenu(event.target);"
++               oncommand="gotoHistoryIndex(event); event.stopPropagation();"
++               onclick="checkForMiddleClick(this, event);"/>
++    <tooltip id="aHTMLTooltip" page="true"/>
++    <tooltip id="remoteBrowserTooltip"/>
++
++    <!-- for search and content formfill/pw manager -->
++    <panel type="autocomplete" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
++
++    <!-- for search with one-off buttons -->
++    <panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
++
++    <!-- for url bar autocomplete -->
++    <panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true">
++#ifdef NIGHTLY_BUILD
++      <hbox id="urlbar-search-footer" flex="1" align="stretch" pack="end">
++        <button id="urlbar-search-settings" label="&changeSearchSettings.button;"
++                oncommand="BrowserUITelemetry.countSearchSettingsEvent('urlbar'); openPreferences('paneSearch')"/>
++      </hbox>
++#endif
++    </panel>
++
++    <!-- for select dropdowns. The menupopup is what shows the list of options,
++         and the popuponly menulist makes things like the menuactive attributes
++         work correctly on the menupopup. ContentSelectDropdown expects the
++         popuponly menulist to be its immediate parent. -->
++    <menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
++      <menupopup rolluponmousewheel="true"
++                 activateontab="true"
++#ifdef XP_WIN
++                 consumeoutsideclicks="false" ignorekeys="handled"
++#endif
++        />
++    </menulist>
++
++    <!-- for invalid form error message -->
++    <panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
++      <description/>
++    </panel>
++
++    <panel id="editBookmarkPanel"
++           type="arrow"
++           footertype="promobox"
++           orient="vertical"
++           ignorekeys="true"
++           hidden="true"
++           onpopupshown="StarUI.panelShown(event);"
++           aria-labelledby="editBookmarkPanelTitle">
++      <row id="editBookmarkPanelHeader" align="center" hidden="true">
++        <vbox align="center">
++          <image id="editBookmarkPanelStarIcon"/>
++        </vbox>
++        <vbox>
++          <label id="editBookmarkPanelTitle"/>
++          <description id="editBookmarkPanelDescription"/>
++          <hbox>
++            <button id="editBookmarkPanelRemoveButton"
++                    class="editBookmarkPanelHeaderButton"
++                    oncommand="StarUI.removeBookmarkButtonCommand();"
++                    accesskey="&editBookmark.removeBookmark.accessKey;"/>
++          </hbox>
++        </vbox>
++      </row>
++      <vbox id="editBookmarkPanelContent" flex="1" hidden="true"/>
++      <hbox id="editBookmarkPanelBottomButtons" pack="end">
++#ifdef XP_UNIX
++        <button id="editBookmarkPanelDoneButton"
++                class="editBookmarkPanelBottomButton"
++                label="&editBookmark.done.label;"
++                default="true"
++                oncommand="StarUI.panel.hidePopup();"/>
++        <button id="editBookmarkPanelDeleteButton"
++                class="editBookmarkPanelBottomButton"
++                label="&editBookmark.cancel.label;"
++                oncommand="StarUI.cancelButtonOnCommand();"/>
++#else
++        <button id="editBookmarkPanelDeleteButton"
++                class="editBookmarkPanelBottomButton"
++                label="&editBookmark.cancel.label;"
++                oncommand="StarUI.cancelButtonOnCommand();"/>
++        <button id="editBookmarkPanelDoneButton"
++                class="editBookmarkPanelBottomButton"
++                label="&editBookmark.done.label;"
++                default="true"
++                oncommand="StarUI.panel.hidePopup();"/>
++#endif
++      </hbox>
++    </panel>
++
++    <!-- UI tour experience -->
++    <panel id="UITourTooltip"
++           type="arrow"
++           hidden="true"
++           noautofocus="true"
++           noautohide="true"
++           align="start"
++           orient="vertical"
++           role="alert">
++     <vbox>
++      <hbox pack="end">
++        <toolbarbutton id="UITourTooltipClose" class="close-icon"
++                       tooltiptext="&uiTour.infoPanel.close;"/>
++      </hbox>
++      <hbox id="UITourTooltipBody">
++        <vbox id="UITourTooltipIconContainer">
++          <image id="UITourTooltipIcon"/>
++        </vbox>
++        <vbox flex="1">
++          <label id="UITourTooltipTitle" flex="1"/>
++          <description id="UITourTooltipDescription" flex="1"/>
++        </vbox>
++      </hbox>
++      <hbox id="UITourTooltipButtons" flex="1" align="center"/>
++     </vbox>
++    </panel>
++    <!-- type="default" forces frames to be created so that the panel's size can be determined -->
++    <panel id="UITourHighlightContainer"
++           type="default"
++           hidden="true"
++           noautofocus="true"
++           noautohide="true"
++           flip="none"
++           consumeoutsideclicks="false"
++           mousethrough="always">
++      <box id="UITourHighlight"></box>
++    </panel>
++
++    <panel id="abouthome-search-panel" orient="vertical" type="arrow" hidden="true"
++           onclick="this.hidePopup()">
++      <hbox id="abouthome-search-panel-manage"
++            onclick="openPreferences('paneSearch')">
++        <label>&changeSearchSettings.button;</label>
++      </hbox>
++    </panel>
++
++    <panel id="social-share-panel"
++           class="social-panel"
++           type="arrow"
++           orient="vertical"
++           onpopupshowing="SocialShare.onShowing()"
++           onpopuphidden="SocialShare.onHidden()"
++           hidden="true">
++      <hbox class="social-share-toolbar">
++        <toolbarbutton id="manage-share-providers" class="toolbarbutton share-provider-button"
++                       tooltiptext="&social.addons.label;"
++                       oncommand="BrowserOpenAddonsMgr('addons://list/service');
++                                  this.parentNode.parentNode.hidePopup();"/>
++        <arrowscrollbox id="social-share-provider-buttons" orient="horizontal" flex="1" pack="end">
++          <toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
++                         group="share-providers" tooltiptext="&findShareServices.label;"
++                         oncommand="SocialShare.showDirectory()"/>
++        </arrowscrollbox>
++      </hbox>
++      <hbox id="share-container" flex="1"/>
++    </panel>
++
++    <panel id="social-notification-panel"
++           class="social-panel"
++           type="arrow"
++           hidden="true"
++           noautofocus="true"/>
++    <panel id="social-flyout-panel"
++           class="social-panel"
++           onpopupshown="SocialFlyout.onShown()"
++           onpopuphidden="SocialFlyout.onHidden()"
++           side="right"
++           type="arrow"
++           hidden="true"
++           flip="slide"
++           rolluponmousewheel="true"
++           noautofocus="true"
++           position="topcenter topright"/>
++
++    <panel id="loop-notification-panel"
++           class="loop-panel social-panel"
++           type="arrow"
++           hidden="true"
++           noautofocus="true"/>
++
++    <panel id="loop-panel"
++           class="loop-panel social-panel"
++           type="arrow"
++           orient="horizontal"
++           hidden="true"/>
++
++    <menupopup id="processHangOptions"
++               onpopupshowing="ProcessHangMonitor.refreshMenu(window);">
++      <menuitem id="processHangTerminateScript"
++                oncommand="ProcessHangMonitor.terminateScript(window)"
++                accesskey="&processHang.terminateScript.accessKey;"
++                label="&processHang.terminateScript.label;"/>
++      <menuitem id="processHangDebugScript"
++                oncommand="ProcessHangMonitor.debugScript(window)"
++                accesskey="&processHang.debugScript.accessKey;"
++                label="&processHang.debugScript.label;"/>
++      <menuitem id="processHangTerminatePlugin"
++                oncommand="ProcessHangMonitor.terminatePlugin(window)"
++                accesskey="&processHang.terminatePlugin.accessKey;"
++                label="&processHang.terminatePlugin.label;"/>
++      <menuitem id="processHangTerminateProcess"
++                oncommand="ProcessHangMonitor.terminateProcess(window)"
++                accesskey="&processHang.terminateProcess.accessKey;"
++                label="&processHang.terminateProcess.label;"/>
++    </menupopup>
++
++    <menupopup id="toolbar-context-menu"
++               onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
++      <menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
++                accesskey="&customizeMenu.moveToPanel.accesskey;"
++                label="&customizeMenu.moveToPanel.label;"
++                contexttype="toolbaritem"
++                class="customize-context-moveToPanel"/>
++      <menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode)"
++                accesskey="&customizeMenu.removeFromToolbar.accesskey;"
++                label="&customizeMenu.removeFromToolbar.label;"
++                contexttype="toolbaritem"
++                class="customize-context-removeFromToolbar"/>
++      <menuitem id="toolbar-context-reloadAllTabs"
++                class="toolbaritem-tabsmenu"
++                contexttype="tabbar"
++                oncommand="gBrowser.reloadAllTabs();"
++                label="&toolbarContextMenu.reloadAllTabs.label;"
++                accesskey="&toolbarContextMenu.reloadAllTabs.accesskey;"/>
++      <menuitem id="toolbar-context-bookmarkAllTabs"
++                class="toolbaritem-tabsmenu"
++                contexttype="tabbar"
++                command="Browser:BookmarkAllTabs"
++                label="&toolbarContextMenu.bookmarkAllTabs.label;"
++                accesskey="&toolbarContextMenu.bookmarkAllTabs.accesskey;"/>
++      <menuitem id="toolbar-context-undoCloseTab"
++                class="toolbaritem-tabsmenu"
++                contexttype="tabbar"
++                label="&toolbarContextMenu.undoCloseTab.label;"
++                accesskey="&toolbarContextMenu.undoCloseTab.accesskey;"
++                observes="History:UndoCloseTab"/>
++      <menuseparator/>
++      <menuseparator id="viewToolbarsMenuSeparator"/>
++      <!-- XXXgijs: we're using oncommand handler here to avoid the event being
++                    redirected to the command element, thus preventing
++                    listeners on the menupopup or further up the tree from
++                    seeing the command event pass by. The observes attribute is
++                    here so that the menuitem is still disabled and re-enabled
++                    correctly. -->
++      <menuitem oncommand="BrowserCustomizeToolbar()"
++                observes="cmd_CustomizeToolbars"
++                class="viewCustomizeToolbar"
++                label="&viewCustomizeToolbar.label;"
++                accesskey="&viewCustomizeToolbar.accesskey;"/>
++    </menupopup>
++
++    <menupopup id="blockedPopupOptions"
++               onpopupshowing="gPopupBlockerObserver.fillPopupList(event);"
++               onpopuphiding="gPopupBlockerObserver.onPopupHiding(event);">
++      <menuitem observes="blockedPopupAllowSite"/>
++      <menuitem observes="blockedPopupEditSettings"/>
++      <menuitem observes="blockedPopupDontShowMessage"/>
++      <menuseparator observes="blockedPopupsSeparator"/>
++    </menupopup>
++
++    <menupopup id="autohide-context"
++           onpopupshowing="FullScreen.getAutohide(this.firstChild);">
++      <menuitem type="checkbox" label="&fullScreenAutohide.label;"
++                accesskey="&fullScreenAutohide.accesskey;"
++                oncommand="FullScreen.setAutohide();"/>
++      <menuseparator/>
++      <menuitem label="&fullScreenExit.label;"
++                accesskey="&fullScreenExit.accesskey;"
++                oncommand="BrowserFullScreen();"/>
++    </menupopup>
++
++    <menupopup id="contentAreaContextMenu" pagemenu="#page-menu-separator"
++               onpopupshowing="if (event.target != this)
++                                 return true;
++                               gContextMenu = new nsContextMenu(this, event.shiftKey);
++                               if (gContextMenu.shouldDisplay)
++                                 updateEditUIVisibility();
++                               return gContextMenu.shouldDisplay;"
++               onpopuphiding="if (event.target != this)
++                                return;
++                              gContextMenu.hiding();
++                              gContextMenu = null;
++                              updateEditUIVisibility();">
++#include browser-context.inc
++    </menupopup>
++
++    <menupopup id="placesContext"/>
++
++    <panel id="ctrlTab-panel" class="KUI-panel" hidden="true" norestorefocus="true" level="top">
++      <hbox>
++        <button class="ctrlTab-preview" flex="1"/>
++        <button class="ctrlTab-preview" flex="1"/>
++        <button class="ctrlTab-preview" flex="1"/>
++        <button class="ctrlTab-preview" flex="1"/>
++        <button class="ctrlTab-preview" flex="1"/>
++        <button class="ctrlTab-preview" flex="1"/>
++      </hbox>
++      <hbox pack="center">
++        <button id="ctrlTab-showAll" class="ctrlTab-preview" noicon="true"/>
++      </hbox>
++    </panel>
++
++    <!-- Sync Panel -->
++    <panel id="sync-start-panel" class="sync-panel" type="arrow" hidden="true"
++           noautofocus="true" onclick="this.hidePopup();"
++           flip="slide">
++      <hbox class="sync-panel-outer">
++        <image class="sync-panel-icon"/>
++        <vbox class="sync-panel-inner">
++          <description id="sync-start-panel-title"
++                       value="&syncStartPanel2.heading;"/>
++          <description id="sync-start-panel-subtitle"
++                       value="&syncStartPanel2.subTitle;"/>
++        </vbox>
++      </hbox>
++    </panel>
++
++    <!-- Bookmarks and history tooltip -->
++    <tooltip id="bhTooltip"/>
++
++    <tooltip id="tabbrowser-tab-tooltip" onpopupshowing="gBrowser.createTooltip(event);"/>
++
++    <tooltip id="back-button-tooltip">
++      <label class="tooltip-label" value="&backButton.tooltip;"/>
++#ifdef XP_MACOSX
++      <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
++#else
++      <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
++#endif
++    </tooltip>
++
++    <tooltip id="forward-button-tooltip">
++      <label class="tooltip-label" value="&forwardButton.tooltip;"/>
++#ifdef XP_MACOSX
++      <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
++#else
++      <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
++#endif
++    </tooltip>
++
++    <tooltip id="share-button-tooltip" onpopupshowing="SocialShare.createTooltip(event);">
++      <label class="tooltip-label"/>
++      <label class="tooltip-label"/>
++    </tooltip>
++
++#include popup-notifications.inc
++
++#include ../../components/customizableui/content/panelUI.inc.xul
++#include ../../components/controlcenter/content/panel.inc.xul
++
++    <hbox id="downloads-animation-container" mousethrough="always">
++      <vbox id="downloads-notification-anchor">
++        <vbox id="downloads-indicator-notification"/>
++      </vbox>
++    </hbox>
++
++    <hbox id="bookmarked-notification-container" mousethrough="always">
++      <vbox id="bookmarked-notification-anchor">
++        <vbox id="bookmarked-notification"/>
++      </vbox>
++      <vbox id="bookmarked-notification-dropmarker-anchor">
++        <image id="bookmarked-notification-dropmarker-icon"/>
++      </vbox>
++    </hbox>
++
++    <tooltip id="dynamic-shortcut-tooltip"
++             onpopupshowing="UpdateDynamicShortcutTooltipText(this);"/>
++
++    <menupopup id="emeNotificationsPopup">
++      <menuitem id="emeNotificationsNotNow"
++                label="&emeNotificationsNotNow.label;"
++                acceskey="&emeNotificationsNotNow.accesskey;"
++                oncommand="gEMEHandler.onNotNow(this);"/>
++      <menuitem id="emeNotificationsDontAskAgain"
++                label="&emeNotificationsDontAskAgain.label;"
++                acceskey="&emeNotificationsDontAskAgain.accesskey;"
++                oncommand="gEMEHandler.onDontAskAgain(this);"/>
++    </menupopup>
++  </popupset>
++
++#ifdef CAN_DRAW_IN_TITLEBAR
++<vbox id="titlebar">
++  <hbox id="titlebar-content">
++    <spacer id="titlebar-spacer" flex="1"/>
++    <hbox id="titlebar-buttonbox-container">
++#ifdef XP_WIN
++      <hbox id="private-browsing-indicator-titlebar">
++        <hbox class="private-browsing-indicator"/>
++      </hbox>
++#endif
++      <hbox id="titlebar-buttonbox">
++        <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
++        <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
++        <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
++      </hbox>
++    </hbox>
++#ifdef XP_MACOSX
++    <!-- OS X does not natively support RTL for its titlebar items, so we prevent this secondary
++         buttonbox from reversing order in RTL by forcing an LTR direction. -->
++    <hbox id="titlebar-secondary-buttonbox" dir="ltr">
++      <hbox class="private-browsing-indicator"/>
++      <hbox id="titlebar-fullscreen-button"/>
++    </hbox>
++#endif
++  </hbox>
++</vbox>
++#endif
++
++<deck flex="1" id="tab-view-deck">
++<vbox flex="1" id="browser-panel">
++
++  <toolbox id="navigator-toolbox" mode="icons">
++    <!-- Menu -->
++    <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
++             defaultset="menubar-items"
++             mode="icons" iconsize="small"
++#ifdef MENUBAR_CAN_AUTOHIDE
++             toolbarname="&menubarCmd.label;"
++             accesskey="&menubarCmd.accesskey;"
++#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
++             autohide="true"
++#endif
++#endif
++             context="toolbar-context-menu">
++      <toolbaritem id="menubar-items" align="center">
++# The entire main menubar is placed into browser-menubar.inc, so that it can be shared by
++# hiddenWindow.xul.
++#include browser-menubar.inc
++      </toolbaritem>
++
++#ifdef CAN_DRAW_IN_TITLEBAR
++#ifndef XP_MACOSX
++      <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"
++            id="titlebar-placeholder-on-menubar-for-caption-buttons" persist="width"
++            skipintoolbarset="true"/>
++#endif
++#endif
++    </toolbar>
++
++    <toolbar id="TabsToolbar"
++             fullscreentoolbar="true"
++             customizable="true"
++             mode="icons"
++             iconsize="small"
++             aria-label="&tabsToolbar.label;"
++             context="toolbar-context-menu"
++             defaultset="tabbrowser-tabs,new-tab-button,alltabs-button"
++             collapsed="true">
++
++#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
++      <hbox id="private-browsing-indicator"
++            skipintoolbarset="true"/>
++#endif
++
++      <tabs id="tabbrowser-tabs"
++            class="tabbrowser-tabs"
++            tabbrowser="content"
++            flex="1"
++            setfocus="false"
++            tooltip="tabbrowser-tab-tooltip"
++            stopwatchid="FX_TAB_CLICK_MS">
++        <tab class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
++      </tabs>
++
++      <toolbarbutton id="new-tab-button"
++                     class="toolbarbutton-1 chromeclass-toolbar-additional"
++                     label="&tabCmd.label;"
++                     command="cmd_newNavigatorTab"
++                     onclick="checkForMiddleClick(this, event);"
++                     tooltip="dynamic-shortcut-tooltip"
++                     ondrop="newTabButtonObserver.onDrop(event)"
++                     ondragover="newTabButtonObserver.onDragOver(event)"
++                     ondragenter="newTabButtonObserver.onDragOver(event)"
++                     ondragexit="newTabButtonObserver.onDragExit(event)"
++                     cui-areatype="toolbar"
++                     removable="true"/>
++
++      <toolbarbutton id="alltabs-button"
++                     class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button"
++                     type="menu"
++                     label="&listAllTabs.label;"
++                     tooltiptext="&listAllTabs.label;"
++                     removable="false">
++        <menupopup id="alltabs-popup"
++                   position="after_end">
++          <menuitem id="menu_tabview"
++                    class="menuitem-iconic"
++                    key="key_tabview"
++                    label="&viewTabGroups.label;"
++                    command="Browser:ToggleTabView"
++                    observes="tabviewGroupsNumber"/>
++          <menuitem id="alltabs_undoCloseTab"
++                    class="menuitem-iconic"
++                    key="key_undoCloseTab"
++                    label="&undoCloseTab.label;"
++                    observes="History:UndoCloseTab"/>
++          <menuseparator id="alltabs-popup-separator"/>
++        </menupopup>
++      </toolbarbutton>
++
++#if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
++      <hbox class="private-browsing-indicator" skipintoolbarset="true"/>
++#endif
++#ifdef CAN_DRAW_IN_TITLEBAR
++      <hbox class="titlebar-placeholder" type="caption-buttons"
++            id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
++#ifndef XP_MACOSX
++            ordinal="1000"
++#endif
++            skipintoolbarset="true"/>
++
++#ifdef XP_MACOSX
++      <hbox class="titlebar-placeholder" type="fullscreen-button"
++            id="titlebar-placeholder-on-TabsToolbar-for-fullscreen-button" persist="width"
++            skipintoolbarset="true"/>
++#endif
++#endif
++    </toolbar>
++
++    <!--
++           CAVEAT EMPTOR
++           Should you need to add items to the toolbar here, make sure to also add them
++           to the default placements of buttons in CustomizableUI.jsm, so the
++           customization code doesn't get confused.
++      -->
++    <toolbar id="nav-bar"
++             aria-label="&navbarCmd.label;"
++             fullscreentoolbar="true" mode="icons" customizable="true"
++             iconsize="small"
++#ifdef MOZ_DEV_EDITION
++             defaultset="urlbar-container,search-container,developer-button,bookmarks-menu-button,pocket-button,downloads-button,home-button,loop-button"
++#else
++             defaultset="urlbar-container,search-container,bookmarks-menu-button,pocket-button,downloads-button,home-button,loop-button"
++#endif
++             customizationtarget="nav-bar-customization-target"
++             overflowable="true"
++             overflowbutton="nav-bar-overflow-button"
++             overflowtarget="widget-overflow-list"
++             overflowpanel="widget-overflow"
++             context="toolbar-context-menu">
++
++      <hbox id="nav-bar-customization-target" flex="1">
++        <toolbaritem id="urlbar-container" flex="400" persist="width"
++                     removable="false"
++                     class="chromeclass-location" overflows="false">
++          <toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                         label="&backCmd.label;"
++                         command="Browser:BackOrBackDuplicate"
++                         onclick="checkForMiddleClick(this, event);"
++                         tooltip="back-button-tooltip"
++                         context="backForwardMenu"/>
++          <hbox id="urlbar-wrapper" flex="1">
++            <toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                           label="&forwardCmd.label;"
++                           command="Browser:ForwardOrForwardDuplicate"
++                           onclick="checkForMiddleClick(this, event);"
++                           tooltip="forward-button-tooltip"
++                           context="backForwardMenu"/>
++            <textbox id="urlbar" flex="1"
++                     placeholder="&urlbar.placeholder2;"
++                     type="autocomplete"
++                     autocompletesearch="urlinline history"
++                     autocompletesearchparam="enable-actions"
++                     autocompletepopup="PopupAutoCompleteRichResult"
++                     completeselectedindex="true"
++                     shrinkdelay="250"
++                     tabscrolling="true"
++                     showcommentcolumn="true"
++                     showimagecolumn="true"
++                     enablehistory="true"
++                     maxrows="6"
++                     newlines="stripsurroundingwhitespace"
++                     ontextentered="this.handleCommand(param);"
++                     ontextreverted="return this.handleRevert();"
++                     pageproxystate="invalid"
++                     onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
++                     onblur="setTimeout(() => { document.getElementById('identity-box').style.MozUserFocus = ''; }, 0);">
++              <box id="notification-popup-box" hidden="true" align="center">
++                <image id="default-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.defaultNotificationAnchor.label;"/>
++                <!-- NB: the identity-notification-icon is used for persona-based auth and preffed
++                     off by default. It hasn't been updated for some time and liable to being
++                     removed.-->
++                <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
++                <image id="geo-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.geolocationNotificationAnchor.label;"/>
++                <image id="addons-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.addonsNotificationAnchor.label;"/>
++                <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.indexedDBNotificationAnchor.label;"/>
++                <image id="login-fill-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.loginFillNotificationAnchor.label;"/>
++                <image id="password-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.passwordNotificationAnchor.label;"/>
++                <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webappsNotificationAnchor.label;"/>
++                <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.pluginsNotificationAnchor.label;"/>
++                <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webNotsNotificationAnchor.label;"/>
++                <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webRTCShareDevicesNotificationAnchor.label;"/>
++                <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webRTCSharingDevicesNotificationAnchor.label;"/>
++                <image id="webRTC-shareMicrophone-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webRTCShareMicrophoneNotificationAnchor.label;"/>
++                <image id="webRTC-sharingMicrophone-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webRTCSharingMicrophoneNotificationAnchor.label;"/>
++                <image id="webRTC-shareScreen-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webRTCShareScreenNotificationAnchor.label;"/>
++                <image id="webRTC-sharingScreen-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.webRTCSharingScreenNotificationAnchor.label;"/>
++                <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.pointerLockNotificationAnchor.label;"/>
++                <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.servicesNotificationAnchor.label;"/>
++                <image id="translate-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.translateNotificationAnchor.label;"/>
++                <image id="translated-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.translatedNotificationAnchor.label;"/>
++                <image id="eme-notification-icon" class="notification-anchor-icon" role="button"
++                       aria-label="&urlbar.emeNotificationAnchor.label;"/>
++              </box>
++              <!-- Use onclick instead of normal popup= syntax since the popup
++                   code fires onmousedown, and hence eats our favicon drag events.
++                   We only add the identity-box button to the tab order when the location bar
++                   has focus, otherwise pressing F6 focuses it instead of the location bar -->
++              <box id="identity-box" role="button"
++                   align="center"
++                   aria-label="&urlbar.viewSiteInfo.label;"
++                   onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
++                   onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
++                   ondragstart="gIdentityHandler.onDragStart(event);">
++                <hbox id="identity-icons"
++                      consumeanchor="identity-box">
++                  <image id="tracking-protection-icon"/>
++                  <image id="page-proxy-favicon"
++                         onclick="PageProxyClickHandler(event);"
++                         pageproxystate="invalid"/>
++                </hbox>
++                <hbox id="identity-icon-labels">
++                  <label id="identity-icon-label" class="plain" flex="1"/>
++                  <label id="identity-icon-country-label" class="plain"/>
++                </hbox>
++              </box>
++              <box id="urlbar-display-box" align="center">
++                <label class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
++              </box>
++              <hbox id="urlbar-icons">
++                <image id="page-report-button"
++                       class="urlbar-icon"
++                       hidden="true"
++                       tooltiptext="&pageReportIcon.tooltip;"
++                       onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
++                <image id="reader-mode-button"
++                       class="urlbar-icon"
++                       hidden="true"
++                       onclick="ReaderParent.buttonClick(event);"/>
++              </hbox>
++              <hbox id="userContext-icons">
++                <label id="userContext-label"/>
++                <image id="userContext-indicator"/>
++              </hbox>
++              <toolbarbutton id="urlbar-go-button"
++                             class="chromeclass-toolbar-additional"
++                             onclick="gURLBar.handleCommand(event);"
++                             tooltiptext="&goEndCap.tooltip;"/>
++              <toolbarbutton id="urlbar-reload-button"
++                             class="chromeclass-toolbar-additional"
++                             command="Browser:ReloadOrDuplicate"
++                             onclick="checkForMiddleClick(this, event);"
++                             tooltiptext="&reloadButton.tooltip;"/>
++              <toolbarbutton id="urlbar-stop-button"
++                             class="chromeclass-toolbar-additional"
++                             command="Browser:Stop"
++                             tooltiptext="&stopButton.tooltip;"/>
++            </textbox>
++          </hbox>
++        </toolbaritem>
++
++        <toolbaritem id="search-container" title="&searchItem.title;"
++                     align="center" class="chromeclass-toolbar-additional panel-wide-item"
++                     cui-areatype="toolbar"
++                     flex="100" persist="width" removable="true">
++          <searchbar id="searchbar" flex="1"/>
++        </toolbaritem>
++
++        <toolbarbutton id="bookmarks-menu-button"
++                       class="toolbarbutton-1 chromeclass-toolbar-additional"
++                       removable="true"
++                       type="menu-button"
++                       label="&bookmarksMenuButton.label;"
++                       tooltip="dynamic-shortcut-tooltip"
++                       anchor="dropmarker"
++                       ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
++                       ondragover="PlacesMenuDNDHandler.onDragOver(event);"
++                       ondragleave="PlacesMenuDNDHandler.onDragLeave(event);"
++                       ondrop="PlacesMenuDNDHandler.onDrop(event);"
++                       cui-areatype="toolbar"
++                       oncommand="BookmarkingUI.onCommand(event);">
++          <observes element="bookmarkThisPageBroadcaster" attribute="starred"/>
++          <observes element="bookmarkThisPageBroadcaster" attribute="buttontooltiptext"/>
++          <menupopup id="BMB_bookmarksPopup"
++                     class="cui-widget-panel cui-widget-panelview cui-widget-panelWithFooter PanelUI-subView"
++                     placespopup="true"
++                     context="placesContext"
++                     openInTabs="children"
++                     oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
++                     onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
++                     onpopupshowing="BookmarkingUI.onPopupShowing(event);
++                                     BookmarkingUI.updatePocketItemVisibility('BMB_');
++                                     BookmarkingUI.attachPlacesView(event, this);"
++                     tooltip="bhTooltip" popupsinherittooltip="true">
++            <menuitem id="BMB_viewBookmarksSidebar"
++                      class="subviewbutton"
++                      label="&viewBookmarksSidebar2.label;"
++                      type="checkbox"
++                      oncommand="SidebarUI.toggle('viewBookmarksSidebar');">
++              <observes element="viewBookmarksSidebar" attribute="checked"/>
++            </menuitem>
++            <!-- NB: temporary solution for bug 985024, this should go away soon. -->
++            <menuitem id="BMB_bookmarksShowAllTop"
++                      class="menuitem-iconic subviewbutton"
++                      label="&showAllBookmarks2.label;"
++                      command="Browser:ShowAllBookmarks"
++                      key="manBookmarkKb"/>
++            <menuseparator/>
++            <menuitem id="BMB_pocket"
++                      class="menuitem-iconic bookmark-item subviewbutton"
++                      label="&pocketMenuitem.label;"
++                      oncommand="openUILink(Pocket.listURL, event);"/>
++            <menuseparator id="BMB_pocketSeparator"/>
++            <menuitem id="BMB_subscribeToPageMenuitem"
++#ifndef XP_MACOSX
++                      class="menuitem-iconic subviewbutton"
++#else
++                      class="subviewbutton"
++#endif
++                      label="&subscribeToPageMenuitem.label;"
++                      oncommand="return FeedHandler.subscribeToFeed(null, event);"
++                      onclick="checkForMiddleClick(this, event);"
++                      observes="singleFeedMenuitemState"/>
++            <menu id="BMB_subscribeToPageMenupopup"
++#ifndef XP_MACOSX
++                  class="menu-iconic subviewbutton"
++#else
++                  class="subviewbutton"
++#endif
++                  label="&subscribeToPageMenupopup.label;"
++                  observes="multipleFeedsMenuState">
++              <menupopup id="BMB_subscribeToPageSubmenuMenupopup"
++                         onpopupshowing="return FeedHandler.buildFeedList(event.target);"
++                         oncommand="return FeedHandler.subscribeToFeed(null, event);"
++                         onclick="checkForMiddleClick(this, event);"/>
++            </menu>
++            <menuseparator/>
++            <menu id="BMB_bookmarksToolbar"
++                  class="menu-iconic bookmark-item subviewbutton"
++                  label="&personalbarCmd.label;"
++                  container="true">
++              <menupopup id="BMB_bookmarksToolbarPopup"
++                         placespopup="true"
++                         context="placesContext"
++                         onpopupshowing="if (!this.parentNode._placesView)
++                                           new PlacesMenu(event, 'place:folder=TOOLBAR',
++                                                          PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);">
++                <menuitem id="BMB_viewBookmarksToolbar"
++                          placesanonid="view-toolbar"
++                          toolbarId="PersonalToolbar"
++                          type="checkbox"
++                          oncommand="onViewToolbarCommand(event)"
++                          label="&viewBookmarksToolbar.label;"/>
++                <menuseparator/>
++                <!-- Bookmarks toolbar items -->
++              </menupopup>
++            </menu>
++            <menu id="BMB_unsortedBookmarks"
++                  class="menu-iconic bookmark-item subviewbutton"
++                  label="&bookmarksMenuButton.unsorted.label;"
++                  container="true">
++              <menupopup id="BMB_unsortedBookmarksPopup"
++                         placespopup="true"
++                         context="placesContext"
++                         onpopupshowing="if (!this.parentNode._placesView)
++                                           new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS',
++                                                          PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
++            </menu>
++            <menuseparator/>
++            <!-- Bookmarks menu items will go here -->
++            <menuitem id="BMB_bookmarksShowAll"
++                      class="subviewbutton panel-subview-footer"
++                      label="&showAllBookmarks2.label;"
++                      command="Browser:ShowAllBookmarks"
++                      key="manBookmarkKb"/>
++          </menupopup>
++        </toolbarbutton>
++
++        <!-- This is a placeholder for the Downloads Indicator.  It is visible
++             during the customization of the toolbar, in the palette, and before
++             the Downloads Indicator overlay is loaded. -->
++        <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                       key="key_openDownloads"
++                       oncommand="DownloadsIndicatorView.onCommand(event);"
++                       ondrop="DownloadsIndicatorView.onDrop(event);"
++                       ondragover="DownloadsIndicatorView.onDragOver(event);"
++                       ondragenter="DownloadsIndicatorView.onDragOver(event);"
++                       label="&downloads.label;"
++                       removable="true"
++                       cui-areatype="toolbar"
++                       tooltip="dynamic-shortcut-tooltip"/>
++
++        <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                       removable="true"
++                       label="&homeButton.label;"
++                       ondragover="homeButtonObserver.onDragOver(event)"
++                       ondragenter="homeButtonObserver.onDragOver(event)"
++                       ondrop="homeButtonObserver.onDrop(event)"
++                       ondragexit="homeButtonObserver.onDragExit(event)"
++                       key="goHome"
++                       onclick="BrowserGoHome(event);"
++                       cui-areatype="toolbar"
++                       aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
++      </hbox>
++
++      <toolbarbutton id="nav-bar-overflow-button"
++                     class="toolbarbutton-1 chromeclass-toolbar-additional overflow-button"
++                     skipintoolbarset="true"
++                     tooltiptext="&navbarOverflow.label;"/>
++
++      <toolbaritem id="PanelUI-button"
++                   class="chromeclass-toolbar-additional"
++                   removable="false">
++        <toolbarbutton id="PanelUI-menu-button"
++                       class="toolbarbutton-1 badged-button"
++                       consumeanchor="PanelUI-button"
++                       label="&brandShortName;"
++                       tooltiptext="&appmenu.tooltip;"/>
++      </toolbaritem>
++
++      <hbox id="window-controls" hidden="true" pack="end" skipintoolbarset="true"
++            ordinal="1000">
++        <toolbarbutton id="minimize-button"
++                       tooltiptext="&fullScreenMinimize.tooltip;"
++                       oncommand="window.minimize();"/>
++
++        <toolbarbutton id="restore-button"
++#ifdef XP_MACOSX
++# Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button
++# to exit fullscreen and want it to behave like other toolbar buttons.
++                       class="toolbarbutton-1"
++#endif
++                       tooltiptext="&fullScreenRestore.tooltip;"
++                       oncommand="BrowserFullScreen();"/>
++
++        <toolbarbutton id="close-button"
++                       tooltiptext="&fullScreenClose.tooltip;"
++                       oncommand="BrowserTryToCloseWindow();"/>
++      </hbox>
++    </toolbar>
++
++    <toolbarset id="customToolbars" context="toolbar-context-menu"/>
++
++    <toolbar id="PersonalToolbar"
++             mode="icons" iconsize="small"
++             class="chromeclass-directories"
++             context="toolbar-context-menu"
++             defaultset="personal-bookmarks"
++             toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
++             collapsed="true"
++             customizable="true">
++      <toolbaritem id="personal-bookmarks"
++                   title="&bookmarksToolbarItem.label;"
++                   cui-areatype="toolbar"
++                   removable="true">
++        <toolbarbutton id="bookmarks-toolbar-placeholder"
++                       class="toolbarbutton-1"
++                       mousethrough="never"
++                       label="&bookmarksToolbarItem.label;"
++                       oncommand="PlacesToolbarHelper.onPlaceholderCommand();"/>
++        <hbox flex="1"
++              id="PlacesToolbar"
++              context="placesContext"
++              onclick="BookmarksEventHandler.onClick(event, this._placesView);"
++              oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
++              tooltip="bhTooltip"
++              popupsinherittooltip="true">
++          <hbox flex="1">
++            <hbox id="PlacesToolbarDropIndicatorHolder" align="center" collapsed="true">
++              <image id="PlacesToolbarDropIndicator"
++                     mousethrough="always"
++                     collapsed="true"/>
++            </hbox>
++            <scrollbox orient="horizontal"
++                       id="PlacesToolbarItems"
++                       flex="1"/>
++            <toolbarbutton type="menu"
++                           id="PlacesChevron"
++                           class="chevron"
++                           mousethrough="never"
++                           collapsed="true"
++                           tooltiptext="&bookmarksToolbarChevron.tooltip;"
++                           onpopupshowing="document.getElementById('PlacesToolbar')
++                                                   ._placesView._onChevronPopupShowing(event);">
++              <menupopup id="PlacesChevronPopup"
++                         placespopup="true"
++                         tooltip="bhTooltip" popupsinherittooltip="true"
++                         context="placesContext"/>
++            </toolbarbutton>
++          </hbox>
++        </hbox>
++      </toolbaritem>
++    </toolbar>
++
++    <!-- This is a shim which will go away ASAP. See bug 749804 for details -->
++    <toolbar id="addon-bar" toolbar-delegate="nav-bar" mode="icons" iconsize="small"
++             customizable="true">
++      <hbox id="addonbar-closebutton"/>
++      <statusbar id="status-bar"/>
++    </toolbar>
++
++    <toolbarpalette id="BrowserToolbarPalette">
++
++# Update primaryToolbarButtons in browser/themes/shared/browser.inc when adding
++# or removing default items with the toolbarbutton-1 class.
++
++      <toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++#ifdef XP_MACOSX
++                     command="cmd_print"
++                     tooltip="dynamic-shortcut-tooltip"
++#else
++                     command="cmd_printPreview"
++                     tooltiptext="&printButton.tooltip;"
++#endif
++                     label="&printButton.label;"/>
++
++
++      <toolbarbutton id="new-window-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                     label="&newNavigatorCmd.label;"
++                     command="key_newNavigator"
++                     tooltip="dynamic-shortcut-tooltip"
++                     ondrop="newWindowButtonObserver.onDrop(event)"
++                     ondragover="newWindowButtonObserver.onDragOver(event)"
++                     ondragenter="newWindowButtonObserver.onDragOver(event)"
++                     ondragexit="newWindowButtonObserver.onDragExit(event)"/>
++
++      <toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                     observes="View:FullScreen"
++                     type="checkbox"
++                     label="&fullScreenCmd.label;"
++                     tooltip="dynamic-shortcut-tooltip"/>
++
++#ifdef MOZ_SERVICES_SYNC
++      <toolbarbutton id="sync-button"
++                     class="toolbarbutton-1 chromeclass-toolbar-additional"
++                     label="&syncToolbarButton.label;"
++                     oncommand="gSyncUI.handleToolbarButton()"/>
++#endif
++
++      <toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++                     label="&tabGroupsButton.label;"
++                     command="Browser:ToggleTabView"
++                     tooltip="dynamic-shortcut-tooltip"
++                     observes="tabviewGroupsNumber"/>
++    </toolbarpalette>
++  </toolbox>
++
++  <hbox id="fullscr-toggler" hidden="true"/>
++
++  <deck id="content-deck" flex="1">
++    <hbox flex="1" id="browser">
++      <vbox id="browser-border-start" hidden="true" layer="true"/>
++      <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
++        <sidebarheader id="sidebar-header" align="center">
++          <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
++          <image id="sidebar-throbber"/>
++          <toolbarbutton class="close-icon tabbable" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="SidebarUI.hide();"/>
++        </sidebarheader>
++        <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true"
++                  style="min-width: 14em; width: 18em; max-width: 36em;" tooltip="aHTMLTooltip"/>
++      </vbox>
++
++      <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
++      <vbox id="appcontent" flex="1">
++        <notificationbox id="high-priority-global-notificationbox" notificationside="top"/>
++        <tabbrowser id="content"
++                    flex="1" contenttooltip="aHTMLTooltip"
++                    tabcontainer="tabbrowser-tabs"
++                    contentcontextmenu="contentAreaContextMenu"
++                    autocompletepopup="PopupAutoComplete"
++                    selectmenulist="ContentSelectDropdown"/>
++        <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
++      </vbox>
++      <splitter id="social-sidebar-splitter"
++                class="chromeclass-extrachrome sidebar-splitter"
++                observes="socialSidebarBroadcaster"/>
++      <vbox id="social-sidebar-box"
++            class="chromeclass-extrachrome"
++            observes="socialSidebarBroadcaster"
++            persist="width">
++
++        <sidebarheader id="social-sidebar-header" class="sidebar-header" align="center">
++          <image id="social-sidebar-favico"/>
++          <label id="social-sidebar-title" class="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
++          <toolbarbutton id="social-sidebar-button"
++                         class="toolbarbutton-1"
++                         type="menu">
++            <menupopup id="social-statusarea-popup" position="after_end">
++              <menuitem class="social-toggle-sidebar-menuitem"
++                        type="checkbox"
++                        autocheck="false"
++                        command="Social:ToggleSidebar"
++                        label="&social.toggleSidebar.label;"
++                        accesskey="&social.toggleSidebar.accesskey;"/>
++              <menuitem class="social-toggle-notifications-menuitem"
++                        type="checkbox"
++                        autocheck="false"
++                        command="Social:ToggleNotifications"
++                        label="&social.toggleNotifications.label;"
++                        accesskey="&social.toggleNotifications.accesskey;"/>
++              <menuseparator/>
++              <menuseparator class="social-provider-menu" hidden="true"/>
++              <menuitem class="social-addons-menuitem" command="Social:Addons"
++                        label="&social.addons.label;"/>
++              <menuitem label="&social.learnMore.label;"
++                        accesskey="&social.learnMore.accesskey;"
++                        oncommand="SocialUI.showLearnMore();"/>
++            </menupopup>
++          </toolbarbutton>
++        </sidebarheader>
++
++        <browser id="social-sidebar-browser"
++                 type="content"
++                 context="contentAreaContextMenu"
++                 message="true"
++                 messagemanagergroup="social"
++                 disableglobalhistory="true"
++                 tooltip="aHTMLTooltip"
++                 popupnotificationanchor="social-sidebar-favico"
++                 flex="1"
++                 style="min-width: 14em; width: 18em; max-width: 36em;"/>
++      </vbox>
++      <vbox id="browser-border-end" hidden="true" layer="true"/>
++    </hbox>
++#include ../../components/customizableui/content/customizeMode.inc.xul
++  </deck>
++
++  <html:div id="fullscreen-warning" hidden="true">
++    <html:div id="fullscreen-domain-text">
++      &fullscreenWarning.beforeDomain.label;
++      <html:span id="fullscreen-domain"/>
++      &fullscreenWarning.afterDomain.label;
++    </html:div>
++    <html:div id="fullscreen-generic-text">
++      &fullscreenWarning.generic.label;
++    </html:div>
++    <html:button id="fullscreen-exit-button"
++                 onclick="FullScreen.exitDomFullScreen();">
++#ifdef XP_MACOSX
++            &exitDOMFullscreenMac.button;
++#else
++            &exitDOMFullscreen.button;
++#endif
++    </html:button>
++  </html:div>
++
++  <vbox id="browser-bottombox" layer="true">
++    <notificationbox id="global-notificationbox" notificationside="bottom"/>
++    <toolbar id="developer-toolbar"
++             hidden="true">
++#ifdef XP_MACOSX
++          <toolbarbutton id="developer-toolbar-closebutton"
++                         class="devtools-closebutton"
++                         oncommand="DeveloperToolbar.hide();"
++                         tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
++#endif
++          <stack class="gclitoolbar-stack-node" flex="1">
++            <textbox class="gclitoolbar-input-node" rows="1"/>
++            <hbox class="gclitoolbar-complete-node"/>
++          </stack>
++          <toolbarbutton id="developer-toolbar-toolbox-button"
++                         class="developer-toolbar-button"
++                         observes="devtoolsMenuBroadcaster_DevToolbox"
++                         tooltiptext="&devToolbarToolsButton.tooltip;"/>
++#ifndef XP_MACOSX
++          <toolbarbutton id="developer-toolbar-closebutton"
++                         class="devtools-closebutton"
++                         oncommand="DeveloperToolbar.hide();"
++                         tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
++#endif
++   </toolbar>
++  </vbox>
++
++  <svg:svg height="0">
++#include tab-shape.inc.svg
++    <svg:clipPath id="urlbar-back-button-clip-path">
++#ifndef XP_MACOSX
++      <svg:path d="M -9,-4 l 0,1 a 15 15 0 0,1 0,30 l 0,1 l 10000,0 l 0,-32 l -10000,0 z" />
++#else
++      <svg:path d="M -11,-5 a 16 16 0 0 1 0,34 l 10000,0 l 0,-34 l -10000,0 z"/>
++#endif
++    </svg:clipPath>
++#ifdef XP_WIN
++    <svg:clipPath id="urlbar-back-button-clip-path-win10">
++      <svg:path d="M -6,-2 l 0,1 a 15 15 0 0,1 0,30 l 0,1 l 10000,0 l 0,-32 l -10000,0 z" />
++    </svg:clipPath>
++#endif
++  </svg:svg>
++
++</vbox>
++# <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
++#     Introducing the iframe dynamically, as needed, was found to be better than
++#     starting with an empty iframe here in browser.xul from a Ts standpoint.
++</deck>
++
++</window>
+diff --git a/browser/base/jar.mn b/browser/base/jar.mn
+--- a/browser/base/jar.mn
++++ b/browser/base/jar.mn
+@@ -70,16 +70,18 @@ browser.jar:
+         content/browser/aboutSocialError.xhtml        (content/aboutSocialError.xhtml)
+         content/browser/aboutProviderDirectory.xhtml  (content/aboutProviderDirectory.xhtml)
+         content/browser/aboutTabCrashed.css           (content/aboutTabCrashed.css)
+         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
+         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
+ *       content/browser/browser.css                   (content/browser.css)
+ *       content/browser/browser.js                    (content/browser.js)
+ *       content/browser/browser.xul                   (content/browser.xul)
++*       content/browser/browser-kde.xul               (content/browser-kde.xul)
++%       override chrome://browser/content/browser.xul chrome://browser/content/browser-kde.xul desktop=kde
+ *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
+ *       content/browser/chatWindow.xul                (content/chatWindow.xul)
+         content/browser/tab-content.js                (content/tab-content.js)
+         content/browser/content.js                    (content/content.js)
+         content/browser/social-content.js             (content/social-content.js)
+         content/browser/defaultthemes/1.footer.jpg    (content/defaultthemes/1.footer.jpg)
+         content/browser/defaultthemes/1.header.jpg    (content/defaultthemes/1.header.jpg)
+         content/browser/defaultthemes/1.icon.jpg      (content/defaultthemes/1.icon.jpg)
+diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp
+--- a/browser/components/build/nsModule.cpp
++++ b/browser/components/build/nsModule.cpp
+@@ -8,17 +8,17 @@
+ #include "nsBrowserCompsCID.h"
+ #include "DirectoryProvider.h"
+ 
+ #if defined(XP_WIN)
+ #include "nsWindowsShellService.h"
+ #elif defined(XP_MACOSX)
+ #include "nsMacShellService.h"
+ #elif defined(MOZ_WIDGET_GTK)
+-#include "nsGNOMEShellService.h"
++#include "nsUnixShellService.h"
+ #endif
+ 
+ #if defined(XP_WIN)
+ #include "nsIEHistoryEnumerator.h"
+ #include "nsEdgeReadingListExtractor.h"
+ #endif
+ 
+ #include "rdf.h"
+@@ -32,18 +32,16 @@ using namespace mozilla::browser;
+ 
+ /////////////////////////////////////////////////////////////////////////////
+ 
+ NS_GENERIC_FACTORY_CONSTRUCTOR(DirectoryProvider)
+ #if defined(XP_WIN)
+ NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindowsShellService)
+ #elif defined(XP_MACOSX)
+ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService)
+-#elif defined(MOZ_WIDGET_GTK)
+-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
+ #endif
+ 
+ #if defined(XP_WIN)
+ NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
+ NS_GENERIC_FACTORY_CONSTRUCTOR(nsEdgeReadingListExtractor)
+ #endif
+ 
+ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
+@@ -63,17 +61,17 @@ NS_DEFINE_NAMED_CID(NS_EDGEREADINGLISTEX
+ NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
+ #endif
+ 
+ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
+     { &kNS_BROWSERDIRECTORYPROVIDER_CID, false, nullptr, DirectoryProviderConstructor },
+ #if defined(XP_WIN)
+     { &kNS_SHELLSERVICE_CID, false, nullptr, nsWindowsShellServiceConstructor },
+ #elif defined(MOZ_WIDGET_GTK)
+-    { &kNS_SHELLSERVICE_CID, false, nullptr, nsGNOMEShellServiceConstructor },
++    { &kNS_SHELLSERVICE_CID, false, nullptr, nsUnixShellServiceConstructor },
+ #endif
+     { &kNS_FEEDSNIFFER_CID, false, nullptr, nsFeedSnifferConstructor },
+     { &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
+ #if defined(XP_WIN)
+     { &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
+     { &kNS_EDGEREADINGLISTEXTRACTOR_CID, false, nullptr, nsEdgeReadingListExtractorConstructor },
+ #elif defined(XP_MACOSX)
+     { &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
+diff --git a/browser/components/preferences/in-content/main.js b/browser/components/preferences/in-content/main.js
+--- a/browser/components/preferences/in-content/main.js
++++ b/browser/components/preferences/in-content/main.js
+@@ -14,16 +14,22 @@ var gMainPane = {
+   init: function ()
+   {
+     function setEventListener(aId, aEventType, aCallback)
+     {
+       document.getElementById(aId)
+               .addEventListener(aEventType, aCallback.bind(gMainPane));
+     }
+ 
++    var env = Components.classes["@mozilla.org/process/environment;1"]
++                          .getService(Components.interfaces.nsIEnvironment);
++    var kde_session = 0;
++    if (env.get('KDE_FULL_SESSION') == "true")
++        kde_session = 1;
++
+ #ifdef HAVE_SHELL_SERVICE
+     this.updateSetDefaultBrowser();
+ #ifdef XP_WIN
+     // In Windows 8 we launch the control panel since it's the only
+     // way to get all file type association prefs. So we don't know
+     // when the user will select the default.  We refresh here periodically
+     // in case the default changes.  On other Windows OS's defaults can also
+     // be set while the prefs are open.
+@@ -711,16 +717,27 @@ var gMainPane = {
+    */
+   setDefaultBrowser: function()
+   {
+     let shellSvc = getShellService();
+     if (!shellSvc)
+       return;
+     try {
+       shellSvc.setDefaultBrowser(true, false);
++      if (kde_session == 1) {
++        var shellObj = Components.classes["@mozilla.org/file/local;1"]
++                                   .createInstance(Components.interfaces.nsILocalFile);
++        shellObj.initWithPath("/usr/bin/kwriteconfig");
++        var process = Components.classes["@mozilla.org/process/util;1"]
++                                  .createInstance(Components.interfaces.nsIProcess);
++        process.init(shellObj);
++        var args = ["--file", "kdeglobals", "--group", "General", "--key",
++            "BrowserApplication", "firefox"];
++        process.run(false, args, args.length);
++      }
+     } catch (ex) {
+       Cu.reportError(ex);
+       return;
+     }
+     let selectedIndex =
+       shellSvc.isDefaultBrowser(false, true) ? 1 : 0;
+     document.getElementById("setDefaultPane").selectedIndex = selectedIndex;
+   }
+diff --git a/browser/components/shell/moz.build b/browser/components/shell/moz.build
+--- a/browser/components/shell/moz.build
++++ b/browser/components/shell/moz.build
+@@ -30,16 +30,18 @@ if CONFIG['OS_ARCH'] == 'WINNT':
+     ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+     SOURCES += [
+         'nsMacShellService.cpp',
+     ]
+ elif CONFIG['MOZ_WIDGET_GTK']:
+     SOURCES += [
+         'nsGNOMEShellService.cpp',
++	'nsKDEShellService.cpp',
++	'nsUnixShellService.cpp',
+     ]
+ 
+ if SOURCES:
+     FINAL_LIBRARY = 'browsercomps'
+ 
+ EXTRA_COMPONENTS += [
+     'nsSetDefaultBrowser.js',
+     'nsSetDefaultBrowser.manifest',
+diff --git a/browser/components/shell/nsKDEShellService.cpp b/browser/components/shell/nsKDEShellService.cpp
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/nsKDEShellService.cpp
+@@ -0,0 +1,292 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "mozilla/ArrayUtils.h"
++
++#include "nsCOMPtr.h"
++#include "nsKDEShellService.h"
++#include "nsShellService.h"
++#include "nsKDEUtils.h"
++#include "nsIPrefService.h"
++#include "nsIProcess.h"
++#include "nsIFile.h"
++#include "nsServiceManagerUtils.h"
++#include "nsComponentManagerUtils.h"
++#include "nsIMutableArray.h"
++#include "nsISupportsPrimitives.h"
++#include "nsArrayUtils.h"
++
++using namespace mozilla;
++
++nsresult
++nsKDEShellService::Init()
++{
++    if( !nsKDEUtils::kdeSupport())
++        return NS_ERROR_NOT_AVAILABLE;
++    return NS_OK;
++}
++
++NS_IMPL_ISUPPORTS(nsKDEShellService, nsIShellService)
++
++NS_IMETHODIMP
++nsKDEShellService::IsDefaultBrowser(bool aStartupCheck,
++                                    bool aForAllTypes,
++                                    bool* aIsDefaultBrowser)
++{
++    *aIsDefaultBrowser = false;
++    if (aStartupCheck)
++        mCheckedThisSession = true;
++
++    nsCOMPtr<nsIMutableArray> command = do_CreateInstance( NS_ARRAY_CONTRACTID );
++    if (!command)
++        return NS_ERROR_FAILURE;
++
++    nsCOMPtr<nsISupportsCString> str = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    if (!str)
++        return NS_ERROR_FAILURE;
++
++    str->SetData( NS_LITERAL_CSTRING( "ISDEFAULTBROWSER" ));
++    command->AppendElement( str, false );
++
++    if( nsKDEUtils::command( command ))
++        *aIsDefaultBrowser = true;
++    return NS_OK;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::SetDefaultBrowser(bool aClaimAllTypes,
++                                     bool aForAllUsers)
++{
++    nsCOMPtr<nsIMutableArray> command = do_CreateInstance( NS_ARRAY_CONTRACTID );
++    if (!command)
++        return NS_ERROR_FAILURE;
++
++    nsCOMPtr<nsISupportsCString> cmdstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    nsCOMPtr<nsISupportsCString> paramstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    if (!cmdstr || !paramstr)
++        return NS_ERROR_FAILURE;
++
++    cmdstr->SetData( NS_LITERAL_CSTRING( "SETDEFAULTBROWSER" ));
++    command->AppendElement( cmdstr, false );
++
++    paramstr->SetData( aClaimAllTypes ? NS_LITERAL_CSTRING( "ALLTYPES" ) : NS_LITERAL_CSTRING( "NORMAL" ));
++    command->AppendElement( paramstr, false );
++
++    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
++{
++  NS_ENSURE_ARG_POINTER(aResult);
++
++  nsresult rv;
++  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++
++  rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++  if (*aResult) {
++    // Only skip the default browser check once. The next attempt in
++    // a new session should proceed.
++    return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
++  }
++
++  int32_t defaultBrowserCheckCount;
++  rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
++                         &defaultBrowserCheckCount);
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++  if (defaultBrowserCheckCount < 4) {
++    *aResult = false;
++    return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
++                             defaultBrowserCheckCount + 1);
++  }
++
++  // Disable the default browser check after three attempts.
++  // Don't modify PREF_CHECKDEFAULTBROWSER since that is a
++  // user-initiated action and it shouldn't get re-enabled
++  // if it has been user disabled.
++  *aResult = true;
++  return rv;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::GetShouldCheckDefaultBrowser(bool* aResult)
++{
++  // If we've already checked, the browser has been started and this is a
++  // new window open, and we don't want to check again.
++  if (mCheckedThisSession) {
++    *aResult = false;
++    return NS_OK;
++  }
++
++  nsresult rv;
++#ifndef RELEASE_BUILD
++  bool skipDefaultBrowserCheck;
++  rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++  if (skipDefaultBrowserCheck) {
++    *aResult = false;
++    return rv;
++  }
++#endif
++
++  nsCOMPtr<nsIPrefBranch> prefs;
++  nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
++  if (pserve)
++    pserve->GetBranch("", getter_AddRefs(prefs));
++
++  if (prefs)
++    prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
++
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck)
++{
++  nsCOMPtr<nsIPrefBranch> prefs;
++  nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
++  if (pserve)
++    pserve->GetBranch("", getter_AddRefs(prefs));
++
++  if (prefs)
++    prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
++
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::GetCanSetDesktopBackground(bool* aResult)
++{
++  *aResult = true;
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::SetDesktopBackground(nsIDOMElement* aElement,
++                                          PRInt32 aPosition)
++{
++    return NS_ERROR_NOT_IMPLEMENTED;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::GetDesktopBackgroundColor(PRUint32 *aColor)
++{
++    return NS_ERROR_NOT_IMPLEMENTED;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::SetDesktopBackgroundColor(PRUint32 aColor)
++{
++    return NS_ERROR_NOT_IMPLEMENTED;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::OpenApplication(PRInt32 aApplication)
++{
++    nsCOMPtr<nsIMutableArray> command = do_CreateInstance( NS_ARRAY_CONTRACTID );
++    if (!command)
++        return NS_ERROR_FAILURE;
++
++    nsCOMPtr<nsISupportsCString> str = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    if (!str)
++        return NS_ERROR_FAILURE;
++
++    if( aApplication == APPLICATION_MAIL )
++        str->SetData( NS_LITERAL_CSTRING( "OPENMAIL" ));
++    else if( aApplication == APPLICATION_NEWS )
++        str->SetData( NS_LITERAL_CSTRING( "OPENNEWS" ));
++    else
++        return NS_ERROR_NOT_IMPLEMENTED;
++
++    command->AppendElement( str, false );
++    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI)
++{
++    nsCOMPtr<nsIMutableArray> command = do_CreateInstance( NS_ARRAY_CONTRACTID );
++    if (!command)
++        return NS_ERROR_FAILURE;
++
++    nsCOMPtr<nsISupportsCString> cmdstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    nsCOMPtr<nsISupportsCString> appstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    nsCOMPtr<nsISupportsCString> uristr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    if (!cmdstr || !appstr || !uristr)
++        return NS_ERROR_FAILURE;
++
++    cmdstr->SetData( NS_LITERAL_CSTRING( "RUN" ));
++    command->AppendElement( cmdstr, false );
++    nsAutoCString app;
++    nsresult rv = aApplication->GetNativePath( app );
++    NS_ENSURE_SUCCESS( rv, rv );
++    appstr->SetData( app );
++    command->AppendElement( appstr, false );
++    uristr->SetData( aURI );
++    command->AppendElement( uristr, false );
++    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::GetDefaultFeedReader(nsIFile** _retval)
++{
++    *_retval = nullptr;
++
++    nsCOMPtr<nsIMutableArray> command = do_CreateInstance( NS_ARRAY_CONTRACTID );
++    if( !command )
++        return NS_ERROR_FAILURE;
++
++    nsCOMPtr<nsISupportsCString> str = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++    if( !str )
++        return NS_ERROR_FAILURE;
++
++    str->SetData( NS_LITERAL_CSTRING( "GETDEFAULTFEEDREADER" ));
++    command->AppendElement( str, false );
++
++    nsCOMPtr<nsIArray> output;
++    if( !nsKDEUtils::command( command, getter_AddRefs( output ) ) )
++        return NS_ERROR_FAILURE;
++
++    PRUint32 length;
++    output->GetLength( &length );
++    if( length != 1 )
++        return NS_ERROR_FAILURE;
++
++    nsCOMPtr<nsISupportsCString> resstr = do_QueryElementAt( output, 0 );
++    if( !resstr )
++        return NS_ERROR_FAILURE;
++
++    nsAutoCString path;
++    resstr->GetData( path );
++    if (path.IsEmpty())
++        return NS_ERROR_FAILURE;
++
++    nsresult rv;
++    nsCOMPtr<nsIFile> defaultReader =
++        do_CreateInstance("@mozilla.org/file/local;1", &rv);
++    NS_ENSURE_SUCCESS(rv, rv);
++
++    rv = defaultReader->InitWithNativePath(path);
++    NS_ENSURE_SUCCESS(rv, rv);
++
++    bool exists;
++    rv = defaultReader->Exists(&exists);
++    NS_ENSURE_SUCCESS(rv, rv);
++    if (!exists)
++        return NS_ERROR_FAILURE;
++
++    NS_ADDREF(*_retval = defaultReader);
++    return NS_OK;
++}
+diff --git a/browser/components/shell/nsKDEShellService.h b/browser/components/shell/nsKDEShellService.h
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/nsKDEShellService.h
+@@ -0,0 +1,29 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef nskdeshellservice_h____
++#define nskdeshellservice_h____
++
++#include "nsIShellService.h"
++#include "nsStringAPI.h"
++#include "mozilla/Attributes.h"
++
++class nsKDEShellService final : public nsIShellService
++{
++public:
++  nsKDEShellService() : mCheckedThisSession(false) { }
++
++  NS_DECL_ISUPPORTS
++  NS_DECL_NSISHELLSERVICE
++
++  nsresult Init();
++
++private:
++  ~nsKDEShellService() {}
++
++  bool mCheckedThisSession;
++};
++
++#endif // nskdeshellservice_h____
+diff --git a/browser/components/shell/nsUnixShellService.cpp b/browser/components/shell/nsUnixShellService.cpp
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/nsUnixShellService.cpp
+@@ -0,0 +1,22 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++
++#include "nsUnixShellService.h"
++#include "nsGNOMEShellService.h"
++#include "nsKDEShellService.h"
++#include "nsKDEUtils.h"
++#include "mozilla/ModuleUtils.h"
++
++NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
++NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsKDEShellService, Init)
++
++NS_METHOD
++nsUnixShellServiceConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult)
++{
++    if( nsKDEUtils::kdeSupport())
++        return nsKDEShellServiceConstructor( aOuter, aIID, aResult );
++    return nsGNOMEShellServiceConstructor( aOuter, aIID, aResult );
++}
+diff --git a/browser/components/shell/nsUnixShellService.h b/browser/components/shell/nsUnixShellService.h
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/nsUnixShellService.h
+@@ -0,0 +1,15 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++
++#ifndef nsunixshellservice_h____
++#define nsunixshellservice_h____
++
++#include "nsIShellService.h"
++
++NS_METHOD
++nsUnixShellServiceConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult);
++
++#endif // nsunixshellservice_h____
+diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
+--- a/browser/installer/package-manifest.in
++++ b/browser/installer/package-manifest.in
+@@ -709,16 +709,17 @@
+ @RESPATH@/defaults/autoconfig/prefcalls.js
+ @RESPATH@/browser/defaults/profile/prefs.js
+ @RESPATH@/browser/defaults/permissions
+ 
+ ; Warning: changing the path to channel-prefs.js can cause bugs (Bug 756325)
+ ; Technically this is an app pref file, but we are keeping it in the original
+ ; gre location for now.
+ @RESPATH@/defaults/pref/channel-prefs.js
++@BINPATH@/defaults/pref/kde.js
+ 
+ ; Services (gre) prefs
+ #ifdef MOZ_SERVICES_NOTIFICATIONS
+ @RESPATH@/defaults/pref/services-notifications.js
+ #endif
+ #ifdef MOZ_SERVICES_SYNC
+ @RESPATH@/defaults/pref/services-sync.js
+ #endif
diff --git a/helpers/DATA/firefox/mozilla-kde.patch b/helpers/DATA/firefox/mozilla-kde.patch
new file mode 100644
index 00000000..6816da49
--- /dev/null
+++ b/helpers/DATA/firefox/mozilla-kde.patch
@@ -0,0 +1,3780 @@
+# HG changeset patch
+# Parent  d9c9ae52f0338a60d1626d9209248341815e597a
+Description: Add KDE integration to Firefox (toolkit parts)
+Author: Wolfgang Rosenauer <wolfgang@rosenauer.org>
+Author: Lubos Lunak <lunak@suse.com>
+Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751
+     https://bugzilla.novell.com/show_bug.cgi?id=170055
+
+diff --git a/modules/libpref/Makefile.in b/modules/libpref/Makefile.in
+--- a/modules/libpref/Makefile.in
++++ b/modules/libpref/Makefile.in
+@@ -21,13 +21,15 @@ endif
+ ifdef MOZ_SERVICES_HEALTHREPORT
+ ifneq (android,$(MOZ_WIDGET_TOOLKIT))
+ grepref_files += $(topsrcdir)/services/healthreport/healthreport-prefs.js
+ else
+ grepref_files += $(topsrcdir)/mobile/android/chrome/content/healthreport-prefs.js
+ endif
+ endif
+ 
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
++
+ greprefs.js: $(grepref_files)
+ 	$(call py_action,preprocessor,$(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(MOZ_DEBUG_DEFINES) $^ -o $@)
+ 
+ libs:: greprefs.js
+ 	$(INSTALL) $^ $(DIST)/bin/
+diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp
+--- a/modules/libpref/Preferences.cpp
++++ b/modules/libpref/Preferences.cpp
+@@ -30,16 +30,17 @@
+ #include "nsIZipReader.h"
+ #include "nsPrefBranch.h"
+ #include "nsXPIDLString.h"
+ #include "nsCRT.h"
+ #include "nsCOMArray.h"
+ #include "nsXPCOMCID.h"
+ #include "nsAutoPtr.h"
+ #include "nsPrintfCString.h"
++#include "nsKDEUtils.h"
+ 
+ #include "nsQuickSort.h"
+ #include "PLDHashTable.h"
+ 
+ #include "prefapi.h"
+ #include "prefread.h"
+ #include "prefapi_private_data.h"
+ 
+@@ -1148,16 +1149,34 @@ pref_LoadPrefsInDir(nsIFile* aDir, char 
+ 
+ static nsresult pref_LoadPrefsInDirList(const char *listId)
+ {
+   nsresult rv;
+   nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+   if (NS_FAILED(rv))
+     return rv;
+ 
++  // make sure we load these special files after all the others
++  static const char* specialFiles[] = {
++#if defined(XP_UNIX)
++    ""
++#endif
++  };
++
++  if (nsKDEUtils::kdeSession()) {
++    for(int i = 0;
++        i < MOZ_ARRAY_LENGTH(specialFiles);
++        ++i ) {
++      if (*specialFiles[ i ] == '\0') {
++        specialFiles[ i ] = "kde.js";
++        break;
++      }
++    }
++  }
++
+   nsCOMPtr<nsISimpleEnumerator> list;
+   dirSvc->Get(listId,
+               NS_GET_IID(nsISimpleEnumerator),
+               getter_AddRefs(list));
+   if (!list)
+     return NS_OK;
+ 
+   bool hasMore;
+@@ -1173,17 +1192,17 @@ static nsresult pref_LoadPrefsInDirList(
+ 
+     nsAutoCString leaf;
+     path->GetNativeLeafName(leaf);
+ 
+     // Do we care if a file provided by this process fails to load?
+     if (Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi"))
+       ReadExtensionPrefs(path);
+     else
+-      pref_LoadPrefsInDir(path, nullptr, 0);
++      pref_LoadPrefsInDir(path, specialFiles, MOZ_ARRAY_LENGTH(specialFiles));
+   }
+   return NS_OK;
+ }
+ 
+ static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
+ {
+   nsZipItemPtr<char> manifest(jarReader, name, true);
+   NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
+@@ -1277,26 +1296,38 @@ static nsresult pref_InitInitialObjects(
+   /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
+   static const char* specialFiles[] = {
+ #if defined(XP_MACOSX)
+     "macprefs.js"
+ #elif defined(XP_WIN)
+     "winpref.js"
+ #elif defined(XP_UNIX)
+     "unix.js"
++    , "" // placeholder for KDE  (empty is otherwise harmless)
+ #if defined(VMS)
+     , "openvms.js"
+ #elif defined(_AIX)
+     , "aix.js"
+ #endif
+ #elif defined(XP_BEOS)
+     "beos.js"
+ #endif
+   };
+ 
++  if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper?
++    for(int i = 0;
++        i < MOZ_ARRAY_LENGTH(specialFiles);
++        ++i ) {
++      if( *specialFiles[ i ] == '\0' ) {
++        specialFiles[ i ] = "kde.js";
++        break;
++      }
++    }
++  }
++
+   rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
+   if (NS_FAILED(rv))
+     NS_WARNING("Error parsing application default preferences.");
+ 
+   // Load jar:$app/omni.jar!/defaults/preferences/*.js
+   // or jar:$gre/omni.jar!/defaults/preferences/*.js.
+   RefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
+   // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
+diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py
+--- a/python/mozbuild/mozpack/chrome/flags.py
++++ b/python/mozbuild/mozpack/chrome/flags.py
+@@ -211,16 +211,17 @@ class Flags(OrderedDict):
+         'contentaccessible': Flag,
+         'os': StringFlag,
+         'osversion': VersionFlag,
+         'abi': StringFlag,
+         'platform': Flag,
+         'xpcnativewrappers': Flag,
+         'tablet': Flag,
+         'process': StringFlag,
++        'desktop': StringFlag,
+     }
+     RE = re.compile(r'([!<>=]+)')
+ 
+     def __init__(self, *flags):
+         '''
+         Initialize a set of flags given in string form.
+            flags = Flags('contentaccessible=yes', 'appversion>=3.5')
+         '''
+diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py
+--- a/python/mozbuild/mozpack/chrome/manifest.py
++++ b/python/mozbuild/mozpack/chrome/manifest.py
+@@ -33,16 +33,17 @@ class ManifestEntry(object):
+         'application',
+         'platformversion',
+         'os',
+         'osversion',
+         'abi',
+         'xpcnativewrappers',
+         'tablet',
+         'process',
++        'desktop',
+     ]
+ 
+     def __init__(self, base, *flags):
+         '''
+         Initialize a manifest entry with the given base path and flags.
+         '''
+         self.base = base
+         self.flags = Flags(*flags)
+diff --git a/toolkit/components/downloads/moz.build b/toolkit/components/downloads/moz.build
+--- a/toolkit/components/downloads/moz.build
++++ b/toolkit/components/downloads/moz.build
+@@ -65,15 +65,16 @@ if not CONFIG['MOZ_SUITE']:
+         'nsDownloadManagerUI.js',
+         'nsDownloadManagerUI.manifest',
+     ]
+ 
+ FINAL_LIBRARY = 'xul'
+ 
+ LOCAL_INCLUDES += [
+     '../protobuf',
+-    '/ipc/chromium/src'
++    '/ipc/chromium/src',
++    '/toolkit/xre'
+ ]
+ 
+ DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
+ DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
+ 
+ CXXFLAGS += CONFIG['TK_CFLAGS']
+diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
+--- a/toolkit/components/downloads/nsDownloadManager.cpp
++++ b/toolkit/components/downloads/nsDownloadManager.cpp
+@@ -51,16 +51,20 @@
+ #ifdef XP_WIN
+ #include <shlobj.h>
+ #include "nsWindowsHelpers.h"
+ #ifdef DOWNLOAD_SCANNER
+ #include "nsDownloadScanner.h"
+ #endif
+ #endif
+ 
++#if defined(XP_UNIX) && !defined(XP_MACOSX)
++#include "nsKDEUtils.h"
++#endif
++
+ #ifdef XP_MACOSX
+ #include <CoreFoundation/CoreFoundation.h>
+ #endif
+ 
+ #ifdef MOZ_WIDGET_ANDROID
+ #include "AndroidBridge.h"
+ #endif
+ 
+@@ -2714,16 +2718,25 @@ nsDownload::SetState(DownloadState aStat
+       nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ 
+       // Master pref to control this function.
+       bool showTaskbarAlert = true;
+       if (pref)
+         pref->GetBoolPref(PREF_BDM_SHOWALERTONCOMPLETE, &showTaskbarAlert);
+ 
+       if (showTaskbarAlert) {
++        if( nsKDEUtils::kdeSupport()) {
++          nsTArray<nsCString> command;
++          command.AppendElement( NS_LITERAL_CSTRING( "DOWNLOADFINISHED" ));
++          nsAutoString displayName;
++          GetDisplayName( displayName );
++          command.AppendElement( nsAutoCString( ToNewUTF8String( displayName )));
++          nsKDEUtils::command( command );
++        } else {
++        // begin non-KDE block
+         int32_t alertInterval = 2000;
+         if (pref)
+           pref->GetIntPref(PREF_BDM_SHOWALERTINTERVAL, &alertInterval);
+ 
+         int64_t alertIntervalUSec = alertInterval * PR_USEC_PER_MSEC;
+         int64_t goat = PR_Now() - mStartTime;
+         showTaskbarAlert = goat > alertIntervalUSec;
+ 
+@@ -2754,16 +2767,17 @@ nsDownload::SetState(DownloadState aStat
+                   NS_LITERAL_STRING(DOWNLOAD_MANAGER_ALERT_ICON), title,
+                   message, !removeWhenDone,
+                   mPrivate ? NS_LITERAL_STRING("private") : NS_LITERAL_STRING("non-private"),
+                   mDownloadManager, EmptyString(), NS_LITERAL_STRING("auto"),
+                   EmptyString(), EmptyString(), nullptr, mPrivate);
+             }
+         }
+       }
++      }
+ 
+ #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
+       nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget);
+       nsCOMPtr<nsIFile> file;
+       nsAutoString path;
+ 
+       if (fileURL &&
+           NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) &&
+diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
+--- a/toolkit/content/jar.mn
++++ b/toolkit/content/jar.mn
+@@ -64,29 +64,33 @@ toolkit.jar:
+    content/global/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/remote-browser.xml  (widgets/remote-browser.xml)
+    content/global/bindings/resizer.xml         (widgets/resizer.xml)
+    content/global/bindings/richlistbox.xml     (widgets/richlistbox.xml)
+    content/global/bindings/scale.xml           (widgets/scale.xml)
+    content/global/bindings/scrollbar.xml       (widgets/scrollbar.xml)
+    content/global/bindings/scrollbox.xml       (widgets/scrollbox.xml)
+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,460 @@
++<?xml version="1.0"?>
++<!-- This Source Code Form is subject to the terms of the Mozilla Public
++   - License, v. 2.0. If a copy of the MPL was not distributed with this
++   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
++
++
++<bindings id="dialogBindings"
++          xmlns="http://www.mozilla.org/xbl"
++          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
++          xmlns:xbl="http://www.mozilla.org/xbl">
++  
++  <binding id="dialog" extends="chrome://global/content/bindings/general.xml#root-element">
++    <resources>
++      <stylesheet src="chrome://global/skin/dialog.css"/>
++    </resources>
++    <content>
++      <xul:vbox class="box-inherit dialog-content-box" flex="1">
++        <children/>
++      </xul:vbox>
++          
++      <xul:hbox class="dialog-button-box" anonid="buttons"
++                xbl:inherits="pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient"
++#ifdef XP_UNIX_GNOME
++                >
++        <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++        <xul:spacer anonid="spacer" flex="1"/>
++        <xul:button dlgtype="cancel" class="dialog-button"/>
++        <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
++#elif XP_UNIX
++                >
++	<xul:button dlgtype="help" class="dialog-button" hidden="true"/>
++	<xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++	<xul:spacer anonid="spacer" flex="1"/>
++	<xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
++	<xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++	<xul:button dlgtype="cancel" class="dialog-button"/>
++	<xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++#else
++                pack="end">
++        <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++        <xul:spacer anonid="spacer" flex="1" hidden="true"/>
++        <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
++        <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="cancel" class="dialog-button"/>
++        <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++#endif
++      </xul:hbox>
++    </content>
++
++    <implementation>
++      <field name="_mStrBundle">null</field>
++      <field name="_closeHandler">(function(event) {
++        if (!document.documentElement.cancelDialog())
++          event.preventDefault();
++      })</field>
++
++      <property name="buttons"
++                onget="return this.getAttribute('buttons');"
++                onset="this._configureButtons(val); return val;"/>
++
++      <property name="defaultButton">
++        <getter>
++        <![CDATA[
++          if (this.hasAttribute("defaultButton"))
++            return this.getAttribute("defaultButton");
++          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();
++          }
++
++          if (opener) {
++            var xOffset = (opener.outerWidth - window.outerWidth) / 2;
++            var yOffset = opener.outerHeight / 5;
++
++            var newX = opener.screenX + xOffset;
++            var newY = opener.screenY + yOffset;
++          } else {
++            newX = (screen.availWidth - window.outerWidth) / 2;
++            newY = (screen.availHeight - window.outerHeight) / 2;
++          }
++
++          // ensure the window is fully onscreen (if smaller than the screen)
++          if (newX < screen.availLeft)
++            newX = screen.availLeft + 20;
++          if ((newX + window.outerWidth) > (screen.availLeft + screen.availWidth))
++            newX = (screen.availLeft + screen.availWidth) - window.outerWidth - 20;
++
++          if (newY < screen.availTop)
++            newY = screen.availTop + 20;
++          if ((newY + window.outerHeight) > (screen.availTop + screen.availHeight))
++            newY = (screen.availTop + screen.availHeight) - window.outerHeight - 60;
++
++          window.moveTo( newX, newY );
++        ]]>
++        </body>
++      </method>
++
++      <method name="centerWindowOnScreen">
++        <body>
++        <![CDATA[
++          var xOffset = screen.availWidth/2 - window.outerWidth/2;
++          var yOffset = screen.availHeight/2 - window.outerHeight/2; //(opener.outerHeight *2)/10;
++  
++          xOffset = xOffset > 0 ? xOffset : 0;
++          yOffset = yOffset > 0 ? yOffset : 0;
++          window.moveTo(xOffset, yOffset);
++        ]]>
++        </body>
++      </method>
++
++      <constructor>
++      <![CDATA[
++        this._configureButtons(this.buttons);
++
++        // listen for when window is closed via native close buttons
++        window.addEventListener("close", this._closeHandler, false);
++
++        // for things that we need to initialize after onload fires
++        window.addEventListener("load", this.postLoadInit, false);
++
++        window.moveToAlertPosition = this.moveToAlertPosition;
++        window.centerWindowOnScreen = this.centerWindowOnScreen;
++      ]]>
++      </constructor>
++
++      <method name="postLoadInit">
++        <parameter name="aEvent"/>
++        <body>
++        <![CDATA[
++          function focusInit() {
++            const dialog = document.documentElement;
++            const defaultButton = dialog.getButton(dialog.defaultButton);
++            // give focus to the first focusable element in the dialog
++            if (!document.commandDispatcher.focusedElement) {
++              document.commandDispatcher.advanceFocusIntoSubtree(dialog);
++
++              var focusedElt = document.commandDispatcher.focusedElement;
++              if (focusedElt) {
++                var initialFocusedElt = focusedElt;
++                while (focusedElt.localName == "tab" ||
++                       focusedElt.getAttribute("noinitialfocus") == "true") {
++                  document.commandDispatcher.advanceFocusIntoSubtree(focusedElt);
++                  focusedElt = document.commandDispatcher.focusedElement;
++                  if (focusedElt == initialFocusedElt)
++                    break;
++                }
++
++                if (initialFocusedElt.localName == "tab") {
++                  if (focusedElt.hasAttribute("dlgtype")) {
++                    // We don't want to focus on anonymous OK, Cancel, etc. buttons,
++                    // so return focus to the tab itself
++                    initialFocusedElt.focus();
++                  }
++                }
++#ifndef XP_MACOSX
++                else if (focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton) {
++                  defaultButton.focus();
++                }
++#endif
++              }
++            }
++
++            try {
++              if (defaultButton)
++                window.notifyDefaultButtonLoaded(defaultButton);
++            } catch (e) { }
++          }
++
++          // Give focus after onload completes, see bug 103197.
++          setTimeout(focusInit, 0);
++        ]]>
++        </body>
++      </method>                
++
++      <property name="mStrBundle">
++        <getter>
++        <![CDATA[
++          if (!this._mStrBundle) {
++            // need to create string bundle manually instead of using <xul:stringbundle/>
++            // see bug 63370 for details
++            this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
++                                         .getService(Components.interfaces.nsIStringBundleService)
++                                         .createBundle("chrome://global/locale/dialog.properties");
++          }
++          return this._mStrBundle;
++        ]]></getter>
++      </property>
++      
++      <method name="_configureButtons">
++        <parameter name="aButtons"/>
++        <body>
++        <![CDATA[
++          // by default, get all the anonymous button elements
++          var buttons = {};
++          this._buttons = buttons;
++          buttons.accept = document.getAnonymousElementByAttribute(this, "dlgtype", "accept");
++          buttons.cancel = document.getAnonymousElementByAttribute(this, "dlgtype", "cancel");
++          buttons.extra1 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra1");
++          buttons.extra2 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra2");
++          buttons.help = document.getAnonymousElementByAttribute(this, "dlgtype", "help");
++          buttons.disclosure = document.getAnonymousElementByAttribute(this, "dlgtype", "disclosure");
++
++          // look for any overriding explicit button elements
++          var exBtns = this.getElementsByAttribute("dlgtype", "*");
++          var dlgtype;
++          var i;
++          for (i = 0; i < exBtns.length; ++i) {
++            dlgtype = exBtns[i].getAttribute("dlgtype");
++            buttons[dlgtype].hidden = true; // hide the anonymous button
++            buttons[dlgtype] = exBtns[i];
++          }
++
++          // add the label and oncommand handler to each button
++          for (dlgtype in buttons) {
++            var button = buttons[dlgtype];
++            button.addEventListener("command", this._handleButtonCommand, true);
++
++            // don't override custom labels with pre-defined labels on explicit buttons
++            if (!button.hasAttribute("label")) {
++              // dialog attributes override the default labels in dialog.properties
++              if (this.hasAttribute("buttonlabel"+dlgtype)) {
++                button.setAttribute("label", this.getAttribute("buttonlabel"+dlgtype));
++                if (this.hasAttribute("buttonaccesskey"+dlgtype))
++                  button.setAttribute("accesskey", this.getAttribute("buttonaccesskey"+dlgtype));
++              } else if (dlgtype != "extra1" && dlgtype != "extra2") {
++                button.setAttribute("label", this.mStrBundle.GetStringFromName("button-"+dlgtype));
++                var accessKey = this.mStrBundle.GetStringFromName("accesskey-"+dlgtype);
++                if (accessKey)
++                  button.setAttribute("accesskey", accessKey);
++              }
++            }
++            // allow specifying alternate icons in the dialog header
++            if (!button.hasAttribute("icon")) {
++              // if there's an icon specified, use that
++              if (this.hasAttribute("buttonicon"+dlgtype))
++                button.setAttribute("icon", this.getAttribute("buttonicon"+dlgtype));
++              // otherwise set defaults
++              else
++                switch (dlgtype) {
++                  case "accept":
++                    button.setAttribute("icon","accept");
++                    break;
++                  case "cancel":
++                    button.setAttribute("icon","cancel");
++                    break;
++                  case "disclosure":
++                    button.setAttribute("icon","properties");
++                    break;
++                  case "help":
++                    button.setAttribute("icon","help");
++                    break;
++                  default:
++                    break;
++                }
++            }
++          }
++
++          // ensure that hitting enter triggers the default button command
++          this.defaultButton = this.defaultButton;
++          
++          // if there is a special button configuration, use it
++          if (aButtons) {
++            // expect a comma delimited list of dlgtype values
++            var list = aButtons.split(",");
++
++            // mark shown dlgtypes as true
++            var shown = { accept: false, cancel: false, help: false,
++                          disclosure: false, extra1: false, extra2: false };
++            for (i = 0; i < list.length; ++i)
++              shown[list[i].replace(/ /g, "")] = true;
++
++            // hide/show the buttons we want
++            for (dlgtype in buttons) 
++              buttons[dlgtype].hidden = !shown[dlgtype];
++
++#ifdef XP_WIN
++#           show the spacer on Windows only when the extra2 button is present
++            var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer");
++            spacer.removeAttribute("hidden");
++            spacer.setAttribute("flex", shown["extra2"]?"1":"0");
++#endif
++
++          }
++        ]]>
++        </body>
++      </method>
++
++      <method name="_setDefaultButton">
++        <parameter name="aNewDefault"/>
++        <body>
++        <![CDATA[
++          // remove the default attribute from the previous default button, if any
++          var oldDefaultButton = this.getButton(this.defaultButton);
++          if (oldDefaultButton)
++            oldDefaultButton.removeAttribute("default");
++
++          var newDefaultButton = this.getButton(aNewDefault);
++          if (newDefaultButton) {
++            this.setAttribute("defaultButton", aNewDefault);
++            newDefaultButton.setAttribute("default", "true");
++          }
++          else {
++            this.setAttribute("defaultButton", "none");
++            if (aNewDefault != "none")
++              dump("invalid new default button: " +  aNewDefault + ", assuming: none\n");
++          }
++        ]]>
++        </body>
++      </method>
++
++      <method name="_handleButtonCommand">
++        <parameter name="aEvent"/>
++        <body>
++        <![CDATA[
++          return document.documentElement._doButtonCommand(
++                                        aEvent.target.getAttribute("dlgtype"));
++        ]]>
++        </body>
++      </method>
++      
++      <method name="_doButtonCommand">
++        <parameter name="aDlgType"/>
++        <body>
++        <![CDATA[
++          var button = this.getButton(aDlgType);
++          if (!button.disabled) {
++            var noCancel = this._fireButtonEvent(aDlgType);
++            if (noCancel) {
++              if (aDlgType == "accept" || aDlgType == "cancel") {
++                var closingEvent = new CustomEvent("dialogclosing", {
++                  bubbles: true,
++                  detail: { button: aDlgType },
++                });
++                this.dispatchEvent(closingEvent);
++                window.close();
++              }
++            }
++            return noCancel;
++          }
++          return true;
++        ]]>
++        </body>
++      </method>
++      
++      <method name="_fireButtonEvent">
++        <parameter name="aDlgType"/>
++        <body>
++        <![CDATA[
++          var event = document.createEvent("Events");
++          event.initEvent("dialog"+aDlgType, true, true);
++          
++          // handle dom event handlers
++          var noCancel = this.dispatchEvent(event);
++          
++          // handle any xml attribute event handlers
++          var handler = this.getAttribute("ondialog"+aDlgType);
++          if (handler != "") {
++            var fn = new Function("event", handler);
++            var returned = fn(event);
++            if (returned == false)
++              noCancel = false;
++          }
++          
++          return noCancel;
++        ]]>
++        </body>
++      </method>
++
++      <method name="_hitEnter">
++        <parameter name="evt"/>
++        <body>
++        <![CDATA[
++          if (evt.defaultPrevented)
++            return;
++
++          var btn = this.getButton(this.defaultButton);
++          if (btn)
++            this._doButtonCommand(this.defaultButton);
++        ]]>
++        </body>
++      </method>
++
++    </implementation>
++    
++    <handlers>
++      <handler event="keypress" keycode="VK_RETURN"
++               group="system" action="this._hitEnter(event);"/>
++      <handler event="keypress" keycode="VK_ESCAPE" group="system">
++        if (!event.defaultPrevented)
++          this.cancelDialog();
++      </handler>
++#ifdef XP_MACOSX
++      <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/>
++#else
++      <handler event="focus" phase="capturing">
++        var btn = this.getButton(this.defaultButton);
++        if (btn)
++          btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement));
++      </handler>
++#endif
++    </handlers>
++
++  </binding>
++
++  <binding id="dialogheader">
++    <resources>
++      <stylesheet src="chrome://global/skin/dialog.css"/>
++    </resources>
++    <content>
++      <xul:label class="dialogheader-title" xbl:inherits="value=title,crop" crop="right" flex="1"/>
++      <xul:label class="dialogheader-description" xbl:inherits="value=description"/>
++    </content>
++  </binding>
++
++</bindings>
+diff --git a/toolkit/content/widgets/preferences-kde.xml b/toolkit/content/widgets/preferences-kde.xml
+new file mode 100644
+--- /dev/null
++++ b/toolkit/content/widgets/preferences-kde.xml
+@@ -0,0 +1,1403 @@
++<?xml version="1.0"?>
++
++<!DOCTYPE bindings [
++  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
++  %preferencesDTD;
++  <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
++  %globalKeysDTD;
++]>
++
++<bindings id="preferencesBindings"
++          xmlns="http://www.mozilla.org/xbl"
++          xmlns:xbl="http://www.mozilla.org/xbl"
++          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
++
++#
++# = Preferences Window Framework
++#
++#   The syntax for use looks something like:
++#
++#   <prefwindow>
++#     <prefpane id="prefPaneA">
++#       <preferences>
++#         <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
++#         <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
++#       </preferences>
++#       <checkbox label="Preference" preference="preference1"/>
++#     </prefpane>
++#   </prefwindow>
++#
++
++  <binding id="preferences">
++    <implementation implements="nsIObserver">
++      <method name="_constructAfterChildren">
++      <body>
++      <![CDATA[
++      // This method will be called after each one of the child
++      // <preference> elements is constructed. Its purpose is to propagate
++      // the values to the associated form elements
++
++      var elements = this.getElementsByTagName("preference");
++      for (let element of elements) {
++        if (!element._constructed) {
++          return;
++        }
++      }
++      for (let element of elements) {
++        element.updateElements();
++      }
++      ]]>
++      </body>
++      </method>
++      <method name="observe">
++        <parameter name="aSubject"/>
++        <parameter name="aTopic"/>
++        <parameter name="aData"/>
++        <body>
++        <![CDATA[
++          for (var i = 0; i < this.childNodes.length; ++i) {
++            var preference = this.childNodes[i];
++            if (preference.name == aData) {
++              preference.value = preference.valueFromPreferences;
++            }
++          }
++        ]]>
++        </body>
++      </method>
++      
++      <method name="fireChangedEvent">
++        <parameter name="aPreference"/>
++        <body>
++        <![CDATA[
++          // Value changed, synthesize an event
++          try {
++            var event = document.createEvent("Events");
++            event.initEvent("change", true, true);
++            aPreference.dispatchEvent(event);
++          }
++          catch (e) {
++            Components.utils.reportError(e);
++          }
++        ]]>
++        </body>
++      </method>
++      
++      <field name="service">
++        Components.classes["@mozilla.org/preferences-service;1"]
++                  .getService(Components.interfaces.nsIPrefService);
++      </field>
++      <field name="rootBranch">
++        Components.classes["@mozilla.org/preferences-service;1"]
++                  .getService(Components.interfaces.nsIPrefBranch);
++      </field>
++      <field name="defaultBranch">
++        this.service.getDefaultBranch("");
++      </field>
++      <field name="rootBranchInternal">
++        Components.classes["@mozilla.org/preferences-service;1"]
++                  .getService(Components.interfaces.nsIPrefBranchInternal);
++      </field>
++      <property name="type" readonly="true">
++        <getter>
++          <![CDATA[
++            return document.documentElement.type || "";
++          ]]>
++        </getter>
++      </property>
++      <property name="instantApply" readonly="true">
++        <getter>
++          <![CDATA[
++            var doc = document.documentElement;
++            return this.type == "child" ? doc.instantApply
++                                        : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
++          ]]>
++        </getter>
++      </property>
++    </implementation>
++  </binding>
++
++  <binding id="preference">
++    <implementation>
++      <constructor>
++      <![CDATA[
++        this._constructed = true;
++
++        // if the element has been inserted without the name attribute set,
++        // we have nothing to do here
++        if (!this.name)
++          return;
++
++        this.preferences.rootBranchInternal
++            .addObserver(this.name, this.preferences, false);
++        // In non-instant apply mode, we must try and use the last saved state
++        // from any previous opens of a child dialog instead of the value from
++        // preferences, to pick up any edits a user may have made. 
++
++        var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
++                    .getService(Components.interfaces.nsIScriptSecurityManager);
++        if (this.preferences.type == "child" && 
++            !this.instantApply && window.opener &&
++            secMan.isSystemPrincipal(window.opener.document.nodePrincipal)) {
++          var pdoc = window.opener.document;
++
++          // Try to find a preference element for the same preference.
++          var preference = null;
++          var parentPreferences = pdoc.getElementsByTagName("preferences");
++          for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
++            var parentPrefs = parentPreferences[k]
++                                    .getElementsByAttribute("name", this.name);
++            for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
++              if (parentPrefs[l].localName == "preference")
++                preference = parentPrefs[l];
++            }
++          }
++
++          // Don't use the value setter here, we don't want updateElements to be prematurely fired.
++          this._value = preference ? preference.value : this.valueFromPreferences;
++        }
++        else
++          this._value = this.valueFromPreferences;
++        this.preferences._constructAfterChildren();
++      ]]>
++      </constructor>
++      <destructor>
++        this.preferences.rootBranchInternal
++            .removeObserver(this.name, this.preferences);
++      </destructor>
++      <field name="_constructed">false</field>
++      <property name="instantApply">
++        <getter>
++          return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
++        </getter>
++      </property>
++
++      <property name="preferences" onget="return this.parentNode"/>
++      <property name="name" onget="return this.getAttribute('name');">
++        <setter>
++          if (val == this.name)
++            return val;
++            
++          this.preferences.rootBranchInternal
++              .removeObserver(this.name, this.preferences);
++          this.setAttribute('name', val);
++          this.preferences.rootBranchInternal
++              .addObserver(val, this.preferences, false);
++              
++          return val;
++        </setter>
++      </property>
++      <property name="type" onget="return this.getAttribute('type');"
++                            onset="this.setAttribute('type', val); return val;"/>
++      <property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
++                                onset="this.setAttribute('inverted', val); return val;"/>
++      <property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
++                                onset="this.setAttribute('readonly', val); return val;"/>
++
++      <field name="_value">null</field>
++      <method name="_setValue">
++        <parameter name="aValue"/>
++        <body>
++        <![CDATA[
++          if (this.value !== aValue) {
++            this._value = aValue;
++            if (this.instantApply)
++              this.valueFromPreferences = aValue;
++            this.preferences.fireChangedEvent(this);
++          }
++          return aValue;
++        ]]>
++        </body>
++      </method>
++      <property name="value" onget="return this._value" onset="return this._setValue(val);"/>
++      
++      <property name="locked">
++        <getter>
++          return this.preferences.rootBranch.prefIsLocked(this.name);
++        </getter>
++      </property>
++      
++      <property name="disabled">
++        <getter>
++          return this.getAttribute("disabled") == "true";
++        </getter>
++        <setter>
++        <![CDATA[
++          if (val) 
++            this.setAttribute("disabled", "true");
++          else
++            this.removeAttribute("disabled");
++
++          if (!this.id)
++            return val;
++
++          var elements = document.getElementsByAttribute("preference", this.id);
++          for (var i = 0; i < elements.length; ++i) {
++            elements[i].disabled = val;
++            
++            var labels = document.getElementsByAttribute("control", elements[i].id);
++            for (var j = 0; j < labels.length; ++j)
++              labels[j].disabled = val;
++          }
++            
++          return val;
++        ]]>
++        </setter>
++      </property>
++      
++      <property name="tabIndex">
++        <getter>
++          return parseInt(this.getAttribute("tabindex"));
++        </getter>
++        <setter>
++        <![CDATA[
++          if (val) 
++            this.setAttribute("tabindex", val);
++          else
++            this.removeAttribute("tabindex");
++
++          if (!this.id)
++            return val;
++
++          var elements = document.getElementsByAttribute("preference", this.id);
++          for (var i = 0; i < elements.length; ++i) {
++            elements[i].tabIndex = val;
++            
++            var labels = document.getElementsByAttribute("control", elements[i].id);
++            for (var j = 0; j < labels.length; ++j)
++              labels[j].tabIndex = val;
++          }
++            
++          return val;
++        ]]>
++        </setter>
++      </property>
++
++      <property name="hasUserValue">
++        <getter>
++        <![CDATA[
++          return this.preferences.rootBranch.prefHasUserValue(this.name) &&
++                 this.value !== undefined;
++        ]]>
++        </getter>
++      </property>
++      
++      <method name="reset">
++        <body>
++          // defer reset until preference update
++          this.value = undefined;
++        </body>
++      </method>
++
++      <field name="_useDefault">false</field>      
++      <property name="defaultValue">
++        <getter>
++        <![CDATA[
++          this._useDefault = true;
++          var val = this.valueFromPreferences;
++          this._useDefault = false;
++          return val;
++        ]]>
++        </getter>
++      </property>
++      
++      <property name="_branch">
++        <getter>
++          return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
++        </getter>
++      </property>
++      
++      <field name="batching">false</field>
++      
++      <method name="_reportUnknownType">
++        <body>
++        <![CDATA[
++          var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
++                                         .getService(Components.interfaces.nsIConsoleService);
++          var msg = "<preference> with id='" + this.id + "' and name='" + 
++                    this.name + "' has unknown type '" + this.type + "'.";
++          consoleService.logStringMessage(msg);
++        ]]>
++        </body>
++      </method>
++      
++      <property name="valueFromPreferences">
++        <getter>
++        <![CDATA[
++          try {
++            // Force a resync of value with preferences.
++            switch (this.type) {
++            case "int":
++              return this._branch.getIntPref(this.name);
++            case "bool":
++              var val = this._branch.getBoolPref(this.name);
++              return this.inverted ? !val : val;
++            case "wstring":
++              return this._branch
++                         .getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
++                         .data;
++            case "string":
++            case "unichar":
++              return this._branch
++                         .getComplexValue(this.name, Components.interfaces.nsISupportsString)
++                         .data;
++            case "fontname":
++              var family = this._branch
++                               .getComplexValue(this.name, Components.interfaces.nsISupportsString)
++                               .data;
++              var fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
++                                             .createInstance(Components.interfaces.nsIFontEnumerator);
++              return fontEnumerator.getStandardFamilyName(family);
++            case "file":
++              var f = this._branch
++                          .getComplexValue(this.name, Components.interfaces.nsILocalFile);
++              return f;
++            default:
++              this._reportUnknownType();
++            }
++          }
++          catch (e) { }
++          return null;
++        ]]>
++        </getter>
++        <setter>
++        <![CDATA[
++          // Exit early if nothing to do.
++          if (this.readonly || this.valueFromPreferences == val)
++            return val;
++
++          // The special value undefined means 'reset preference to default'.
++          if (val === undefined) {
++            this.preferences.rootBranch.clearUserPref(this.name);
++            return val;
++          }
++
++          // Force a resync of preferences with value.
++          switch (this.type) {
++          case "int":
++            this.preferences.rootBranch.setIntPref(this.name, val);
++            break;
++          case "bool":
++            this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
++            break;
++          case "wstring":
++            var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
++                                .createInstance(Components.interfaces.nsIPrefLocalizedString);
++            pls.data = val;
++            this.preferences.rootBranch
++                .setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
++            break;
++          case "string":
++          case "unichar":
++          case "fontname":
++            var iss = Components.classes["@mozilla.org/supports-string;1"]
++                                .createInstance(Components.interfaces.nsISupportsString);
++            iss.data = val;
++            this.preferences.rootBranch
++                .setComplexValue(this.name, Components.interfaces.nsISupportsString, iss);
++            break;
++          case "file":
++            var lf;
++            if (typeof(val) == "string") {
++              lf = Components.classes["@mozilla.org/file/local;1"]
++                             .createInstance(Components.interfaces.nsILocalFile);
++              lf.persistentDescriptor = val;
++              if (!lf.exists())
++                lf.initWithPath(val);
++            }
++            else 
++              lf = val.QueryInterface(Components.interfaces.nsILocalFile);
++            this.preferences.rootBranch
++                .setComplexValue(this.name, Components.interfaces.nsILocalFile, lf);
++            break;
++          default:
++            this._reportUnknownType();
++          }
++          if (!this.batching)
++            this.preferences.service.savePrefFile(null);
++          return val;
++        ]]>
++        </setter>
++      </property>
++      
++      <method name="setElementValue">
++        <parameter name="aElement"/>
++        <body>
++        <![CDATA[
++          if (this.locked)
++            aElement.disabled = true;
++
++          if (!this.isElementEditable(aElement))
++            return;
++
++          var rv = undefined;
++          if (aElement.hasAttribute("onsyncfrompreference")) {
++            // Value changed, synthesize an event
++            try {
++              var event = document.createEvent("Events");
++              event.initEvent("syncfrompreference", true, true);
++              var f = new Function ("event", 
++                                    aElement.getAttribute("onsyncfrompreference"));
++              rv = f.call(aElement, event);
++            }
++            catch (e) {
++              Components.utils.reportError(e);
++            }
++          }
++          var val = rv !== 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" pack="end">
++#ifndef XP_UNIX
++        <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
++        <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++        <xul:spacer anonid="spacer" flex="1"/>
++        <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
++        <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
++#else
++        <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++        <xul:spacer anonid="spacer" flex="1"/>
++        <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
++        <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++        <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
++        <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
++        <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++#endif
++      </xul:hbox>
++      <xul:hbox>
++        <children/>
++      </xul:hbox>
++    </content>
++    <implementation implements="nsITimerCallback">
++      <constructor>
++      <![CDATA[
++        if (this.type != "child") {
++          if (!this._instantApplyInitialized) {
++            let psvc = Components.classes["@mozilla.org/preferences-service;1"]
++                                 .getService(Components.interfaces.nsIPrefBranch);
++            this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
++          }
++          if (this.instantApply) {
++            var docElt = document.documentElement;
++            var acceptButton = docElt.getButton("accept");
++            acceptButton.hidden = true;
++            var cancelButton  = docElt.getButton("cancel");
++#ifdef XP_MACOSX
++            // no buttons on Mac except Help
++            cancelButton.hidden = true;
++            // Move Help button to the end
++            document.getAnonymousElementByAttribute(this, "anonid", "spacer").hidden = true;         
++            // Also, don't fire onDialogAccept on enter
++            acceptButton.disabled = true;
++#else
++            // morph the Cancel button into the Close button
++            cancelButton.setAttribute ("icon", "close");
++            cancelButton.label = docElt.getAttribute("closebuttonlabel");
++            cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
++#endif
++          }
++        }
++        this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
++        var panes = this.preferencePanes;
++
++        var lastPane = null;
++        if (this.lastSelected) {
++          lastPane = document.getElementById(this.lastSelected);
++          if (!lastPane) {
++            this.lastSelected = "";
++          }
++        }
++
++        var paneToLoad;
++        if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
++          paneToLoad = document.getElementById(window.arguments[0]);
++          this.lastSelected = paneToLoad.id;
++        }
++        else if (lastPane)
++          paneToLoad = lastPane;
++        else
++          paneToLoad = panes[0];
++
++        for (var i = 0; i < panes.length; ++i) {
++          this._makePaneButton(panes[i]);
++          if (panes[i].loaded) {
++            // Inline pane content, fire load event to force initialization.
++            this._fireEvent("paneload", panes[i]);
++          }
++        }
++        this.showPane(paneToLoad);
++
++        if (panes.length == 1)
++          this._selector.setAttribute("collapsed", "true");
++      ]]>
++      </constructor>
++
++      <destructor>
++      <![CDATA[
++        // Release timers to avoid reference cycles.
++        if (this._animateTimer) {
++          this._animateTimer.cancel();
++          this._animateTimer = null;
++        }
++        if (this._fadeTimer) {
++          this._fadeTimer.cancel();
++          this._fadeTimer = null;
++        }
++      ]]>
++      </destructor>
++
++      <!-- Derived bindings can set this to true to cause us to skip
++           reading the browser.preferences.instantApply pref in the constructor.
++           Then they can set instantApply to their wished value. -->
++      <field name="_instantApplyInitialized">false</field>
++      <!-- Controls whether changed pref values take effect immediately. -->
++      <field name="instantApply">false</field>
++
++      <property name="preferencePanes"
++                onget="return this.getElementsByTagName('prefpane');"/>
++
++      <property name="type" onget="return this.getAttribute('type');"/>
++      <property name="_paneDeck"
++                onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
++      <property name="_paneDeckContainer"
++                onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
++      <property name="_selector"
++                onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
++      <property name="lastSelected" 
++                onget="return this.getAttribute('lastSelected');">
++        <setter>
++          this.setAttribute("lastSelected", val); 
++          document.persist(this.id, "lastSelected");
++          return val;
++        </setter>          
++      </property>
++      <property name="currentPane"
++                onset="return this._currentPane = val;">
++        <getter>
++          if (!this._currentPane)
++            this._currentPane = this.preferencePanes[0];
++          
++          return this._currentPane;
++        </getter> 
++      </property>
++      <field name="_currentPane">null</field>
++      
++      
++      <method name="_makePaneButton">
++        <parameter name="aPaneElement"/>
++        <body>
++        <![CDATA[
++          var radio = document.createElement("radio");
++          radio.setAttribute("pane", aPaneElement.id);
++          radio.setAttribute("label", aPaneElement.label);
++          // Expose preference group choice to accessibility APIs as an unchecked list item
++          // The parent group is exposed to accessibility APIs as a list
++          if (aPaneElement.image)
++            radio.setAttribute("src", aPaneElement.image);
++          radio.style.listStyleImage = aPaneElement.style.listStyleImage;
++          this._selector.appendChild(radio);
++          return radio;
++        ]]>
++        </body>
++      </method>
++
++      <method name="showPane">
++        <parameter name="aPaneElement"/>
++        <body>
++        <![CDATA[
++          if (!aPaneElement)
++            return;
++
++          this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
++          if (!aPaneElement.loaded) {
++            let OverlayLoadObserver = function(aPane)
++            {
++              this._pane = aPane;
++            }
++            OverlayLoadObserver.prototype = { 
++              _outer: this,
++              observe: function (aSubject, aTopic, aData) 
++              {
++                this._pane.loaded = true;
++                this._outer._fireEvent("paneload", this._pane);
++                this._outer._selectPane(this._pane);
++              }
++            };
++            
++            var obs = new OverlayLoadObserver(aPaneElement);
++            document.loadOverlay(aPaneElement.src, obs);
++          }
++          else
++            this._selectPane(aPaneElement);
++        ]]>
++        </body>
++      </method>
++      
++      <method name="_fireEvent">
++        <parameter name="aEventName"/>
++        <parameter name="aTarget"/>
++        <body>
++        <![CDATA[
++          // Panel loaded, synthesize a load event. 
++          try {
++            var event = document.createEvent("Events");
++            event.initEvent(aEventName, true, true);
++            var cancel = !aTarget.dispatchEvent(event);
++            if (aTarget.hasAttribute("on" + aEventName)) {
++              var fn = new Function ("event", aTarget.getAttribute("on" + aEventName));
++              var rv = fn.call(aTarget, event);
++              if (rv == false)
++                cancel = true;
++            }
++            return !cancel;  
++          }
++          catch (e) { 
++            Components.utils.reportError(e);
++          }
++          return false;
++        ]]>
++        </body>
++      </method>
++      
++      <field name="_initialized">false</field>
++      <method name="_selectPane">
++        <parameter name="aPaneElement"/>
++        <body>
++        <![CDATA[
++#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 false;
++        }
++
++        var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
++                    .getService(Components.interfaces.nsIScriptSecurityManager);
++        if (this.type == "child" && window.opener &&
++            secMan.isSystemPrincipal(window.opener.document.nodePrincipal)) {
++          var psvc = Components.classes["@mozilla.org/preferences-service;1"]
++                               .getService(Components.interfaces.nsIPrefBranch);
++          var pdocEl = window.opener.document.documentElement;
++          if (pdocEl.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);
++        }
++
++        return true;
++      ]]>
++      </handler>
++      <handler event="command">
++        if (event.originalTarget.hasAttribute("pane")) {
++          var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
++          this.showPane(pane);
++        }
++      </handler>
++
++      <handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
++      <![CDATA[
++        if (this.instantApply)
++          window.close();
++        event.stopPropagation();
++        event.preventDefault();
++      ]]>
++      </handler>
++
++      <handler event="keypress"
++#ifdef XP_MACOSX
++               key="&openHelpMac.commandkey;" modifiers="accel"
++#else
++               keycode="&openHelp.commandkey;"
++#endif
++               phase="capturing">
++      <![CDATA[
++        var helpButton = this.getButton("help");
++        if (helpButton.disabled || helpButton.hidden)
++          return;
++        this._fireEvent("dialoghelp", this);
++        event.stopPropagation();
++        event.preventDefault();
++      ]]>
++      </handler>
++    </handlers>
++  </binding>
++  
++  <binding id="prefpane">
++    <resources>
++      <stylesheet src="chrome://global/skin/preferences.css"/>
++    </resources>
++    <content>
++      <xul:vbox class="content-box" xbl:inherits="flex">
++        <children/>
++      </xul:vbox>
++    </content>
++    <implementation>
++      <method name="writePreferences">
++        <parameter name="aFlushToDisk"/>
++        <body>
++        <![CDATA[
++          // Write all values to preferences.
++          if (this._deferredValueUpdateElements.size) {
++            this._finalizeDeferredElements();
++          }
++
++          var preferences = this.preferences;
++          for (var i = 0; i < preferences.length; ++i) {
++            var preference = preferences[i];
++            preference.batching = true;
++            preference.valueFromPreferences = preference.value;
++            preference.batching = false;
++          }
++          if (aFlushToDisk) {
++            var psvc = Components.classes["@mozilla.org/preferences-service;1"]
++                                 .getService(Components.interfaces.nsIPrefService);
++            psvc.savePrefFile(null);
++          }
++        ]]>
++        </body>
++      </method>
++      
++      <property name="src" 
++                onget="return this.getAttribute('src');"
++                onset="this.setAttribute('src', val); return val;"/>
++      <property name="selected" 
++                onget="return this.getAttribute('selected') == 'true';"
++                onset="this.setAttribute('selected', val); return val;"/>
++      <property name="image" 
++                onget="return this.getAttribute('image');"
++                onset="this.setAttribute('image', val); return val;"/>
++      <property name="label" 
++                onget="return this.getAttribute('label');"
++                onset="this.setAttribute('label', val); return val;"/>
++      
++      <property name="preferenceElements"
++                onget="return this.getElementsByAttribute('preference', '*');"/>
++      <property name="preferences"
++                onget="return this.getElementsByTagName('preference');"/>
++
++      <property name="helpTopic">
++        <getter>
++        <![CDATA[
++          // if there are tabs, and the selected tab provides a helpTopic, return that
++          var box = this.getElementsByTagName("tabbox");
++          if (box[0]) {
++            var tab = box[0].selectedTab;
++            if (tab && tab.hasAttribute("helpTopic"))
++              return tab.getAttribute("helpTopic");
++          }
++
++          // otherwise, return the helpTopic of the current panel
++          return this.getAttribute("helpTopic");
++        ]]>
++        </getter>
++      </property>
++
++      <field name="_loaded">false</field>
++      <property name="loaded" 
++                onget="return !this.src ? true : this._loaded;"
++                onset="this._loaded = val; return val;"/>
++      
++      <method name="preferenceForElement">
++        <parameter name="aElement"/>
++        <body>
++          return document.getElementById(aElement.getAttribute("preference"));
++        </body>
++      </method>
++      
++      <method name="getPreferenceElement">
++        <parameter name="aStartElement"/>
++        <body>
++        <![CDATA[
++          var temp = aStartElement;
++          while (temp && temp.nodeType == Node.ELEMENT_NODE && 
++                 !temp.hasAttribute("preference"))
++            temp = temp.parentNode;
++          return temp.nodeType == Node.ELEMENT_NODE ? temp : aStartElement;
++        ]]>
++        </body>
++      </method>
++      
++      <field name="DeferredTask" readonly="true">
++        let targetObj = {};
++        Components.utils.import("resource://gre/modules/DeferredTask.jsm", targetObj);
++        targetObj.DeferredTask;
++      </field>
++      <method name="_deferredValueUpdate">
++        <parameter name="aElement"/>
++        <body>
++        <![CDATA[
++          delete aElement._deferredValueUpdateTask;
++          let preference = document.getElementById(aElement.getAttribute("preference"));
++          let prefVal = preference.getElementValue(aElement);
++          preference.value = prefVal;
++          this._deferredValueUpdateElements.delete(aElement);
++        ]]>
++        </body>
++      </method>
++      <field name="_deferredValueUpdateElements">
++        new Set();
++      </field>
++      <method name="_finalizeDeferredElements">
++        <body>
++        <![CDATA[
++          for (let el of this._deferredValueUpdateElements) {
++            if (el._deferredValueUpdateTask) {
++              el._deferredValueUpdateTask.finalize();
++            }
++          }
++        ]]>
++        </body>
++      </method>
++      <method name="userChangedValue">
++        <parameter name="aElement"/>
++        <body>
++        <![CDATA[
++          let element = this.getPreferenceElement(aElement);
++          if (element.hasAttribute("preference")) {
++            if (element.getAttribute("delayprefsave") != "true") {
++              var preference = document.getElementById(element.getAttribute("preference"));
++              var prefVal = preference.getElementValue(element);
++              preference.value = prefVal;
++            } else {
++              if (!element._deferredValueUpdateTask) {
++                element._deferredValueUpdateTask = new this.DeferredTask(this._deferredValueUpdate.bind(this, element), 1000);
++                this._deferredValueUpdateElements.add(element);
++              } else {
++                // Each time the preference is changed, restart the delay.
++                element._deferredValueUpdateTask.disarm();
++              }
++              element._deferredValueUpdateTask.arm();
++            }
++          }
++        ]]>
++        </body>
++      </method>
++      
++      <property name="contentHeight">
++        <getter>
++          var targetHeight = parseInt(window.getComputedStyle(this._content, "").height);
++          targetHeight += parseInt(window.getComputedStyle(this._content, "").marginTop);
++          targetHeight += parseInt(window.getComputedStyle(this._content, "").marginBottom);
++          return targetHeight;
++        </getter>
++      </property>
++      <field name="_content">
++        document.getAnonymousElementByAttribute(this, "class", "content-box");
++      </field>
++    </implementation>
++    <handlers>
++      <handler event="command">
++        // This "command" event handler tracks changes made to preferences by 
++        // the user in this window.
++        if (event.sourceEvent)
++          event = event.sourceEvent;
++        this.userChangedValue(event.target);
++      </handler>
++      <handler event="select">
++        // This "select" event handler tracks changes made to colorpicker 
++        // preferences by the user in this window.
++        if (event.target.localName == "colorpicker") 
++          this.userChangedValue(event.target);
++      </handler>
++      <handler event="change">
++        // This "change" event handler tracks changes made to preferences by 
++        // the user in this window. 
++        this.userChangedValue(event.target);
++      </handler>
++      <handler event="input">
++        // This "input" event handler tracks changes made to preferences by 
++        // the user in this window.
++        this.userChangedValue(event.target);
++      </handler>
++      <handler event="paneload">
++      <![CDATA[
++        // Initialize all values from preferences.
++        var elements = this.preferenceElements;
++        for (var i = 0; i < elements.length; ++i) {
++          try {
++            var preference = this.preferenceForElement(elements[i]);
++            preference.setElementValue(elements[i]);
++          }
++          catch (e) {
++            dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
++          }
++        }
++      ]]>      
++      </handler>
++    </handlers>
++  </binding>
++          
++  <binding id="panebutton" role="xul:listitem"
++           extends="chrome://global/content/bindings/radio.xml#radio">
++    <resources>
++      <stylesheet src="chrome://global/skin/preferences.css"/>
++    </resources>
++    <content>
++      <xul:image class="paneButtonIcon" xbl:inherits="src"/>
++      <xul:label class="paneButtonLabel" xbl:inherits="value=label"/>
++    </content>
++  </binding>
++
++</bindings>
++
++# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++# This Source Code Form is subject to the terms of the Mozilla Public
++# License, v. 2.0. If a copy of the MPL was not distributed with this
++# file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#
++# This is PrefWindow 6. The Code Could Well Be Ready, Are You?
++#
++#    Historical References:
++#    PrefWindow V   (February 1, 2003)
++#    PrefWindow IV  (April 24, 2000)
++#    PrefWindow III (January 6, 2000)
++#    PrefWindow II  (???)
++#    PrefWindow I   (June 4, 1999)
++#
+diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
+--- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
++++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
+@@ -15,16 +15,17 @@
+ #include "nsPrintfCString.h"
+ #include "nsNetCID.h"
+ #include "nsNetUtil.h"
+ #include "nsISupportsPrimitives.h"
+ #include "nsIGSettingsService.h"
+ #include "nsInterfaceHashtable.h"
+ #include "mozilla/Attributes.h"
+ #include "nsIURI.h"
++#include "nsKDEUtils.h"
+ 
+ class nsUnixSystemProxySettings final : public nsISystemProxySettings {
+ public:
+   NS_DECL_ISUPPORTS
+   NS_DECL_NSISYSTEMPROXYSETTINGS
+ 
+   nsUnixSystemProxySettings()
+     : mSchemeProxySettings(4)
+@@ -39,16 +40,17 @@ private:
+   nsCOMPtr<nsIGSettingsService> mGSettings;
+   nsCOMPtr<nsIGSettingsCollection> mProxySettings;
+   nsInterfaceHashtable<nsCStringHashKey, nsIGSettingsCollection> mSchemeProxySettings;
+   bool IsProxyMode(const char* aMode);
+   nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult);
+   nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult);
+   nsresult GetProxyFromGSettings(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult);
+   nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, nsACString& aResult);
++  nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost, PRInt32 aPort, nsACString& aResult);
+ };
+ 
+ NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings)
+ 
+ NS_IMETHODIMP
+ nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
+ {
+   // dbus prevents us from being threadsafe, but this routine should not block anyhow
+@@ -505,16 +507,19 @@ nsUnixSystemProxySettings::GetProxyFromG
+ 
+ nsresult
+ nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
+                                           const nsACString & aScheme,
+                                           const nsACString & aHost,
+                                           const int32_t      aPort,
+                                           nsACString & aResult)
+ {
++  if (nsKDEUtils::kdeSupport())
++    return GetProxyFromKDE(aScheme, aHost, aPort, aResult);
++
+   if (mProxySettings) {
+     nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult);
+     if (NS_SUCCEEDED(rv))
+       return rv;
+   }
+   if (mGConf)
+     return GetProxyFromGConf(aScheme, aHost, aPort, aResult);
+ 
+@@ -540,8 +545,34 @@ static const mozilla::Module::ContractID
+ 
+ static const mozilla::Module kUnixProxyModule = {
+   mozilla::Module::kVersion,
+   kUnixProxyCIDs,
+   kUnixProxyContracts
+ };
+ 
+ NSMODULE_DEFN(nsUnixProxyModule) = &kUnixProxyModule;
++
++nsresult
++nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme,
++                                           const nsACString& aHost,
++                                           PRInt32 aPort,
++                                           nsACString& aResult)
++{
++  nsAutoCString url;
++  url = aScheme;
++  url += "://";
++  url += aHost;
++  if( aPort >= 0 )
++  {
++    url += ":";
++    url += nsPrintfCString("%d", aPort);
++  }
++  nsTArray<nsCString> command;
++  command.AppendElement( NS_LITERAL_CSTRING( "GETPROXY" ));
++  command.AppendElement( url );
++  nsTArray<nsCString> result;
++  if( !nsKDEUtils::command( command, &result ) || result.Length() != 1 )
++    return NS_ERROR_FAILURE;
++  aResult = result[0];
++  return NS_OK;
++}
++
+diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build
+--- a/toolkit/xre/moz.build
++++ b/toolkit/xre/moz.build
+@@ -48,17 +48,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'ui
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
+     EXPORTS += ['nsQAppInstance.h']
+     SOURCES += [
+         '!moc_nsNativeAppSupportQt.cpp',
+         'nsNativeAppSupportQt.cpp',
+         'nsQAppInstance.cpp',
+     ]
+ elif CONFIG['MOZ_ENABLE_GTK']:
++    EXPORTS += ['nsKDEUtils.h']
+     UNIFIED_SOURCES += [
++        'nsKDEUtils.cpp',
+         'nsNativeAppSupportUnix.cpp',
+     ]
+ else:
+     UNIFIED_SOURCES += [
+         'nsNativeAppSupportDefault.cpp',
+     ]
+ 
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
+diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp
+new file mode 100644
+--- /dev/null
++++ b/toolkit/xre/nsKDEUtils.cpp
+@@ -0,0 +1,339 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsKDEUtils.h"
++#include "nsIWidget.h"
++#include "nsISupportsPrimitives.h"
++#include "nsIMutableArray.h"
++#include "nsComponentManagerUtils.h"
++#include "nsArrayUtils.h"
++
++#include <gtk/gtk.h>
++
++#include <limits.h>
++#include <stdio.h>
++#include <sys/wait.h>
++#include <sys/resource.h>
++#include <unistd.h>
++#include <X11/Xlib.h>
++
++//#define DEBUG_KDE
++#ifdef DEBUG_KDE
++#define KMOZILLAHELPER "kmozillahelper"
++#else
++// not need for lib64, it's a binary
++#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper"
++#endif
++
++#define KMOZILLAHELPER_VERSION 6
++#define MAKE_STR2( n ) #n
++#define MAKE_STR( n ) MAKE_STR2( n )
++
++static bool getKdeSession()
++    {
++    Display* dpy = XOpenDisplay( NULL );
++    if( dpy == NULL )
++        return false;
++    Atom kde_full_session = XInternAtom( dpy, "KDE_FULL_SESSION", True );
++    bool kde = false;
++    if( kde_full_session != None )
++        {
++        int cnt;
++        if( Atom* props = XListProperties( dpy, DefaultRootWindow( dpy ), &cnt ))
++            {
++            for( int i = 0;
++                 i < cnt;
++                 ++i )
++                {
++                if( props[ i ] == kde_full_session )
++                    {
++                    kde = true;
++#ifdef DEBUG_KDE
++                    fprintf( stderr, "KDE SESSION %d\n", kde );
++#endif
++                    break;
++                    }
++                }
++            XFree( props );
++            }
++        }
++    XCloseDisplay( dpy );
++    return kde;
++    }
++
++static bool getKdeSupport()
++    {
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "CHECK" ));
++    command.AppendElement( NS_LITERAL_CSTRING( MAKE_STR( KMOZILLAHELPER_VERSION )));
++    bool kde = nsKDEUtils::command( command );
++#ifdef DEBUG_KDE
++    fprintf( stderr, "KDE RUNNING %d\n", kde );
++#endif
++    return kde;
++    }
++
++nsKDEUtils::nsKDEUtils()
++    : commandFile( NULL )
++    , replyFile( NULL )
++    {
++    }
++
++nsKDEUtils::~nsKDEUtils()
++    {
++//    closeHelper(); not actually useful, exiting will close the fd too
++    }
++
++nsKDEUtils* nsKDEUtils::self()
++    {
++    static nsKDEUtils s;
++    return &s;
++    }
++
++static bool helperRunning = false;
++static bool helperFailed = false;
++
++bool nsKDEUtils::kdeSession()
++    {
++    static bool session = getKdeSession();
++    return session;
++    }
++
++bool nsKDEUtils::kdeSupport()
++    {
++    static bool support = kdeSession() && getKdeSupport();
++    return support && helperRunning;
++    }
++
++struct nsKDECommandData
++    {
++    FILE* file;
++    nsTArray<nsCString>* output;
++    GMainLoop* loop;
++    bool success;
++    };
++
++static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data )
++    {
++    nsKDECommandData* p = static_cast< nsKDECommandData* >( data );
++    char buf[ 8192 ]; // TODO big enough
++    bool command_done = false;
++    bool command_failed = false;
++    while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL )
++        { // TODO what if the kernel splits a line into two chunks?
++//#ifdef DEBUG_KDE
++//        fprintf( stderr, "READ: %s %d\n", buf, feof( p->file ));
++//#endif
++        if( char* eol = strchr( buf, '\n' ))
++            *eol = '\0';
++        command_done = ( strcmp( buf, "\\1" ) == 0 );
++        command_failed = ( strcmp( buf, "\\0" ) == 0 );
++        nsAutoCString line( buf );
++        line.ReplaceSubstring( "\\n", "\n" );
++        line.ReplaceSubstring( "\\" "\\", "\\" ); //  \\ -> \ , i.e. unescape
++        if( p->output && !( command_done || command_failed ))
++            p->output->AppendElement( nsCString( buf )); // TODO utf8?
++        }
++    bool quit = false;
++    if( feof( p->file ) || command_failed )
++        {
++        quit = true;
++        p->success = false;
++        }
++    if( command_done )
++        { // reading one reply finished
++        quit = true;
++        p->success = true;
++        }
++    if( quit )
++        {
++        if( p->loop )
++            g_main_loop_quit( p->loop );
++        return FALSE;
++        }
++    return TRUE;
++    }
++
++bool nsKDEUtils::command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output )
++    {
++    return self()->internalCommand( command, NULL, false, output );
++    }
++
++bool nsKDEUtils::command( nsIArray* command, nsIArray** output)
++    {
++    nsTArray<nsCString> in;
++    PRUint32 length;
++    command->GetLength( &length );
++    for ( PRUint32 i = 0; i < length; i++ )
++        {
++        nsCOMPtr<nsISupportsCString> str = do_QueryElementAt( command, i );
++        if( str )
++            {
++            nsAutoCString s;
++            str->GetData( s );
++            in.AppendElement( s );
++            }
++        }
++
++    nsTArray<nsCString> out;
++    bool ret = self()->internalCommand( in, NULL, false, &out );
++
++    if ( !output ) return ret;
++
++    nsCOMPtr<nsIMutableArray> result = do_CreateInstance( NS_ARRAY_CONTRACTID );
++    if ( !result ) return false;
++
++    for ( PRUint32 i = 0; i < out.Length(); i++ )
++        {
++        nsCOMPtr<nsISupportsCString> rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++        if ( !rstr ) return false;
++
++        rstr->SetData( out[i] );
++        result->AppendElement( rstr, false );
++        }
++
++    NS_ADDREF( *output = result);
++    return ret;
++    }
++
++
++bool nsKDEUtils::commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output )
++    {
++    return self()->internalCommand( command, parent, true, output );
++    }
++
++bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool blockUi,
++    nsTArray<nsCString>* output )
++    {
++    if( !startHelper())
++        return false;
++    feedCommand( command );
++    // do not store the data in 'this' but in extra structure, just in case there
++    // is reentrancy (can there be? the event loop is re-entered)
++    nsKDECommandData data;
++    data.file = replyFile;
++    data.output = output;
++    data.success = false;
++    if( blockUi )
++        {
++        data.loop = g_main_loop_new( NULL, FALSE );
++        GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
++        if( parent && gtk_window_get_group(parent) )
++            gtk_window_group_add_window( gtk_window_get_group(parent), GTK_WINDOW( window ));
++        gtk_widget_realize( window );
++        gtk_widget_set_sensitive( window, TRUE );
++        gtk_grab_add( window );
++        GIOChannel* channel = g_io_channel_unix_new( fileno( data.file ));
++        g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data );
++        g_io_channel_unref( channel );
++        g_main_loop_run( data.loop );
++        g_main_loop_unref( data.loop );
++        gtk_grab_remove( window );
++        gtk_widget_destroy( window );
++        }
++    else
++        {
++        data.loop = NULL;
++        while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data ))
++            ;
++        }
++    return data.success;
++    }
++
++bool nsKDEUtils::startHelper()
++    {
++    if( helperRunning )
++        return true;
++    if( helperFailed )
++        return false;
++    helperFailed = true;
++    int fdcommand[ 2 ];
++    int fdreply[ 2 ];
++    if( pipe( fdcommand ) < 0 )
++        return false;
++    if( pipe( fdreply ) < 0 )
++        {
++        close( fdcommand[ 0 ] );
++        close( fdcommand[ 1 ] );
++        return false;
++        }
++    char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL };
++    switch( fork())
++        {
++        case -1:
++            {
++            close( fdcommand[ 0 ] );
++            close( fdcommand[ 1 ] );
++            close( fdreply[ 0 ] );
++            close( fdreply[ 1 ] );
++            return false;
++            }
++        case 0: // child
++            {
++            if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 )
++                _exit( 1 );
++            if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 )
++                _exit( 1 );
++            int maxfd = 1024; // close all other fds
++            struct rlimit rl;
++            if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
++                maxfd = rl.rlim_max;
++            for( int i = 3;
++                 i < maxfd;
++                 ++i )
++                close( i );
++#ifdef DEBUG_KDE
++            execvp( KMOZILLAHELPER, args );
++#else
++            execv( KMOZILLAHELPER, args );
++#endif
++            _exit( 1 ); // failed
++            }
++        default: // parent
++            {
++            commandFile = fdopen( fdcommand[ 1 ], "w" );
++            replyFile = fdopen( fdreply[ 0 ], "r" );
++            close( fdcommand[ 0 ] );
++            close( fdreply[ 1 ] );
++            if( commandFile == NULL || replyFile == NULL )
++                {
++                closeHelper();
++                return false;
++                }
++            // ok, helper ready, getKdeRunning() will check if it works
++            }
++        }
++    helperFailed = false;
++    helperRunning = true;
++    return true;
++    }
++
++void nsKDEUtils::closeHelper()
++    {
++    if( commandFile != NULL )
++        fclose( commandFile ); // this will also make the helper quit
++    if( replyFile != NULL )
++        fclose( replyFile );
++    helperRunning = false;
++    }
++
++void nsKDEUtils::feedCommand( const nsTArray<nsCString>& command )
++    {
++    for( int i = 0;
++         i < command.Length();
++         ++i )
++        {
++        nsCString line = command[ i ];
++        line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape
++        line.ReplaceSubstring( "\n", "\\n" );
++#ifdef DEBUG_KDE
++        fprintf( stderr, "COMM: %s\n", line.get());
++#endif
++        fputs( line.get(), commandFile );
++        fputs( "\n", commandFile );
++        }
++    fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data
++    fflush( commandFile );
++    }
+diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h
+new file mode 100644
+--- /dev/null
++++ b/toolkit/xre/nsKDEUtils.h
+@@ -0,0 +1,48 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef nsKDEUtils_h__
++#define nsKDEUtils_h__
++
++#include "nsStringGlue.h"
++#include "nsTArray.h"
++#include <stdio.h>
++
++typedef struct _GtkWindow GtkWindow;
++
++class nsIArray;
++
++class NS_EXPORT nsKDEUtils
++    {
++    public:
++        /* Returns true if running inside a KDE session (regardless of whether there is KDE
++           support available for Firefox). This should be used e.g. when determining
++           dialog button order but not for code that requires the KDE support. */
++        static bool kdeSession();
++        /* Returns true if running inside a KDE session and KDE support is available
++           for Firefox. This should be used everywhere where the external helper is needed. */
++        static bool kdeSupport();
++        /* Executes the given helper command, returns true if helper returned success. */
++        static bool command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output = NULL );
++        static bool command( nsIArray* command, nsIArray** output = NULL );
++        /* Like command(), but additionally blocks the parent widget like if there was
++           a modal dialog shown and enters the event loop (i.e. there are still paint updates,
++           this is for commands that take long). */
++        static bool commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output = NULL );
++
++    private:
++        nsKDEUtils();
++        ~nsKDEUtils();
++        static nsKDEUtils* self();
++        bool startHelper();
++        void closeHelper();
++        void feedCommand( const nsTArray<nsCString>& command );
++        bool internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool isParent,
++            nsTArray<nsCString>* output );
++        FILE* commandFile;
++        FILE* replyFile;
++    };
++
++#endif // nsKDEUtils
+diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
+--- a/uriloader/exthandler/moz.build
++++ b/uriloader/exthandler/moz.build
+@@ -72,17 +72,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'ui
+ else:
+     # These files can't be built in unified mode because they redefine LOG.
+     SOURCES += [
+         osdir + '/nsOSHelperAppService.cpp',
+     ]
+ 
+ if CONFIG['MOZ_ENABLE_GTK']:
+     UNIFIED_SOURCES += [
++        'unix/nsCommonRegistry.cpp',
+         'unix/nsGNOMERegistry.cpp',
++	'unix/nsKDERegistry.cpp',
+         'unix/nsMIMEInfoUnix.cpp',
+     ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
+     UNIFIED_SOURCES += [
+         'android/nsAndroidHandlerApp.cpp',
+         'android/nsExternalSharingAppService.cpp',
+         'android/nsExternalURLHandlerService.cpp',
+         'android/nsMIMEInfoAndroid.cpp',
+@@ -125,16 +127,17 @@ include('/ipc/chromium/chromium-config.m
+ 
+ FINAL_LIBRARY = 'xul'
+ 
+ LOCAL_INCLUDES += [
+     '/dom/base',
+     '/dom/ipc',
+     '/netwerk/base',
+     '/netwerk/protocol/http',
++    '/toolkit/xre',
+ ]
+ 
+ if CONFIG['MOZ_ENABLE_DBUS']:
+     CXXFLAGS += CONFIG['TK_CFLAGS']
+     CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
+ 
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('qt', 'gtk2', 'gtk3'):
+     CXXFLAGS += CONFIG['TK_CFLAGS']
+diff --git a/uriloader/exthandler/unix/nsCommonRegistry.cpp b/uriloader/exthandler/unix/nsCommonRegistry.cpp
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsCommonRegistry.cpp
+@@ -0,0 +1,53 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsCommonRegistry.h"
++
++#include "nsGNOMERegistry.h"
++#include "nsKDERegistry.h"
++#include "nsString.h"
++#include "nsKDEUtils.h"
++
++/* static */ bool
++nsCommonRegistry::HandlerExists(const char *aProtocolScheme)
++{
++    if( nsKDEUtils::kdeSupport())
++        return nsKDERegistry::HandlerExists( aProtocolScheme );
++    return nsGNOMERegistry::HandlerExists( aProtocolScheme );
++}
++
++/* static */ nsresult
++nsCommonRegistry::LoadURL(nsIURI *aURL)
++{
++    if( nsKDEUtils::kdeSupport())
++        return nsKDERegistry::LoadURL( aURL );
++    return nsGNOMERegistry::LoadURL( aURL );
++}
++
++/* static */ void
++nsCommonRegistry::GetAppDescForScheme(const nsACString& aScheme,
++                                     nsAString& aDesc)
++{
++    if( nsKDEUtils::kdeSupport())
++        return nsKDERegistry::GetAppDescForScheme( aScheme, aDesc );
++    return nsGNOMERegistry::GetAppDescForScheme( aScheme, aDesc );
++}
++
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsCommonRegistry::GetFromExtension(const nsACString& aFileExt)
++{
++    if( nsKDEUtils::kdeSupport())
++        return nsKDERegistry::GetFromExtension( aFileExt );
++    return nsGNOMERegistry::GetFromExtension( aFileExt );
++}
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsCommonRegistry::GetFromType(const nsACString& aMIMEType)
++{
++    if( nsKDEUtils::kdeSupport())
++        return nsKDERegistry::GetFromType( aMIMEType );
++    return nsGNOMERegistry::GetFromType( aMIMEType );
++}
+diff --git a/uriloader/exthandler/unix/nsCommonRegistry.h b/uriloader/exthandler/unix/nsCommonRegistry.h
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsCommonRegistry.h
+@@ -0,0 +1,28 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef nsCommonRegistry_h__
++#define nsCommonRegistry_h__
++
++#include "nsIURI.h"
++#include "nsCOMPtr.h"
++
++class nsMIMEInfoBase;
++
++class nsCommonRegistry
++{
++ public:
++  static bool HandlerExists(const char *aProtocolScheme);
++
++  static nsresult LoadURL(nsIURI *aURL);
++
++  static void GetAppDescForScheme(const nsACString& aScheme,
++                                  nsAString& aDesc);
++
++  static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
++
++  static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
++};
++
++#endif
+diff --git a/uriloader/exthandler/unix/nsKDERegistry.cpp b/uriloader/exthandler/unix/nsKDERegistry.cpp
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsKDERegistry.cpp
+@@ -0,0 +1,88 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsKDERegistry.h"
++#include "prlink.h"
++#include "prmem.h"
++#include "nsString.h"
++#include "nsILocalFile.h"
++#include "nsMIMEInfoUnix.h"
++#include "nsAutoPtr.h"
++#include "nsKDEUtils.h"
++
++/* static */ bool
++nsKDERegistry::HandlerExists(const char *aProtocolScheme)
++{
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "HANDLEREXISTS" ));
++    command.AppendElement( nsAutoCString( aProtocolScheme ));
++    return nsKDEUtils::command( command );
++}
++
++/* static */ nsresult
++nsKDERegistry::LoadURL(nsIURI *aURL)
++{
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "OPEN" ));
++    nsCString url;
++    aURL->GetSpec( url );
++    command.AppendElement( url );
++    bool rv = nsKDEUtils::command( command );
++    if (!rv)
++      return NS_ERROR_FAILURE;
++
++    return NS_OK;
++}
++
++/* static */ void
++nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme,
++                                     nsAString& aDesc)
++{
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "GETAPPDESCFORSCHEME" ));
++    command.AppendElement( aScheme );
++    nsTArray<nsCString> output;
++    if( nsKDEUtils::command( command, &output ) && output.Length() == 1 )
++        CopyUTF8toUTF16( output[ 0 ], aDesc );
++}
++
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsKDERegistry::GetFromExtension(const nsACString& aFileExt)
++{
++    NS_ASSERTION(aFileExt[0] != '.', "aFileExt shouldn't start with a dot");
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "GETFROMEXTENSION" ));
++    command.AppendElement( aFileExt );
++    return GetFromHelper( command );
++}
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsKDERegistry::GetFromType(const nsACString& aMIMEType)
++{
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "GETFROMTYPE" ));
++    command.AppendElement( aMIMEType );
++    return GetFromHelper( command );
++}
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsKDERegistry::GetFromHelper(const nsTArray<nsCString>& command)
++{
++    nsTArray<nsCString> output;
++    if( nsKDEUtils::command( command, &output ) && output.Length() == 3 )
++        {
++        nsCString mimetype = output[ 0 ];
++        RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix( mimetype );
++        NS_ENSURE_TRUE(mimeInfo, nullptr);
++        nsCString description = output[ 1 ];
++        mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
++        nsCString handlerAppName = output[ 2 ];
++        mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(handlerAppName));
++        mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
++        return mimeInfo.forget();
++        }
++    return nullptr;
++}
+diff --git a/uriloader/exthandler/unix/nsKDERegistry.h b/uriloader/exthandler/unix/nsKDERegistry.h
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsKDERegistry.h
+@@ -0,0 +1,34 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef nsKDERegistry_h__
++#define nsKDERegistry_h__
++
++#include "nsIURI.h"
++#include "nsCOMPtr.h"
++#include "nsTArray.h"
++
++class nsMIMEInfoBase;
++class nsAutoCString;
++class nsCString;
++
++class nsKDERegistry
++{
++ public:
++  static bool HandlerExists(const char *aProtocolScheme);
++
++  static nsresult LoadURL(nsIURI *aURL);
++
++  static void GetAppDescForScheme(const nsACString& aScheme,
++                                  nsAString& aDesc);
++
++  static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
++
++  static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
++ private:
++  static already_AddRefed<nsMIMEInfoBase> GetFromHelper(const nsTArray<nsCString>& command);
++
++};
++
++#endif //nsKDERegistry_h__
+diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
+--- a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
++++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
+@@ -7,32 +7,35 @@
+ #ifdef MOZ_WIDGET_QT
+ #if (MOZ_ENABLE_CONTENTACTION)
+ #include <contentaction/contentaction.h>
+ #include "nsContentHandlerApp.h"
+ #endif
+ #endif
+ 
+ #include "nsMIMEInfoUnix.h"
+-#include "nsGNOMERegistry.h"
++#include "nsCommonRegistry.h"
+ #include "nsIGIOService.h"
+ #include "nsNetCID.h"
+ #include "nsIIOService.h"
+ #include "nsAutoPtr.h"
+ #ifdef MOZ_ENABLE_DBUS
+ #include "nsDBusHandlerApp.h"
+ #endif
+ #ifdef MOZ_WIDGET_QT
+ #include "nsMIMEInfoQt.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_WIDGET_QT
+   if (NS_FAILED(rv)) {
+     rv = nsMIMEInfoQt::LoadUriInternal(aURI);
+   }
+ #endif
+ 
+   return rv;
+@@ -45,24 +48,24 @@ nsMIMEInfoUnix::GetHasDefaultHandler(boo
+   // either /etc/mailcap or ${HOME}/.mailcap, in which case we don't want to
+   // give the GNOME answer.
+   if (mDefaultApplication)
+     return nsMIMEInfoImpl::GetHasDefaultHandler(_retval);
+ 
+   *_retval = false;
+ 
+   if (mClass == eProtocolInfo) {
+-    *_retval = nsGNOMERegistry::HandlerExists(mSchemeOrType.get());
++    *_retval = nsCommonRegistry::HandlerExists(mSchemeOrType.get());
+   } else {
+-    RefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mSchemeOrType);
++    RefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromType(mSchemeOrType);
+     if (!mimeInfo) {
+       nsAutoCString ext;
+       nsresult rv = GetPrimaryExtension(ext);
+       if (NS_SUCCEEDED(rv)) {
+-        mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
++        mimeInfo = nsCommonRegistry::GetFromExtension(ext);
+       }
+     }
+     if (mimeInfo)
+       *_retval = true;
+   }
+ 
+   if (*_retval)
+     return NS_OK;
+@@ -97,16 +100,33 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(ns
+     ContentAction::Action::defaultActionForFile(uri, QString(mSchemeOrType.get()));
+   if (action.isValid()) {
+     action.trigger();
+     return NS_OK;
+   }
+   return NS_ERROR_FAILURE;
+ #endif
+ 
++  if( nsKDEUtils::kdeSupport()) {
++    bool supports;
++    if( NS_SUCCEEDED( GetHasDefaultHandler( &supports )) && supports ) {
++      nsTArray<nsCString> command;
++      command.AppendElement( NS_LITERAL_CSTRING( "OPEN" ));
++      command.AppendElement( nativePath );
++      command.AppendElement( NS_LITERAL_CSTRING( "MIMETYPE" ));
++      command.AppendElement( mSchemeOrType );
++      if( nsKDEUtils::command( command ))
++        return NS_OK;
++    }
++    if (!mDefaultApplication)
++      return NS_ERROR_FILE_NOT_FOUND;
++
++    return LaunchWithIProcess(mDefaultApplication, nativePath);
++  }
++
+   nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+   if (!giovfs) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+   // nsGIOMimeApp->Launch wants a URI string instead of local file
+   nsresult rv;
+   nsCOMPtr<nsIIOService> ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+diff --git a/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
+--- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp
++++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
+@@ -10,17 +10,17 @@
+ #if defined(MOZ_ENABLE_CONTENTACTION)
+ #include <contentaction/contentaction.h>
+ #include <QString>
+ #endif
+ 
+ #include "nsOSHelperAppService.h"
+ #include "nsMIMEInfoUnix.h"
+ #ifdef MOZ_WIDGET_GTK
+-#include "nsGNOMERegistry.h"
++#include "nsCommonRegistry.h"
+ #endif
+ #include "nsISupports.h"
+ #include "nsString.h"
+ #include "nsReadableUtils.h"
+ #include "nsUnicharUtils.h"
+ #include "nsXPIDLString.h"
+ #include "nsIURL.h"
+ #include "nsIFileStreams.h"
+@@ -1146,26 +1146,26 @@ nsresult nsOSHelperAppService::OSProtoco
+     ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':');
+ 
+   if (action.isValid())
+     *aHandlerExists = true;
+ #endif
+ 
+ #ifdef MOZ_WIDGET_GTK
+   // Check the GNOME registry for a protocol handler
+-  *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
++  *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
+ #endif
+ 
+   return NS_OK;
+ }
+ 
+ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
+ {
+ #ifdef MOZ_WIDGET_GTK
+-  nsGNOMERegistry::GetAppDescForScheme(aScheme, _retval);
++  nsCommonRegistry::GetAppDescForScheme(aScheme, _retval);
+   return _retval.IsEmpty() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
+ #else
+   return NS_ERROR_NOT_AVAILABLE;
+ #endif
+ }
+ 
+ nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t * platformAppPath, nsIFile ** aFile)
+ {
+@@ -1252,17 +1252,17 @@ nsOSHelperAppService::GetFromExtension(c
+                                          mime_types_description,
+                                          true);
+ 
+   if (NS_FAILED(rv) || majorType.IsEmpty()) {
+ 
+ #ifdef MOZ_WIDGET_GTK
+     LOG(("Looking in GNOME registry\n"));
+     RefPtr<nsMIMEInfoBase> gnomeInfo =
+-      nsGNOMERegistry::GetFromExtension(aFileExt);
++      nsCommonRegistry::GetFromExtension(aFileExt);
+     if (gnomeInfo) {
+       LOG(("Got MIMEInfo from GNOME registry\n"));
+       return gnomeInfo.forget();
+     }
+ #endif
+ 
+     rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt),
+                                   majorType,
+@@ -1373,17 +1373,17 @@ nsOSHelperAppService::GetFromType(const 
+   nsAutoString extensions, mime_types_description;
+   LookUpExtensionsAndDescription(majorType,
+                                  minorType,
+                                  extensions,
+                                  mime_types_description);
+ 
+ #ifdef MOZ_WIDGET_GTK
+   if (handler.IsEmpty()) {
+-    RefPtr<nsMIMEInfoBase> gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
++    RefPtr<nsMIMEInfoBase> gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType);
+     if (gnomeInfo) {
+       LOG(("Got MIMEInfo from GNOME registry without extensions; setting them "
+            "to %s\n", NS_LossyConvertUTF16toASCII(extensions).get()));
+ 
+       NS_ASSERTION(!gnomeInfo->HasExtensions(), "How'd that happen?");
+       gnomeInfo->SetFileExtensions(NS_ConvertUTF16toUTF8(extensions));
+       return gnomeInfo.forget();
+     }
+diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build
+--- a/widget/gtk/moz.build
++++ b/widget/gtk/moz.build
+@@ -86,16 +86,17 @@ else:
+ include('/ipc/chromium/chromium-config.mozbuild')
+ 
+ FINAL_LIBRARY = 'xul'
+ 
+ LOCAL_INCLUDES += [
+     '/layout/generic',
+     '/layout/xul',
+     '/other-licenses/atk-1.0',
++    '/toolkit/xre',
+     '/widget',
+ ]
+ 
+ if CONFIG['MOZ_X11']:
+     LOCAL_INCLUDES += [
+         '/widget/x11',
+     ]
+ 
+diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp
+--- a/widget/gtk/nsFilePicker.cpp
++++ b/widget/gtk/nsFilePicker.cpp
+@@ -4,32 +4,34 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "mozilla/Types.h"
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+ 
+ #include <gtk/gtk.h>
++#include <gdk/gdkx.h>
+ 
+ #include "nsGtkUtils.h"
+ #include "nsIFileURL.h"
+ #include "nsIURI.h"
+ #include "nsIWidget.h"
+ #include "nsIFile.h"
+ #include "nsIStringBundle.h"
+ 
+ #include "nsArrayEnumerator.h"
+ #include "nsMemory.h"
+ #include "nsEnumeratorUtils.h"
+ #include "nsNetUtil.h"
+ #include "nsReadableUtils.h"
+ #include "mozcontainer.h"
+ 
+ #include "nsFilePicker.h"
++#include "nsKDEUtils.h"
+ 
+ using namespace mozilla;
+ 
+ #define MAX_PREVIEW_SIZE 180
+ // bug 1184009
+ #define MAX_PREVIEW_SOURCE_SIZE 4096
+ 
+ nsIFile *nsFilePicker::mPrevDisplayDirectory = nullptr;
+@@ -246,17 +248,19 @@ nsFilePicker::AppendFilters(int32_t aFil
+   return nsBaseFilePicker::AppendFilters(aFilterMask);
+ }
+ 
+ NS_IMETHODIMP
+ nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
+ {
+   if (aFilter.EqualsLiteral("..apps")) {
+     // No platform specific thing we can do here, really....
+-    return NS_OK;
++    // Unless it's KDE.
++    if( mMode != modeOpen || !nsKDEUtils::kdeSupport())
++      return NS_OK;
+   }
+ 
+   nsAutoCString filter, name;
+   CopyUTF16toUTF8(aFilter, filter);
+   CopyUTF16toUTF8(aTitle, name);
+ 
+   mFilters.AppendElement(filter);
+   mFilterNames.AppendElement(name);
+@@ -371,16 +375,32 @@ nsFilePicker::Show(int16_t *aReturn)
+ 
+ NS_IMETHODIMP
+ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
+ {
+   // Can't show two dialogs concurrently with the same filepicker
+   if (mRunning)
+     return NS_ERROR_NOT_AVAILABLE;
+ 
++  // KDE file picker is not handled via callback
++  if( nsKDEUtils::kdeSupport()) {
++    int16_t result;
++    mCallback = aCallback;
++    mRunning = true;
++    kdeFileDialog(&result);
++    if (mCallback) {
++      mCallback->Done(result);
++      mCallback = nullptr;
++    } else {
++      mResult = result;
++    }
++    mRunning = false;
++    return NS_OK;
++  }
++
+   nsXPIDLCString title;
+   title.Adopt(ToNewUTF8String(mTitle));
+ 
+   GtkWindow *parent_widget =
+     GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
+ 
+   GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
+   const gchar *accept_button = (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+@@ -595,8 +615,235 @@ nsFilePicker::Done(GtkWidget* file_choos
+   if (mCallback) {
+     mCallback->Done(result);
+     mCallback = nullptr;
+   } else {
+     mResult = result;
+   }
+   NS_RELEASE_THIS();
+ }
++
++nsCString nsFilePicker::kdeMakeFilter( int index )
++    {
++    nsCString buf = mFilters[ index ];
++    for( PRUint32 i = 0;
++         i < buf.Length();
++         ++i )
++        if( buf[ i ] == ';' ) // KDE separates just using spaces
++            buf.SetCharAt( ' ', i );
++    if (!mFilterNames[index].IsEmpty())
++        {
++        buf += "|";
++        buf += mFilterNames[index].get();
++        }
++    return buf;
++    }
++
++static PRInt32 windowToXid( nsIWidget* widget )
++    {
++    GtkWindow *parent_widget = GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
++    GdkWindow* gdk_window = gtk_widget_get_window( gtk_widget_get_toplevel( GTK_WIDGET( parent_widget )));
++    return GDK_WINDOW_XID( gdk_window );
++    }
++
++NS_IMETHODIMP nsFilePicker::kdeFileDialog(PRInt16 *aReturn)
++    {
++    NS_ENSURE_ARG_POINTER(aReturn);
++
++    if( mMode == modeOpen && mFilters.Length() == 1 && mFilters[ 0 ].EqualsLiteral( "..apps" ))
++        return kdeAppsDialog( aReturn );
++
++    nsXPIDLCString title;
++    title.Adopt(ToNewUTF8String(mTitle));
++
++    const char* arg = NULL;
++    if( mAllowURLs )
++        {
++        switch( mMode )
++            {
++            case nsIFilePicker::modeOpen:
++            case nsIFilePicker::modeOpenMultiple:
++                arg = "GETOPENURL";
++                break;
++            case nsIFilePicker::modeSave:
++                arg = "GETSAVEURL";
++                break;
++            case nsIFilePicker::modeGetFolder:
++                arg = "GETDIRECTORYURL";
++                break;
++            }
++        }
++    else
++        {
++        switch( mMode )
++            {
++            case nsIFilePicker::modeOpen:
++            case nsIFilePicker::modeOpenMultiple:
++                arg = "GETOPENFILENAME";
++                break;
++            case nsIFilePicker::modeSave:
++                arg = "GETSAVEFILENAME";
++                break;
++            case nsIFilePicker::modeGetFolder:
++                arg = "GETDIRECTORYFILENAME";
++                break;
++            }
++        }
++
++  nsAutoCString directory;
++  if (mDisplayDirectory) {
++    mDisplayDirectory->GetNativePath(directory);
++  } else if (mPrevDisplayDirectory) {
++    mPrevDisplayDirectory->GetNativePath(directory);
++  }
++
++    nsAutoCString startdir;
++  if (!directory.IsEmpty()) {
++    startdir = directory;
++  }
++  if (mMode == nsIFilePicker::modeSave) {
++    if( !startdir.IsEmpty())
++      {
++      startdir += "/";
++      startdir += ToNewUTF8String(mDefault);
++      }
++    else
++      startdir = ToNewUTF8String(mDefault);
++  }
++  if( startdir.IsEmpty())
++      startdir = ".";
++
++    nsAutoCString filters;
++    PRInt32 count = mFilters.Length();
++    if( count == 0 ) //just in case
++        filters = "*";
++    else
++        {
++        filters = kdeMakeFilter( 0 );
++        for (PRInt32 i = 1; i < count; ++i)
++            {
++            filters += "\n";
++            filters += kdeMakeFilter( i );
++            }
++        }
++
++    nsTArray<nsCString> command;
++    command.AppendElement( nsAutoCString( arg ));
++    command.AppendElement( startdir );
++    if( mMode != nsIFilePicker::modeGetFolder )
++        {
++        command.AppendElement( filters );
++        nsAutoCString selected;
++        selected.AppendInt( mSelectedType );
++        command.AppendElement( selected );
++        }
++    command.AppendElement( title );
++    if( mMode == nsIFilePicker::modeOpenMultiple )
++        command.AppendElement( NS_LITERAL_CSTRING( "MULTIPLE" ));
++    if( PRInt32 xid = windowToXid( mParentWidget ))
++        {
++        command.AppendElement( NS_LITERAL_CSTRING( "PARENT" ));
++        nsAutoCString parent;
++        parent.AppendInt( xid );
++        command.AppendElement( parent );
++        }
++
++    nsTArray<nsCString> output;
++    if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
++        {
++        *aReturn = nsIFilePicker::returnOK;
++        mFiles.Clear();
++        if( mMode != nsIFilePicker::modeGetFolder )
++            {
++            mSelectedType = atoi( output[ 0 ].get());
++            output.RemoveElementAt( 0 );
++            }
++        if (mMode == nsIFilePicker::modeOpenMultiple)
++            {
++            mFileURL.Truncate();
++            PRUint32 count = output.Length();
++            for( PRUint32 i = 0;
++                 i < count;
++                 ++i )
++                {
++                nsCOMPtr<nsIFile> localfile;
++                nsresult rv = NS_NewNativeLocalFile( output[ i ],
++                                      PR_FALSE,
++                                      getter_AddRefs(localfile));
++                if (NS_SUCCEEDED(rv))
++                    mFiles.AppendObject(localfile);
++                }
++            }
++        else
++            {
++            if( output.Length() == 0 )
++                mFileURL = nsCString();
++            else if( mAllowURLs )
++                mFileURL = output[ 0 ];
++            else // GetFile() actually requires it to be url even for local files :-/
++                {
++                mFileURL = nsCString( "file://" );
++                mFileURL.Append( output[ 0 ] );
++                }
++            }
++  // Remember last used directory.
++  nsCOMPtr<nsIFile> file;
++  GetFile(getter_AddRefs(file));
++  if (file) {
++    nsCOMPtr<nsIFile> dir;
++    file->GetParent(getter_AddRefs(dir));
++    nsCOMPtr<nsIFile> localDir(do_QueryInterface(dir));
++    if (localDir) {
++      localDir.swap(mPrevDisplayDirectory);
++    }
++  }
++        if (mMode == nsIFilePicker::modeSave)
++            {
++            nsCOMPtr<nsIFile> file;
++            GetFile(getter_AddRefs(file));
++            if (file)
++                {
++                bool exists = false;
++                file->Exists(&exists);
++                if (exists) // TODO do overwrite check in the helper app
++                    *aReturn = nsIFilePicker::returnReplace;
++                }
++            }
++        }
++    else
++        {
++        *aReturn = nsIFilePicker::returnCancel;
++        }
++    return NS_OK;
++    }
++
++
++NS_IMETHODIMP nsFilePicker::kdeAppsDialog(PRInt16 *aReturn)
++    {
++    NS_ENSURE_ARG_POINTER(aReturn);
++
++    nsXPIDLCString title;
++    title.Adopt(ToNewUTF8String(mTitle));
++
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING( "APPSDIALOG" ));
++    command.AppendElement( title );
++    if( PRInt32 xid = windowToXid( mParentWidget ))
++        {
++        command.AppendElement( NS_LITERAL_CSTRING( "PARENT" ));
++        nsAutoCString parent;
++        parent.AppendInt( xid );
++        command.AppendElement( parent );
++        }
++
++    nsTArray<nsCString> output;
++    if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
++        {
++        *aReturn = nsIFilePicker::returnOK;
++        mFileURL = output.Length() > 0 ? output[ 0 ] : nsCString();
++        }
++    else
++        {
++        *aReturn = nsIFilePicker::returnCancel;
++        }
++    return NS_OK;
++    }
++
+diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h
+--- a/widget/gtk/nsFilePicker.h
++++ b/widget/gtk/nsFilePicker.h
+@@ -69,14 +69,20 @@ protected:
+   nsString  mDefaultExtension;
+ 
+   nsTArray<nsCString> mFilters;
+   nsTArray<nsCString> mFilterNames;
+ 
+ private:
+   static nsIFile *mPrevDisplayDirectory;
+ 
++  bool kdeRunning();
++  bool getKdeRunning();
++  NS_IMETHODIMP kdeFileDialog(PRInt16 *aReturn);
++  NS_IMETHODIMP kdeAppsDialog(PRInt16 *aReturn);
++  nsCString kdeMakeFilter( int index );
++
+ #if (MOZ_WIDGET_GTK == 3)
+   GtkFileChooserWidget *mFileChooserDelegate;
+ #endif
+ };
+ 
+ #endif
+diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
+--- a/xpcom/components/ManifestParser.cpp
++++ b/xpcom/components/ManifestParser.cpp
+@@ -35,16 +35,17 @@
+ 
+ #include "nsIConsoleService.h"
+ #include "nsIScriptError.h"
+ #include "nsIXULAppInfo.h"
+ #include "nsIXULRuntime.h"
+ #ifdef MOZ_B2G_LOADER
+ #include "mozilla/XPTInterfaceInfoManager.h"
+ #endif
++#include "nsKDEUtils.h"
+ 
+ #ifdef MOZ_B2G_LOADER
+ #define XPTONLY_MANIFEST &nsComponentManagerImpl::XPTOnlyManifestManifest
+ #define XPTONLY_XPT &nsComponentManagerImpl::XPTOnlyManifestXPT
+ #else
+ #define XPTONLY_MANIFEST nullptr
+ #define XPTONLY_XPT nullptr
+ #endif
+@@ -494,16 +495,17 @@ ParseManifest(NSLocationType aType, File
+   NS_NAMED_LITERAL_STRING(kRemoteEnabled, "remoteenabled");
+   NS_NAMED_LITERAL_STRING(kRemoteRequired, "remoterequired");
+   NS_NAMED_LITERAL_STRING(kApplication, "application");
+   NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
+   NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
+   NS_NAMED_LITERAL_STRING(kOs, "os");
+   NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
+   NS_NAMED_LITERAL_STRING(kABI, "abi");
++  NS_NAMED_LITERAL_STRING(kDesktop, "desktop");
+   NS_NAMED_LITERAL_STRING(kProcess, "process");
+ #if defined(MOZ_WIDGET_ANDROID)
+   NS_NAMED_LITERAL_STRING(kTablet, "tablet");
+ #endif
+ 
+   NS_NAMED_LITERAL_STRING(kMain, "main");
+   NS_NAMED_LITERAL_STRING(kContent, "content");
+ 
+@@ -554,44 +556,49 @@ ParseManifest(NSLocationType aType, File
+         CopyUTF8toUTF16(s, abi);
+         abi.Insert(char16_t('_'), 0);
+         abi.Insert(osTarget, 0);
+       }
+     }
+   }
+ 
+   nsAutoString osVersion;
++  nsAutoString desktop;
+ #if defined(XP_WIN)
+ #pragma warning(push)
+ #pragma warning(disable:4996) // VC12+ deprecates GetVersionEx
+   OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
+   if (GetVersionEx(&info)) {
+     nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
+                               info.dwMajorVersion,
+                               info.dwMinorVersion);
+   }
++  desktop = NS_LITERAL_STRING("win");
+ #pragma warning(pop)
+ #elif defined(MOZ_WIDGET_COCOA)
+   SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
+   SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
+   nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
+                             majorVersion,
+                             minorVersion);
++  desktop = NS_LITERAL_STRING("macosx");
+ #elif defined(MOZ_WIDGET_GTK)
+   nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
+                             gtk_major_version,
+                             gtk_minor_version);
++  desktop = nsKDEUtils::kdeSession() ? NS_LITERAL_STRING("kde") : NS_LITERAL_STRING("gnome");
+ #elif defined(MOZ_WIDGET_ANDROID)
+   bool isTablet = false;
+   if (mozilla::AndroidBridge::Bridge()) {
+     mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION",
+                                                            "RELEASE",
+                                                            osVersion);
+     isTablet = mozilla::widget::GeckoAppShell::IsTablet();
+   }
++  desktop = NS_LITERAL_STRING("android");
+ #endif
+ 
+   if (XRE_IsContentProcess()) {
+     process = kContent;
+   } else {
+     process = kMain;
+   }
+ 
+@@ -694,25 +701,27 @@ ParseManifest(NSLocationType aType, File
+     TriState stOsVersion = eUnspecified;
+     TriState stOs = eUnspecified;
+     TriState stABI = eUnspecified;
+     TriState stProcess = eUnspecified;
+ #if defined(MOZ_WIDGET_ANDROID)
+     TriState stTablet = eUnspecified;
+ #endif
+     int flags = 0;
++    TriState stDesktop = eUnspecified;
+ 
+     while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+            ok) {
+       ToLowerCase(token);
+       NS_ConvertASCIItoUTF16 wtoken(token);
+ 
+       if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+           CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+           CheckStringFlag(kABI, wtoken, abi, stABI) ||
++          CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+           CheckStringFlag(kProcess, wtoken, process, stProcess) ||
+           CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
+           CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
+           CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
+         continue;
+       }
+ 
+ #if defined(MOZ_WIDGET_ANDROID)
+@@ -762,16 +771,17 @@ ParseManifest(NSLocationType aType, File
+     }
+ 
+     if (!ok ||
+         stApp == eBad ||
+         stAppVersion == eBad ||
+         stGeckoVersion == eBad ||
+         stOs == eBad ||
+         stOsVersion == eBad ||
++        stDesktop == eBad ||
+ #ifdef MOZ_WIDGET_ANDROID
+         stTablet == eBad ||
+ #endif
+         stABI == eBad ||
+         stProcess == eBad) {
+       continue;
+     }
+ 
+diff --git a/xpcom/components/moz.build b/xpcom/components/moz.build
+--- a/xpcom/components/moz.build
++++ b/xpcom/components/moz.build
+@@ -47,12 +47,13 @@ FINAL_LIBRARY = 'xul'
+ GENERATED_INCLUDES += ['..']
+ LOCAL_INCLUDES += [
+     '../base',
+     '../build',
+     '../ds',
+     '../reflect/xptinfo',
+     '/chrome',
+     '/modules/libjar',
++    '/toolkit/xre'
+ ]
+ 
+ if CONFIG['MOZ_WIDGET_GTK']:
+     CXXFLAGS += CONFIG['TK_CFLAGS']
+diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
+--- a/xpcom/io/nsLocalFileUnix.cpp
++++ b/xpcom/io/nsLocalFileUnix.cpp
+@@ -47,16 +47,17 @@
+ #include "prproces.h"
+ #include "nsIDirectoryEnumerator.h"
+ #include "nsISimpleEnumerator.h"
+ #include "private/pprio.h"
+ #include "prlink.h"
+ 
+ #ifdef MOZ_WIDGET_GTK
+ #include "nsIGIOService.h"
++#include "nsKDEUtils.h"
+ #endif
+ 
+ #ifdef MOZ_WIDGET_COCOA
+ #include <Carbon/Carbon.h>
+ #include "CocoaFileUtils.h"
+ #include "prmem.h"
+ #include "plbase64.h"
+ 
+@@ -1963,42 +1964,52 @@ nsLocalFile::SetPersistentDescriptor(con
+   return InitWithNativePath(aPersistentDescriptor);
+ #endif
+ }
+ 
+ NS_IMETHODIMP
+ nsLocalFile::Reveal()
+ {
+ #ifdef MOZ_WIDGET_GTK
+-  nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+-  if (!giovfs) {
+-    return NS_ERROR_FAILURE;
+-  }
++  nsAutoCString url;
+ 
+   bool isDirectory;
+   if (NS_FAILED(IsDirectory(&isDirectory))) {
+     return NS_ERROR_FAILURE;
+   }
+ 
++  nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+   if (isDirectory) {
+-    return giovfs->ShowURIForInput(mPath);
++    url = mPath;
+   } else if (NS_SUCCEEDED(giovfs->OrgFreedesktopFileManager1ShowItems(mPath))) {
+     return NS_OK;
+   } else {
+     nsCOMPtr<nsIFile> parentDir;
+     nsAutoCString dirPath;
+     if (NS_FAILED(GetParent(getter_AddRefs(parentDir)))) {
+       return NS_ERROR_FAILURE;
+     }
+     if (NS_FAILED(parentDir->GetNativePath(dirPath))) {
+       return NS_ERROR_FAILURE;
+     }
+ 
+-    return giovfs->ShowURIForInput(dirPath);
++    url = dirPath;
+   }
++
++  if(nsKDEUtils::kdeSupport()) {
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING("REVEAL") );
++    command.AppendElement( mPath );
++    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++  }
++
++  if (!giovfs)
++    return NS_ERROR_FAILURE;
++
++  return giovfs->ShowURIForInput(url);
+ #elif defined(MOZ_WIDGET_COCOA)
+   CFURLRef url;
+   if (NS_SUCCEEDED(GetCFURL(&url))) {
+     nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
+     ::CFRelease(url);
+     return rv;
+   }
+   return NS_ERROR_FAILURE;
+@@ -2006,16 +2017,22 @@ nsLocalFile::Reveal()
+   return NS_ERROR_FAILURE;
+ #endif
+ }
+ 
+ NS_IMETHODIMP
+ nsLocalFile::Launch()
+ {
+ #ifdef MOZ_WIDGET_GTK
++  if( nsKDEUtils::kdeSupport()) {
++    nsTArray<nsCString> command;
++    command.AppendElement( NS_LITERAL_CSTRING("OPEN") );
++    command.AppendElement( mPath );
++    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++  }
+   nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+   if (!giovfs) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+   return giovfs->ShowURIForInput(mPath);
+ #elif defined(MOZ_ENABLE_CONTENTACTION)
+   QUrl uri = QUrl::fromLocalFile(QString::fromUtf8(mPath.get()));
-- 
GitLab