$ git diff --patch-with-stat --summary 24d4528eab4ae69a85ccfa5ba260eb424e08b678..0681306249af77a63ca4eec1bd91e71293ca7700
.abf.yml | 142 ++--
firefox-78.0-kde.patch | 282 +++++++
firefox.spec | 15 +-
mozilla-78.0-kde.patch | 1941 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 2300 insertions(+), 80 deletions(-)
create mode 100644 firefox-78.0-kde.patch
create mode 100644 mozilla-78.0-kde.patch
diff --git a/.abf.yml b/.abf.yml
index bc0840e..d4a8960 100644
--- a/.abf.yml
+++ b/.abf.yml
@@ -1,75 +1,75 @@
sources:
- af.xpi: dd78f710a1afa05f6f79b65ef108ff4bad722a37
- ar.xpi: adfbaee5e842e0cefe5de89bb2160a6b60adddfd
- ast.xpi: 0a46aaedf8430deb91dcbad75ae567a7e7a20040
+ af.xpi: 0642084af964082c208b1ccecf887e178b28df8b
+ ar.xpi: 7aaeb9adeb185d12b07e1aa60ca06b2f85d35b5a
+ ast.xpi: 828f2eab993b43c0f602367c9ff7f75685e50338
autoconf-2.13.tar.gz: e4826c8bd85325067818f19b2b2ad2b625da66fc
be.xpi: 12e55652aa01c3531dbeb1ac59b97eb649f937db
- bg.xpi: 42242785f77867a1cbb92ffb62b84d15d36fce46
- bn.xpi: 030f15a15eabcb7d65392b8c1709d475b36a5b5e
- br.xpi: 73730828743c7f0e8445ea2b76791397e2480afe
- bs.xpi: ca42373dc546205541886baa7fbe77394170cb3d
- ca.xpi: 5d3d0d0fb8bde77faa40579dd20b98c89de02c76
- cbindgen-vendor.tar.xz: 58b84451be4fbaa3b1bd5a6ed14a127be0096eb7
- cs.xpi: 1c57f949997999df4d74fc546cf9853ec50e8080
- cy.xpi: 02e75d140f45103ceddeacb5c10f3dad41203426
- da.xpi: 1850edc6edaf9443ecbd43631a12f4c6aec71e25
- de.xpi: 19ba34613d89ff6fea87d845457b341c3878638b
- el.xpi: 9d149f5bbfb20682525a67bf4a1f1ba4da074308
- en-GB.xpi: f1f9bc2d107ad1f9b6e414e94e18482afc855bf9
- eo.xpi: b793e723a496e1539004618d21b78a9f4f670f51
- es-AR.xpi: 1b64ffe9f8bc1cc2b8aa5297c4f9a5318b08a365
- es-CL.xpi: e7f2d22d312a0becfd49ebe32fa07cbf780d259b
- es-ES.xpi: e55e2ddd86a8d79ba97bdd3fa0e5bb9518920c95
- es-MX.xpi: 8762a9be0182a904a3d79f54ac2b634beb6470f4
- et.xpi: 208b6211e81b1e296f8b19de859b385b810fbb14
- eu.xpi: fbd2289b25bb9b8e0d9f65a23e3487b63bbd15ea
- fa.xpi: ee167b02d818905455fbfe97cfe579e3a94115d3
- fi.xpi: 4c54b0f3ddc76023f37976fa2e558ef8aeaee98b
- firefox-75.0.source.tar.xz: df7904c16d525eb791728d655258b7d1fe064db9
+ bg.xpi: 96195abf0309ab5b00bcf1088ce36a5c117422e1
+ bn.xpi: db93555ea52ab0f4bb6f9d1337e1013d35f9f3f4
+ br.xpi: 7123b5a9d56f133aed3a000e6f883b59d307ebb2
+ bs.xpi: d8b87325e230f9aa1ef5124ea77e02cd81844f86
+ ca.xpi: fdad0689c36acb5940d52e66c0a2de2f3653b8a5
+ cbindgen-vendor.tar.xz: 04a46d43f7f05e426bf2bd9f36592437353a3efc
+ cs.xpi: b80b1abef319651a0d5aca17d76aedbd99c5a69b
+ cy.xpi: 14a62092c45bd40b825a7b429a12085c90634295
+ da.xpi: c829bf1742b67be170476224ea78c6cb71eb35cf
+ de.xpi: 93fd3e1cbbedf8050e90d341c69ca53f2c15bd76
+ el.xpi: 7db2c4aa44cecec3946d762dada1de7000239702
+ en-GB.xpi: 9504d69a9fcf19585ecbf0f0c2e14a8ca1825167
+ eo.xpi: 56636402da3cb4d36f8a1aacf219493f30cd7a07
+ es-AR.xpi: 6e7bfd6c346a7a40e00a2ab9f5e7a452698437aa
+ es-CL.xpi: 69a7c94fe3f9e7768fdbe7bc512f56259dcd1b9e
+ es-ES.xpi: 18f54d16a019ab34c9dd69dfed7b9e6d01b5d7bc
+ es-MX.xpi: 1c60989fbf1350eb769c9c3b7dcf29e6d5ddf3b9
+ et.xpi: fcaf8f978085194f31e53e6fad62d9649de7ba72
+ eu.xpi: ce9475989457ff7261630b0981e0fab443e17413
+ fa.xpi: ff9a631d5b4dd4e2acf26877da44059d12a010e2
+ fi.xpi: c7fd00920eb7c658f85a1e3dfd10e407e23df1d4
+ firefox-78.0.1.source.tar.xz: 3de95657c9d26bacd9a36e62f756d090d09db63b
firefox-omv-default-prefs.js: 7010f8f73032df2e7799843863b97c6a3ba36378
- fr.xpi: 6b5dc528ed4a56dea484eff525aa7d6bb7f2114d
- fy-NL.xpi: cbbbf6cb69db8bbca226ea853d6470bf41bb4e13
- ga-IE.xpi: 38a1ffed9057719e39844f61ad74fc2d0fbb7555
- gd.xpi: 31a0a85dbff3fd7d81d0d02b5a558835f2816ffe
- gl.xpi: b6ce86c8a096b1ae50a2ac74def4966c00b2dcf3
- gu-IN.xpi: 3ec2ac36248965324c68990c557b3d59fe6165c4
- he.xpi: 8087d583692231d1302eca6348f76d290ed5918a
- hi-IN.xpi: 0647675b8d643c9a57b8062d3b69a651b3fd96ba
- hr.xpi: beffad499504babb52e3266a3d67c5f972b21754
- hu.xpi: 7415938577d63c7b38b0bf13435454c11f5f60d8
- hy-AM.xpi: 7e0041044072f30d508ac7ed095b5ad8aba743a6
- id.xpi: d8872d0efe7ad15dc1d316d43fbf287d07d25218
- is.xpi: aeeec37927843d6fe75b43a817adb2ad87a90b6d
- it.xpi: 586c7e2f899ca0601f1dd1bcc0911423ba7410ee
- ja.xpi: 2dfdd426492a95215580b0730a2bc82210976539
- kk.xpi: 2c7f22000ea42265a7433ca24e32f318b7b72fa5
- km.xpi: cd9216a6ac6f2e2f27985609bc9f3ecb9966cdfe
- kn.xpi: 0194bf05396c8037ccea84f5a88bd39cd38aa0d8
- ko.xpi: 5a6d7672509e3a3486d90a79777e077ee3cd5e5b
- lt.xpi: 3d70de04785305bb015e9238045d07a9df0e9139
- lv.xpi: 047abcf7777404cd6578e968675d59481e83c2e3
- mk.xpi: 4569197cf5a1e96bdd4c99bd58c57e11f2176756
- mr.xpi: 24dac739b84bc17317cf70b6d4aa3f555936390d
- nb-NO.xpi: 2ea22d48972518f510778b55f3b13557ffd7700e
- nl.xpi: 33210cbae5864d90b88c33b826c8234f670b74c6
- nn-NO.xpi: 5b7311b2d2593df76e448457e1165eae22026e11
- pa-IN.xpi: 38dc6e4185a333f59f813c3ab9a110b7cfe62184
- pl.xpi: 249a278c0eb9f4c1a2c2ccdba1855e6b98b7483b
- pt-BR.xpi: df928f89e747fc0903e25a227ce4ddfac0d2034e
- pt-PT.xpi: 821fffce6b5a87bf8d556ca5bea7992964e0ccb3
- ro.xpi: 86bd7197405065e1d3a95236a819b2cfa9f5d909
- ru.xpi: 8690dd9fcae40e85318c6d06b59b52e1b17f4ec1
- si.xpi: c4c4d8387a32febf378d32c2d3f3243d029289dd
- sk.xpi: c6ecc80c7eccfe770eccab4ce0f2566b9eb4b765
- sl.xpi: 27f62acf184cb0e452a5097fb2304740463109c8
- sq.xpi: 9c68cdbf0821d5962231281eec4d695aeb034aa5
- sr.xpi: a274cf71197495d6a1d28d1c0d444f7f7958537a
- sv-SE.xpi: 24e9934afeac95f0bc460cce32196ad4cc350f70
- ta.xpi: 341c3aa1b78994250abd758d222233192c81de9d
- te.xpi: fedbe109a9af4956e0be433102f1342a76d4414f
- th.xpi: 4542eb9c056e0ea7095b3fb6f0e82a18b20bc927
- tr.xpi: baf35ba20e4471de4536950e87b7afa93ac2fb3f
- uk.xpi: e85348e74b693937d68862a63364e7ef5f705a93
- vi.xpi: 37cce01e54c53fabd5f54e49eb33a6a03c1f28f9
- zh-CN.xpi: 2286194e00b578086ec084d00f41f6ee568391c3
- zh-TW.xpi: 56d891fa7adc8c8577d320b9d2bdf07281287cd9
+ fr.xpi: f7cbbe3aadbded4578c20e469c619b8e0ae33dca
+ fy-NL.xpi: a30c8de02a4ea38949624ce01543ff63f15e7686
+ ga-IE.xpi: 819614ce45bbdd822c2400dca8187a717690446d
+ gd.xpi: 143410a717cf09ed3caf2271f3656ae6f1562eb4
+ gl.xpi: 5fc34aee753cbdf264602c36652a8c48e46aa049
+ gu-IN.xpi: 1bfefa9de7413410b6d5a00740eaadbb70e14bc6
+ he.xpi: 9bb1bc76ca36fa3d9233d880037732ddcfdda7d6
+ hi-IN.xpi: bf5040a55992f1d2ceff35e4de5313c9b77ba362
+ hr.xpi: bc31884c038e5ed86c8ffcd229b45c6e027faf42
+ hu.xpi: c9aa2604911c8007e66a091aac7327afa8d35403
+ hy-AM.xpi: fc4825063898e026206d1240ba0e14e3a2edd87b
+ id.xpi: 26830dc97fa93226b3f04dc2a86ad0dcb7156887
+ is.xpi: c032a6c838132739d47c43139a94ceceba3c3e8a
+ it.xpi: 7cbbbf34b985bbf610d79a53d93490f3d0206c9e
+ ja.xpi: 73908f5b9f1f2b8f46f8d1609cc120c96fbf56f4
+ kk.xpi: e63074e827c295b37e17fdb632af9a46ee94c153
+ km.xpi: 6467a40617a687e0aded4cffe76745f97cfd8d59
+ kn.xpi: 029489f97a4c801fcafd8258fce2210bddf004de
+ ko.xpi: 70cb6698f68beab3858de969fe35cb1ec44e6b6f
+ lt.xpi: b0e62367f6c658702bba250e4037c3023b799119
+ lv.xpi: b0b8458f8fe4b1d2f8371ac0c83352172bebd13f
+ mk.xpi: d06badf5bd05a2f15608ebbf6152dbb87fced9e4
+ mr.xpi: 3975167f3bc1141cacc7565813d0e1f862564311
+ nb-NO.xpi: 6aae5af8f7184c4682c3066a05e927ec3b1095ad
+ nl.xpi: 810c3376bd673da5f300a844d5416020cb5d1719
+ nn-NO.xpi: 794be4b6e51d019a6522d37c9089f02ad00fe081
+ pa-IN.xpi: 042a1e134084bce13e70b9218bc3f3b9552cbb05
+ pl.xpi: 3e5f863f9acfef14d4aadb4536bd31deaa2f9d67
+ pt-BR.xpi: c0b497d78646016546bbdfdcc4153d5a11dba66c
+ pt-PT.xpi: b29c7e19307f42208d0272ab62037bea5f9885fb
+ ro.xpi: ed2ccae7cd86723de29e13d65106e6e6d921d798
+ ru.xpi: 722c897c90ae0e7c68b30e6cc8b23549438231d1
+ si.xpi: d1bca1c62e9dfb92300a183708f6b158d89cacc8
+ sk.xpi: bc4f5bcecd1f9f5b57f75b97ab6e760236e5d351
+ sl.xpi: 6ba53fca405315a36196aeb24472821b09508f9d
+ sq.xpi: de163da759a68e3caba15b42007614846fd8fb85
+ sr.xpi: 04f196523a001bcd6f5d387abbad41b27a8bebcc
+ sv-SE.xpi: ba84feb496a7b024fd1bc56ad2d9a38e46f86805
+ ta.xpi: 05d62de79cc8153c24e818d93a230e35477f6e7e
+ te.xpi: 3fffc8a34172677b1dbc0491c49426a46828df08
+ th.xpi: 1fcd54f2a24ecb980cd79cfd78af9db3b42715e0
+ tr.xpi: 5a6678a58d82f99ff2f9483ce881e983b2d2bf6e
+ uk.xpi: 12e1691cbcc82e6e96a98697bc9c254da7580ef4
+ vi.xpi: b20d52e1a3afb93641696b2945a34c443b2d59d4
+ zh-CN.xpi: 8aa9cb260f8ec0d742e31dfb91ea6725eed008f5
+ zh-TW.xpi: 6457ae20bbebc0547fff90edae496f6b42ea2035
diff --git a/firefox-78.0-kde.patch b/firefox-78.0-kde.patch
new file mode 100644
index 0000000..40d6aae
--- /dev/null
+++ b/firefox-78.0-kde.patch
@@ -0,0 +1,282 @@
+# HG changeset patch
+# User msirringhaus@suse.de
+# Date 1559300151 -7200
+# Fri May 31 12:55:51 2019 +0200
+# Node ID 54d41b0033b8d649d842a1f862c6fed8b9874dec
+# Parent 0fd58e0df883086574263e0881e1503cf110562a
+How to apply this patch:
+1. Import and apply it
+2. cp browser/base/content/browser.xul browser/base/content/browser-kde.xul
+3. Find editBookmarkPanelDoneButton
+4. Replace #ifndef with #ifdef in the line above (this hanges the button order from Gnome-style to KDE-style)
+5. hg qrefresh
+
+diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
+--- a/browser/components/preferences/main.js
++++ b/browser/components/preferences/main.js
+@@ -336,16 +336,23 @@ var gMainPane = {
+ }, backoffTimes[this._backoffIndex + 1 < backoffTimes.length ? this._backoffIndex++ : backoffTimes.length - 1]);
+ };
+
+ window.setTimeout(() => {
+ window.requestIdleCallback(pollForDefaultBrowser);
+ }, backoffTimes[this._backoffIndex]);
+ }
+
++ 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;
++ }
++
+ this.initBrowserContainers();
+ this.buildContentProcessCountMenuList();
+
+ let performanceSettingsLink = document.getElementById(
+ "performanceSettingsLearnMore"
+ );
+ let performanceSettingsUrl =
+ Services.urlFormatter.formatURLPref("app.support.baseURL") +
+@@ -1301,16 +1308,27 @@ var gMainPane = {
+ this._backoffIndex = 0;
+
+ 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
+@@ -34,16 +34,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
+ ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk':
+ XPIDL_SOURCES += [
+ 'nsIGNOMEShellService.idl',
+ ]
+
+ SOURCES += [
+ 'nsGNOMEShellService.cpp',
++ 'nsKDEShellService.cpp',
++ 'nsUnixShellService.cpp',
+ ]
+ if CONFIG['MOZ_ENABLE_DBUS']:
+ SOURCES += [
+ 'nsGNOMEShellDBusHelper.cpp',
+ 'nsGNOMEShellSearchProvider.cpp',
+ ]
+ include('/ipc/chromium/chromium-config.mozbuild')
+
+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,103 @@
++/* -*- 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, nsIGNOMEShellService, nsIShellService)
++
++NS_IMETHODIMP
++nsKDEShellService::IsDefaultBrowser(bool aForAllTypes,
++ bool* aIsDefaultBrowser)
++{
++ *aIsDefaultBrowser = false;
++
++ 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 );
++
++ 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 );
++
++ paramstr->SetData( aClaimAllTypes ? NS_LITERAL_CSTRING( "ALLTYPES" ) : NS_LITERAL_CSTRING( "NORMAL" ));
++ command->AppendElement( paramstr );
++
++ return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::GetCanSetDesktopBackground(bool* aResult)
++{
++ *aResult = true;
++ return NS_OK;
++}
++
++NS_IMETHODIMP
++nsKDEShellService::SetDesktopBackground(dom::Element* aElement,
++ int32_t aPosition,
++ const nsACString& aImageName)
++{
++ 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;
++}
++
+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,32 @@
++/* -*- 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 "nsIGNOMEShellService.h"
++#include "nsToolkitShellService.h"
++#include "nsString.h"
++#include "mozilla/Attributes.h"
++
++class nsKDEShellService final : public nsIGNOMEShellService,
++ public nsToolkitShellService
++{
++public:
++ nsKDEShellService() : mCheckedThisSession(false) { }
++
++ NS_DECL_ISUPPORTS
++ NS_DECL_NSISHELLSERVICE
++ NS_DECL_NSIGNOMESHELLSERVICE
++
++ 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_IMETHODIMP
++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 "nsIGNOMEShellService.h"
++
++NS_IMETHODIMP
++nsUnixShellServiceConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult);
++
++#endif // nsunixshellservice_h____
diff --git a/firefox.spec b/firefox.spec
index 67aaf32..c997561 100644
--- a/firefox.spec
+++ b/firefox.spec
@@ -224,7 +224,7 @@ Name: firefox
Epoch: 0
# IMPORTANT: When updating, you MUST also update the l10n files by running
# download.sh after editing the version number
-Version: 75.0
+Version: 78.0.1
Release: 1
License: MPLv1+
Group: Networking/WWW
@@ -260,8 +260,8 @@ Patch0: firefox-67.0-webrtc-compile.patch
#Patch1: firefox-72.0.2-sqlite-3.31.patch
# Patches for kde integration of FF from http://www.rosenauer.org/hg/mozilla/
-Patch11: firefox-73.0-kde.patch
-Patch12: mozilla-73.0-kde.patch
+Patch11: firefox-78.0-kde.patch
+Patch12: mozilla-78.0-kde.patch
Patch14: build-aarch64-skia.patch
Patch15: build-arm-libopus.patch
@@ -284,7 +284,7 @@ BuildRequires: bzip2-devel
BuildRequires: jpeg-devel
BuildRequires: libiw-devel
%if %mdvver > 3000000
-BuildRequires: icu-devel >= 59.1
+#BuildRequires: icu-devel >= 1:67.1
%endif
BuildRequires: pkgconfig(harfbuzz)
BuildRequires: pkgconfig(alsa)
@@ -312,7 +312,7 @@ BuildRequires: pkgconfig(libproxy-1.0)
BuildRequires: pkgconfig(libpulse)
BuildRequires: pkgconfig(libstartup-notification-1.0)
BuildRequires: pkgconfig(nspr) >= 4.25.0
-BuildRequires: pkgconfig(nss) >= 3.51
+BuildRequires: pkgconfig(nss) >= 3.53.1
BuildRequires: pkgconfig(ogg)
BuildRequires: pkgconfig(opus)
BuildRequires: pkgconfig(libpulse)
@@ -488,24 +488,21 @@ ac_add_options --enable-av1
%endif
%if %mdvver > 3000000
ac_add_options --with-system-libevent
-ac_add_options --with-system-icu
+#ac_add_options --with-system-icu
%endif
%if %mdvver <= 3000000
ac_add_options --with-system-libvpx
%endif
ac_add_options --enable-system-pixman
-ac_add_options --disable-gconf
ac_add_options --disable-updater
ac_add_options --disable-tests
ac_add_options --disable-debug
ac_add_options --enable-official-branding
ac_add_options --enable-libproxy
-ac_add_options --with-system-bz2
ac_add_options --with-system-jpeg
ac_add_options --with-system-png
ac_add_options --enable-jemalloc
ac_add_options --enable-replace-malloc
-ac_add_options --enable-startup-notification
#ac_add_options --with-system-ply
ac_add_options --with-distribution-id=org.openmandriva
ac_add_options --disable-crashreporter
diff --git a/mozilla-78.0-kde.patch b/mozilla-78.0-kde.patch
new file mode 100644
index 0000000..ae5b040
--- /dev/null
+++ b/mozilla-78.0-kde.patch
@@ -0,0 +1,1941 @@
+# HG changeset patch
+# User msirringhaus@suse.de
+# Date 1559294891 -7200
+# Fri May 31 11:28:11 2019 +0200
+# Node ID c2aa7198fb925e7fde96abf65b6f68b9b755f112
+# Parent aa58e8c70d1448a08407c6c191ea8b76d61e8bf6
+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/Preferences.cpp b/modules/libpref/Preferences.cpp
+--- a/modules/libpref/Preferences.cpp
++++ b/modules/libpref/Preferences.cpp
+@@ -83,16 +83,17 @@
+ #include "nsXPCOM.h"
+ #include "nsXULAppAPI.h"
+ #include "nsZipArchive.h"
+ #include "plbase64.h"
+ #include "PLDHashTable.h"
+ #include "plstr.h"
+ #include "prlink.h"
+ #include "xpcpublic.h"
++#include "nsKDEUtils.h"
+
+ #ifdef DEBUG
+ # include <map>
+ #endif
+
+ #ifdef MOZ_MEMORY
+ # include "mozmemory.h"
+ #endif
+@@ -4566,25 +4567,37 @@ nsresult Preferences::InitInitialObjects
+ // 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(_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.
+@@ -4630,17 +4643,17 @@ nsresult Preferences::InitInitialObjects
+ }
+
+ nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
+ if (!path) {
+ continue;
+ }
+
+ // Do we care if a file provided by this process fails to load?
+- pref_LoadPrefsInDir(path, nullptr, 0);
++ pref_LoadPrefsInDir(path, specialFiles, ArrayLength(specialFiles));
+ }
+ }
+
+ if (XRE_IsParentProcess()) {
+ SetupTelemetryPref();
+ }
+
+ if (aIsStartup) {
+diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build
+--- a/modules/libpref/moz.build
++++ b/modules/libpref/moz.build
+@@ -114,16 +114,20 @@ EXPORTS.mozilla += [
+ ]
+ EXPORTS.mozilla += sorted(['!' + g for g in gen_h])
+
+ UNIFIED_SOURCES += [
+ 'Preferences.cpp',
+ 'SharedPrefMap.cpp',
+ ]
+
++LOCAL_INCLUDES += [
++ '/toolkit/xre'
++]
++
+ gen_all_tuple = tuple(gen_h + gen_cpp + gen_rs)
+
+ GENERATED_FILES += [gen_all_tuple]
+
+ static_pref_list = GENERATED_FILES[gen_all_tuple]
+ static_pref_list.script = 'init/generate_static_pref_list.py:emit_code'
+ static_pref_list.inputs = ['init/StaticPrefList.yaml']
+
+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
+@@ -227,16 +227,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
+@@ -37,16 +37,17 @@ class ManifestEntry(object):
+ 'platformversion',
+ 'os',
+ 'osversion',
+ 'abi',
+ 'xpcnativewrappers',
+ 'tablet',
+ 'process',
+ 'contentaccessible',
++ '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
+@@ -46,10 +46,14 @@ XPCOM_MANIFESTS += [
+
+ if CONFIG['MOZ_PLACES']:
+ EXTRA_JS_MODULES += [
+ 'DownloadHistory.jsm',
+ ]
+
+ FINAL_LIBRARY = 'xul'
+
++LOCAL_INCLUDES += [
++ '/toolkit/xre'
++]
++
+ with Files('**'):
+ BUG_COMPONENT = ('Toolkit', 'Downloads API')
+diff --git a/toolkit/mozapps/downloads/HelperAppDlg.jsm b/toolkit/mozapps/downloads/HelperAppDlg.jsm
+--- a/toolkit/mozapps/downloads/HelperAppDlg.jsm
++++ b/toolkit/mozapps/downloads/HelperAppDlg.jsm
+@@ -1203,36 +1203,66 @@ nsUnknownContentTypeDialog.prototype = {
+ params.handlerApp &&
+ params.handlerApp.executable &&
+ params.handlerApp.executable.isFile()
+ ) {
+ // Remember the file they chose to run.
+ this.chosenApp = params.handlerApp;
+ }
+ } else if ("@mozilla.org/applicationchooser;1" in Cc) {
+- var nsIApplicationChooser = Ci.nsIApplicationChooser;
+- var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance(
+- nsIApplicationChooser
+- );
+- appChooser.init(
+- this.mDialog,
+- this.dialogElement("strings").getString("chooseAppFilePickerTitle")
+- );
+- var contentTypeDialogObj = this;
+- let appChooserCallback = function appChooserCallback_done(aResult) {
+- if (aResult) {
+- contentTypeDialogObj.chosenApp = aResult.QueryInterface(
+- Ci.nsILocalHandlerApp
+- );
+- }
+- contentTypeDialogObj.finishChooseApp();
+- };
+- appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
+- // The finishChooseApp is called from appChooserCallback
+- return;
++ // handle the KDE case which is implemented in the filepicker
++ // therefore falling back to Gtk2 like behaviour if KDE is running
++ // FIXME this should be better handled in the nsIApplicationChooser
++ // interface
++ var env = Components.classes["@mozilla.org/process/environment;1"]
++ .getService(Components.interfaces.nsIEnvironment);
++ if (env.get('KDE_FULL_SESSION') == "true")
++ {
++ var nsIFilePicker = Ci.nsIFilePicker;
++ var fp = Cc["@mozilla.org/filepicker;1"]
++ .createInstance(nsIFilePicker);
++ fp.init(this.mDialog,
++ this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
++ nsIFilePicker.modeOpen);
++
++ fp.appendFilters(nsIFilePicker.filterApps);
++
++ fp.open(aResult => {
++ if (aResult == nsIFilePicker.returnOK && fp.file) {
++ // Remember the file they chose to run.
++ var localHandlerApp =
++ Cc["@mozilla.org/uriloader/local-handler-app;1"].
++ createInstance(Ci.nsILocalHandlerApp);
++ localHandlerApp.executable = fp.file;
++ this.chosenApp = localHandlerApp;
++ }
++ this.finishChooseApp();
++ });
++ } else {
++ var nsIApplicationChooser = Ci.nsIApplicationChooser;
++ var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance(
++ nsIApplicationChooser
++ );
++ appChooser.init(
++ this.mDialog,
++ this.dialogElement("strings").getString("chooseAppFilePickerTitle")
++ );
++ var contentTypeDialogObj = this;
++ let appChooserCallback = function appChooserCallback_done(aResult) {
++ if (aResult) {
++ contentTypeDialogObj.chosenApp = aResult.QueryInterface(
++ Ci.nsILocalHandlerApp
++ );
++ }
++ contentTypeDialogObj.finishChooseApp();
++ };
++ appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
++ // The finishChooseApp is called from appChooserCallback
++ return;
++ }
+ } else {
+ var nsIFilePicker = Ci.nsIFilePicker;
+ var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+ fp.init(
+ this.mDialog,
+ this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
+ nsIFilePicker.modeOpen
+ );
+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
+@@ -13,16 +13,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"
+
+ using namespace mozilla;
+
+ class nsUnixSystemProxySettings final : public nsISystemProxySettings {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISYSTEMPROXYSETTINGS
+
+@@ -36,16 +37,18 @@ class nsUnixSystemProxySettings final :
+ nsCOMPtr<nsIGSettingsCollection> mProxySettings;
+ nsInterfaceHashtable<nsCStringHashKey, nsIGSettingsCollection>
+ mSchemeProxySettings;
+ 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
+@@ -384,21 +387,50 @@ nsresult nsUnixSystemProxySettings::GetP
+ return NS_OK;
+ }
+
+ 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;
+ }
+
+ return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult);
+ }
+
++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;
++}
++
++
+ NS_IMPL_COMPONENT_FACTORY(nsUnixSystemProxySettings) {
+ auto result = MakeRefPtr<nsUnixSystemProxySettings>();
+ result->Init();
+ return result.forget().downcast<nsISupports>();
+ }
+diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build
+--- a/toolkit/xre/moz.build
++++ b/toolkit/xre/moz.build
+@@ -88,17 +88,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
+ '../components/printingui',
+ ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
+ UNIFIED_SOURCES += [
+ 'nsNativeAppSupportDefault.cpp',
+ 'UIKitDirProvider.mm',
+ ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk':
++ EXPORTS += ['nsKDEUtils.h']
+ UNIFIED_SOURCES += [
++ 'nsKDEUtils.cpp',
+ 'nsNativeAppSupportUnix.cpp',
+ ]
+ else:
+ UNIFIED_SOURCES += [
+ 'nsNativeAppSupportDefault.cpp',
+ ]
+
+ if CONFIG['MOZ_HAS_REMOTE']:
+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,344 @@
++/* -*- 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>
++// copied from X11/X.h as a hack since for an unknown
++// reason it's not picked up from X11/X.h
++#ifndef None
++#define None 0L /* universal null resource or null atom */
++#endif
++
++//#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 );
++ }
++
++ 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 "nsString.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/HandlerServiceParent.cpp b/uriloader/exthandler/HandlerServiceParent.cpp
+--- a/uriloader/exthandler/HandlerServiceParent.cpp
++++ b/uriloader/exthandler/HandlerServiceParent.cpp
+@@ -7,17 +7,17 @@
+ #include "mozilla/ipc/ProtocolUtils.h"
+ #include "mozilla/Logging.h"
+ #include "HandlerServiceParent.h"
+ #include "nsIHandlerService.h"
+ #include "nsIMIMEInfo.h"
+ #include "ContentHandlerService.h"
+ #include "nsStringEnumerator.h"
+ #ifdef MOZ_WIDGET_GTK
+-# include "unix/nsGNOMERegistry.h"
++# include "unix/nsCommonRegistry.h"
+ #endif
+
+ using mozilla::dom::ContentHandlerService;
+ using mozilla::dom::HandlerApp;
+ using mozilla::dom::HandlerInfo;
+ using mozilla::dom::RemoteHandlerApp;
+
+ namespace {
+@@ -299,17 +299,17 @@ mozilla::ipc::IPCResult HandlerServicePa
+ mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocolOS(
+ const nsCString& aProtocolScheme, bool* aHandlerExists) {
+ if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) {
+ *aHandlerExists = false;
+ return IPC_OK();
+ }
+ #ifdef MOZ_WIDGET_GTK
+ // Check the GNOME registry for a protocol handler
+- *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme.get());
++ *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme.get());
+ #else
+ *aHandlerExists = false;
+ #endif
+ return IPC_OK();
+ }
+
+ /*
+ * Check if a handler exists for the provided protocol. Check the datastore
+@@ -328,17 +328,17 @@ mozilla::ipc::IPCResult HandlerServicePa
+ nsCOMPtr<nsIExternalProtocolService> protoSvc =
+ do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ *aHandlerExists = false;
+ return IPC_OK();
+ }
+ rv = protoSvc->ExternalProtocolHandlerExists(aProtocolScheme.get(),
+ aHandlerExists);
+-
++##
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ *aHandlerExists = false;
+ }
+ #else
+ MOZ_RELEASE_ASSERT(false, "No implementation on this platform.");
+ *aHandlerExists = false;
+ #endif
+ return IPC_OK();
+diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
+--- a/uriloader/exthandler/moz.build
++++ b/uriloader/exthandler/moz.build
+@@ -85,17 +85,19 @@ else:
+ SOURCES += [
+ osdir + '/nsOSHelperAppService.cpp',
+ ]
+ if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
+ CXXFLAGS += ['-Wno-error=shadow']
+
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == '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/nsExternalURLHandlerService.cpp',
+ 'android/nsMIMEInfoAndroid.cpp',
+ ]
+@@ -135,16 +137,17 @@ include('/ipc/chromium/chromium-config.m
+ FINAL_LIBRARY = 'xul'
+
+ LOCAL_INCLUDES += [
+ '/docshell/base',
+ '/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'] == 'gtk':
+ 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,86 @@
++/* -*- 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 "nsMIMEInfoUnix.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
+@@ -1,46 +1,49 @@
+ /* -*- Mode: C++; tab-width: 3; 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 "nsMIMEInfoUnix.h"
+-#include "nsGNOMERegistry.h"
++#include "nsCommonRegistry.h"
+ #include "nsIGIOService.h"
+ #include "nsNetCID.h"
+ #include "nsIIOService.h"
+ #ifdef MOZ_ENABLE_DBUS
+ # include "nsDBusHandlerApp.h"
+ #endif
++#if defined(XP_UNIX) && !defined(XP_MACOSX)
++#include "nsKDEUtils.h"
++#endif
+
+ nsresult nsMIMEInfoUnix::LoadUriInternal(nsIURI* aURI) {
+- return nsGNOMERegistry::LoadURL(aURI);
++ return nsCommonRegistry::LoadURL(aURI);
+ }
+
+ NS_IMETHODIMP
+ nsMIMEInfoUnix::GetHasDefaultHandler(bool* _retval) {
+ // if mDefaultApplication is set, it means the application has been set from
+ // either /etc/mailcap or ${HOME}/.mailcap, in which case we don't want to
+ // give the GNOME answer.
+ if (mDefaultApplication) return nsMIMEInfoImpl::GetHasDefaultHandler(_retval);
+
+ *_retval = false;
+
+ if (mClass == eProtocolInfo) {
+- *_retval = nsGNOMERegistry::HandlerExists(mSchemeOrType.get());
++ *_retval = nsCommonRegistry::HandlerExists(mSchemeOrType.get());
+ } else {
+ RefPtr<nsMIMEInfoBase> mimeInfo =
+- nsGNOMERegistry::GetFromType(mSchemeOrType);
++ 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;
+
+ return NS_OK;
+@@ -50,16 +53,33 @@ nsresult nsMIMEInfoUnix::LaunchDefaultWi
+ // if mDefaultApplication is set, it means the application has been set from
+ // either /etc/mailcap or ${HOME}/.mailcap, in which case we don't want to
+ // give the GNOME answer.
+ if (mDefaultApplication) return nsMIMEInfoImpl::LaunchDefaultWithFile(aFile);
+
+ nsAutoCString nativePath;
+ aFile->GetNativePath(nativePath);
+
++ 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 =
+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
+@@ -5,17 +5,17 @@
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+ #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 "nsIFileStreams.h"
+ #include "nsILineInputStream.h"
+ #include "nsIFile.h"
+@@ -1022,17 +1022,17 @@ nsresult nsOSHelperAppService::GetHandle
+
+ nsresult nsOSHelperAppService::OSProtocolHandlerExists(
+ const char* aProtocolScheme, bool* aHandlerExists) {
+ nsresult rv = NS_OK;
+
+ if (!XRE_IsContentProcess()) {
+ #ifdef MOZ_WIDGET_GTK
+ // Check the GNOME registry for a protocol handler
+- *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
++ *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
+ #else
+ *aHandlerExists = false;
+ #endif
+ } else {
+ *aHandlerExists = false;
+ nsCOMPtr<nsIHandlerService> handlerSvc =
+ do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv) && handlerSvc) {
+@@ -1042,17 +1042,17 @@ nsresult nsOSHelperAppService::OSProtoco
+ }
+
+ return rv;
+ }
+
+ 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
+ }
+
+ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
+ const nsACString& aScheme, bool* _retval) {
+@@ -1139,17 +1139,17 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel
+ nsresult rv =
+ LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt), majorType,
+ minorType, 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,
+ minorType, mime_types_description, false);
+@@ -1251,17 +1251,17 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel
+
+ // Now look up our extensions
+ 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));
+diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build
+--- a/widget/gtk/moz.build
++++ b/widget/gtk/moz.build
+@@ -131,16 +131,17 @@ include('/ipc/chromium/chromium-config.m
+
+ FINAL_LIBRARY = 'xul'
+
+ LOCAL_INCLUDES += [
+ '/layout/base',
+ '/layout/generic',
+ '/layout/xul',
+ '/other-licenses/atk-1.0',
++ '/toolkit/xre',
+ '/widget',
+ '/widget/headless',
+ ]
+
+ 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
+@@ -1,15 +1,16 @@
+ /* -*- 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 <dlfcn.h>
+ #include <gtk/gtk.h>
++#include <gdk/gdkx.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+
+ #include "mozilla/Types.h"
+ #include "nsGtkUtils.h"
+ #include "nsIFileURL.h"
+ #include "nsIGIOService.h"
+@@ -22,16 +23,18 @@
+ #include "nsMemory.h"
+ #include "nsEnumeratorUtils.h"
+ #include "nsNetUtil.h"
+ #include "nsReadableUtils.h"
+ #include "MozContainer.h"
+ #include "gfxPlatformGtk.h"
+
+ #include "nsFilePicker.h"
++#include "nsKDEUtils.h"
++#include "nsURLHelper.h"
+
+ using namespace mozilla;
+
+ #define MAX_PREVIEW_SIZE 180
+ // bug 1184009
+ #define MAX_PREVIEW_SOURCE_SIZE 4096
+
+ nsIFile* nsFilePicker::mPrevDisplayDirectory = nullptr;
+@@ -231,17 +234,19 @@ nsFilePicker::AppendFilters(int32_t aFil
+ mAllowURLs = !!(aFilterMask & filterAllowURLs);
+ 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);
+@@ -341,16 +346,39 @@ nsresult nsFilePicker::Show(int16_t* aRe
+ return NS_OK;
+ }
+
+ 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()) {
++ mCallback = aCallback;
++ mRunning = true;
++ NS_ADDREF_THIS();
++ g_idle_add([](gpointer data) -> gboolean {
++ nsFilePicker* queuedPicker = (nsFilePicker*) data;
++ int16_t result;
++ queuedPicker->kdeFileDialog(&result);
++ if (queuedPicker->mCallback) {
++ queuedPicker->mCallback->Done(result);
++ queuedPicker->mCallback = nullptr;
++ } else {
++ queuedPicker->mResult = result;
++ }
++ queuedPicker->mRunning = false;
++ NS_RELEASE(queuedPicker);
++ return G_SOURCE_REMOVE;
++ }, this);
++
++ return NS_OK;
++ }
++
+ NS_ConvertUTF16toUTF8 title(mTitle);
+
+ GtkWindow* parent_widget =
+ GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
+
+ GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
+
+ const gchar* accept_button;
+@@ -570,16 +598,244 @@ void nsFilePicker::Done(void* file_choos
+ 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 );
++
++ nsCString 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);
++ }
++
++ 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 :-/
++ {
++ nsCOMPtr<nsIFile> localfile;
++ nsresult rv = NS_NewNativeLocalFile( output[ 0 ],
++ PR_FALSE,
++ getter_AddRefs(localfile));
++ if (NS_SUCCEEDED(rv))
++ rv = net_GetURLSpecFromActualFile(localfile, mFileURL);
++ }
++ }
++ // 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);
++
++ nsCString 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;
++ }
++
+ // All below functions available as of GTK 3.20+
+ void* nsFilePicker::GtkFileChooserNew(const gchar* title, GtkWindow* parent,
+ GtkFileChooserAction action,
+ const gchar* accept_label) {
+ static auto sGtkFileChooserNativeNewPtr =
+ (void* (*)(const gchar*, GtkWindow*, GtkFileChooserAction, const gchar*,
+ const gchar*))dlsym(RTLD_DEFAULT,
+ "gtk_file_chooser_native_new");
+diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h
+--- a/widget/gtk/nsFilePicker.h
++++ b/widget/gtk/nsFilePicker.h
+@@ -67,16 +67,22 @@ class nsFilePicker : public nsBaseFilePi
+ 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 );
++
+ void* GtkFileChooserNew(const gchar* title, GtkWindow* parent,
+ GtkFileChooserAction action,
+ const gchar* accept_label);
+ void GtkFileChooserShow(void* file_chooser);
+ void GtkFileChooserDestroy(void* file_chooser);
+ void GtkFileChooserSetModal(void* file_chooser, GtkWindow* parent_widget,
+ gboolean modal);
+
+diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
+--- a/xpcom/components/ManifestParser.cpp
++++ b/xpcom/components/ManifestParser.cpp
+@@ -34,16 +34,17 @@
+ #include "nsTextFormatter.h"
+ #include "nsVersionComparator.h"
+ #include "nsXPCOMCIDInternal.h"
+
+ #include "nsIConsoleService.h"
+ #include "nsIScriptError.h"
+ #include "nsIXULAppInfo.h"
+ #include "nsIXULRuntime.h"
++#include "nsKDEUtils.h"
+
+ using namespace mozilla;
+
+ struct ManifestDirective {
+ const char* directive;
+ int argc;
+
+ bool ischrome;
+@@ -394,16 +395,17 @@ void ParseManifest(NSLocationType aType,
+ 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");
+
+@@ -449,39 +451,44 @@ void ParseManifest(NSLocationType aType,
+ 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, u"%ld.%ld", info.dwMajorVersion,
+ info.dwMinorVersion);
+ }
++ desktop = NS_LITERAL_STRING("win");
+ # pragma warning(pop)
+ #elif defined(MOZ_WIDGET_COCOA)
+ SInt32 majorVersion = nsCocoaFeatures::macOSVersionMajor();
+ SInt32 minorVersion = nsCocoaFeatures::macOSVersionMinor();
+ nsTextFormatter::ssprintf(osVersion, u"%ld.%ld", majorVersion, minorVersion);
++ desktop = NS_LITERAL_STRING("macosx");
+ #elif defined(MOZ_WIDGET_GTK)
+ nsTextFormatter::ssprintf(osVersion, u"%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 = java::GeckoAppShell::IsTablet();
+ }
++ desktop = NS_LITERAL_STRING("android");
+ #endif
+
+ if (XRE_IsContentProcess()) {
+ process = kContent;
+ } else {
+ process = kMain;
+ }
+
+@@ -568,25 +575,27 @@ void ParseManifest(NSLocationType aType,
+ 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) ||
+ CheckOsFlag(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;
+ }
+
+@@ -623,17 +632,17 @@ void ParseManifest(NSLocationType aType,
+ }
+
+ LogMessageWithContext(
+ aFile, line, "Unrecognized chrome manifest modifier '%s'.", token);
+ ok = false;
+ }
+
+ if (!ok || stApp == eBad || stAppVersion == eBad ||
+- stGeckoVersion == eBad || stOs == eBad || stOsVersion == eBad ||
++ stGeckoVersion == eBad || stOs == eBad || stOsVersion == eBad || stDesktop == eBad ||
+ #ifdef MOZ_WIDGET_ANDROID
+ stTablet == eBad ||
+ #endif
+ stABI == eBad || stProcess == eBad) {
+ continue;
+ }
+
+ if (directive->regfunc) {
+diff --git a/xpcom/components/moz.build b/xpcom/components/moz.build
+--- a/xpcom/components/moz.build
++++ b/xpcom/components/moz.build
+@@ -62,16 +62,17 @@ LOCAL_INCLUDES += [
+ '!..',
+ '../base',
+ '../build',
+ '../ds',
+ '/chrome',
+ '/js/xpconnect/loader',
+ '/layout/build',
+ '/modules/libjar',
++ '/toolkit/xre',
+ ]
+
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk':
+ CXXFLAGS += CONFIG['TK_CFLAGS']
+ if CONFIG['MOZ_ENABLE_DBUS']:
+ CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
+
+ include('/ipc/chromium/chromium-config.mozbuild')
+diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
+--- a/xpcom/io/nsLocalFileUnix.cpp
++++ b/xpcom/io/nsLocalFileUnix.cpp
+@@ -46,16 +46,17 @@
+ #include "prproces.h"
+ #include "nsIDirectoryEnumerator.h"
+ #include "nsSimpleEnumerator.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"
+
+@@ -1898,62 +1899,77 @@ nsLocalFile::SetPersistentDescriptor(con
+
+ NS_IMETHODIMP
+ nsLocalFile::Reveal() {
+ if (!FilePreferences::IsAllowedPath(mPath)) {
+ return NS_ERROR_FILE_ACCESS_DENIED;
+ }
+
+ #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;
+ }
+ if (NS_SUCCEEDED(giovfs->OrgFreedesktopFileManager1ShowItems(mPath))) {
+ return NS_OK;
+ }
+ 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;
+ #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;
+ #else
+ return NS_ERROR_FAILURE;
+ #endif
++ 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);
+ }
+
+ NS_IMETHODIMP
+ nsLocalFile::Launch() {
+ if (!FilePreferences::IsAllowedPath(mPath)) {
+ return NS_ERROR_FILE_ACCESS_DENIED;
+ }
+
+ #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_WIDGET_ANDROID)
+ // Try to get a mimetype, if this fails just use the file uri alone