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