[Trisquel-devel] [PATCH] Added OpenSUSE patches for Abrowser KDE support.
Legimet
legimet.calc at gmail.com
Sat Mar 29 01:32:32 CET 2014
---
helpers/DATA/firefox/abrowser-kde.patch | 1789 +++++++++++++++
helpers/DATA/firefox/mozilla-kde.patch | 3707 +++++++++++++++++++++++++++++++
helpers/make-firefox | 14 +-
3 files changed, 5509 insertions(+), 1 deletion(-)
create mode 100644 helpers/DATA/firefox/abrowser-kde.patch
create mode 100644 helpers/DATA/firefox/mozilla-kde.patch
diff --git a/helpers/DATA/firefox/abrowser-kde.patch b/helpers/DATA/firefox/abrowser-kde.patch
new file mode 100644
index 0000000..d076e73
--- /dev/null
+++ b/helpers/DATA/firefox/abrowser-kde.patch
@@ -0,0 +1,1789 @@
+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,1177 @@
++#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://browser/skin/devtools/common.css" type="text/css"?>
++<?xml-stylesheet href="chrome://browser/skin/" 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
++ titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
++ lightweightthemes="true"
++ lightweightthemesfooter="browser-bottombox"
++ windowtype="navigator:browser"
++ macanimationtype="document"
++ screenX="4" screenY="4"
++ fullscreenbutton="true"
++ 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);"/>
++ <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);"/>
++ <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"/>
++
++ <!-- for search and content formfill/pw manager -->
++ <panel type="autocomplete" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
++
++ <!-- for url bar autocomplete -->
++ <panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
++
++ <!-- for select dropdowns -->
++ <menupopup id="ContentSelectDropdown" rolluponmousewheel="true" hidden="true"/>
++
++ <!-- 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"
++ align="start"
++ orient="vertical"
++ role="alert">
++ <label id="UITourTooltipTitle" flex="1"/>
++ <description id="UITourTooltipDescription" flex="1"/>
++ </panel>
++ <html:div id="UITourHighlightContainer" style="position:relative">
++ <html:div id="UITourHighlight"></html:div>
++ </html:div>
++
++ <panel id="socialActivatedNotification"
++ type="arrow"
++ hidden="true"
++ align="start"
++ orient="horizontal"
++ role="alert">
++ <image id="social-activation-icon" class="popup-notification-icon"/>
++ <vbox flex="1">
++ <description id="social-activation-message" class="popup-notification-description">&social.activated.description;</description>
++ <spacer flex="1"/>
++ <hbox pack="start" align="center" class="popup-notification-button-container">
++ <label id="social-undoactivation-button"
++ class="text-link"
++ value="&social.activated.undo.label;"
++ accesskey="&social.activated.undo.accesskey;"
++ onclick="SocialUI.undoActivation(this);"/>
++ <spacer flex="1"/>
++ <button id="social-activation-button"
++ default="true"
++ autofocus="autofocus"
++ label="&social.ok.label;"
++ accesskey="&social.ok.accesskey;"
++ oncommand="SocialUI.activationPanel.hidePopup();"/>
++ </hbox>
++ </vbox>
++ </panel>
++
++ <panel id="social-share-panel"
++ class="social-panel"
++ type="arrow"
++ orient="horizontal"
++ onpopupshowing="SocialShare.onShowing()"
++ onpopuphidden="SocialShare.onHidden()"
++ hidden="true">
++ <vbox class="social-share-toolbar">
++ <vbox id="social-share-provider-buttons" flex="1"/>
++ </vbox>
++ </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"/>
++
++ <menupopup id="toolbar-context-menu"
++ onpopupshowing="onViewToolbarsPopupShowing(event);">
++ <menuseparator/>
++ <menuitem command="cmd_ToggleTabsOnTop"
++ type="checkbox"
++ label="&viewTabsOnTop.label;"
++ accesskey="&viewTabsOnTop.accesskey;"/>
++ <menuitem command="cmd_CustomizeToolbars"
++ 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="start"
++ 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"/>
++
++ <!-- Popup for site identity information -->
++ <panel id="identity-popup"
++ type="arrow"
++ hidden="true"
++ noautofocus="true"
++ onpopupshown="if (event.target == this)
++ gIdentityHandler.onPopupShown(event);"
++ orient="vertical"
++ level="top">
++ <hbox id="identity-popup-container" align="top">
++ <image id="identity-popup-icon"/>
++ <vbox id="identity-popup-content-box">
++ <label id="identity-popup-brandName"
++ class="identity-popup-label"
++ value="&brandFullName;"/>
++ <label id="identity-popup-chromeLabel"
++ class="identity-popup-label"/>
++ <label id="identity-popup-connectedToLabel"
++ class="identity-popup-label"
++ value="&identity.connectedTo;"/>
++ <label id="identity-popup-connectedToLabel2"
++ class="identity-popup-label"
++ value="&identity.unverifiedsite2;"/>
++ <description id="identity-popup-content-host"
++ class="identity-popup-description"/>
++ <label id="identity-popup-runByLabel"
++ class="identity-popup-label"
++ value="&identity.runBy;"/>
++ <description id="identity-popup-content-owner"
++ class="identity-popup-description"/>
++ <description id="identity-popup-content-supplemental"
++ class="identity-popup-description"/>
++ <description id="identity-popup-content-verifier"
++ class="identity-popup-description"/>
++ <hbox id="identity-popup-encryption" flex="1">
++ <vbox>
++ <image id="identity-popup-encryption-icon"/>
++ </vbox>
++ <description id="identity-popup-encryption-label" flex="1"
++ class="identity-popup-description"/>
++ </hbox>
++ <vbox id="identity-popup-permissions">
++ <separator class="thin"/>
++ <label class="identity-popup-label header"
++ value="&identity.permissions;"/>
++ <vbox id="identity-popup-permission-list" class="indent"/>
++ </vbox>
++ </vbox>
++ </hbox>
++ <!-- Footer button to open security page info -->
++ <hbox id="identity-popup-button-container" align="center">
++ <button id="identity-popup-help-icon"
++ oncommand="gIdentityHandler.handleHelpCommand(event);"
++ tooltiptext="&identity.help.tooltip;"/>
++ <spacer flex="1"/>
++ <button id="identity-popup-more-info-button"
++ label="&identity.moreInfoLinkText;"
++ oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
++ </hbox>
++ </panel>
++
++ <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>
++
++ <!-- Bookmarks and history tooltip -->
++ <tooltip id="bhTooltip"/>
++
++ <panel id="customizeToolbarSheetPopup"
++ noautohide="true"
++ sheetstyle="&dialog.dimensions;"/>
++
++ <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>
++
++#include popup-notifications.inc
++
++ <hbox id="downloads-animation-container" mousethrough="always">
++ <vbox id="downloads-notification-anchor">
++ <vbox id="downloads-indicator-notification"/>
++ </vbox>
++ </hbox>
++ </popupset>
++
++#ifdef CAN_DRAW_IN_TITLEBAR
++<vbox id="titlebar">
++ <hbox id="titlebar-content">
++#ifdef MENUBAR_CAN_AUTOHIDE
++ <hbox id="appmenu-button-container">
++ <button id="appmenu-button"
++ type="menu"
++ label="&brandShortName;"
++ style="-moz-user-focus: ignore;">
++#include browser-appmenu.inc
++ </button>
++ </hbox>
++#endif
++ <spacer id="titlebar-spacer" flex="1"/>
++ <hbox id="titlebar-buttonbox-container" align="start">
++ <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>
++ </hbox>
++</vbox>
++#endif
++
++<deck flex="1" id="tab-view-deck">
++<vbox flex="1" id="browser-panel">
++
++ <toolbox id="navigator-toolbox"
++ defaultmode="icons" mode="icons"
++ iconsize="large">
++ <!-- Menu -->
++ <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
++ defaultset="menubar-items"
++ mode="icons" iconsize="small" defaulticonsize="small"
++ lockiconsize="true"
++#ifdef MENUBAR_CAN_AUTOHIDE
++ toolbarname="&menubarCmd.label;"
++ accesskey="&menubarCmd.accesskey;"
++#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
++ <hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
++ <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
++#endif
++ </toolbar>
++
++ <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
++ toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
++ fullscreentoolbar="true" mode="icons" customizable="true"
++ iconsize="large"
++ defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,window-controls"
++ context="toolbar-context-menu">
++
++ <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
++ context="backForwardMenu" removable="true"
++ forwarddisabled="true"
++ title="&backForwardItem.title;">
++ <toolbarbutton id="back-button" class="toolbarbutton-1"
++ label="&backCmd.label;"
++ command="Browser:BackOrBackDuplicate"
++ onclick="checkForMiddleClick(this, event);"
++ tooltip="back-button-tooltip"/>
++ <toolbarbutton id="forward-button" class="toolbarbutton-1"
++ label="&forwardCmd.label;"
++ command="Browser:ForwardOrForwardDuplicate"
++ onclick="checkForMiddleClick(this, event);"
++ tooltip="forward-button-tooltip"/>
++ <dummyobservertarget hidden="true"
++ onbroadcast="if (this.getAttribute('disabled') == 'true')
++ this.parentNode.setAttribute('forwarddisabled', 'true');
++ else
++ this.parentNode.removeAttribute('forwarddisabled');">
++ <observes element="Browser:ForwardOrForwardDuplicate" attribute="disabled"/>
++ </dummyobservertarget>
++ </toolbaritem>
++
++ <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
++ title="&locationItem.title;" class="chromeclass-location" removable="true">
++ <textbox id="urlbar" flex="1"
++ placeholder="&urlbar.placeholder2;"
++ type="autocomplete"
++ autocompletesearch="urlinline history"
++ autocompletesearchparam="enable-actions"
++ autocompletepopup="PopupAutoCompleteRichResult"
++ completeselectedindex="true"
++ tabscrolling="true"
++ showcommentcolumn="true"
++ showimagecolumn="true"
++ enablehistory="true"
++ maxrows="6"
++ newlines="stripsurroundingwhitespace"
++ oninput="gBrowser.userTypedValue = this.value;"
++ ontextentered="this.handleCommand(param);"
++ ontextreverted="return this.handleRevert();"
++ pageproxystate="invalid"
++ onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
++ onblur="setTimeout(function() 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"/>
++ <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="plugin-install-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/>
++ <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/>
++ </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"
++ onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
++ onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
++ ondragstart="gIdentityHandler.onDragStart(event);">
++ <image id="page-proxy-favicon"
++ onclick="PageProxyClickHandler(event);"
++ pageproxystate="invalid"/>
++ <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 id="urlbar-display" 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="star-button"
++ class="urlbar-icon"
++ onclick="if (event.button === 0) BookmarkingUI.onCommand(event);"/>
++ <image id="go-button"
++ class="urlbar-icon"
++ tooltiptext="&goEndCap.tooltip;"
++ onclick="gURLBar.handleCommand(event);"/>
++ </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>
++ </toolbaritem>
++
++ <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&reloadCmd.label;" removable="true"
++ command="Browser:ReloadOrDuplicate"
++ onclick="checkForMiddleClick(this, event);"
++ tooltiptext="&reloadButton.tooltip;"/>
++
++ <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&stopCmd.label;" removable="true"
++ command="Browser:Stop"
++ tooltiptext="&stopButton.tooltip;"/>
++
++ <toolbaritem id="search-container" title="&searchItem.title;"
++ align="center" class="chromeclass-toolbar-additional"
++ flex="100" persist="width" removable="true">
++ <searchbar id="searchbar" flex="1"/>
++ </toolbaritem>
++
++ <toolbarbutton id="webrtc-status-button"
++ class="toolbarbutton-1 chromeclass-toolbar-additional"
++ type="menu"
++ hidden="true"
++ orient="horizontal"
++ label="&webrtcIndicatorButton.label;"
++ tooltiptext="&webrtcIndicatorButton.tooltip;">
++ <menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
++ onpopuphiding="WebrtcIndicator.clearPopup(this);"
++ oncommand="WebrtcIndicator.menuCommand(event.target);"/>
++ </toolbarbutton>
++
++ <toolbarbutton id="bookmarks-menu-button"
++ class="toolbarbutton-1 chromeclass-toolbar-additional"
++ persist="class"
++ removable="true"
++ type="menu"
++ label="&bookmarksMenuButton.label;"
++ tooltiptext="&bookmarksMenuButton.tooltip;"
++ ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
++ ondragover="PlacesMenuDNDHandler.onDragOver(event);"
++ ondragleave="PlacesMenuDNDHandler.onDragLeave(event);"
++ ondrop="PlacesMenuDNDHandler.onDrop(event);">
++ <menupopup id="BMB_bookmarksPopup"
++ placespopup="true"
++ context="placesContext"
++ openInTabs="children"
++ oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
++ onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
++ onpopupshowing="BookmarkingUI.onPopupShowing(event);
++ if (!this.parentNode._placesView)
++ new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
++ tooltip="bhTooltip" popupsinherittooltip="true">
++ <menuitem id="BMB_viewBookmarksToolbar"
++ placesanonid="view-toolbar"
++ toolbarId="PersonalToolbar"
++ type="checkbox"
++ oncommand="onViewToolbarCommand(event)"
++ label="&viewBookmarksToolbar.label;"/>
++ <menuseparator/>
++ <menuitem id="BMB_bookmarksShowAll"
++ label="&showAllBookmarks2.label;"
++ command="Browser:ShowAllBookmarks"
++ key="manBookmarkKb"/>
++ <menuseparator/>
++ <menuitem id="BMB_bookmarkThisPage"
++#ifndef XP_MACOSX
++ class="menuitem-iconic"
++#endif
++ label="&bookmarkThisPageCmd.label;"
++ command="Browser:AddBookmarkAs"
++ key="addBookmarkAsKb"/>
++ <menuitem id="BMB_subscribeToPageMenuitem"
++#ifndef XP_MACOSX
++ class="menuitem-iconic"
++#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"
++#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"
++ placesanonid="toolbar-autohide"
++ class="menu-iconic bookmark-item"
++ label="&personalbarCmd.label;"
++ container="true">
++ <menupopup id="BMB_bookmarksToolbarPopup"
++ placespopup="true"
++ context="placesContext"
++ onpopupshowing="if (!this.parentNode._placesView)
++ new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
++ </menu>
++ <menuseparator/>
++ <!-- Bookmarks menu items -->
++ <menuseparator builder="end"
++ class="hide-if-empty-places-result"/>
++ <menuitem id="BMB_unsortedBookmarks"
++ label="&bookmarksMenuButton.unsorted.label;"
++ oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
++ class="menuitem-iconic"/>
++ </menupopup>
++ </toolbarbutton>
++
++ <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ persist="class" removable="true"
++ label="&homeButton.label;"
++ ondragover="homeButtonObserver.onDragOver(event)"
++ ondragenter="homeButtonObserver.onDragOver(event)"
++ ondrop="homeButtonObserver.onDrop(event)"
++ ondragexit="homeButtonObserver.onDragExit(event)"
++ onclick="BrowserGoHome(event);"
++ aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
++
++ <toolbarbutton id="social-share-button"
++ class="toolbarbutton-1 chromeclass-toolbar-additional"
++ hidden="true"
++ label="&sharePageCmd.label;"
++ tooltiptext="&sharePageCmd.label;"
++ command="Social:SharePage"/>
++
++ <toolbaritem id="social-toolbar-item"
++ class="chromeclass-toolbar-additional"
++ removable="false"
++ title="&socialToolbar.title;"
++ hidden="true"
++ skipintoolbarset="true"
++ observes="socialActiveBroadcaster">
++ <toolbarbutton id="social-notification-icon" class="default-notification-icon toolbarbutton-1 notification-anchor-icon"
++ oncommand="PopupNotifications._reshowNotifications(this,
++ document.getElementById('social-sidebar-browser'));"/>
++ <toolbarbutton id="social-provider-button"
++ class="toolbarbutton-1"
++ type="menu">
++ <menupopup id="social-statusarea-popup">
++ <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center"
++ observes="socialBroadcaster_userDetails"
++ oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();">
++ <image class="social-statusarea-user-portrait"
++ observes="socialBroadcaster_userDetails"/>
++ <vbox>
++ <label class="social-statusarea-loggedInStatus"
++ observes="socialBroadcaster_userDetails"/>
++ </vbox>
++ </menuitem>
++#ifndef XP_WIN
++ <menuseparator class="social-statusarea-separator"/>
++#endif
++ <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;"/>
++ <menuitem class="social-toggle-menuitem" command="Social:Toggle"/>
++ <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>
++ </toolbaritem>
++
++ <hbox id="window-controls" hidden="true" pack="end">
++ <toolbarbutton id="minimize-button"
++ tooltiptext="&fullScreenMinimize.tooltip;"
++ oncommand="window.minimize();"/>
++
++ <toolbarbutton id="restore-button"
++ 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" defaulticonsize="small"
++ lockiconsize="true"
++ class="chromeclass-directories"
++ context="toolbar-context-menu"
++ defaultset="personal-bookmarks"
++ toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
++ collapsed="true"
++ customizable="true">
++ <toolbaritem flex="1" id="personal-bookmarks" title="&bookmarksItem.title;"
++ removable="true">
++ <hbox flex="1"
++ id="PlacesToolbar"
++ context="placesContext"
++ onclick="BookmarksEventHandler.onClick(event, this._placesView);"
++ oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
++ tooltip="bhTooltip"
++ popupsinherittooltip="true">
++ <toolbarbutton class="bookmark-item bookmarks-toolbar-customize"
++ mousethrough="never"
++ label="&bookmarksToolbarItem.label;"/>
++ <hbox flex="1">
++ <hbox align="center">
++ <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>
++
++#ifdef MENUBAR_CAN_AUTOHIDE
++#ifndef CAN_DRAW_IN_TITLEBAR
++#define APPMENU_ON_TABBAR
++#endif
++#endif
++
++
++ <toolbar id="TabsToolbar"
++ class="toolbar-primary"
++ fullscreentoolbar="true"
++ customizable="true"
++ mode="icons" lockmode="true"
++ iconsize="small" defaulticonsize="small" lockiconsize="true"
++ aria-label="&tabsToolbar.label;"
++ context="toolbar-context-menu"
++#ifdef APPMENU_ON_TABBAR
++ defaultset="appmenu-toolbar-button,tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton"
++#else
++ defaultset="tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton"
++#endif
++ collapsed="true">
++
++#ifdef APPMENU_ON_TABBAR
++ <toolbarbutton id="appmenu-toolbar-button"
++ class="chromeclass-toolbar-additional"
++ type="menu"
++ label="&brandShortName;"
++ tooltiptext="&appMenuButton.tooltip;">
++#include browser-appmenu.inc
++ </toolbarbutton>
++#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" fadein="true"/>
++ </tabs>
++
++ <toolbarbutton id="new-tab-button"
++ class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&tabCmd.label;"
++ command="cmd_newNavigatorTab"
++ onclick="checkForMiddleClick(this, event);"
++ tooltiptext="&newTabButton.tooltip;"
++ ondrop="newTabButtonObserver.onDrop(event)"
++ ondragover="newTabButtonObserver.onDragOver(event)"
++ ondragenter="newTabButtonObserver.onDragOver(event)"
++ ondragexit="newTabButtonObserver.onDragExit(event)"
++ removable="true"/>
++
++ <toolbarbutton id="alltabs-button"
++ class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button"
++ type="menu"
++ label="&listAllTabs.label;"
++ tooltiptext="&listAllTabs.label;"
++ removable="true">
++ <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"/>
++ <menuseparator id="alltabs-popup-separator"/>
++ </menupopup>
++ </toolbarbutton>
++
++ <toolbarbutton id="tabs-closebutton"
++ class="close-button tabs-closebutton"
++ command="cmd_close"
++ label="&closeTab.label;"
++ tooltiptext="&closeTab.label;"/>
++
++#ifdef CAN_DRAW_IN_TITLEBAR
++ <hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
++ <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
++#endif
++ </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"
++ label="&printButton.label;" command="cmd_print"
++ tooltiptext="&printButton.tooltip;"/>
++
++ <!-- 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"
++ oncommand="DownloadsIndicatorView.onCommand(event);"
++ ondrop="DownloadsIndicatorView.onDrop(event);"
++ ondragover="DownloadsIndicatorView.onDragOver(event);"
++ ondragenter="DownloadsIndicatorView.onDragOver(event);"
++ label="&downloads.label;"
++ tooltiptext="&downloads.tooltip;"/>
++
++ <toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ observes="viewHistorySidebar" label="&historyButton.label;"
++ tooltiptext="&historyButton.tooltip;"/>
++
++ <toolbarbutton id="bookmarks-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ observes="viewBookmarksSidebar"
++ tooltiptext="&bookmarksButton.tooltip;"
++ ondrop="bookmarksButtonObserver.onDrop(event)"
++ ondragover="bookmarksButtonObserver.onDragOver(event)"
++ ondragenter="bookmarksButtonObserver.onDragOver(event)"
++ ondragexit="bookmarksButtonObserver.onDragExit(event)"/>
++
++ <toolbarbutton id="new-window-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&newNavigatorCmd.label;"
++ command="key_newNavigator"
++ tooltiptext="&newWindowButton.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;"
++ tooltiptext="&fullScreenButton.tooltip;"/>
++
++ <toolbaritem id="zoom-controls" class="chromeclass-toolbar-additional"
++ title="&zoomControls.label;">
++ <toolbarbutton id="zoom-out-button" class="toolbarbutton-1"
++ label="&fullZoomReduceCmd.label;"
++ command="cmd_fullZoomReduce"
++ tooltiptext="&zoomOutButton.tooltip;"/>
++ <toolbarbutton id="zoom-in-button" class="toolbarbutton-1"
++ label="&fullZoomEnlargeCmd.label;"
++ command="cmd_fullZoomEnlarge"
++ tooltiptext="&zoomInButton.tooltip;"/>
++ </toolbaritem>
++
++ <toolbarbutton id="feed-button"
++ type="menu"
++ class="toolbarbutton-1 chromeclass-toolbar-additional"
++ disabled="true"
++ label="&feedButton.label;"
++ tooltiptext="&feedButton.tooltip;"
++ onclick="return FeedHandler.onFeedButtonClick(event);">
++ <menupopup position="after_end"
++ id="feed-menu"
++ onpopupshowing="return FeedHandler.buildFeedList(this);"
++ oncommand="return FeedHandler.subscribeToFeed(null, event);"
++ onclick="checkForMiddleClick(this, event);"/>
++ </toolbarbutton>
++
++ <toolbarbutton id="cut-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&cutCmd.label;"
++ command="cmd_cut"
++ tooltiptext="&cutButton.tooltip;"/>
++
++ <toolbarbutton id="copy-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="©Cmd.label;"
++ command="cmd_copy"
++ tooltiptext="©Button.tooltip;"/>
++
++ <toolbarbutton id="paste-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&pasteCmd.label;"
++ command="cmd_paste"
++ tooltiptext="&pasteButton.tooltip;"/>
++
++#ifdef MOZ_SERVICES_SYNC
++ <toolbarbutton id="sync-button"
++ class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&syncToolbarButton.label;"
++ oncommand="gSyncUI.handleToolbarButton()"/>
++#endif
++
++ <toolbaritem id="navigator-throbber" title="&throbberItem.title;" align="center" pack="center"
++ mousethrough="always">
++ <image/>
++ </toolbaritem>
++
++ <toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
++ label="&tabGroupsButton.label;"
++ command="Browser:ToggleTabView"
++ tooltiptext="&tabGroupsButton.tooltip;"
++ observes="tabviewGroupsNumber"/>
++ </toolbarpalette>
++ </toolbox>
++
++ <hbox id="fullscr-toggler" collapsed="true"/>
++
++ <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="tabs-closebutton" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/>
++ </sidebarheader>
++ <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true"
++ style="min-width: 14em; width: 18em; max-width: 36em;"/>
++ </vbox>
++
++ <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
++ <vbox id="appcontent" flex="1">
++ <tabbrowser id="content"
++ flex="1" contenttooltip="aHTMLTooltip"
++ tabcontainer="tabbrowser-tabs"
++ contentcontextmenu="contentAreaContextMenu"
++ autocompletepopup="PopupAutoComplete"
++ selectpopup="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">
++ <browser id="social-sidebar-browser"
++ type="content"
++ context="contentAreaContextMenu"
++ disableglobalhistory="true"
++ tooltip="aHTMLTooltip"
++ popupnotificationanchor="social-notification-icon"
++ flex="1"
++ style="min-width: 14em; width: 18em; max-width: 36em;"/>
++ </vbox>
++ <vbox id="browser-border-end" hidden="true" layer="true"/>
++ </hbox>
++
++ <hbox id="full-screen-warning-container" hidden="true" fadeout="true">
++ <hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
++ <vbox id="full-screen-warning-message" align="center">
++ <description id="full-screen-domain-text"/>
++ <description class="full-screen-description" value="&fullscreenExitHint2.value;"/>
++ <vbox id="full-screen-approval-pane" align="center">
++ <hbox>
++#ifndef XP_UNIX
++ <button label="&fullscreenExitButton.label;"
++ oncommand="FullScreen.setFullscreenAllowed(false);"
++ class="full-screen-approval-button"/>
++ <button label="&fullscreenAllowButton.label;"
++ oncommand="FullScreen.setFullscreenAllowed(true);"
++ class="full-screen-approval-button"/>
++#else
++ <button label="&fullscreenAllowButton.label;"
++ oncommand="FullScreen.setFullscreenAllowed(true);"
++ class="full-screen-approval-button"/>
++ <button label="&fullscreenExitButton.label;"
++ oncommand="FullScreen.setFullscreenAllowed(false);"
++ class="full-screen-approval-button"/>
++#endif
++ </hbox>
++ <checkbox id="full-screen-remember-decision"/>
++ </vbox>
++ </vbox>
++ </hbox>
++ </hbox>
++
++ <vbox id="browser-bottombox" layer="true">
++ <notificationbox id="global-notificationbox"/>
++ <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>
++
++ <toolbar id="addon-bar"
++ toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;"
++ collapsed="true"
++ class="toolbar-primary chromeclass-toolbar"
++ context="toolbar-context-menu" toolboxid="navigator-toolbox"
++ mode="icons" iconsize="small" defaulticonsize="small"
++ lockiconsize="true"
++ defaultset="addonbar-closebutton,spring,status-bar"
++ customizable="true"
++ key="key_toggleAddonBar">
++ <toolbarbutton id="addonbar-closebutton"
++ tooltiptext="&addonBarCloseButton.tooltip;"
++ oncommand="setToolbarVisibility(this.parentNode, false);"/>
++ <statusbar id="status-bar" ordinal="1000"/>
++ </toolbar>
++ </vbox>
++
++#ifndef XP_UNIX
++ <svg:svg height="0">
++ <svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
++ <svg:path d="M 0,0 C 0.16,0.11 0.28,0.29 0.28,0.5 0.28,0.71 0.16,0.89 0,1 L 1,1 1,0 0,0 z"/>
++ </svg:clipPath>
++ <svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
++ <svg:path d="M 0,0 0,7.8 C 2.5,11 4,14 4,18 4,22 2.5,25 0,28 l 0,22 10000,0 0,-50 L 0,0 z"/>
++ </svg:clipPath>
++ </svg:svg>
++#endif
++#ifdef XP_MACOSX
++ <svg:svg height="0">
++ <svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
++ <svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/>
++ </svg:clipPath>
++ <svg:clipPath id="osx-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
++ <svg:path d="m 0,-5 0,4.03 C 3.6,1.8 6,6.1 6,11 6,16 3.6,20 0,23 l 0,27 10000,0 0,-55 L 0,-5 z"/>
++ </svg:clipPath>
++ <svg:clipPath id="osx-tab-ontop-left-curve-clip-path" clipPathUnits="userSpaceOnUse">
++ <svg:path d="M 9,0 C 7.3,0 6,1.3 6,3 l 0,14 c 0,3 -2.2,5 -5,5 l -1,0 0,1 12,0 0,-1 0,-19 0,-3 -3,0 z"/>
++ </svg:clipPath>
++ <svg:clipPath id="osx-tab-ontop-right-curve-clip-path" clipPathUnits="userSpaceOnUse">
++ <svg:path d="m 0,0 0,3 0,19 0,1 12,0 0,-1 -1,0 C 8.2,22 6,20 6,17 L 6,3 C 6,1.3 4.7,0 3,0 L 0,0 z"/>
++ </svg:clipPath>
++ <svg:clipPath id="osx-tab-onbottom-left-curve-clip-path" clipPathUnits="userSpaceOnUse">
++ <svg:path d="m 0,0 0,1 1,0 c 2.8,0 5,2.2 5,5 l 0,14 c 0,2 1.3,3 3,3 l 3,0 0,-3 L 12,1 12,0 0,0 z"/>
++ </svg:clipPath>
++ <svg:clipPath id="osx-tab-onbottom-right-curve-clip-path" clipPathUnits="userSpaceOnUse">
++ <svg:path d="m 0,0 0,1 0,19 0,3 3,0 c 1.7,0 3,-1 3,-3 L 6,6 C 6,3.2 8.2,1 11,1 L 12,1 12,0 0,0 z"/>
++ </svg:clipPath>
++ </svg:svg>
++#endif
++
++</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
+@@ -53,16 +53,18 @@ browser.jar:
+ #endif
+ content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
+ content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
+ content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
+ 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/content.js (content/content.js)
+ content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
+ * content/browser/newtab/newTab.js (content/newtab/newTab.js)
+ content/browser/newtab/newTab.css (content/newtab/newTab.css)
+ content/browser/newtab/preloaderContent.js (content/newtab/preloaderContent.js)
+ * content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
+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"
+ #endif
+
+ #include "rdf.h"
+ #include "nsFeedSniffer.h"
+@@ -31,18 +31,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)
+ #endif
+
+ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
+
+@@ -60,17 +58,17 @@ NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUME
+ 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 },
+ #elif defined(XP_MACOSX)
+ { &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
+ #endif
+diff --git a/browser/components/preferences/advanced.js b/browser/components/preferences/advanced.js
+--- a/browser/components/preferences/advanced.js
++++ b/browser/components/preferences/advanced.js
+@@ -24,16 +24,22 @@ var gAdvancedPane = {
+ if (extraArgs && extraArgs["advancedTab"]){
+ advancedPrefs.selectedTab = document.getElementById(extraArgs["advancedTab"]);
+ } else {
+ var preference = document.getElementById("browser.preferences.advanced.selectedTabIndex");
+ if (preference.value !== null)
+ advancedPrefs.selectedIndex = preference.value;
+ }
+
++ 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.
+@@ -903,14 +909,25 @@ var gAdvancedPane = {
+ * Set browser as the operating system default browser.
+ */
+ setDefaultBrowser: function()
+ {
+ let shellSvc = getShellService();
+ if (!shellSvc)
+ return;
+ 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", "abrowser"];
++ process.run(false, args, args.length);
++ }
+ let selectedIndex =
+ shellSvc.isDefaultBrowser(false, true) ? 1 : 0;
+ document.getElementById("setDefaultPane").selectedIndex = selectedIndex;
+ }
+ #endif
+ };
+diff --git a/browser/components/shell/src/Makefile.in b/browser/components/shell/src/Makefile.in
+--- a/browser/components/shell/src/Makefile.in
++++ b/browser/components/shell/src/Makefile.in
+@@ -2,10 +2,12 @@
+ # 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 $(topsrcdir)/config/rules.mk
+
+ CXXFLAGS += $(TK_CFLAGS)
+
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
++
+ clobber::
+ rm -f $(DIST)/lib/$(LIBRARY_NAME).lib
+diff --git a/browser/components/shell/src/moz.build b/browser/components/shell/src/moz.build
+--- a/browser/components/shell/src/moz.build
++++ b/browser/components/shell/src/moz.build
+@@ -10,16 +10,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/src/nsKDEShellService.cpp b/browser/components/shell/src/nsKDEShellService.cpp
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/src/nsKDEShellService.cpp
+@@ -0,0 +1,234 @@
++/* -*- 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 "nsKDEShellService.h"
++#include "nsShellService.h"
++#include "nsKDEUtils.h"
++#include "nsCOMPtr.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"
++
++nsresult
++nsKDEShellService::Init()
++ {
++ if( !nsKDEUtils::kdeSupport())
++ return NS_ERROR_NOT_AVAILABLE;
++ return NS_OK;
++ }
++
++NS_IMPL_ISUPPORTS1(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::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;
++ }
++
++ 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/src/nsKDEShellService.h b/browser/components/shell/src/nsKDEShellService.h
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/src/nsKDEShellService.h
+@@ -0,0 +1,59 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is Shell Service.
++ *
++ * The Initial Developer of the Original Code is mozilla.org.
++ * Portions created by the Initial Developer are Copyright (C) 2004
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#ifndef nskdeshellservice_h____
++#define nskdeshellservice_h____
++
++#include "nsIShellService.h"
++#include "nsStringAPI.h"
++
++class nsKDEShellService : public nsIShellService
++{
++public:
++ nsKDEShellService() : mCheckedThisSession(PR_FALSE) { }
++
++ NS_DECL_ISUPPORTS
++ NS_DECL_NSISHELLSERVICE
++
++ nsresult Init() NS_HIDDEN;
++
++private:
++ ~nsKDEShellService() {}
++
++ PRPackedBool mCheckedThisSession;
++};
++
++#endif // nskdeshellservice_h____
+diff --git a/browser/components/shell/src/nsUnixShellService.cpp b/browser/components/shell/src/nsUnixShellService.cpp
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/src/nsUnixShellService.cpp
+@@ -0,0 +1,52 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is Shell Service.
++ *
++ * The Initial Developer of the Original Code is mozilla.org.
++ * Portions created by the Initial Developer are Copyright (C) 2004
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include "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/src/nsUnixShellService.h b/browser/components/shell/src/nsUnixShellService.h
+new file mode 100644
+--- /dev/null
++++ b/browser/components/shell/src/nsUnixShellService.h
+@@ -0,0 +1,45 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is Shell Service.
++ *
++ * The Initial Developer of the Original Code is mozilla.org.
++ * Portions created by the Initial Developer are Copyright (C) 2004
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#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
+@@ -640,19 +640,21 @@
+ @BINPATH@/defaults/autoconfig/prefcalls.js
+ @BINPATH@/browser/defaults/profile/prefs.js
+
+ #ifndef LIBXUL_SDK
+ ; 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.
+ @BINPATH@/defaults/pref/channel-prefs.js
++ at BINPATH@/defaults/pref/kde.js
+ #else
+ ; For Fx-on-xr, channel-prefs lives with the app preferences. (Bug 762588)
+ @BINPATH@/@PREF_DIR@/channel-prefs.js
++ at BINPATH@/@PREF_DIR@/kde.js
+ #endif
+
+ ; Services (gre) prefs
+ #ifdef MOZ_SERVICES_NOTIFICATIONS
+ @BINPATH@/defaults/pref/services-notifications.js
+ #endif
+ #ifdef MOZ_SERVICES_SYNC
+ @BINPATH@/defaults/pref/services-sync.js
diff --git a/helpers/DATA/firefox/mozilla-kde.patch b/helpers/DATA/firefox/mozilla-kde.patch
new file mode 100644
index 0000000..01959d0
--- /dev/null
+++ b/helpers/DATA/firefox/mozilla-kde.patch
@@ -0,0 +1,3707 @@
+Description: Add KDE integration to Abrowser (toolkit parts)
+Author: Wolfgang Rosenauer <wolfgang at rosenauer.org>
+Author: Lubos Lunak <lunak at suse.com>
+Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751
+ https://bugzilla.novell.com/show_bug.cgi?id=170055
+
+diff --git a/modules/libpref/src/Makefile.in b/modules/libpref/src/Makefile.in
+--- a/modules/libpref/src/Makefile.in
++++ b/modules/libpref/src/Makefile.in
+@@ -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) $(XULPPFLAGS) $^ -o $@)
+
+ libs:: greprefs.js
+ $(INSTALL) $^ $(DIST)/bin/
+diff --git a/modules/libpref/src/Preferences.cpp b/modules/libpref/src/Preferences.cpp
+--- a/modules/libpref/src/Preferences.cpp
++++ b/modules/libpref/src/Preferences.cpp
+@@ -27,16 +27,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 "pldhash.h"
+
+ #include "prefapi.h"
+ #include "prefread.h"
+ #include "prefapi_private_data.h"
+
+@@ -1115,16 +1116,34 @@ pref_LoadPrefsInDir(nsIFile* aDir, char
+
+ static nsresult pref_LoadPrefsInDirList(const char *listId)
+ {
+ nsresult rv;
+ nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+
++ // make sure we load these special files after all the others
++ static const char* specialFiles[] = {
++#if defined(XP_UNIX)
++ ""
++#endif
++ };
++
++ if (nsKDEUtils::kdeSession()) {
++ for(int i = 0;
++ i < NS_ARRAY_LENGTH(specialFiles);
++ ++i ) {
++ if (*specialFiles[ i ] == '\0') {
++ specialFiles[ i ] = "kde.js";
++ break;
++ }
++ }
++ }
++
+ nsCOMPtr<nsISimpleEnumerator> list;
+ dirSvc->Get(listId,
+ NS_GET_IID(nsISimpleEnumerator),
+ getter_AddRefs(list));
+ if (!list)
+ return NS_OK;
+
+ bool hasMore;
+@@ -1140,17 +1159,17 @@ static nsresult pref_LoadPrefsInDirList(
+
+ nsAutoCString leaf;
+ path->GetNativeLeafName(leaf);
+
+ // Do we care if a file provided by this process fails to load?
+ if (Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi")))
+ ReadExtensionPrefs(path);
+ else
+- pref_LoadPrefsInDir(path, nullptr, 0);
++ pref_LoadPrefsInDir(path, specialFiles, NS_ARRAY_LENGTH(specialFiles));
+ }
+ return NS_OK;
+ }
+
+ static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
+ {
+ nsZipItemPtr<char> manifest(jarReader, name, true);
+ NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
+@@ -1244,28 +1263,40 @@ static nsresult pref_InitInitialObjects(
+ /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
+ static const char* specialFiles[] = {
+ #if defined(XP_MACOSX)
+ "macprefs.js"
+ #elif defined(XP_WIN)
+ "winpref.js"
+ #elif defined(XP_UNIX)
+ "unix.js"
++ , "" // placeholder for KDE (empty is otherwise harmless)
+ #if defined(VMS)
+ , "openvms.js"
+ #elif defined(_AIX)
+ , "aix.js"
+ #endif
+ #elif defined(XP_OS2)
+ "os2pref.js"
+ #elif defined(XP_BEOS)
+ "beos.js"
+ #endif
+ };
+
++ if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper?
++ for(int i = 0;
++ i < NS_ARRAY_LENGTH(specialFiles);
++ ++i ) {
++ if( *specialFiles[ i ] == '\0' ) {
++ specialFiles[ i ] = "kde.js";
++ break;
++ }
++ }
++ }
++
+ rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
+ if (NS_FAILED(rv))
+ NS_WARNING("Error parsing application default preferences.");
+
+ // Load jar:$app/omni.jar!/defaults/preferences/*.js
+ // or jar:$gre/omni.jar!/defaults/preferences/*.js.
+ nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
+ // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
+diff --git a/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
+@@ -208,16 +208,17 @@ class Flags(OrderedDict):
+ 'platformversion': VersionFlag,
+ 'contentaccessible': Flag,
+ 'os': StringFlag,
+ 'osversion': VersionFlag,
+ 'abi': StringFlag,
+ 'platform': Flag,
+ 'xpcnativewrappers': Flag,
+ 'tablet': Flag,
++ '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
+@@ -30,16 +30,17 @@ class ManifestEntry(object):
+ allowed_flags = [
+ 'application',
+ 'platformversion',
+ 'os',
+ 'osversion',
+ 'abi',
+ 'xpcnativewrappers',
+ 'tablet',
++ '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/Makefile.in b/toolkit/components/downloads/Makefile.in
+--- a/toolkit/components/downloads/Makefile.in
++++ b/toolkit/components/downloads/Makefile.in
+@@ -4,9 +4,10 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ include $(topsrcdir)/config/rules.mk
+
+ CXXFLAGS += $(TK_CFLAGS) -DGOOGLE_PROTOBUF_NO_RTTI
+
+ LOCAL_INCLUDES += \
+ -I$(srcdir)/../protobuf \
++ -I$(topsrcdir)/toolkit/xre \
+ $(NULL)
+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
+@@ -41,16 +41,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"
+ using namespace mozilla::widget::android;
+ #endif
+@@ -2687,16 +2691,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;
+
+@@ -2724,19 +2737,20 @@ nsDownload::SetState(DownloadState aStat
+ // because if it is, they'll click open the download manager and
+ // the items they downloaded will have been removed.
+ alerts->ShowAlertNotification(
+ NS_LITERAL_STRING(DOWNLOAD_MANAGER_ALERT_ICON), title,
+ message, !removeWhenDone,
+ mPrivate ? NS_LITERAL_STRING("private") : NS_LITERAL_STRING("non-private"),
+ mDownloadManager, EmptyString(), NS_LITERAL_STRING("auto"),
+ EmptyString(), nullptr);
+- }
++ }
+ }
+ }
++ }
+
+ #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
+@@ -53,29 +53,33 @@ toolkit.jar:
+ content/global/viewZoomOverlay.js (viewZoomOverlay.js)
+ *+ content/global/bindings/autocomplete.xml (widgets/autocomplete.xml)
+ content/global/bindings/browser.xml (widgets/browser.xml)
+ content/global/bindings/button.xml (widgets/button.xml)
+ content/global/bindings/checkbox.xml (widgets/checkbox.xml)
+ content/global/bindings/colorpicker.xml (widgets/colorpicker.xml)
+ content/global/bindings/datetimepicker.xml (widgets/datetimepicker.xml)
+ *+ content/global/bindings/dialog.xml (widgets/dialog.xml)
++*+ content/global/bindings/dialog-kde.xml (widgets/dialog-kde.xml)
++% override chrome://global/content/bindings/dialog.xml chrome://global/content/bindings/dialog-kde.xml desktop=kde
+ content/global/bindings/editor.xml (widgets/editor.xml)
+ content/global/bindings/expander.xml (widgets/expander.xml)
+ * content/global/bindings/filefield.xml (widgets/filefield.xml)
+ *+ content/global/bindings/findbar.xml (widgets/findbar.xml)
+ content/global/bindings/general.xml (widgets/general.xml)
+ content/global/bindings/groupbox.xml (widgets/groupbox.xml)
+ *+ content/global/bindings/listbox.xml (widgets/listbox.xml)
+ content/global/bindings/menu.xml (widgets/menu.xml)
+ content/global/bindings/menulist.xml (widgets/menulist.xml)
+ content/global/bindings/notification.xml (widgets/notification.xml)
+ content/global/bindings/numberbox.xml (widgets/numberbox.xml)
+ content/global/bindings/popup.xml (widgets/popup.xml)
+ *+ content/global/bindings/preferences.xml (widgets/preferences.xml)
++*+ content/global/bindings/preferences-kde.xml (widgets/preferences-kde.xml)
++% override chrome://global/content/bindings/preferences.xml chrome://global/content/bindings/preferences-kde.xml desktop=kde
+ content/global/bindings/progressmeter.xml (widgets/progressmeter.xml)
+ content/global/bindings/radio.xml (widgets/radio.xml)
+ content/global/bindings/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,451 @@
++<?xml version="1.0"?>
++<!-- This Source Code Form is subject to the terms of the Mozilla Public
++ - License, v. 2.0. If a copy of the MPL was not distributed with this
++ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
++
++
++<bindings id="dialogBindings"
++ xmlns="http://www.mozilla.org/xbl"
++ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
++ xmlns:xbl="http://www.mozilla.org/xbl">
++
++ <binding id="dialog" extends="chrome://global/content/bindings/general.xml#root-element">
++ <resources>
++ <stylesheet src="chrome://global/skin/dialog.css"/>
++ </resources>
++ <content>
++ <xul:vbox class="box-inherit dialog-content-box" flex="1">
++ <children/>
++ </xul:vbox>
++
++ <xul:hbox class="dialog-button-box" anonid="buttons"
++ xbl:inherits="pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient"
++#ifdef XP_UNIX_GNOME
++ >
++ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++ <xul:spacer anonid="spacer" flex="1"/>
++ <xul:button dlgtype="cancel" class="dialog-button"/>
++ <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
++#elif XP_UNIX
++ pack="end">
++ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++ <xul:spacer anonid="spacer" flex="1" hidden="true"/>
++ <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
++ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="cancel" class="dialog-button"/>
++ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++#else
++ pack="end">
++ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++ <xul:spacer anonid="spacer" flex="1" hidden="true"/>
++ <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
++ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="cancel" class="dialog-button"/>
++ <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++#endif
++ </xul:hbox>
++ </content>
++
++ <implementation>
++ <field name="_mStrBundle">null</field>
++ <field name="_closeHandler">(function(event) {
++ if (!document.documentElement.cancelDialog())
++ event.preventDefault();
++ })</field>
++
++ <property name="buttons"
++ onget="return this.getAttribute('buttons');"
++ onset="this._configureButtons(val); return val;"/>
++
++ <property name="defaultButton">
++ <getter>
++ <![CDATA[
++ if (this.hasAttribute("defaultButton"))
++ return this.getAttribute("defaultButton");
++ else // default to the accept button
++ return "accept";
++ ]]>
++ </getter>
++ <setter>
++ <![CDATA[
++ this._setDefaultButton(val);
++ return val;
++ ]]>
++ </setter>
++ </property>
++
++ <method name="acceptDialog">
++ <body>
++ <![CDATA[
++ return this._doButtonCommand("accept");
++ ]]>
++ </body>
++ </method>
++
++ <method name="cancelDialog">
++ <body>
++ <![CDATA[
++ return this._doButtonCommand("cancel");
++ ]]>
++ </body>
++ </method>
++
++ <method name="getButton">
++ <parameter name="aDlgType"/>
++ <body>
++ <![CDATA[
++ return this._buttons[aDlgType];
++ ]]>
++ </body>
++ </method>
++
++ <method name="moveToAlertPosition">
++ <body>
++ <![CDATA[
++ // hack. we need this so the window has something like its final size
++ if (window.outerWidth == 1) {
++ dump("Trying to position a sizeless window; caller should have called sizeToContent() or sizeTo(). See bug 75649.\n");
++ sizeToContent();
++ }
++
++ var xOffset = (opener.outerWidth - window.outerWidth) / 2;
++ var yOffset = opener.outerHeight / 5;
++
++ var newX = opener.screenX + xOffset;
++ var newY = opener.screenY + yOffset;
++
++ // ensure the window is fully onscreen (if smaller than the screen)
++ if (newX < screen.availLeft)
++ newX = screen.availLeft + 20;
++ if ((newX + window.outerWidth) > (screen.availLeft + screen.availWidth))
++ newX = (screen.availLeft + screen.availWidth) - window.outerWidth - 20;
++
++ if (newY < screen.availTop)
++ newY = screen.availTop + 20;
++ if ((newY + window.outerHeight) > (screen.availTop + screen.availHeight))
++ newY = (screen.availTop + screen.availHeight) - window.outerHeight - 60;
++
++ window.moveTo( newX, newY );
++ ]]>
++ </body>
++ </method>
++
++ <method name="centerWindowOnScreen">
++ <body>
++ <![CDATA[
++ var xOffset = screen.availWidth/2 - window.outerWidth/2;
++ var yOffset = screen.availHeight/2 - window.outerHeight/2; //(opener.outerHeight *2)/10;
++
++ xOffset = xOffset > 0 ? xOffset : 0;
++ yOffset = yOffset > 0 ? yOffset : 0;
++ window.moveTo(xOffset, yOffset);
++ ]]>
++ </body>
++ </method>
++
++ <constructor>
++ <![CDATA[
++ this._configureButtons(this.buttons);
++
++ // listen for when window is closed via native close buttons
++ window.addEventListener("close", this._closeHandler, false);
++
++ // for things that we need to initialize after onload fires
++ window.addEventListener("load", this.postLoadInit, false);
++
++ window.moveToAlertPosition = this.moveToAlertPosition;
++ window.centerWindowOnScreen = this.centerWindowOnScreen;
++ ]]>
++ </constructor>
++
++ <method name="postLoadInit">
++ <parameter name="aEvent"/>
++ <body>
++ <![CDATA[
++ function focusInit() {
++ const dialog = document.documentElement;
++ const defaultButton = dialog.getButton(dialog.defaultButton);
++ // give focus to the first focusable element in the dialog
++ if (!document.commandDispatcher.focusedElement) {
++ document.commandDispatcher.advanceFocusIntoSubtree(dialog);
++
++ var focusedElt = document.commandDispatcher.focusedElement;
++ if (focusedElt) {
++ var initialFocusedElt = focusedElt;
++ while (focusedElt.localName == "tab" ||
++ focusedElt.getAttribute("noinitialfocus") == "true") {
++ document.commandDispatcher.advanceFocusIntoSubtree(focusedElt);
++ focusedElt = document.commandDispatcher.focusedElement;
++ if (focusedElt == initialFocusedElt)
++ break;
++ }
++
++ if (initialFocusedElt.localName == "tab") {
++ if (focusedElt.hasAttribute("dlgtype")) {
++ // We don't want to focus on anonymous OK, Cancel, etc. buttons,
++ // so return focus to the tab itself
++ initialFocusedElt.focus();
++ }
++ }
++#ifndef XP_MACOSX
++ else if (focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton) {
++ defaultButton.focus();
++ }
++#endif
++ }
++ }
++
++ try {
++ if (defaultButton)
++ window.notifyDefaultButtonLoaded(defaultButton);
++ } catch (e) { }
++ }
++
++ // Give focus after onload completes, see bug 103197.
++ setTimeout(focusInit, 0);
++ ]]>
++ </body>
++ </method>
++
++ <property name="mStrBundle">
++ <getter>
++ <![CDATA[
++ if (!this._mStrBundle) {
++ // need to create string bundle manually instead of using <xul:stringbundle/>
++ // see bug 63370 for details
++ this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
++ .getService(Components.interfaces.nsIStringBundleService)
++ .createBundle("chrome://global/locale/dialog.properties");
++ }
++ return this._mStrBundle;
++ ]]></getter>
++ </property>
++
++ <method name="_configureButtons">
++ <parameter name="aButtons"/>
++ <body>
++ <![CDATA[
++ // by default, get all the anonymous button elements
++ var buttons = {};
++ this._buttons = buttons;
++ buttons.accept = document.getAnonymousElementByAttribute(this, "dlgtype", "accept");
++ buttons.cancel = document.getAnonymousElementByAttribute(this, "dlgtype", "cancel");
++ buttons.extra1 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra1");
++ buttons.extra2 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra2");
++ buttons.help = document.getAnonymousElementByAttribute(this, "dlgtype", "help");
++ buttons.disclosure = document.getAnonymousElementByAttribute(this, "dlgtype", "disclosure");
++
++ // look for any overriding explicit button elements
++ var exBtns = this.getElementsByAttribute("dlgtype", "*");
++ var dlgtype;
++ var i;
++ for (i = 0; i < exBtns.length; ++i) {
++ dlgtype = exBtns[i].getAttribute("dlgtype");
++ buttons[dlgtype].hidden = true; // hide the anonymous button
++ buttons[dlgtype] = exBtns[i];
++ }
++
++ // add the label and oncommand handler to each button
++ for (dlgtype in buttons) {
++ var button = buttons[dlgtype];
++ button.addEventListener("command", this._handleButtonCommand, true);
++
++ // don't override custom labels with pre-defined labels on explicit buttons
++ if (!button.hasAttribute("label")) {
++ // dialog attributes override the default labels in dialog.properties
++ if (this.hasAttribute("buttonlabel"+dlgtype)) {
++ button.setAttribute("label", this.getAttribute("buttonlabel"+dlgtype));
++ if (this.hasAttribute("buttonaccesskey"+dlgtype))
++ button.setAttribute("accesskey", this.getAttribute("buttonaccesskey"+dlgtype));
++ } else if (dlgtype != "extra1" && dlgtype != "extra2") {
++ button.setAttribute("label", this.mStrBundle.GetStringFromName("button-"+dlgtype));
++ var accessKey = this.mStrBundle.GetStringFromName("accesskey-"+dlgtype);
++ if (accessKey)
++ button.setAttribute("accesskey", accessKey);
++ }
++ }
++ // allow specifying alternate icons in the dialog header
++ if (!button.hasAttribute("icon")) {
++ // if there's an icon specified, use that
++ if (this.hasAttribute("buttonicon"+dlgtype))
++ button.setAttribute("icon", this.getAttribute("buttonicon"+dlgtype));
++ // otherwise set defaults
++ else
++ switch (dlgtype) {
++ case "accept":
++ button.setAttribute("icon","accept");
++ break;
++ case "cancel":
++ button.setAttribute("icon","cancel");
++ break;
++ case "disclosure":
++ button.setAttribute("icon","properties");
++ break;
++ case "help":
++ button.setAttribute("icon","help");
++ break;
++ default:
++ break;
++ }
++ }
++ }
++
++ // ensure that hitting enter triggers the default button command
++ this.defaultButton = this.defaultButton;
++
++ // if there is a special button configuration, use it
++ if (aButtons) {
++ // expect a comma delimited list of dlgtype values
++ var list = aButtons.split(",");
++
++ // mark shown dlgtypes as true
++ var shown = { accept: false, cancel: false, help: false,
++ disclosure: false, extra1: false, extra2: false };
++ for (i = 0; i < list.length; ++i)
++ shown[list[i].replace(/ /g, "")] = true;
++
++ // hide/show the buttons we want
++ for (dlgtype in buttons)
++ buttons[dlgtype].hidden = !shown[dlgtype];
++
++#ifdef XP_WIN
++# show the spacer on Windows only when the extra2 button is present
++ var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer");
++ spacer.removeAttribute("hidden");
++ spacer.setAttribute("flex", shown["extra2"]?"1":"0");
++#endif
++
++ }
++ ]]>
++ </body>
++ </method>
++
++ <method name="_setDefaultButton">
++ <parameter name="aNewDefault"/>
++ <body>
++ <![CDATA[
++ // remove the default attribute from the previous default button, if any
++ var oldDefaultButton = this.getButton(this.defaultButton);
++ if (oldDefaultButton)
++ oldDefaultButton.removeAttribute("default");
++
++ var newDefaultButton = this.getButton(aNewDefault);
++ if (newDefaultButton) {
++ this.setAttribute("defaultButton", aNewDefault);
++ newDefaultButton.setAttribute("default", "true");
++ }
++ else {
++ this.setAttribute("defaultButton", "none");
++ if (aNewDefault != "none")
++ dump("invalid new default button: " + aNewDefault + ", assuming: none\n");
++ }
++ ]]>
++ </body>
++ </method>
++
++ <method name="_handleButtonCommand">
++ <parameter name="aEvent"/>
++ <body>
++ <![CDATA[
++ return document.documentElement._doButtonCommand(
++ aEvent.target.getAttribute("dlgtype"));
++ ]]>
++ </body>
++ </method>
++
++ <method name="_doButtonCommand">
++ <parameter name="aDlgType"/>
++ <body>
++ <![CDATA[
++ var button = this.getButton(aDlgType);
++ if (!button.disabled) {
++ var noCancel = this._fireButtonEvent(aDlgType);
++ if (noCancel) {
++ if (aDlgType == "accept" || aDlgType == "cancel")
++ window.close();
++ }
++ return noCancel;
++ }
++ return true;
++ ]]>
++ </body>
++ </method>
++
++ <method name="_fireButtonEvent">
++ <parameter name="aDlgType"/>
++ <body>
++ <![CDATA[
++ var event = document.createEvent("Events");
++ event.initEvent("dialog"+aDlgType, true, true);
++
++ // handle dom event handlers
++ var noCancel = this.dispatchEvent(event);
++
++ // handle any xml attribute event handlers
++ var handler = this.getAttribute("ondialog"+aDlgType);
++ if (handler != "") {
++ var fn = new Function("event", handler);
++ var returned = fn(event);
++ if (returned == false)
++ noCancel = false;
++ }
++
++ return noCancel;
++ ]]>
++ </body>
++ </method>
++
++ <method name="_hitEnter">
++ <parameter name="evt"/>
++ <body>
++ <![CDATA[
++ if (evt.defaultPrevented)
++ return;
++
++ var btn = this.getButton(this.defaultButton);
++ if (btn)
++ this._doButtonCommand(this.defaultButton);
++ ]]>
++ </body>
++ </method>
++
++ </implementation>
++
++ <handlers>
++ <handler event="keypress" keycode="VK_ENTER"
++ group="system" action="this._hitEnter(event);"/>
++ <handler event="keypress" keycode="VK_RETURN"
++ group="system" action="this._hitEnter(event);"/>
++ <handler event="keypress" keycode="VK_ESCAPE" group="system">
++ if (!event.defaultPrevented)
++ this.cancelDialog();
++ </handler>
++#ifdef XP_MACOSX
++ <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/>
++#else
++ <handler event="focus" phase="capturing">
++ var btn = this.getButton(this.defaultButton);
++ if (btn)
++ btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement));
++ </handler>
++#endif
++ </handlers>
++
++ </binding>
++
++ <binding id="dialogheader">
++ <resources>
++ <stylesheet src="chrome://global/skin/dialog.css"/>
++ </resources>
++ <content>
++ <xul:label class="dialogheader-title" xbl:inherits="value=title,crop" crop="right" flex="1"/>
++ <xul:label class="dialogheader-description" xbl:inherits="value=description"/>
++ </content>
++ </binding>
++
++</bindings>
+diff --git a/toolkit/content/widgets/preferences-kde.xml b/toolkit/content/widgets/preferences-kde.xml
+new file mode 100644
+--- /dev/null
++++ b/toolkit/content/widgets/preferences-kde.xml
+@@ -0,0 +1,1332 @@
++<?xml version="1.0"?>
++
++<!DOCTYPE bindings [
++ <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
++ %preferencesDTD;
++ <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
++ %globalKeysDTD;
++]>
++
++<bindings id="preferencesBindings"
++ xmlns="http://www.mozilla.org/xbl"
++ xmlns:xbl="http://www.mozilla.org/xbl"
++ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
++
++#
++# = Preferences Window Framework
++#
++# The syntax for use looks something like:
++#
++# <prefwindow>
++# <prefpane id="prefPaneA">
++# <preferences>
++# <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
++# <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
++# </preferences>
++# <checkbox label="Preference" preference="preference1"/>
++# </prefpane>
++# </prefwindow>
++#
++
++ <binding id="preferences">
++ <implementation implements="nsIObserver">
++ <method name="observe">
++ <parameter name="aSubject"/>
++ <parameter name="aTopic"/>
++ <parameter name="aData"/>
++ <body>
++ <![CDATA[
++ for (var i = 0; i < this.childNodes.length; ++i) {
++ var preference = this.childNodes[i];
++ if (preference.name == aData) {
++ preference.value = preference.valueFromPreferences;
++ }
++ }
++ ]]>
++ </body>
++ </method>
++
++ <method name="fireChangedEvent">
++ <parameter name="aPreference"/>
++ <body>
++ <![CDATA[
++ // Value changed, synthesize an event
++ try {
++ var event = document.createEvent("Events");
++ event.initEvent("change", true, true);
++ aPreference.dispatchEvent(event);
++ }
++ catch (e) {
++ Components.utils.reportError(e);
++ }
++ ]]>
++ </body>
++ </method>
++
++ <field name="service">
++ Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefService);
++ </field>
++ <field name="rootBranch">
++ Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefBranch);
++ </field>
++ <field name="defaultBranch">
++ this.service.getDefaultBranch("");
++ </field>
++ <field name="rootBranchInternal">
++ Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefBranchInternal);
++ </field>
++ <property name="type" readonly="true">
++ <getter>
++ <![CDATA[
++ return document.documentElement.type || "";
++ ]]>
++ </getter>
++ </property>
++ <property name="instantApply" readonly="true">
++ <getter>
++ <![CDATA[
++ var doc = document.documentElement;
++ return this.type == "child" ? doc.instantApply
++ : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
++ ]]>
++ </getter>
++ </property>
++ </implementation>
++ </binding>
++
++ <binding id="preference">
++ <implementation>
++ <constructor>
++ <![CDATA[
++ // if the element has been inserted without the name attribute set,
++ // we have nothing to do here
++ if (!this.name)
++ return;
++
++ this.preferences.rootBranchInternal
++ .addObserver(this.name, this.preferences, false);
++ // In non-instant apply mode, we must try and use the last saved state
++ // from any previous opens of a child dialog instead of the value from
++ // preferences, to pick up any edits a user may have made.
++ if (this.preferences.type == "child" &&
++ !this.instantApply && window.opener) {
++ var pdoc = window.opener.document;
++
++ // Try to find a preference element for the same preference.
++ var preference = null;
++ var parentPreferences = pdoc.getElementsByTagName("preferences");
++ for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
++ var parentPrefs = parentPreferences[k]
++ .getElementsByAttribute("name", this.name);
++ for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
++ if (parentPrefs[l].localName == "preference")
++ preference = parentPrefs[l];
++ }
++ }
++ this._setValue(preference ? preference.value
++ : this.valueFromPreferences, false);
++ }
++ else
++ this._setValue(this.valueFromPreferences, false);
++ ]]>
++ </constructor>
++ <destructor>
++ this.preferences.rootBranchInternal
++ .removeObserver(this.name, this.preferences);
++ </destructor>
++
++ <property name="instantApply">
++ <getter>
++ return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
++ </getter>
++ </property>
++
++ <property name="preferences" onget="return this.parentNode"/>
++ <property name="name" onget="return this.getAttribute('name');">
++ <setter>
++ if (val == this.name)
++ return val;
++
++ this.preferences.rootBranchInternal
++ .removeObserver(this.name, this.preferences);
++ this.setAttribute('name', val);
++ this.preferences.rootBranchInternal
++ .addObserver(val, this.preferences, false);
++
++ return val;
++ </setter>
++ </property>
++ <property name="type" onget="return this.getAttribute('type');"
++ onset="this.setAttribute('type', val); return val;"/>
++ <property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
++ onset="this.setAttribute('inverted', val); return val;"/>
++ <property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
++ onset="this.setAttribute('readonly', val); return val;"/>
++
++ <field name="_value">null</field>
++ <method name="_setValue">
++ <parameter name="aValue"/>
++ <parameter name="aUpdate"/>
++ <body>
++ <![CDATA[
++ if (aUpdate && this.value !== aValue) {
++ this._value = aValue;
++ if (this.instantApply)
++ this.valueFromPreferences = aValue;
++ this.preferences.fireChangedEvent(this);
++ }
++ else if (!aUpdate) {
++ this._value = aValue;
++ this.updateElements();
++ }
++ return aValue;
++ ]]>
++ </body>
++ </method>
++ <property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
++
++ <property name="locked">
++ <getter>
++ return this.preferences.rootBranch.prefIsLocked(this.name);
++ </getter>
++ </property>
++
++ <property name="disabled">
++ <getter>
++ return this.getAttribute("disabled") == "true";
++ </getter>
++ <setter>
++ <![CDATA[
++ if (val)
++ this.setAttribute("disabled", "true");
++ else
++ this.removeAttribute("disabled");
++
++ if (!this.id)
++ return val;
++
++ var elements = document.getElementsByAttribute("preference", this.id);
++ for (var i = 0; i < elements.length; ++i) {
++ elements[i].disabled = val;
++
++ var labels = document.getElementsByAttribute("control", elements[i].id);
++ for (var j = 0; j < labels.length; ++j)
++ labels[j].disabled = val;
++ }
++
++ return val;
++ ]]>
++ </setter>
++ </property>
++
++ <property name="tabIndex">
++ <getter>
++ return parseInt(this.getAttribute("tabindex"));
++ </getter>
++ <setter>
++ <![CDATA[
++ if (val)
++ this.setAttribute("tabindex", val);
++ else
++ this.removeAttribute("tabindex");
++
++ if (!this.id)
++ return val;
++
++ var elements = document.getElementsByAttribute("preference", this.id);
++ for (var i = 0; i < elements.length; ++i) {
++ elements[i].tabIndex = val;
++
++ var labels = document.getElementsByAttribute("control", elements[i].id);
++ for (var j = 0; j < labels.length; ++j)
++ labels[j].tabIndex = val;
++ }
++
++ return val;
++ ]]>
++ </setter>
++ </property>
++
++ <property name="hasUserValue">
++ <getter>
++ <![CDATA[
++ return this.preferences.rootBranch.prefHasUserValue(this.name) &&
++ this.value !== undefined;
++ ]]>
++ </getter>
++ </property>
++
++ <method name="reset">
++ <body>
++ // defer reset until preference update
++ this.value = undefined;
++ </body>
++ </method>
++
++ <field name="_useDefault">false</field>
++ <property name="defaultValue">
++ <getter>
++ <![CDATA[
++ this._useDefault = true;
++ var val = this.valueFromPreferences;
++ this._useDefault = false;
++ return val;
++ ]]>
++ </getter>
++ </property>
++
++ <property name="_branch">
++ <getter>
++ return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
++ </getter>
++ </property>
++
++ <field name="batching">false</field>
++
++ <method name="_reportUnknownType">
++ <body>
++ <![CDATA[
++ var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
++ .getService(Components.interfaces.nsIConsoleService);
++ var msg = "<preference> with id='" + this.id + "' and name='" +
++ this.name + "' has unknown type '" + this.type + "'.";
++ consoleService.logStringMessage(msg);
++ ]]>
++ </body>
++ </method>
++
++ <property name="valueFromPreferences">
++ <getter>
++ <![CDATA[
++ try {
++ // Force a resync of value with preferences.
++ switch (this.type) {
++ case "int":
++ return this._branch.getIntPref(this.name);
++ case "bool":
++ var val = this._branch.getBoolPref(this.name);
++ return this.inverted ? !val : val;
++ case "wstring":
++ return this._branch
++ .getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
++ .data;
++ case "string":
++ case "unichar":
++ return this._branch
++ .getComplexValue(this.name, Components.interfaces.nsISupportsString)
++ .data;
++ case "fontname":
++ var family = this._branch
++ .getComplexValue(this.name, Components.interfaces.nsISupportsString)
++ .data;
++ var fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
++ .createInstance(Components.interfaces.nsIFontEnumerator);
++ return fontEnumerator.getStandardFamilyName(family);
++ case "file":
++ var f = this._branch
++ .getComplexValue(this.name, Components.interfaces.nsILocalFile);
++ return f;
++ default:
++ this._reportUnknownType();
++ }
++ }
++ catch (e) { }
++ return null;
++ ]]>
++ </getter>
++ <setter>
++ <![CDATA[
++ // Exit early if nothing to do.
++ if (this.readonly || this.valueFromPreferences == val)
++ return val;
++
++ // The special value undefined means 'reset preference to default'.
++ if (val === undefined) {
++ this.preferences.rootBranch.clearUserPref(this.name);
++ return val;
++ }
++
++ // Force a resync of preferences with value.
++ switch (this.type) {
++ case "int":
++ this.preferences.rootBranch.setIntPref(this.name, val);
++ break;
++ case "bool":
++ this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
++ break;
++ case "wstring":
++ var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
++ .createInstance(Components.interfaces.nsIPrefLocalizedString);
++ pls.data = val;
++ this.preferences.rootBranch
++ .setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
++ break;
++ case "string":
++ case "unichar":
++ case "fontname":
++ var iss = Components.classes["@mozilla.org/supports-string;1"]
++ .createInstance(Components.interfaces.nsISupportsString);
++ iss.data = val;
++ this.preferences.rootBranch
++ .setComplexValue(this.name, Components.interfaces.nsISupportsString, iss);
++ break;
++ case "file":
++ var lf;
++ if (typeof(val) == "string") {
++ lf = Components.classes["@mozilla.org/file/local;1"]
++ .createInstance(Components.interfaces.nsILocalFile);
++ lf.persistentDescriptor = val;
++ if (!lf.exists())
++ lf.initWithPath(val);
++ }
++ else
++ lf = val.QueryInterface(Components.interfaces.nsILocalFile);
++ this.preferences.rootBranch
++ .setComplexValue(this.name, Components.interfaces.nsILocalFile, lf);
++ break;
++ default:
++ this._reportUnknownType();
++ }
++ if (!this.batching)
++ this.preferences.service.savePrefFile(null);
++ return val;
++ ]]>
++ </setter>
++ </property>
++
++ <method name="setElementValue">
++ <parameter name="aElement"/>
++ <body>
++ <![CDATA[
++ if (this.locked)
++ aElement.disabled = true;
++
++ if (!this.isElementEditable(aElement))
++ return;
++
++ var rv = undefined;
++ if (aElement.hasAttribute("onsyncfrompreference")) {
++ // Value changed, synthesize an event
++ try {
++ var event = document.createEvent("Events");
++ event.initEvent("syncfrompreference", true, true);
++ var f = new Function ("event",
++ aElement.getAttribute("onsyncfrompreference"));
++ rv = f.call(aElement, event);
++ }
++ catch (e) {
++ Components.utils.reportError(e);
++ }
++ }
++ var val = rv !== undefined ? rv : (this.instantApply ? this.valueFromPreferences : this.value);
++ // if the preference is marked for reset, show default value in UI
++ if (val === undefined)
++ val = this.defaultValue;
++
++ /**
++ * Initialize a UI element property with a value. Handles the case
++ * where an element has not yet had a XBL binding attached for it and
++ * the property setter does not yet exist by setting the same attribute
++ * on the XUL element using DOM apis and assuming the element's
++ * constructor or property getters appropriately handle this state.
++ */
++ function setValue(element, attribute, value) {
++ if (attribute in element)
++ element[attribute] = value;
++ else
++ element.setAttribute(attribute, value);
++ }
++ if (aElement.localName == "checkbox" ||
++ aElement.localName == "listitem")
++ setValue(aElement, "checked", val);
++ else if (aElement.localName == "colorpicker")
++ setValue(aElement, "color", val);
++ else if (aElement.localName == "textbox") {
++ // XXXmano Bug 303998: Avoid a caret placement issue if either the
++ // preference observer or its setter calls updateElements as a result
++ // of the input event handler.
++ if (aElement.value !== val)
++ setValue(aElement, "value", val);
++ }
++ else
++ setValue(aElement, "value", val);
++ ]]>
++ </body>
++ </method>
++
++ <method name="getElementValue">
++ <parameter name="aElement"/>
++ <body>
++ <![CDATA[
++ if (aElement.hasAttribute("onsynctopreference")) {
++ // Value changed, synthesize an event
++ try {
++ var event = document.createEvent("Events");
++ event.initEvent("synctopreference", true, true);
++ var f = new Function ("event",
++ aElement.getAttribute("onsynctopreference"));
++ var rv = f.call(aElement, event);
++ if (rv !== undefined)
++ return rv;
++ }
++ catch (e) {
++ Components.utils.reportError(e);
++ }
++ }
++
++ /**
++ * Read the value of an attribute from an element, assuming the
++ * attribute is a property on the element's node API. If the property
++ * is not present in the API, then assume its value is contained in
++ * an attribute, as is the case before a binding has been attached.
++ */
++ function getValue(element, attribute) {
++ if (attribute in element)
++ return element[attribute];
++ return element.getAttribute(attribute);
++ }
++ if (aElement.localName == "checkbox" ||
++ aElement.localName == "listitem")
++ var value = getValue(aElement, "checked");
++ else if (aElement.localName == "colorpicker")
++ value = getValue(aElement, "color");
++ else
++ value = getValue(aElement, "value");
++
++ switch (this.type) {
++ case "int":
++ return parseInt(value, 10) || 0;
++ case "bool":
++ return typeof(value) == "boolean" ? value : value == "true";
++ }
++ return value;
++ ]]>
++ </body>
++ </method>
++
++ <method name="isElementEditable">
++ <parameter name="aElement"/>
++ <body>
++ <![CDATA[
++ switch (aElement.localName) {
++ case "checkbox":
++ case "colorpicker":
++ case "radiogroup":
++ case "textbox":
++ case "listitem":
++ case "listbox":
++ case "menulist":
++ return true;
++ }
++ return aElement.getAttribute("preference-editable") == "true";
++ ]]>
++ </body>
++ </method>
++
++ <method name="updateElements">
++ <body>
++ <![CDATA[
++ if (!this.id)
++ return;
++
++ // This "change" event handler tracks changes made to preferences by
++ // sources other than the user in this window.
++ var elements = document.getElementsByAttribute("preference", this.id);
++ for (var i = 0; i < elements.length; ++i)
++ this.setElementValue(elements[i]);
++ ]]>
++ </body>
++ </method>
++ </implementation>
++
++ <handlers>
++ <handler event="change">
++ this.updateElements();
++ </handler>
++ </handlers>
++ </binding>
++
++ <binding id="prefwindow"
++ extends="chrome://global/content/bindings/dialog.xml#dialog">
++ <resources>
++ <stylesheet src="chrome://global/skin/preferences.css"/>
++ </resources>
++ <content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
++ closebuttonlabel="&preferencesCloseButton.label;"
++ closebuttonaccesskey="&preferencesCloseButton.accesskey;"
++ role="dialog"
++#ifdef XP_WIN
++ title="&preferencesDefaultTitleWin.title;">
++#else
++ title="&preferencesDefaultTitleMac.title;">
++#endif
++ <xul:windowdragbox orient="vertical">
++ <xul:radiogroup anonid="selector" orient="horizontal" class="paneSelector chromeclass-toolbar"
++ role="listbox"/> <!-- Expose to accessibility APIs as a listbox -->
++ </xul:windowdragbox>
++ <xul:hbox flex="1" class="paneDeckContainer">
++ <xul:deck anonid="paneDeck" flex="1">
++ <children includes="prefpane"/>
++ </xul:deck>
++ </xul:hbox>
++ <xul:hbox anonid="dlg-buttons" class="prefWindow-dlgbuttons"
++#ifdef XP_UNIX_GNOME
++ >
++ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
++ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++ <xul:spacer anonid="spacer" flex="1"/>
++ <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
++ <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
++#elif XP_UNIX
++ pack="end">
++ <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
++ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++ <xul:spacer anonid="spacer" flex="1"/>
++ <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
++ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
++ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++
++#else
++ pack="end">
++ <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
++ <xul:spacer anonid="spacer" flex="1"/>
++ <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
++ <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
++ <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
++ <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
++ <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
++#endif
++ </xul:hbox>
++ <xul:hbox>
++ <children/>
++ </xul:hbox>
++ </content>
++ <implementation implements="nsITimerCallback">
++ <constructor>
++ <![CDATA[
++ if (this.type != "child") {
++ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefBranch);
++ this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
++ if (this.instantApply) {
++ var docElt = document.documentElement;
++ var acceptButton = docElt.getButton("accept");
++ acceptButton.hidden = true;
++ var cancelButton = docElt.getButton("cancel");
++#ifdef XP_MACOSX
++ // no buttons on Mac except Help
++ cancelButton.hidden = true;
++ // Also, don't fire onDialogAccept on enter
++ acceptButton.disabled = true;
++#else
++ // morph the Cancel button into the Close button
++ cancelButton.setAttribute ("icon", "close");
++ cancelButton.label = docElt.getAttribute("closebuttonlabel");
++ cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
++#endif
++ }
++ }
++ this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
++ var panes = this.preferencePanes;
++
++ var lastPane = null;
++ if (this.lastSelected) {
++ lastPane = document.getElementById(this.lastSelected);
++ if (!lastPane) {
++ this.lastSelected = "";
++ }
++ }
++
++ var paneToLoad;
++ if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
++ paneToLoad = document.getElementById(window.arguments[0]);
++ this.lastSelected = paneToLoad.id;
++ }
++ else if (lastPane)
++ paneToLoad = lastPane;
++ else
++ paneToLoad = panes[0];
++
++ for (var i = 0; i < panes.length; ++i) {
++ this._makePaneButton(panes[i]);
++ if (panes[i].loaded) {
++ // Inline pane content, fire load event to force initialization.
++ this._fireEvent("paneload", panes[i]);
++ }
++ }
++ this.showPane(paneToLoad);
++
++ if (panes.length == 1)
++ this._selector.setAttribute("collapsed", "true");
++ ]]>
++ </constructor>
++
++ <destructor>
++ <![CDATA[
++ // Release timers to avoid reference cycles.
++ if (this._animateTimer) {
++ this._animateTimer.cancel();
++ this._animateTimer = null;
++ }
++ if (this._fadeTimer) {
++ this._fadeTimer.cancel();
++ this._fadeTimer = null;
++ }
++ ]]>
++ </destructor>
++
++ <field name="instantApply">false</field>
++
++ <property name="preferencePanes"
++ onget="return this.getElementsByTagName('prefpane');"/>
++
++ <property name="type" onget="return this.getAttribute('type');"/>
++ <property name="_paneDeck"
++ onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
++ <property name="_paneDeckContainer"
++ onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
++ <property name="_selector"
++ onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
++ <property name="lastSelected"
++ onget="return this.getAttribute('lastSelected');">
++ <setter>
++ this.setAttribute("lastSelected", val);
++ document.persist(this.id, "lastSelected");
++ return val;
++ </setter>
++ </property>
++ <property name="currentPane"
++ onset="return this._currentPane = val;">
++ <getter>
++ if (!this._currentPane)
++ this._currentPane = this.preferencePanes[0];
++
++ return this._currentPane;
++ </getter>
++ </property>
++ <field name="_currentPane">null</field>
++
++
++ <method name="_makePaneButton">
++ <parameter name="aPaneElement"/>
++ <body>
++ <![CDATA[
++ var radio = document.createElement("radio");
++ radio.setAttribute("pane", aPaneElement.id);
++ radio.setAttribute("label", aPaneElement.label);
++ // Expose preference group choice to accessibility APIs as an unchecked list item
++ // The parent group is exposed to accessibility APIs as a list
++ if (aPaneElement.image)
++ radio.setAttribute("src", aPaneElement.image);
++ radio.style.listStyleImage = aPaneElement.style.listStyleImage;
++ this._selector.appendChild(radio);
++ return radio;
++ ]]>
++ </body>
++ </method>
++
++ <method name="showPane">
++ <parameter name="aPaneElement"/>
++ <body>
++ <![CDATA[
++ if (!aPaneElement)
++ return;
++
++ this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
++ if (!aPaneElement.loaded) {
++ 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;
++
++ if (this.type == "child" && window.opener) {
++ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefBranch);
++ var instantApply = psvc.getBoolPref("browser.preferences.instantApply");
++ if (instantApply) {
++ var panes = this.preferencePanes;
++ for (var i = 0; i < panes.length; ++i)
++ panes[i].writePreferences(true);
++ }
++ else {
++ // Clone all the preferences elements from the child document and
++ // insert them into the pane collection of the parent.
++ var pdoc = window.opener.document;
++ if (pdoc.documentElement.localName == "prefwindow") {
++ var currentPane = pdoc.documentElement.currentPane;
++ var id = window.location.href + "#childprefs";
++ var childPrefs = pdoc.getElementById(id);
++ if (!childPrefs) {
++ var childPrefs = pdoc.createElement("preferences");
++ currentPane.appendChild(childPrefs);
++ childPrefs.id = id;
++ }
++ var panes = this.preferencePanes;
++ for (var i = 0; i < panes.length; ++i) {
++ var preferences = panes[i].preferences;
++ for (var j = 0; j < preferences.length; ++j) {
++ // Try to find a preference element for the same preference.
++ var preference = null;
++ var parentPreferences = pdoc.getElementsByTagName("preferences");
++ for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
++ var parentPrefs = parentPreferences[k]
++ .getElementsByAttribute("name", preferences[j].name);
++ for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
++ if (parentPrefs[l].localName == "preference")
++ preference = parentPrefs[l];
++ }
++ }
++ if (!preference) {
++ // No matching preference in the parent window.
++ preference = pdoc.createElement("preference");
++ childPrefs.appendChild(preference);
++ preference.name = preferences[j].name;
++ preference.type = preferences[j].type;
++ preference.inverted = preferences[j].inverted;
++ preference.readonly = preferences[j].readonly;
++ preference.disabled = preferences[j].disabled;
++ }
++ preference.value = preferences[j].value;
++ }
++ }
++ }
++ }
++ }
++ else {
++ var panes = this.preferencePanes;
++ for (var i = 0; i < panes.length; ++i)
++ panes[i].writePreferences(false);
++
++ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefService);
++ psvc.savePrefFile(null);
++ }
++ ]]>
++ </handler>
++ <handler event="command">
++ if (event.originalTarget.hasAttribute("pane")) {
++ var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
++ this.showPane(pane);
++ }
++ </handler>
++
++ <handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
++ <![CDATA[
++ if (this.instantApply)
++ window.close();
++ event.stopPropagation();
++ event.preventDefault();
++ ]]>
++ </handler>
++
++ <handler event="keypress"
++#ifdef XP_MACOSX
++ key="&openHelpMac.commandkey;" modifiers="accel"
++#else
++ keycode="&openHelp.commandkey;"
++#endif
++ phase="capturing">
++ <![CDATA[
++ var helpButton = this.getButton("help");
++ if (helpButton.disabled || helpButton.hidden)
++ return;
++ this._fireEvent("dialoghelp", this);
++ event.stopPropagation();
++ event.preventDefault();
++ ]]>
++ </handler>
++ </handlers>
++ </binding>
++
++ <binding id="prefpane">
++ <resources>
++ <stylesheet src="chrome://global/skin/preferences.css"/>
++ </resources>
++ <content>
++ <xul:vbox class="content-box" xbl:inherits="flex">
++ <children/>
++ </xul:vbox>
++ </content>
++ <implementation>
++ <method name="writePreferences">
++ <parameter name="aFlushToDisk"/>
++ <body>
++ <![CDATA[
++ // Write all values to preferences.
++ var preferences = this.preferences;
++ for (var i = 0; i < preferences.length; ++i) {
++ var preference = preferences[i];
++ preference.batching = true;
++ preference.valueFromPreferences = preference.value;
++ preference.batching = false;
++ }
++ if (aFlushToDisk) {
++ var psvc = Components.classes["@mozilla.org/preferences-service;1"]
++ .getService(Components.interfaces.nsIPrefService);
++ psvc.savePrefFile(null);
++ }
++ ]]>
++ </body>
++ </method>
++
++ <property name="src"
++ onget="return this.getAttribute('src');"
++ onset="this.setAttribute('src', val); return val;"/>
++ <property name="selected"
++ onget="return this.getAttribute('selected') == 'true';"
++ onset="this.setAttribute('selected', val); return val;"/>
++ <property name="image"
++ onget="return this.getAttribute('image');"
++ onset="this.setAttribute('image', val); return val;"/>
++ <property name="label"
++ onget="return this.getAttribute('label');"
++ onset="this.setAttribute('label', val); return val;"/>
++
++ <property name="preferenceElements"
++ onget="return this.getElementsByAttribute('preference', '*');"/>
++ <property name="preferences"
++ onget="return this.getElementsByTagName('preference');"/>
++
++ <property name="helpTopic">
++ <getter>
++ <![CDATA[
++ // if there are tabs, and the selected tab provides a helpTopic, return that
++ var box = this.getElementsByTagName("tabbox");
++ if (box[0]) {
++ var tab = box[0].selectedTab;
++ if (tab && tab.hasAttribute("helpTopic"))
++ return tab.getAttribute("helpTopic");
++ }
++
++ // otherwise, return the helpTopic of the current panel
++ return this.getAttribute("helpTopic");
++ ]]>
++ </getter>
++ </property>
++
++ <field name="_loaded">false</field>
++ <property name="loaded"
++ onget="return !this.src ? true : this._loaded;"
++ onset="this._loaded = val; return val;"/>
++
++ <method name="preferenceForElement">
++ <parameter name="aElement"/>
++ <body>
++ return document.getElementById(aElement.getAttribute("preference"));
++ </body>
++ </method>
++
++ <method name="getPreferenceElement">
++ <parameter name="aStartElement"/>
++ <body>
++ <![CDATA[
++ var temp = aStartElement;
++ while (temp && temp.nodeType == Node.ELEMENT_NODE &&
++ !temp.hasAttribute("preference"))
++ temp = temp.parentNode;
++ return temp.nodeType == Node.ELEMENT_NODE ? temp : aStartElement;
++ ]]>
++ </body>
++ </method>
++
++ <method name="userChangedValue">
++ <parameter name="aElement"/>
++ <body>
++ <![CDATA[
++ var element = this.getPreferenceElement(aElement);
++ if (element.hasAttribute("preference")) {
++ var preference = document.getElementById(element.getAttribute("preference"));
++ var prefVal = preference.getElementValue(element);
++ preference.value = prefVal;
++ }
++ ]]>
++ </body>
++ </method>
++
++ <property name="contentHeight">
++ <getter>
++ var targetHeight = parseInt(window.getComputedStyle(this._content, "").height);
++ targetHeight += parseInt(window.getComputedStyle(this._content, "").marginTop);
++ targetHeight += parseInt(window.getComputedStyle(this._content, "").marginBottom);
++ return targetHeight;
++ </getter>
++ </property>
++ <field name="_content">
++ document.getAnonymousElementByAttribute(this, "class", "content-box");
++ </field>
++ </implementation>
++ <handlers>
++ <handler event="command">
++ // This "command" event handler tracks changes made to preferences by
++ // the user in this window.
++ if (event.sourceEvent)
++ event = event.sourceEvent;
++ this.userChangedValue(event.target);
++ </handler>
++ <handler event="select">
++ // This "select" event handler tracks changes made to colorpicker
++ // preferences by the user in this window.
++ if (event.target.localName == "colorpicker")
++ this.userChangedValue(event.target);
++ </handler>
++ <handler event="change">
++ // This "change" event handler tracks changes made to preferences by
++ // the user in this window.
++ this.userChangedValue(event.target);
++ </handler>
++ <handler event="input">
++ // This "input" event handler tracks changes made to preferences by
++ // the user in this window.
++ this.userChangedValue(event.target);
++ </handler>
++ <handler event="paneload">
++ <![CDATA[
++ // Initialize all values from preferences.
++ var elements = this.preferenceElements;
++ for (var i = 0; i < elements.length; ++i) {
++ try {
++ var preference = this.preferenceForElement(elements[i]);
++ preference.setElementValue(elements[i]);
++ }
++ catch (e) {
++ dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
++ }
++ }
++ ]]>
++ </handler>
++ </handlers>
++ </binding>
++
++ <binding id="panebutton" 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
+@@ -14,16 +14,18 @@
+ #include "prenv.h"
+ #include "nsPrintfCString.h"
+ #include "nsNetUtil.h"
+ #include "nsISupportsPrimitives.h"
+ #include "nsIGSettingsService.h"
+ #include "nsInterfaceHashtable.h"
+ #include "mozilla/Attributes.h"
+ #include "nsIURI.h"
++#include "nsVoidArray.h"
++#include "nsKDEUtils.h"
+
+ class nsUnixSystemProxySettings MOZ_FINAL : public nsISystemProxySettings {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISYSTEMPROXYSETTINGS
+
+ nsUnixSystemProxySettings()
+ : mSchemeProxySettings(5)
+@@ -38,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_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings)
+
+ NS_IMETHODIMP
+ nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
+ {
+ // dbus prevents us from being threadsafe, but this routine should not block anyhow
+@@ -504,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);
+
+@@ -539,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
+@@ -45,17 +45,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt
+ 'nsNativeAppSupportQt.cpp',
+ 'nsQAppInstance.cpp',
+ ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'os2':
+ SOURCES += [
+ 'nsNativeAppSupportOS2.cpp',
+ ]
+ elif CONFIG['MOZ_ENABLE_GTK']:
++ EXPORTS += ['nsKDEUtils.h']
+ UNIFIED_SOURCES += [
++ 'nsKDEUtils.cpp',
+ 'nsNativeAppSupportUnix.cpp',
+ ]
+ else:
+ UNIFIED_SOURCES += [
+ 'nsNativeAppSupportDefault.cpp',
+ ]
+
+ if CONFIG['MOZ_X11']:
+diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp
+new file mode 100644
+--- /dev/null
++++ b/toolkit/xre/nsKDEUtils.cpp
+@@ -0,0 +1,339 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsKDEUtils.h"
++#include "nsIWidget.h"
++#include "nsISupportsPrimitives.h"
++#include "nsIMutableArray.h"
++#include "nsComponentManagerUtils.h"
++#include "nsArrayUtils.h"
++
++#include <gtk/gtk.h>
++
++#include <limits.h>
++#include <stdio.h>
++#include <sys/wait.h>
++#include <sys/resource.h>
++#include <unistd.h>
++#include <X11/Xlib.h>
++
++//#define DEBUG_KDE
++#ifdef DEBUG_KDE
++#define KMOZILLAHELPER "kmozillahelper"
++#else
++// not need for lib64, it's a binary
++#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper"
++#endif
++
++#define KMOZILLAHELPER_VERSION 6
++#define MAKE_STR2( n ) #n
++#define MAKE_STR( n ) MAKE_STR2( n )
++
++static bool getKdeSession()
++ {
++ Display* dpy = XOpenDisplay( NULL );
++ if( dpy == NULL )
++ return false;
++ Atom kde_full_session = XInternAtom( dpy, "KDE_FULL_SESSION", True );
++ bool kde = false;
++ if( kde_full_session != None )
++ {
++ int cnt;
++ if( Atom* props = XListProperties( dpy, DefaultRootWindow( dpy ), &cnt ))
++ {
++ for( int i = 0;
++ i < cnt;
++ ++i )
++ {
++ if( props[ i ] == kde_full_session )
++ {
++ kde = true;
++#ifdef DEBUG_KDE
++ fprintf( stderr, "KDE SESSION %d\n", kde );
++#endif
++ break;
++ }
++ }
++ XFree( props );
++ }
++ }
++ XCloseDisplay( dpy );
++ return kde;
++ }
++
++static bool getKdeSupport()
++ {
++ nsTArray<nsCString> command;
++ command.AppendElement( NS_LITERAL_CSTRING( "CHECK" ));
++ command.AppendElement( NS_LITERAL_CSTRING( MAKE_STR( KMOZILLAHELPER_VERSION )));
++ bool kde = nsKDEUtils::command( command );
++#ifdef DEBUG_KDE
++ fprintf( stderr, "KDE RUNNING %d\n", kde );
++#endif
++ return kde;
++ }
++
++nsKDEUtils::nsKDEUtils()
++ : commandFile( NULL )
++ , replyFile( NULL )
++ {
++ }
++
++nsKDEUtils::~nsKDEUtils()
++ {
++// closeHelper(); not actually useful, exiting will close the fd too
++ }
++
++nsKDEUtils* nsKDEUtils::self()
++ {
++ static nsKDEUtils s;
++ return &s;
++ }
++
++static bool helperRunning = false;
++static bool helperFailed = false;
++
++bool nsKDEUtils::kdeSession()
++ {
++ static bool session = getKdeSession();
++ return session;
++ }
++
++bool nsKDEUtils::kdeSupport()
++ {
++ static bool support = kdeSession() && getKdeSupport();
++ return support && helperRunning;
++ }
++
++struct nsKDECommandData
++ {
++ FILE* file;
++ nsTArray<nsCString>* output;
++ GMainLoop* loop;
++ bool success;
++ };
++
++static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data )
++ {
++ nsKDECommandData* p = static_cast< nsKDECommandData* >( data );
++ char buf[ 8192 ]; // TODO big enough
++ bool command_done = false;
++ bool command_failed = false;
++ while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL )
++ { // TODO what if the kernel splits a line into two chunks?
++//#ifdef DEBUG_KDE
++// fprintf( stderr, "READ: %s %d\n", buf, feof( p->file ));
++//#endif
++ if( char* eol = strchr( buf, '\n' ))
++ *eol = '\0';
++ command_done = ( strcmp( buf, "\\1" ) == 0 );
++ command_failed = ( strcmp( buf, "\\0" ) == 0 );
++ nsAutoCString line( buf );
++ line.ReplaceSubstring( "\\n", "\n" );
++ line.ReplaceSubstring( "\\" "\\", "\\" ); // \\ -> \ , i.e. unescape
++ if( p->output && !( command_done || command_failed ))
++ p->output->AppendElement( nsCString( buf )); // TODO utf8?
++ }
++ bool quit = false;
++ if( feof( p->file ) || command_failed )
++ {
++ quit = true;
++ p->success = false;
++ }
++ if( command_done )
++ { // reading one reply finished
++ quit = true;
++ p->success = true;
++ }
++ if( quit )
++ {
++ if( p->loop )
++ g_main_loop_quit( p->loop );
++ return FALSE;
++ }
++ return TRUE;
++ }
++
++bool nsKDEUtils::command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output )
++ {
++ return self()->internalCommand( command, NULL, false, output );
++ }
++
++bool nsKDEUtils::command( nsIArray* command, nsIArray** output)
++ {
++ nsTArray<nsCString> in;
++ PRUint32 length;
++ command->GetLength( &length );
++ for ( PRUint32 i = 0; i < length; i++ )
++ {
++ nsCOMPtr<nsISupportsCString> str = do_QueryElementAt( command, i );
++ if( str )
++ {
++ nsAutoCString s;
++ str->GetData( s );
++ in.AppendElement( s );
++ }
++ }
++
++ nsTArray<nsCString> out;
++ bool ret = self()->internalCommand( in, NULL, false, &out );
++
++ if ( !output ) return ret;
++
++ nsCOMPtr<nsIMutableArray> result = do_CreateInstance( NS_ARRAY_CONTRACTID );
++ if ( !result ) return false;
++
++ for ( PRUint32 i = 0; i < out.Length(); i++ )
++ {
++ nsCOMPtr<nsISupportsCString> rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
++ if ( !rstr ) return false;
++
++ rstr->SetData( out[i] );
++ result->AppendElement( rstr, false );
++ }
++
++ NS_ADDREF( *output = result);
++ return ret;
++ }
++
++
++bool nsKDEUtils::commandBlockUi( const nsTArray<nsCString>& command, const GtkWindow* parent, nsTArray<nsCString>* output )
++ {
++ return self()->internalCommand( command, parent, true, output );
++ }
++
++bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, const GtkWindow* parent, bool blockUi,
++ nsTArray<nsCString>* output )
++ {
++ if( !startHelper())
++ return false;
++ feedCommand( command );
++ // do not store the data in 'this' but in extra structure, just in case there
++ // is reentrancy (can there be? the event loop is re-entered)
++ nsKDECommandData data;
++ data.file = replyFile;
++ data.output = output;
++ data.success = false;
++ if( blockUi )
++ {
++ data.loop = g_main_loop_new( NULL, FALSE );
++ GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
++ if( parent && parent->group )
++ gtk_window_group_add_window( parent->group, GTK_WINDOW( window ));
++ gtk_widget_realize( window );
++ gtk_widget_set_sensitive( window, TRUE );
++ gtk_grab_add( window );
++ GIOChannel* channel = g_io_channel_unix_new( fileno( data.file ));
++ g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data );
++ g_io_channel_unref( channel );
++ g_main_loop_run( data.loop );
++ g_main_loop_unref( data.loop );
++ gtk_grab_remove( window );
++ gtk_widget_destroy( window );
++ }
++ else
++ {
++ data.loop = NULL;
++ while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data ))
++ ;
++ }
++ return data.success;
++ }
++
++bool nsKDEUtils::startHelper()
++ {
++ if( helperRunning )
++ return true;
++ if( helperFailed )
++ return false;
++ helperFailed = true;
++ int fdcommand[ 2 ];
++ int fdreply[ 2 ];
++ if( pipe( fdcommand ) < 0 )
++ return false;
++ if( pipe( fdreply ) < 0 )
++ {
++ close( fdcommand[ 0 ] );
++ close( fdcommand[ 1 ] );
++ return false;
++ }
++ char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL };
++ switch( fork())
++ {
++ case -1:
++ {
++ close( fdcommand[ 0 ] );
++ close( fdcommand[ 1 ] );
++ close( fdreply[ 0 ] );
++ close( fdreply[ 1 ] );
++ return false;
++ }
++ case 0: // child
++ {
++ if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 )
++ _exit( 1 );
++ if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 )
++ _exit( 1 );
++ int maxfd = 1024; // close all other fds
++ struct rlimit rl;
++ if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
++ maxfd = rl.rlim_max;
++ for( int i = 3;
++ i < maxfd;
++ ++i )
++ close( i );
++#ifdef DEBUG_KDE
++ execvp( KMOZILLAHELPER, args );
++#else
++ execv( KMOZILLAHELPER, args );
++#endif
++ _exit( 1 ); // failed
++ }
++ default: // parent
++ {
++ commandFile = fdopen( fdcommand[ 1 ], "w" );
++ replyFile = fdopen( fdreply[ 0 ], "r" );
++ close( fdcommand[ 0 ] );
++ close( fdreply[ 1 ] );
++ if( commandFile == NULL || replyFile == NULL )
++ {
++ closeHelper();
++ return false;
++ }
++ // ok, helper ready, getKdeRunning() will check if it works
++ }
++ }
++ helperFailed = false;
++ helperRunning = true;
++ return true;
++ }
++
++void nsKDEUtils::closeHelper()
++ {
++ if( commandFile != NULL )
++ fclose( commandFile ); // this will also make the helper quit
++ if( replyFile != NULL )
++ fclose( replyFile );
++ helperRunning = false;
++ }
++
++void nsKDEUtils::feedCommand( const nsTArray<nsCString>& command )
++ {
++ for( int i = 0;
++ i < command.Length();
++ ++i )
++ {
++ nsCString line = command[ i ];
++ line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape
++ line.ReplaceSubstring( "\n", "\\n" );
++#ifdef DEBUG_KDE
++ fprintf( stderr, "COMM: %s\n", line.get());
++#endif
++ fputs( line.get(), commandFile );
++ fputs( "\n", commandFile );
++ }
++ fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data
++ fflush( commandFile );
++ }
+diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h
+new file mode 100644
+--- /dev/null
++++ b/toolkit/xre/nsKDEUtils.h
+@@ -0,0 +1,48 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef nsKDEUtils_h__
++#define nsKDEUtils_h__
++
++#include "nsStringGlue.h"
++#include "nsTArray.h"
++#include <stdio.h>
++
++typedef struct _GtkWindow GtkWindow;
++
++class nsIArray;
++
++class NS_EXPORT nsKDEUtils
++ {
++ public:
++ /* Returns true if running inside a KDE session (regardless of whether there is KDE
++ support available for Abrowser). 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 Abrowser. This should be used everywhere where the external helper is needed. */
++ static bool kdeSupport();
++ /* Executes the given helper command, returns true if helper returned success. */
++ static bool command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output = NULL );
++ static bool command( nsIArray* command, nsIArray** output = NULL );
++ /* Like command(), but additionally blocks the parent widget like if there was
++ a modal dialog shown and enters the event loop (i.e. there are still paint updates,
++ this is for commands that take long). */
++ static bool commandBlockUi( const nsTArray<nsCString>& command, const GtkWindow* parent, nsTArray<nsCString>* output = NULL );
++
++ private:
++ nsKDEUtils();
++ ~nsKDEUtils();
++ static nsKDEUtils* self();
++ bool startHelper();
++ void closeHelper();
++ void feedCommand( const nsTArray<nsCString>& command );
++ bool internalCommand( const nsTArray<nsCString>& command, const GtkWindow* parent, bool isParent,
++ nsTArray<nsCString>* output );
++ FILE* commandFile;
++ FILE* replyFile;
++ };
++
++#endif // nsKDEUtils
+diff --git a/uriloader/exthandler/Makefile.in b/uriloader/exthandler/Makefile.in
+--- a/uriloader/exthandler/Makefile.in
++++ b/uriloader/exthandler/Makefile.in
+@@ -19,9 +19,10 @@ endif
+ ifdef MOZ_ENABLE_DBUS
+ LOCAL_INCLUDES += $(TK_CFLAGS) $(MOZ_DBUS_CFLAGS)
+ endif
+
+ include $(topsrcdir)/config/rules.mk
+
+ ifneq (,$(filter qt gtk2 gtk3, $(MOZ_WIDGET_TOOLKIT)))
+ CXXFLAGS += $(TK_CFLAGS) $(MOZ_DBUS_GLIB_CFLAGS)
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
+ endif
+diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
+--- a/uriloader/exthandler/moz.build
++++ b/uriloader/exthandler/moz.build
+@@ -81,17 +81,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
+ else:
+ # These files can't be built in unified mode because they force NSPR logging.
+ 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',
+diff --git a/uriloader/exthandler/unix/nsCommonRegistry.cpp b/uriloader/exthandler/unix/nsCommonRegistry.cpp
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsCommonRegistry.cpp
+@@ -0,0 +1,54 @@
++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsCommonRegistry.h"
++
++#include "nsGNOMERegistry.h"
++#include "nsKDERegistry.h"
++#include "nsString.h"
++#include "nsVoidArray.h"
++#include "nsKDEUtils.h"
++
++/* static */ bool
++nsCommonRegistry::HandlerExists(const char *aProtocolScheme)
++{
++ if( nsKDEUtils::kdeSupport())
++ return nsKDERegistry::HandlerExists( aProtocolScheme );
++ return nsGNOMERegistry::HandlerExists( aProtocolScheme );
++}
++
++/* static */ nsresult
++nsCommonRegistry::LoadURL(nsIURI *aURL)
++{
++ if( nsKDEUtils::kdeSupport())
++ return nsKDERegistry::LoadURL( aURL );
++ return nsGNOMERegistry::LoadURL( aURL );
++}
++
++/* static */ void
++nsCommonRegistry::GetAppDescForScheme(const nsACString& aScheme,
++ nsAString& aDesc)
++{
++ if( nsKDEUtils::kdeSupport())
++ return nsKDERegistry::GetAppDescForScheme( aScheme, aDesc );
++ return nsGNOMERegistry::GetAppDescForScheme( aScheme, aDesc );
++}
++
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsCommonRegistry::GetFromExtension(const nsACString& aFileExt)
++{
++ if( nsKDEUtils::kdeSupport())
++ return nsKDERegistry::GetFromExtension( aFileExt );
++ return nsGNOMERegistry::GetFromExtension( aFileExt );
++}
++
++/* static */ already_AddRefed<nsMIMEInfoBase>
++nsCommonRegistry::GetFromType(const nsACString& aMIMEType)
++{
++ if( nsKDEUtils::kdeSupport())
++ return nsKDERegistry::GetFromType( aMIMEType );
++ return nsGNOMERegistry::GetFromType( aMIMEType );
++}
+diff --git a/uriloader/exthandler/unix/nsCommonRegistry.h b/uriloader/exthandler/unix/nsCommonRegistry.h
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsCommonRegistry.h
+@@ -0,0 +1,23 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsIURI.h"
++#include "nsCOMPtr.h"
++
++class nsMIMEInfoBase;
++
++class nsCommonRegistry
++{
++ public:
++ static bool HandlerExists(const char *aProtocolScheme);
++
++ static nsresult LoadURL(nsIURI *aURL);
++
++ static void GetAppDescForScheme(const nsACString& aScheme,
++ nsAString& aDesc);
++
++ static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
++
++ static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
++};
+diff --git a/uriloader/exthandler/unix/nsKDERegistry.cpp b/uriloader/exthandler/unix/nsKDERegistry.cpp
+new file mode 100644
+--- /dev/null
++++ b/uriloader/exthandler/unix/nsKDERegistry.cpp
+@@ -0,0 +1,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 ];
++ nsRefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix( mimetype );
++ NS_ENSURE_TRUE(mimeInfo, nullptr);
++ nsCString description = output[ 1 ];
++ mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
++ nsCString handlerAppName = output[ 2 ];
++ mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(handlerAppName));
++ mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
++ 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,29 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "nsIURI.h"
++#include "nsCOMPtr.h"
++#include "nsTArray.h"
++
++class nsMIMEInfoBase;
++class nsAutoCString;
++class nsCString;
++
++class nsKDERegistry
++{
++ public:
++ static bool HandlerExists(const char *aProtocolScheme);
++
++ static nsresult LoadURL(nsIURI *aURL);
++
++ static void GetAppDescForScheme(const nsACString& aScheme,
++ nsAString& aDesc);
++
++ static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
++
++ static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
++ private:
++ static already_AddRefed<nsMIMEInfoBase> GetFromHelper(const nsTArray<nsCString>& command);
++
++};
+diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
+--- a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
++++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
+@@ -10,30 +10,33 @@
+ #include <QString>
+ #if (MOZ_ENABLE_CONTENTACTION)
+ #include <contentaction/contentaction.h>
+ #include "nsContentHandlerApp.h"
+ #endif
+ #endif
+
+ #include "nsMIMEInfoUnix.h"
+-#include "nsGNOMERegistry.h"
++#include "nsCommonRegistry.h"
+ #include "nsIGIOService.h"
+ #include "nsNetCID.h"
+ #include "nsIIOService.h"
+ #include "nsIGnomeVFSService.h"
+ #include "nsAutoPtr.h"
+ #ifdef MOZ_ENABLE_DBUS
+ #include "nsDBusHandlerApp.h"
+ #endif
++#if defined(XP_UNIX) && !defined(XP_MACOSX)
++#include "nsKDEUtils.h"
++#endif
+
+ nsresult
+ nsMIMEInfoUnix::LoadUriInternal(nsIURI * aURI)
+ {
+- nsresult rv = nsGNOMERegistry::LoadURL(aURI);
++ nsresult rv = nsCommonRegistry::LoadURL(aURI);
+
+ #ifdef MOZ_WIDGET_QT
+ if (NS_FAILED(rv)) {
+ nsAutoCString spec;
+ aURI->GetAsciiSpec(spec);
+ if (QDesktopServices::openUrl(QUrl(spec.get()))) {
+ rv = NS_OK;
+ }
+@@ -48,22 +51,22 @@ nsMIMEInfoUnix::GetHasDefaultHandler(boo
+ {
+ // if mDefaultApplication is set, it means the application has been set from
+ // 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;
+- nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mSchemeOrType);
++ nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromType(mSchemeOrType);
+ if (!mimeInfo) {
+ nsAutoCString ext;
+ nsresult rv = GetPrimaryExtension(ext);
+ if (NS_SUCCEEDED(rv)) {
+- mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
++ mimeInfo = nsCommonRegistry::GetFromExtension(ext);
+ }
+ }
+ if (mimeInfo)
+ *_retval = true;
+
+ if (*_retval)
+ return NS_OK;
+
+@@ -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);
+ nsAutoCString uriSpec;
+ if (giovfs) {
+ // nsGIOMimeApp->Launch wants a URI string instead of local file
+ nsresult rv;
+ nsCOMPtr<nsIIOService> ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIURI> uri;
+@@ -124,17 +144,17 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(ns
+ /* Fallback to GnomeVFS */
+ nsCOMPtr<nsIGnomeVFSMimeApp> app;
+ if (NS_SUCCEEDED(gnomevfs->GetAppForMimeType(mSchemeOrType, getter_AddRefs(app))) && app)
+ return app->Launch(nativePath);
+ }
+
+ // If we haven't got an app we try to get a valid one by searching for the
+ // extension mapped type
+- nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromExtension(nativePath);
++ nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromExtension(nativePath);
+ if (mimeInfo) {
+ nsAutoCString type;
+ mimeInfo->GetType(type);
+ if (giovfs) {
+ nsCOMPtr<nsIGIOMimeApp> app;
+ if (NS_SUCCEEDED(giovfs->GetAppForMimeType(type, getter_AddRefs(app))) && app)
+ return app->Launch(uriSpec);
+ } else if (gnomevfs) {
+diff --git a/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
+--- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp
++++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
+@@ -10,17 +10,17 @@
+ #if defined(MOZ_ENABLE_CONTENTACTION)
+ #include <contentaction/contentaction.h>
+ #include <QString>
+ #endif
+
+ #include "nsOSHelperAppService.h"
+ #include "nsMIMEInfoUnix.h"
+ #ifdef MOZ_WIDGET_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"
+@@ -1157,26 +1157,26 @@ nsresult nsOSHelperAppService::OSProtoco
+ ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':');
+
+ if (action.isValid())
+ *aHandlerExists = true;
+ #endif
+
+ #ifdef MOZ_WIDGET_GTK
+ // Check the GConf 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 PRUnichar * platformAppPath, nsIFile ** aFile)
+ {
+@@ -1263,17 +1263,17 @@ nsOSHelperAppService::GetFromExtension(c
+ mime_types_description,
+ true);
+
+ if (NS_FAILED(rv) || majorType.IsEmpty()) {
+
+ #ifdef MOZ_WIDGET_GTK
+ LOG(("Looking in GNOME registry\n"));
+ nsRefPtr<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,
+@@ -1386,17 +1386,17 @@ nsOSHelperAppService::GetFromType(const
+ #ifdef MOZ_WIDGET_GTK
+ nsRefPtr<nsMIMEInfoBase> gnomeInfo;
+ if (handler.IsEmpty()) {
+ // No useful data yet. Check the GNOME registry. Unfortunately, newer
+ // GNOME versions no longer have type-to-extension mappings, so we might
+ // get back a MIMEInfo without any extensions set. In that case we'll have
+ // to look in our mime.types files for the extensions.
+ LOG(("Looking in GNOME registry\n"));
+- gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
++ gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType);
+ if (gnomeInfo && gnomeInfo->HasExtensions()) {
+ LOG(("Got MIMEInfo from GNOME registry, and it has extensions set\n"));
+ return gnomeInfo.forget();
+ }
+ }
+ #endif
+
+ // Now look up our extensions
+diff --git a/widget/gtk/Makefile.in b/widget/gtk/Makefile.in
+--- a/widget/gtk/Makefile.in
++++ b/widget/gtk/Makefile.in
+@@ -4,11 +4,13 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ include $(topsrcdir)/config/rules.mk
+
+ CFLAGS += $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
+ CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) \
+ $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
+
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
++
+ CFLAGS += $(TK_CFLAGS)
+ CXXFLAGS += $(TK_CFLAGS)
+
+diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp
+--- a/widget/gtk/nsFilePicker.cpp
++++ b/widget/gtk/nsFilePicker.cpp
+@@ -1,32 +1,34 @@
+ /* -*- 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/Types.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
+
+ nsIFile *nsFilePicker::mPrevDisplayDirectory = nullptr;
+
+ void
+@@ -226,17 +228,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);
+@@ -350,16 +354,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)
+@@ -538,8 +558,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
+@@ -66,11 +66,17 @@ protected:
+ nsString mDefault;
+ nsString mDefaultExtension;
+
+ nsTArray<nsCString> mFilters;
+ nsTArray<nsCString> mFilterNames;
+
+ private:
+ static nsIFile *mPrevDisplayDirectory;
++
++ bool kdeRunning();
++ bool getKdeRunning();
++ NS_IMETHODIMP kdeFileDialog(PRInt16 *aReturn);
++ NS_IMETHODIMP kdeAppsDialog(PRInt16 *aReturn);
++ nsCString kdeMakeFilter( int index );
+ };
+
+ #endif
+diff --git a/xpcom/components/Makefile.in b/xpcom/components/Makefile.in
+--- a/xpcom/components/Makefile.in
++++ b/xpcom/components/Makefile.in
+@@ -14,9 +14,10 @@ LOCAL_INCLUDES = \
+ -I$(topsrcdir)/chrome/src \
+ -I$(topsrcdir)/modules/libjar \
+ $(NULL)
+
+ include $(topsrcdir)/config/rules.mk
+
+ ifdef MOZ_WIDGET_GTK
+ CXXFLAGS += $(TK_CFLAGS)
++LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
+ endif
+diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
+--- a/xpcom/components/ManifestParser.cpp
++++ b/xpcom/components/ManifestParser.cpp
+@@ -30,16 +30,17 @@
+ #include "nsTextFormatter.h"
+ #include "nsVersionComparator.h"
+ #include "nsXPCOMCIDInternal.h"
+
+ #include "nsIConsoleService.h"
+ #include "nsIScriptError.h"
+ #include "nsIXULAppInfo.h"
+ #include "nsIXULRuntime.h"
++#include "nsKDEUtils.h"
+
+ using namespace mozilla;
+
+ struct ManifestDirective
+ {
+ const char* directive;
+ int argc;
+
+@@ -397,16 +398,17 @@ ParseManifest(NSLocationType type, FileL
+ NS_NAMED_LITERAL_STRING(kPlatform, "platform");
+ NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
+ NS_NAMED_LITERAL_STRING(kApplication, "application");
+ NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
+ NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
+ NS_NAMED_LITERAL_STRING(kOs, "os");
+ NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
+ NS_NAMED_LITERAL_STRING(kABI, "abi");
++ NS_NAMED_LITERAL_STRING(kDesktop, "desktop");
+ #if defined(MOZ_WIDGET_ANDROID)
+ NS_NAMED_LITERAL_STRING(kTablet, "tablet");
+ #endif
+
+ // Obsolete
+ NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
+
+ nsAutoString appID;
+@@ -444,41 +446,46 @@ ParseManifest(NSLocationType type, FileL
+ CopyUTF8toUTF16(s, abi);
+ abi.Insert(PRUnichar('_'), 0);
+ abi.Insert(osTarget, 0);
+ }
+ }
+ }
+
+ nsAutoString osVersion;
++ nsAutoString desktop;
+ #if defined(XP_WIN)
+ OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
+ if (GetVersionEx(&info)) {
+ nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+ info.dwMajorVersion,
+ info.dwMinorVersion);
+ }
++ desktop = NS_LITERAL_STRING("win");
+ #elif defined(MOZ_WIDGET_COCOA)
+ SInt32 majorVersion, minorVersion;
+ if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
+ (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
+ nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+ majorVersion,
+ minorVersion);
+ }
++ desktop = NS_LITERAL_STRING("macosx");
+ #elif defined(MOZ_WIDGET_GTK)
+ nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+ gtk_major_version,
+ gtk_minor_version);
++ desktop = nsKDEUtils::kdeSession() ? NS_LITERAL_STRING("kde") : NS_LITERAL_STRING("gnome");
+ #elif defined(MOZ_WIDGET_ANDROID)
+ bool isTablet = false;
+ if (mozilla::AndroidBridge::Bridge()) {
+ mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", osVersion);
+ isTablet = mozilla::widget::android::GeckoAppShell::IsTablet();
+ }
++ desktop = NS_LITERAL_STRING("android");
+ #endif
+
+ // Because contracts must be registered after CIDs, we save and process them
+ // at the end.
+ nsTArray<CachedDirective> contracts;
+
+ char *token;
+ char *newline = buf;
+@@ -560,24 +567,26 @@ ParseManifest(NSLocationType type, FileL
+ TriState stOsVersion = eUnspecified;
+ TriState stOs = eUnspecified;
+ TriState stABI = eUnspecified;
+ #if defined(MOZ_WIDGET_ANDROID)
+ TriState stTablet = eUnspecified;
+ #endif
+ bool platform = false;
+ bool contentAccessible = false;
++ TriState stDesktop = eUnspecified;
+
+ while (nullptr != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) {
+ ToLowerCase(token);
+ NS_ConvertASCIItoUTF16 wtoken(token);
+
+ if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+ CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+ CheckStringFlag(kABI, wtoken, abi, stABI) ||
++ CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
+ CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
+ CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
+ CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion))
+ continue;
+
+ #if defined(MOZ_WIDGET_ANDROID)
+ bool tablet = false;
+ if (CheckFlag(kTablet, wtoken, tablet)) {
+@@ -606,16 +615,17 @@ ParseManifest(NSLocationType type, FileL
+ }
+
+ if (!ok ||
+ stApp == eBad ||
+ stAppVersion == eBad ||
+ stGeckoVersion == eBad ||
+ stOs == eBad ||
+ stOsVersion == eBad ||
++ stDesktop == eBad ||
+ #ifdef MOZ_WIDGET_ANDROID
+ stTablet == eBad ||
+ #endif
+ stABI == eBad)
+ continue;
+
+ if (directive->regfunc) {
+ if (GeckoProcessType_Default != XRE_GetProcessType())
+diff --git a/xpcom/io/Makefile.in b/xpcom/io/Makefile.in
+--- a/xpcom/io/Makefile.in
++++ b/xpcom/io/Makefile.in
+@@ -1,8 +1,8 @@
+ # 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/.
+
+ MOZILLA_INTERNAL_API = 1
+ include $(topsrcdir)/config/rules.mk
+
+-LOCAL_INCLUDES += -I..
++LOCAL_INCLUDES += -I.. -I$(topsrcdir)/toolkit/xre
+diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
+--- a/xpcom/io/nsLocalFileUnix.cpp
++++ b/xpcom/io/nsLocalFileUnix.cpp
+@@ -43,16 +43,17 @@
+ #include "nsIDirectoryEnumerator.h"
+ #include "nsISimpleEnumerator.h"
+ #include "private/pprio.h"
+ #include "prlink.h"
+
+ #ifdef MOZ_WIDGET_GTK
+ #include "nsIGIOService.h"
+ #include "nsIGnomeVFSService.h"
++#include "nsKDEUtils.h"
+ #endif
+
+ #ifdef MOZ_WIDGET_COCOA
+ #include <Carbon/Carbon.h>
+ #include "CocoaFileUtils.h"
+ #include "prmem.h"
+ #include "plbase64.h"
+
+@@ -1811,46 +1812,52 @@ nsLocalFile::SetPersistentDescriptor(con
+ return InitWithNativePath(aPersistentDescriptor);
+ #endif
+ }
+
+ NS_IMETHODIMP
+ nsLocalFile::Reveal()
+ {
+ #ifdef MOZ_WIDGET_GTK
+- nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+- nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
+- if (!giovfs && !gnomevfs)
+- return NS_ERROR_FAILURE;
+-
++ nsAutoCString url;
+ bool isDirectory;
+ if (NS_FAILED(IsDirectory(&isDirectory)))
+ return NS_ERROR_FAILURE;
+
++ nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+ if (isDirectory) {
+- if (giovfs)
+- return giovfs->ShowURIForInput(mPath);
+- else
+- /* Fallback to GnomeVFS */
+- return gnomevfs->ShowURIForInput(mPath);
++ url = mPath;
+ } else if (giovfs && 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;
+
+- if (giovfs)
+- return giovfs->ShowURIForInput(dirPath);
+- else
+- return gnomevfs->ShowURIForInput(dirPath);
++ url = dirPath;
+ }
++
++ if(nsKDEUtils::kdeSupport()) {
++ nsTArray<nsCString> command;
++ command.AppendElement( NS_LITERAL_CSTRING("REVEAL") );
++ command.AppendElement( mPath );
++ return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++ }
++
++ nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
++ if (!giovfs && !gnomevfs)
++ return NS_ERROR_FAILURE;
++
++ if (giovfs)
++ return giovfs->ShowURIForInput(url);
++ else
++ return gnomevfs->ShowURIForInput(url);
+ #elif defined(MOZ_WIDGET_COCOA)
+ CFURLRef url;
+ if (NS_SUCCEEDED(GetCFURL(&url))) {
+ nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
+ ::CFRelease(url);
+ return rv;
+ }
+ return NS_ERROR_FAILURE;
+@@ -1858,16 +1865,23 @@ 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);
+ nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
+ if (giovfs) {
+ return giovfs->ShowURIForInput(mPath);
+ } else if (gnomevfs) {
+ /* GnomeVFS fallback */
+ return gnomevfs->ShowURIForInput(mPath);
+ }
diff --git a/helpers/make-firefox b/helpers/make-firefox
index 5dab04b..ccb7151 100644
--- a/helpers/make-firefox
+++ b/helpers/make-firefox
@@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-VERSION=12
+VERSION=13
. ./config
@@ -30,6 +30,18 @@ cat $DATA/settings.js >> debian/vendor-firefox.js
#sed 's/Depends: lsb-release,/Depends: lsb-release, xul-ext-ubufox,/' -i debian/control.in
#sed 's/iceweasel,/iceweasel, firefox, icecat,/' -i debian/control.in
+# KDE support
+cp $DATA/mozilla-kde.patch debian/patches/mozilla-kde.patch
+cp $DATA/abrowser-kde.patch debian/patches/abrowser-kde.patch
+cat << EOF >> debian/patches/series
+mozilla-kde.patch
+abrowser-kde.patch
+EOF
+cat << EOF >> debian/kde.js
+pref("browser.preferences.instantApply", false);
+EOF
+LINENUM=$(grep -n '# Prefs' abrowser.install.in | cut -d: -f1)
+sed -i ${LINENUM}'a debian/kde.js @MOZ_LIBDIR@/defaults/pref' abrowser.install.in
sed '/mozilla.org\/legal/d' -i services/healthreport/healthreport-prefs.js
cat << EOF >>services/healthreport/healthreport-prefs.js
--
1.7.9.5
More information about the Trisquel-devel
mailing list