mozilla-kde.patch
branchfirefox115
changeset 1190 2a24a948b5cf
parent 1189 ba0c97b018a6
child 1191 37e065158be7
equal deleted inserted replaced
1189:ba0c97b018a6 1190:2a24a948b5cf
     1 # HG changeset patch
     1 # HG changeset patch
     2 # User msirringhaus@suse.de
     2 # User msirringhaus@suse.de
     3 # Date 1559294891 -7200
     3 # Date 1559294891 -7200
     4 #      Fri May 31 11:28:11 2019 +0200
     4 #      Fri May 31 11:28:11 2019 +0200
     5 # Node ID c2aa7198fb925e7fde96abf65b6f68b9b755f112
     5 # Node ID c2aa7198fb925e7fde96abf65b6f68b9b755f112
     6 # Parent  4f8492f0f4bfa17f5b4523a1cdda15a45e3d74d3
     6 # Parent  0086fcc0d5c86a31cbac0a261ed7b526dd2df2e8
     7 Description: Add KDE integration to Firefox (toolkit parts)
     7 Description: Add KDE integration to Firefox (toolkit parts)
     8 Author: Wolfgang Rosenauer <wolfgang@rosenauer.org>
     8 Author: Wolfgang Rosenauer <wolfgang@rosenauer.org>
     9 Author: Lubos Lunak <lunak@suse.com>
     9 Author: Lubos Lunak <lunak@suse.com>
    10 Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751
    10 Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751
    11      https://bugzilla.novell.com/show_bug.cgi?id=170055
    11      https://bugzilla.novell.com/show_bug.cgi?id=170055
    12 
    12 
    13 diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp
    13 Index: firefox-115.0/modules/libpref/Preferences.cpp
    14 --- a/modules/libpref/Preferences.cpp
    14 ===================================================================
    15 +++ b/modules/libpref/Preferences.cpp
    15 --- firefox-115.0.orig/modules/libpref/Preferences.cpp
    16 @@ -91,16 +91,17 @@
    16 +++ firefox-115.0/modules/libpref/Preferences.cpp
    17  #include "plstr.h"
    17 @@ -95,6 +95,7 @@
    18  #include "prdtoa.h"
       
    19  #include "prlink.h"
       
    20  #include "xpcpublic.h"
       
    21  #include "js/RootingAPI.h"
       
    22  #ifdef MOZ_BACKGROUNDTASKS
    18  #ifdef MOZ_BACKGROUNDTASKS
    23  #  include "mozilla/BackgroundTasks.h"
    19  #  include "mozilla/BackgroundTasks.h"
    24  #endif
    20  #endif
    25 +#include "nsKDEUtils.h"
    21 +#include "nsKDEUtils.h"
    26  
    22  
    27  #ifdef DEBUG
    23  #ifdef DEBUG
    28  #  include <map>
    24  #  include <map>
    29  #endif
    25 @@ -4911,6 +4912,16 @@ nsresult Preferences::InitInitialObjects
    30  
       
    31  #ifdef MOZ_MEMORY
       
    32  #  include "mozmemory.h"
       
    33  #endif
       
    34 @@ -4907,16 +4908,27 @@ nsresult Preferences::InitInitialObjects
       
    35      "unix.js"
       
    36  #  if defined(_AIX)
       
    37      ,
       
    38      "aix.js"
       
    39  #  endif
       
    40  #endif
    26  #endif
    41    };
    27    };
    42  
    28  
    43 +  if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper?
    29 +  if (nsKDEUtils::kdeSession()) {  // TODO what if some setup actually requires
    44 +    for(int i = 0;
    30 +                                   // the helper?
    45 +        i < MOZ_ARRAY_LENGTH(specialFiles);
    31 +    for (int i = 0; i < MOZ_ARRAY_LENGTH(specialFiles); ++i) {
    46 +        ++i ) {
    32 +      if (*specialFiles[i] == '\0') {
    47 +      if( *specialFiles[ i ] == '\0' ) {
    33 +        specialFiles[i] = "kde.js";
    48 +        specialFiles[ i ] = "kde.js";
       
    49 +        break;
    34 +        break;
    50 +      }
    35 +      }
    51 +    }
    36 +    }
    52 +  }
    37 +  }
    53 +
    38 +
    54    rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles,
    39    rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles,
    55                             ArrayLength(specialFiles));
    40                             ArrayLength(specialFiles));
    56    if (NS_FAILED(rv)) {
    41    if (NS_FAILED(rv)) {
    57      NS_WARNING("Error parsing application default preferences.");
    42 @@ -4985,7 +4996,7 @@ nsresult Preferences::InitInitialObjects
    58    }
       
    59  
       
    60    // Load jar:$app/omni.jar!/defaults/preferences/*.js
       
    61    // or jar:$gre/omni.jar!/defaults/preferences/*.js.
       
    62 @@ -4981,17 +4993,17 @@ nsresult Preferences::InitInitialObjects
       
    63        }
       
    64  
       
    65        nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
       
    66        if (!path) {
       
    67          continue;
       
    68        }
    43        }
    69  
    44  
    70        // Do we care if a file provided by this process fails to load?
    45        // Do we care if a file provided by this process fails to load?
    71 -      pref_LoadPrefsInDir(path, nullptr, 0);
    46 -      pref_LoadPrefsInDir(path, nullptr, 0);
    72 +      pref_LoadPrefsInDir(path, specialFiles, ArrayLength(specialFiles));
    47 +      pref_LoadPrefsInDir(path, specialFiles, ArrayLength(specialFiles));
    73      }
    48      }
    74    }
    49    }
    75  
    50  
    76  #if defined(MOZ_WIDGET_GTK)
    51 Index: firefox-115.0/modules/libpref/moz.build
    77    // To ensure the system-wide preferences are not overwritten by
    52 ===================================================================
    78    // firefox/browser/defauts/preferences/*.js we need to load
    53 --- firefox-115.0.orig/modules/libpref/moz.build
    79    // the /etc/firefox/defaults/pref/*.js settings as last.
    54 +++ firefox-115.0/modules/libpref/moz.build
    80    // Under Flatpak, the NS_OS_SYSTEM_CONFIG_DIR points to /app/etc/firefox
    55 @@ -126,6 +126,10 @@ UNIFIED_SOURCES += [
    81 diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build
       
    82 --- a/modules/libpref/moz.build
       
    83 +++ b/modules/libpref/moz.build
       
    84 @@ -122,16 +122,20 @@ EXPORTS.mozilla += [
       
    85  ]
       
    86  EXPORTS.mozilla += sorted(["!" + g for g in gen_h])
       
    87  
       
    88  UNIFIED_SOURCES += [
       
    89      "Preferences.cpp",
       
    90      "SharedPrefMap.cpp",
    56      "SharedPrefMap.cpp",
    91  ]
    57  ]
    92  
    58  
    93 +LOCAL_INCLUDES += [
    59 +LOCAL_INCLUDES += [
    94 +    '/toolkit/xre'
    60 +    '/toolkit/xre'
    95 +]
    61 +]
    96 +
    62 +
    97  gen_all_tuple = tuple(gen_h + gen_cpp + gen_rs)
    63  gen_all_tuple = tuple(gen_h + gen_cpp + gen_rs)
    98  
    64  
    99  GeneratedFile(
    65  GeneratedFile(
   100      *gen_all_tuple,
    66 Index: firefox-115.0/python/mozbuild/mozpack/chrome/flags.py
   101      script="init/generate_static_pref_list.py",
    67 ===================================================================
   102      entry_point="emit_code",
    68 --- firefox-115.0.orig/python/mozbuild/mozpack/chrome/flags.py
   103      inputs=["init/StaticPrefList.yaml"]
    69 +++ firefox-115.0/python/mozbuild/mozpack/chrome/flags.py
   104  )
    70 @@ -234,6 +234,7 @@ class Flags(OrderedDict):
   105 diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py
       
   106 --- a/python/mozbuild/mozpack/chrome/flags.py
       
   107 +++ b/python/mozbuild/mozpack/chrome/flags.py
       
   108 @@ -229,16 +229,17 @@ class Flags(OrderedDict):
       
   109          "os": StringFlag,
       
   110          "osversion": VersionFlag,
       
   111          "abi": StringFlag,
       
   112          "platform": Flag,
       
   113          "xpcnativewrappers": Flag,
       
   114          "tablet": Flag,
    71          "tablet": Flag,
   115          "process": StringFlag,
    72          "process": StringFlag,
   116          "backgroundtask": StringFlag,
    73          "backgroundtask": StringFlag,
   117 +        "desktop": StringFlag,
    74 +        "desktop": StringFlag,
   118      }
    75      }
   119      RE = re.compile(r"([!<>=]+)")
    76      RE = re.compile(r"([!<>=]+)")
   120  
    77  
   121      def __init__(self, *flags):
    78 Index: firefox-115.0/python/mozbuild/mozpack/chrome/manifest.py
   122          """
    79 ===================================================================
   123          Initialize a set of flags given in string form.
    80 --- firefox-115.0.orig/python/mozbuild/mozpack/chrome/manifest.py
   124             flags = Flags('contentaccessible=yes', 'appversion>=3.5')
    81 +++ firefox-115.0/python/mozbuild/mozpack/chrome/manifest.py
   125          """
    82 @@ -43,6 +43,7 @@ class ManifestEntry(object):
   126 diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py
       
   127 --- a/python/mozbuild/mozpack/chrome/manifest.py
       
   128 +++ b/python/mozbuild/mozpack/chrome/manifest.py
       
   129 @@ -38,16 +38,17 @@ class ManifestEntry(object):
       
   130          "os",
       
   131          "osversion",
       
   132          "abi",
       
   133          "xpcnativewrappers",
       
   134          "tablet",
       
   135          "process",
    83          "process",
   136          "contentaccessible",
    84          "contentaccessible",
   137          "backgroundtask",
    85          "backgroundtask",
   138 +        "desktop",
    86 +        "desktop",
   139      ]
    87      ]
   140  
    88  
   141      def __init__(self, base, *flags):
    89      def __init__(self, base, *flags):
   142          """
    90 Index: firefox-115.0/toolkit/components/downloads/moz.build
   143          Initialize a manifest entry with the given base path and flags.
    91 ===================================================================
   144          """
    92 --- firefox-115.0.orig/toolkit/components/downloads/moz.build
   145          self.base = base
    93 +++ firefox-115.0/toolkit/components/downloads/moz.build
   146          self.flags = Flags(*flags)
    94 @@ -51,5 +51,9 @@ if CONFIG["MOZ_PLACES"]:
   147 diff --git a/toolkit/components/downloads/moz.build b/toolkit/components/downloads/moz.build
       
   148 --- a/toolkit/components/downloads/moz.build
       
   149 +++ b/toolkit/components/downloads/moz.build
       
   150 @@ -46,10 +46,14 @@ XPCOM_MANIFESTS += [
       
   151  
       
   152  if CONFIG["MOZ_PLACES"]:
       
   153      EXTRA_JS_MODULES += [
       
   154          "DownloadHistory.sys.mjs",
       
   155      ]
       
   156  
    95  
   157  FINAL_LIBRARY = "xul"
    96  FINAL_LIBRARY = "xul"
   158  
    97  
   159 +LOCAL_INCLUDES += [
    98 +LOCAL_INCLUDES += [
   160 +    '/toolkit/xre'
    99 +    '/toolkit/xre'
   161 +]
   100 +]
   162 +
   101 +
   163  with Files("**"):
   102  with Files("**"):
   164      BUG_COMPONENT = ("Toolkit", "Downloads API")
   103      BUG_COMPONENT = ("Toolkit", "Downloads API")
   165 diff --git a/toolkit/mozapps/downloads/HelperAppDlg.jsm b/toolkit/mozapps/downloads/HelperAppDlg.jsm
   104 Index: firefox-115.0/toolkit/mozapps/downloads/HelperAppDlg.sys.mjs
   166 --- a/toolkit/mozapps/downloads/HelperAppDlg.jsm
   105 ===================================================================
   167 +++ b/toolkit/mozapps/downloads/HelperAppDlg.jsm
   106 --- firefox-115.0.orig/toolkit/mozapps/downloads/HelperAppDlg.sys.mjs
   168 @@ -1250,36 +1250,66 @@ nsUnknownContentTypeDialog.prototype = {
   107 +++ firefox-115.0/toolkit/mozapps/downloads/HelperAppDlg.sys.mjs
   169          params.handlerApp &&
   108 @@ -1246,26 +1246,56 @@ nsUnknownContentTypeDialog.prototype = {
   170          params.handlerApp.executable &&
       
   171          params.handlerApp.executable.isFile()
       
   172        ) {
       
   173          // Remember the file they chose to run.
       
   174          this.chosenApp = params.handlerApp;
   109          this.chosenApp = params.handlerApp;
   175        }
   110        }
   176      } else if ("@mozilla.org/applicationchooser;1" in Cc) {
   111      } else if ("@mozilla.org/applicationchooser;1" in Cc) {
   177 -      var nsIApplicationChooser = Ci.nsIApplicationChooser;
   112 -      var nsIApplicationChooser = Ci.nsIApplicationChooser;
   178 -      var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance(
   113 -      var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance(
   245 +        return;
   180 +        return;
   246 +      }
   181 +      }
   247      } else {
   182      } else {
   248        var nsIFilePicker = Ci.nsIFilePicker;
   183        var nsIFilePicker = Ci.nsIFilePicker;
   249        var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
   184        var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
   250        fp.init(
   185 Index: firefox-115.0/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
   251          this.mDialog,
   186 ===================================================================
   252          this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
   187 --- firefox-115.0.orig/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
   253          nsIFilePicker.modeOpen
   188 +++ firefox-115.0/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
   254        );
   189 @@ -16,6 +16,8 @@
   255 diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
       
   256 --- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
       
   257 +++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
       
   258 @@ -11,16 +11,18 @@
       
   259  #include "prenv.h"
       
   260  #include "nsInterfaceHashtable.h"
       
   261  #include "nsHashtablesFwd.h"
       
   262  #include "nsHashKeys.h"
       
   263  #include "nsNetUtil.h"
       
   264  #include "nsISupportsPrimitives.h"
   190  #include "nsISupportsPrimitives.h"
   265  #include "nsIGSettingsService.h"
   191  #include "nsIGSettingsService.h"
   266  #include "nsReadableUtils.h"
   192  #include "nsReadableUtils.h"
   267 +#include "nsPrintfCString.h"
   193 +#include "nsPrintfCString.h"
   268 +#include "nsKDEUtils.h"
   194 +#include "nsKDEUtils.h"
   269  
   195  
   270  using namespace mozilla;
   196  using namespace mozilla;
   271  
   197  
   272  class nsUnixSystemProxySettings final : public nsISystemProxySettings {
   198 @@ -39,6 +41,8 @@ class nsUnixSystemProxySettings final :
   273   public:
       
   274    NS_DECL_ISUPPORTS
       
   275    NS_DECL_NSISYSTEMPROXYSETTINGS
       
   276  
       
   277 @@ -34,16 +36,18 @@ class nsUnixSystemProxySettings final : 
       
   278    nsCOMPtr<nsIGSettingsCollection> mProxySettings;
       
   279    nsInterfaceHashtable<nsCStringHashKey, nsIGSettingsCollection>
       
   280        mSchemeProxySettings;
       
   281    nsresult GetProxyFromGSettings(const nsACString& aScheme,
       
   282                                   const nsACString& aHost, int32_t aPort,
       
   283                                   nsACString& aResult);
   199                                   nsACString& aResult);
   284    nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType,
   200    nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType,
   285                                         nsACString& aResult);
   201                                         nsACString& aResult);
   286 +  nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost,
   202 +  nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost,
   287 +                           PRInt32 aPort, nsACString& aResult);
   203 +                           PRInt32 aPort, nsACString& aResult);
   288  };
   204  };
   289  
   205  
   290  NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings)
   206  NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings)
   291  
   207 @@ -396,6 +400,9 @@ nsresult nsUnixSystemProxySettings::GetP
   292  NS_IMETHODIMP
       
   293  nsUnixSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) {
       
   294    // dbus prevents us from being threadsafe, but this routine should not block
       
   295    // anyhow
       
   296 @@ -392,21 +396,50 @@ nsresult nsUnixSystemProxySettings::GetP
       
   297    return NS_OK;
       
   298  }
       
   299  
       
   300  nsresult nsUnixSystemProxySettings::GetProxyForURI(const nsACString& aSpec,
       
   301                                                     const nsACString& aScheme,
       
   302                                                     const nsACString& aHost,
   208                                                     const nsACString& aHost,
   303                                                     const int32_t aPort,
   209                                                     const int32_t aPort,
   304                                                     nsACString& aResult) {
   210                                                     nsACString& aResult) {
   305 +  if (nsKDEUtils::kdeSupport())
   211 +  if (nsKDEUtils::kdeSupport())
   306 +    return GetProxyFromKDE(aScheme, aHost, aPort, aResult);
   212 +    return GetProxyFromKDE(aScheme, aHost, aPort, aResult);
   307 +
   213 +
   308    if (mProxySettings) {
   214    if (mProxySettings) {
   309      nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult);
   215      nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult);
   310      if (NS_SUCCEEDED(rv)) return rv;
   216      if (NS_SUCCEEDED(rv)) return rv;
   311    }
   217 @@ -404,6 +411,28 @@ nsresult nsUnixSystemProxySettings::GetP
   312  
       
   313    return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult);
   218    return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult);
   314  }
   219  }
   315  
   220  
   316 +nsresult
   221 +nsresult nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme,
   317 +nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme,
   222 +                                                    const nsACString& aHost,
   318 +                                           const nsACString& aHost,
   223 +                                                    PRInt32 aPort,
   319 +                                           PRInt32 aPort,
   224 +                                                    nsACString& aResult) {
   320 +                                           nsACString& aResult)
       
   321 +{
       
   322 +  nsAutoCString url;
   225 +  nsAutoCString url;
   323 +  url = aScheme;
   226 +  url = aScheme;
   324 +  url += "://";
   227 +  url += "://";
   325 +  url += aHost;
   228 +  url += aHost;
   326 +  if( aPort >= 0 )
   229 +  if (aPort >= 0) {
   327 +  {
       
   328 +    url += ":";
   230 +    url += ":";
   329 +    url += nsPrintfCString("%d", aPort);
   231 +    url += nsPrintfCString("%d", aPort);
   330 +  }
   232 +  }
   331 +  nsTArray<nsCString> command;
   233 +  nsTArray<nsCString> command;
   332 +  command.AppendElement( "GETPROXY"_ns );
   234 +  command.AppendElement("GETPROXY"_ns);
   333 +  command.AppendElement( url );
   235 +  command.AppendElement(url);
   334 +  nsTArray<nsCString> result;
   236 +  nsTArray<nsCString> result;
   335 +  if( !nsKDEUtils::command( command, &result ) || result.Length() != 1 )
   237 +  if (!nsKDEUtils::command(command, &result) || result.Length() != 1)
   336 +    return NS_ERROR_FAILURE;
   238 +    return NS_ERROR_FAILURE;
   337 +  aResult = result[0];
   239 +  aResult = result[0];
   338 +  return NS_OK;
   240 +  return NS_OK;
   339 +}
   241 +}
   340 +
   242 +
   341 +
       
   342  NS_IMPL_COMPONENT_FACTORY(nsUnixSystemProxySettings) {
   243  NS_IMPL_COMPONENT_FACTORY(nsUnixSystemProxySettings) {
   343    auto result = MakeRefPtr<nsUnixSystemProxySettings>();
   244    auto result = MakeRefPtr<nsUnixSystemProxySettings>();
   344    result->Init();
   245    result->Init();
   345    return result.forget().downcast<nsISupports>();
   246 Index: firefox-115.0/toolkit/xre/moz.build
   346  }
   247 ===================================================================
   347 diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build
   248 --- firefox-115.0.orig/toolkit/xre/moz.build
   348 --- a/toolkit/xre/moz.build
   249 +++ firefox-115.0/toolkit/xre/moz.build
   349 +++ b/toolkit/xre/moz.build
   250 @@ -96,7 +96,9 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "ui
   350 @@ -91,17 +91,19 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "co
       
   351          "../components/printingui",
       
   352      ]
       
   353  elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "uikit":
       
   354      UNIFIED_SOURCES += [
       
   355          "nsNativeAppSupportDefault.cpp",
       
   356          "UIKitDirProvider.mm",
   251          "UIKitDirProvider.mm",
   357      ]
   252      ]
   358  elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
   253  elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
   359 +    EXPORTS += ['nsKDEUtils.h']
   254 +    EXPORTS += ['nsKDEUtils.h']
   360      UNIFIED_SOURCES += [
   255      UNIFIED_SOURCES += [
   361 +        "nsKDEUtils.cpp",
   256 +        "nsKDEUtils.cpp",
   362          "nsNativeAppSupportUnix.cpp",
   257          "nsNativeAppSupportUnix.cpp",
   363      ]
   258      ]
   364      CXXFLAGS += CONFIG["MOZ_X11_SM_CFLAGS"]
   259      CXXFLAGS += CONFIG["MOZ_X11_SM_CFLAGS"]
   365  else:
   260 Index: firefox-115.0/toolkit/xre/nsKDEUtils.cpp
   366      UNIFIED_SOURCES += [
   261 ===================================================================
   367          "nsNativeAppSupportDefault.cpp",
       
   368      ]
       
   369  
       
   370 diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp
       
   371 new file mode 100644
       
   372 --- /dev/null
   262 --- /dev/null
   373 +++ b/toolkit/xre/nsKDEUtils.cpp
   263 +++ firefox-115.0/toolkit/xre/nsKDEUtils.cpp
   374 @@ -0,0 +1,321 @@
   264 @@ -0,0 +1,286 @@
   375 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
   265 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
   376 +/* This Source Code Form is subject to the terms of the Mozilla Public
   266 +/* This Source Code Form is subject to the terms of the Mozilla Public
   377 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   267 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   378 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   268 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   379 +
   269 +
   393 +#include <unistd.h>
   283 +#include <unistd.h>
   394 +#include <X11/Xlib.h>
   284 +#include <X11/Xlib.h>
   395 +// copied from X11/X.h as a hack since for an unknown
   285 +// copied from X11/X.h as a hack since for an unknown
   396 +// reason it's not picked up from X11/X.h
   286 +// reason it's not picked up from X11/X.h
   397 +#ifndef None
   287 +#ifndef None
   398 +#define None                 0L /* universal null resource or null atom */
   288 +#  define None 0L /* universal null resource or null atom */
   399 +#endif
   289 +#endif
   400 +
   290 +
   401 +//#define DEBUG_KDE
   291 +// #define DEBUG_KDE
   402 +#ifdef DEBUG_KDE
   292 +#ifdef DEBUG_KDE
   403 +#define KMOZILLAHELPER "kmozillahelper"
   293 +#  define KMOZILLAHELPER "kmozillahelper"
   404 +#else
   294 +#else
   405 +// not need for lib64, it's a binary
   295 +// not need for lib64, it's a binary
   406 +#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper"
   296 +#  define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper"
   407 +#endif
   297 +#endif
   408 +
   298 +
   409 +#define KMOZILLAHELPER_VERSION 6
   299 +#define KMOZILLAHELPER_VERSION 6
   410 +#define MAKE_STR2( n ) #n
   300 +#define MAKE_STR2(n) #n
   411 +#define MAKE_STR( n ) MAKE_STR2( n )
   301 +#define MAKE_STR(n) MAKE_STR2(n)
   412 +
   302 +
   413 +static bool getKdeSession()
   303 +static bool getKdeSession() {
   414 +{
   304 +  if (PR_GetEnv("KDE_FULL_SESSION")) {
   415 +    if (PR_GetEnv("KDE_FULL_SESSION"))
   305 +    return true;
   416 +    {
   306 +  }
   417 +      return true;
   307 +  return false;
   418 +    }
   308 +}
   419 +    return false;
   309 +
   420 +}
   310 +static bool getKdeSupport() {
   421 +
   311 +  nsTArray<nsCString> command;
   422 +static bool getKdeSupport()
   312 +  command.AppendElement("CHECK"_ns);
   423 +    {
   313 +  command.AppendElement("KMOZILLAHELPER_VERSION"_ns);
   424 +    nsTArray<nsCString> command;
   314 +  bool kde = nsKDEUtils::command(command);
   425 +    command.AppendElement( "CHECK"_ns );
       
   426 +    command.AppendElement( "KMOZILLAHELPER_VERSION"_ns );
       
   427 +    bool kde = nsKDEUtils::command( command );
       
   428 +#ifdef DEBUG_KDE
   315 +#ifdef DEBUG_KDE
   429 +    fprintf( stderr, "KDE RUNNING %d\n", kde );
   316 +  fprintf(stderr, "KDE RUNNING %d\n", kde);
   430 +#endif
   317 +#endif
   431 +    return kde;
   318 +  return kde;
   432 +    }
   319 +}
   433 +
   320 +
   434 +nsKDEUtils::nsKDEUtils()
   321 +nsKDEUtils::nsKDEUtils() : commandFile(NULL), replyFile(NULL) {}
   435 +    : commandFile( NULL )
   322 +
   436 +    , replyFile( NULL )
   323 +nsKDEUtils::~nsKDEUtils() {
   437 +    {
   324 +  //    closeHelper(); not actually useful, exiting will close the fd too
   438 +    }
   325 +}
   439 +
   326 +
   440 +nsKDEUtils::~nsKDEUtils()
   327 +nsKDEUtils* nsKDEUtils::self() {
   441 +    {
   328 +  static nsKDEUtils s;
   442 +//    closeHelper(); not actually useful, exiting will close the fd too
   329 +  return &s;
   443 +    }
   330 +}
   444 +
       
   445 +nsKDEUtils* nsKDEUtils::self()
       
   446 +    {
       
   447 +    static nsKDEUtils s;
       
   448 +    return &s;
       
   449 +    }
       
   450 +
   331 +
   451 +static bool helperRunning = false;
   332 +static bool helperRunning = false;
   452 +static bool helperFailed = false;
   333 +static bool helperFailed = false;
   453 +
   334 +
   454 +bool nsKDEUtils::kdeSession()
   335 +bool nsKDEUtils::kdeSession() {
       
   336 +  static bool session = getKdeSession();
       
   337 +  return session;
       
   338 +}
       
   339 +
       
   340 +bool nsKDEUtils::kdeSupport() {
       
   341 +  static bool support = kdeSession() && getKdeSupport();
       
   342 +  return support && helperRunning;
       
   343 +}
       
   344 +
       
   345 +struct nsKDECommandData {
       
   346 +  FILE* file;
       
   347 +  nsTArray<nsCString>* output;
       
   348 +  GMainLoop* loop;
       
   349 +  bool success;
       
   350 +};
       
   351 +
       
   352 +static gboolean kdeReadFunc(GIOChannel*, GIOCondition, gpointer data) {
       
   353 +  nsKDECommandData* p = static_cast<nsKDECommandData*>(data);
       
   354 +  char buf[8192];  // TODO big enough
       
   355 +  bool command_done = false;
       
   356 +  bool command_failed = false;
       
   357 +  while (!command_done && !command_failed &&
       
   358 +         fgets(buf, 8192, p->file) !=
       
   359 +             NULL) {  // TODO what if the kernel splits a line into two chunks?
       
   360 +                      // #ifdef DEBUG_KDE
       
   361 +    //         fprintf( stderr, "READ: %s %d\n", buf, feof( p->file ));
       
   362 +    // #endif
       
   363 +    if (char* eol = strchr(buf, '\n')) *eol = '\0';
       
   364 +    command_done = (strcmp(buf, "\\1") == 0);
       
   365 +    command_failed = (strcmp(buf, "\\0") == 0);
       
   366 +    nsAutoCString line(buf);
       
   367 +    line.ReplaceSubstring("\\n", "\n");
       
   368 +    line.ReplaceSubstring(
       
   369 +        "\\"
       
   370 +        "\\",
       
   371 +        "\\");  //  \\ -> \ , i.e. unescape
       
   372 +    if (p->output && !(command_done || command_failed))
       
   373 +      p->output->AppendElement(nsCString(buf));  // TODO utf8?
       
   374 +  }
       
   375 +  bool quit = false;
       
   376 +  if (feof(p->file) || command_failed) {
       
   377 +    quit = true;
       
   378 +    p->success = false;
       
   379 +  }
       
   380 +  if (command_done) {  // reading one reply finished
       
   381 +    quit = true;
       
   382 +    p->success = true;
       
   383 +  }
       
   384 +  if (quit) {
       
   385 +    if (p->loop) g_main_loop_quit(p->loop);
       
   386 +    return FALSE;
       
   387 +  }
       
   388 +  return TRUE;
       
   389 +}
       
   390 +
       
   391 +bool nsKDEUtils::command(const nsTArray<nsCString>& command,
       
   392 +                         nsTArray<nsCString>* output) {
       
   393 +  return self()->internalCommand(command, NULL, false, output);
       
   394 +}
       
   395 +
       
   396 +bool nsKDEUtils::command(nsIArray* command, nsIArray** output) {
       
   397 +  nsTArray<nsCString> in;
       
   398 +  PRUint32 length;
       
   399 +  command->GetLength(&length);
       
   400 +  for (PRUint32 i = 0; i < length; i++) {
       
   401 +    nsCOMPtr<nsISupportsCString> str = do_QueryElementAt(command, i);
       
   402 +    if (str) {
       
   403 +      nsAutoCString s;
       
   404 +      str->GetData(s);
       
   405 +      in.AppendElement(s);
       
   406 +    }
       
   407 +  }
       
   408 +
       
   409 +  nsTArray<nsCString> out;
       
   410 +  bool ret = self()->internalCommand(in, NULL, false, &out);
       
   411 +
       
   412 +  if (!output) return ret;
       
   413 +
       
   414 +  nsCOMPtr<nsIMutableArray> result = do_CreateInstance(NS_ARRAY_CONTRACTID);
       
   415 +  if (!result) return false;
       
   416 +
       
   417 +  for (PRUint32 i = 0; i < out.Length(); i++) {
       
   418 +    nsCOMPtr<nsISupportsCString> rstr =
       
   419 +        do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
       
   420 +    if (!rstr) return false;
       
   421 +
       
   422 +    rstr->SetData(out[i]);
       
   423 +    result->AppendElement(rstr);
       
   424 +  }
       
   425 +
       
   426 +  NS_ADDREF(*output = result);
       
   427 +  return ret;
       
   428 +}
       
   429 +
       
   430 +bool nsKDEUtils::commandBlockUi(const nsTArray<nsCString>& command,
       
   431 +                                GtkWindow* parent,
       
   432 +                                nsTArray<nsCString>* output) {
       
   433 +  return self()->internalCommand(command, parent, true, output);
       
   434 +}
       
   435 +
       
   436 +bool nsKDEUtils::internalCommand(const nsTArray<nsCString>& command,
       
   437 +                                 GtkWindow* parent, bool blockUi,
       
   438 +                                 nsTArray<nsCString>* output) {
       
   439 +  if (!startHelper()) return false;
       
   440 +  feedCommand(command);
       
   441 +  // do not store the data in 'this' but in extra structure, just in case there
       
   442 +  // is reentrancy (can there be? the event loop is re-entered)
       
   443 +  nsKDECommandData data;
       
   444 +  data.file = replyFile;
       
   445 +  data.output = output;
       
   446 +  data.success = false;
       
   447 +  if (blockUi) {
       
   448 +    data.loop = g_main_loop_new(NULL, FALSE);
       
   449 +    GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
       
   450 +    if (parent && gtk_window_get_group(parent))
       
   451 +      gtk_window_group_add_window(gtk_window_get_group(parent),
       
   452 +                                  GTK_WINDOW(window));
       
   453 +    gtk_widget_realize(window);
       
   454 +    gtk_widget_set_sensitive(window, TRUE);
       
   455 +    gtk_grab_add(window);
       
   456 +    GIOChannel* channel = g_io_channel_unix_new(fileno(data.file));
       
   457 +    g_io_add_watch(channel,
       
   458 +                   static_cast<GIOCondition>(G_IO_IN | G_IO_ERR | G_IO_HUP),
       
   459 +                   kdeReadFunc, &data);
       
   460 +    g_io_channel_unref(channel);
       
   461 +    g_main_loop_run(data.loop);
       
   462 +    g_main_loop_unref(data.loop);
       
   463 +    gtk_grab_remove(window);
       
   464 +    gtk_widget_destroy(window);
       
   465 +  } else {
       
   466 +    data.loop = NULL;
       
   467 +    while (kdeReadFunc(NULL, static_cast<GIOCondition>(0), &data))
       
   468 +      ;
       
   469 +  }
       
   470 +  return data.success;
       
   471 +}
       
   472 +
       
   473 +bool nsKDEUtils::startHelper() {
       
   474 +  if (helperRunning) return true;
       
   475 +  if (helperFailed) return false;
       
   476 +  helperFailed = true;
       
   477 +  int fdcommand[2];
       
   478 +  int fdreply[2];
       
   479 +  if (pipe(fdcommand) < 0) return false;
       
   480 +  if (pipe(fdreply) < 0) {
       
   481 +    close(fdcommand[0]);
       
   482 +    close(fdcommand[1]);
       
   483 +    return false;
       
   484 +  }
       
   485 +  char* args[2] = {const_cast<char*>(KMOZILLAHELPER), NULL};
       
   486 +  switch (fork()) {
       
   487 +    case -1: {
       
   488 +      close(fdcommand[0]);
       
   489 +      close(fdcommand[1]);
       
   490 +      close(fdreply[0]);
       
   491 +      close(fdreply[1]);
       
   492 +      return false;
       
   493 +    }
       
   494 +    case 0:  // child
   455 +    {
   495 +    {
   456 +    static bool session = getKdeSession();
   496 +      if (dup2(fdcommand[0], STDIN_FILENO) < 0) _exit(1);
   457 +    return session;
   497 +      if (dup2(fdreply[1], STDOUT_FILENO) < 0) _exit(1);
       
   498 +      int maxfd = 1024;  // close all other fds
       
   499 +      struct rlimit rl;
       
   500 +      if (getrlimit(RLIMIT_NOFILE, &rl) == 0) maxfd = rl.rlim_max;
       
   501 +      for (int i = 3; i < maxfd; ++i) close(i);
       
   502 +#ifdef DEBUG_KDE
       
   503 +      execvp(KMOZILLAHELPER, args);
       
   504 +#else
       
   505 +      execv(KMOZILLAHELPER, args);
       
   506 +#endif
       
   507 +      _exit(1);  // failed
   458 +    }
   508 +    }
   459 +
   509 +    default:  // parent
   460 +bool nsKDEUtils::kdeSupport()
       
   461 +    {
   510 +    {
   462 +    static bool support = kdeSession() && getKdeSupport();
   511 +      commandFile = fdopen(fdcommand[1], "w");
   463 +    return support && helperRunning;
   512 +      replyFile = fdopen(fdreply[0], "r");
       
   513 +      close(fdcommand[0]);
       
   514 +      close(fdreply[1]);
       
   515 +      if (commandFile == NULL || replyFile == NULL) {
       
   516 +        closeHelper();
       
   517 +        return false;
       
   518 +      }
       
   519 +      // ok, helper ready, getKdeRunning() will check if it works
   464 +    }
   520 +    }
   465 +
   521 +  }
   466 +struct nsKDECommandData
   522 +  helperFailed = false;
   467 +    {
   523 +  helperRunning = true;
   468 +    FILE* file;
   524 +  return true;
   469 +    nsTArray<nsCString>* output;
   525 +}
   470 +    GMainLoop* loop;
   526 +
   471 +    bool success;
   527 +void nsKDEUtils::closeHelper() {
   472 +    };
   528 +  if (commandFile != NULL)
   473 +
   529 +    fclose(commandFile);  // this will also make the helper quit
   474 +static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data )
   530 +  if (replyFile != NULL) fclose(replyFile);
   475 +    {
   531 +  helperRunning = false;
   476 +    nsKDECommandData* p = static_cast< nsKDECommandData* >( data );
   532 +}
   477 +    char buf[ 8192 ]; // TODO big enough
   533 +
   478 +    bool command_done = false;
   534 +void nsKDEUtils::feedCommand(const nsTArray<nsCString>& command) {
   479 +    bool command_failed = false;
   535 +  for (int i = 0; i < command.Length(); ++i) {
   480 +    while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL )
   536 +    nsCString line = command[i];
   481 +        { // TODO what if the kernel splits a line into two chunks?
   537 +    line.ReplaceSubstring("\\",
   482 +//#ifdef DEBUG_KDE
   538 +                          "\\"
   483 +//        fprintf( stderr, "READ: %s %d\n", buf, feof( p->file ));
   539 +                          "\\");  // \ -> \\ , i.e. escape
   484 +//#endif
   540 +    line.ReplaceSubstring("\n", "\\n");
   485 +        if( char* eol = strchr( buf, '\n' ))
       
   486 +            *eol = '\0';
       
   487 +        command_done = ( strcmp( buf, "\\1" ) == 0 );
       
   488 +        command_failed = ( strcmp( buf, "\\0" ) == 0 );
       
   489 +        nsAutoCString line( buf );
       
   490 +        line.ReplaceSubstring( "\\n", "\n" );
       
   491 +        line.ReplaceSubstring( "\\" "\\", "\\" ); //  \\ -> \ , i.e. unescape
       
   492 +        if( p->output && !( command_done || command_failed ))
       
   493 +            p->output->AppendElement( nsCString( buf )); // TODO utf8?
       
   494 +        }
       
   495 +    bool quit = false;
       
   496 +    if( feof( p->file ) || command_failed )
       
   497 +        {
       
   498 +        quit = true;
       
   499 +        p->success = false;
       
   500 +        }
       
   501 +    if( command_done )
       
   502 +        { // reading one reply finished
       
   503 +        quit = true;
       
   504 +        p->success = true;
       
   505 +        }
       
   506 +    if( quit )
       
   507 +        {
       
   508 +        if( p->loop )
       
   509 +            g_main_loop_quit( p->loop );
       
   510 +        return FALSE;
       
   511 +        }
       
   512 +    return TRUE;
       
   513 +    }
       
   514 +
       
   515 +bool nsKDEUtils::command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output )
       
   516 +    {
       
   517 +    return self()->internalCommand( command, NULL, false, output );
       
   518 +    }
       
   519 +
       
   520 +bool nsKDEUtils::command( nsIArray* command, nsIArray** output)
       
   521 +    {
       
   522 +    nsTArray<nsCString> in;
       
   523 +    PRUint32 length;
       
   524 +    command->GetLength( &length );
       
   525 +    for ( PRUint32 i = 0; i < length; i++ )
       
   526 +        {
       
   527 +        nsCOMPtr<nsISupportsCString> str = do_QueryElementAt( command, i );
       
   528 +        if( str )
       
   529 +            {
       
   530 +            nsAutoCString s;
       
   531 +            str->GetData( s );
       
   532 +            in.AppendElement( s );
       
   533 +            }
       
   534 +        }
       
   535 +
       
   536 +    nsTArray<nsCString> out;
       
   537 +    bool ret = self()->internalCommand( in, NULL, false, &out );
       
   538 +
       
   539 +    if ( !output ) return ret;
       
   540 +
       
   541 +    nsCOMPtr<nsIMutableArray> result = do_CreateInstance( NS_ARRAY_CONTRACTID );
       
   542 +    if ( !result ) return false;
       
   543 +
       
   544 +    for ( PRUint32 i = 0; i < out.Length(); i++ )
       
   545 +        {
       
   546 +        nsCOMPtr<nsISupportsCString> rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
       
   547 +        if ( !rstr ) return false;
       
   548 +
       
   549 +        rstr->SetData( out[i] );
       
   550 +        result->AppendElement( rstr );
       
   551 +        }
       
   552 +
       
   553 +    NS_ADDREF( *output = result);
       
   554 +    return ret;
       
   555 +    }
       
   556 +
       
   557 +
       
   558 +bool nsKDEUtils::commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output )
       
   559 +    {
       
   560 +    return self()->internalCommand( command, parent, true, output );
       
   561 +    }
       
   562 +
       
   563 +bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool blockUi,
       
   564 +    nsTArray<nsCString>* output )
       
   565 +    {
       
   566 +    if( !startHelper())
       
   567 +        return false;
       
   568 +    feedCommand( command );
       
   569 +    // do not store the data in 'this' but in extra structure, just in case there
       
   570 +    // is reentrancy (can there be? the event loop is re-entered)
       
   571 +    nsKDECommandData data;
       
   572 +    data.file = replyFile;
       
   573 +    data.output = output;
       
   574 +    data.success = false;
       
   575 +    if( blockUi )
       
   576 +        {
       
   577 +        data.loop = g_main_loop_new( NULL, FALSE );
       
   578 +        GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
       
   579 +        if( parent && gtk_window_get_group(parent) )
       
   580 +            gtk_window_group_add_window( gtk_window_get_group(parent), GTK_WINDOW( window ));
       
   581 +        gtk_widget_realize( window );
       
   582 +        gtk_widget_set_sensitive( window, TRUE );
       
   583 +        gtk_grab_add( window );
       
   584 +        GIOChannel* channel = g_io_channel_unix_new( fileno( data.file ));
       
   585 +        g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data );
       
   586 +        g_io_channel_unref( channel );
       
   587 +        g_main_loop_run( data.loop );
       
   588 +        g_main_loop_unref( data.loop );
       
   589 +        gtk_grab_remove( window );
       
   590 +        gtk_widget_destroy( window );
       
   591 +        }
       
   592 +    else
       
   593 +        {
       
   594 +        data.loop = NULL;
       
   595 +        while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data ))
       
   596 +            ;
       
   597 +        }
       
   598 +    return data.success;
       
   599 +    }
       
   600 +
       
   601 +bool nsKDEUtils::startHelper()
       
   602 +    {
       
   603 +    if( helperRunning )
       
   604 +        return true;
       
   605 +    if( helperFailed )
       
   606 +        return false;
       
   607 +    helperFailed = true;
       
   608 +    int fdcommand[ 2 ];
       
   609 +    int fdreply[ 2 ];
       
   610 +    if( pipe( fdcommand ) < 0 )
       
   611 +        return false;
       
   612 +    if( pipe( fdreply ) < 0 )
       
   613 +        {
       
   614 +        close( fdcommand[ 0 ] );
       
   615 +        close( fdcommand[ 1 ] );
       
   616 +        return false;
       
   617 +        }
       
   618 +    char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL };
       
   619 +    switch( fork())
       
   620 +        {
       
   621 +        case -1:
       
   622 +            {
       
   623 +            close( fdcommand[ 0 ] );
       
   624 +            close( fdcommand[ 1 ] );
       
   625 +            close( fdreply[ 0 ] );
       
   626 +            close( fdreply[ 1 ] );
       
   627 +            return false;
       
   628 +            }
       
   629 +        case 0: // child
       
   630 +            {
       
   631 +            if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 )
       
   632 +                _exit( 1 );
       
   633 +            if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 )
       
   634 +                _exit( 1 );
       
   635 +            int maxfd = 1024; // close all other fds
       
   636 +            struct rlimit rl;
       
   637 +            if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
       
   638 +                maxfd = rl.rlim_max;
       
   639 +            for( int i = 3;
       
   640 +                 i < maxfd;
       
   641 +                 ++i )
       
   642 +                close( i );
       
   643 +#ifdef DEBUG_KDE
   541 +#ifdef DEBUG_KDE
   644 +            execvp( KMOZILLAHELPER, args );
   542 +    fprintf(stderr, "COMM: %s\n", line.get());
   645 +#else
       
   646 +            execv( KMOZILLAHELPER, args );
       
   647 +#endif
   543 +#endif
   648 +            _exit( 1 ); // failed
   544 +    fputs(line.get(), commandFile);
   649 +            }
   545 +    fputs("\n", commandFile);
   650 +        default: // parent
   546 +  }
   651 +            {
   547 +  fputs("\\E\n",
   652 +            commandFile = fdopen( fdcommand[ 1 ], "w" );
   548 +        commandFile);  // done as \E, so it cannot happen in normal data
   653 +            replyFile = fdopen( fdreply[ 0 ], "r" );
   549 +  fflush(commandFile);
   654 +            close( fdcommand[ 0 ] );
   550 +}
   655 +            close( fdreply[ 1 ] );
   551 Index: firefox-115.0/toolkit/xre/nsKDEUtils.h
   656 +            if( commandFile == NULL || replyFile == NULL )
   552 ===================================================================
   657 +                {
       
   658 +                closeHelper();
       
   659 +                return false;
       
   660 +                }
       
   661 +            // ok, helper ready, getKdeRunning() will check if it works
       
   662 +            }
       
   663 +        }
       
   664 +    helperFailed = false;
       
   665 +    helperRunning = true;
       
   666 +    return true;
       
   667 +    }
       
   668 +
       
   669 +void nsKDEUtils::closeHelper()
       
   670 +    {
       
   671 +    if( commandFile != NULL )
       
   672 +        fclose( commandFile ); // this will also make the helper quit
       
   673 +    if( replyFile != NULL )
       
   674 +        fclose( replyFile );
       
   675 +    helperRunning = false;
       
   676 +    }
       
   677 +
       
   678 +void nsKDEUtils::feedCommand( const nsTArray<nsCString>& command )
       
   679 +    {
       
   680 +    for( int i = 0;
       
   681 +         i < command.Length();
       
   682 +         ++i )
       
   683 +        {
       
   684 +        nsCString line = command[ i ];
       
   685 +        line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape
       
   686 +        line.ReplaceSubstring( "\n", "\\n" );
       
   687 +#ifdef DEBUG_KDE
       
   688 +        fprintf( stderr, "COMM: %s\n", line.get());
       
   689 +#endif
       
   690 +        fputs( line.get(), commandFile );
       
   691 +        fputs( "\n", commandFile );
       
   692 +        }
       
   693 +    fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data
       
   694 +    fflush( commandFile );
       
   695 +    }
       
   696 diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h
       
   697 new file mode 100644
       
   698 --- /dev/null
   553 --- /dev/null
   699 +++ b/toolkit/xre/nsKDEUtils.h
   554 +++ firefox-115.0/toolkit/xre/nsKDEUtils.h
   700 @@ -0,0 +1,48 @@
   555 @@ -0,0 +1,53 @@
   701 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   556 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   702 +/* This Source Code Form is subject to the terms of the Mozilla Public
   557 +/* This Source Code Form is subject to the terms of the Mozilla Public
   703 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   558 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   704 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   559 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   705 +
   560 +
   712 +
   567 +
   713 +typedef struct _GtkWindow GtkWindow;
   568 +typedef struct _GtkWindow GtkWindow;
   714 +
   569 +
   715 +class nsIArray;
   570 +class nsIArray;
   716 +
   571 +
   717 +class NS_EXPORT nsKDEUtils
   572 +class NS_EXPORT nsKDEUtils {
   718 +    {
   573 + public:
   719 +    public:
   574 +  /* Returns true if running inside a KDE session (regardless of whether there
   720 +        /* Returns true if running inside a KDE session (regardless of whether there is KDE
   575 +     is KDE support available for Firefox). This should be used e.g. when
   721 +           support available for Firefox). This should be used e.g. when determining
   576 +     determining dialog button order but not for code that requires the KDE
   722 +           dialog button order but not for code that requires the KDE support. */
   577 +     support. */
   723 +        static bool kdeSession();
   578 +  static bool kdeSession();
   724 +        /* Returns true if running inside a KDE session and KDE support is available
   579 +  /* Returns true if running inside a KDE session and KDE support is available
   725 +           for Firefox. This should be used everywhere where the external helper is needed. */
   580 +     for Firefox. This should be used everywhere where the external helper is
   726 +        static bool kdeSupport();
   581 +     needed. */
   727 +        /* Executes the given helper command, returns true if helper returned success. */
   582 +  static bool kdeSupport();
   728 +        static bool command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output = NULL );
   583 +  /* Executes the given helper command, returns true if helper returned success.
   729 +        static bool command( nsIArray* command, nsIArray** output = NULL );
   584 +   */
   730 +        /* Like command(), but additionally blocks the parent widget like if there was
   585 +  static bool command(const nsTArray<nsCString>& command,
   731 +           a modal dialog shown and enters the event loop (i.e. there are still paint updates,
   586 +                      nsTArray<nsCString>* output = NULL);
   732 +           this is for commands that take long). */
   587 +  static bool command(nsIArray* command, nsIArray** output = NULL);
   733 +        static bool commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output = NULL );
   588 +  /* Like command(), but additionally blocks the parent widget like if there was
   734 +
   589 +     a modal dialog shown and enters the event loop (i.e. there are still paint
   735 +    private:
   590 +     updates, this is for commands that take long). */
   736 +        nsKDEUtils();
   591 +  static bool commandBlockUi(const nsTArray<nsCString>& command,
   737 +        ~nsKDEUtils();
   592 +                             GtkWindow* parent,
   738 +        static nsKDEUtils* self();
   593 +                             nsTArray<nsCString>* output = NULL);
   739 +        bool startHelper();
   594 +
   740 +        void closeHelper();
   595 + private:
   741 +        void feedCommand( const nsTArray<nsCString>& command );
   596 +  nsKDEUtils();
   742 +        bool internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool isParent,
   597 +  ~nsKDEUtils();
   743 +            nsTArray<nsCString>* output );
   598 +  static nsKDEUtils* self();
   744 +        FILE* commandFile;
   599 +  bool startHelper();
   745 +        FILE* replyFile;
   600 +  void closeHelper();
   746 +    };
   601 +  void feedCommand(const nsTArray<nsCString>& command);
   747 +
   602 +  bool internalCommand(const nsTArray<nsCString>& command, GtkWindow* parent,
   748 +#endif // nsKDEUtils
   603 +                       bool isParent, nsTArray<nsCString>* output);
   749 diff --git a/uriloader/exthandler/HandlerServiceParent.cpp b/uriloader/exthandler/HandlerServiceParent.cpp
   604 +  FILE* commandFile;
   750 --- a/uriloader/exthandler/HandlerServiceParent.cpp
   605 +  FILE* replyFile;
   751 +++ b/uriloader/exthandler/HandlerServiceParent.cpp
   606 +};
   752 @@ -13,17 +13,17 @@
   607 +
   753  #include "ContentHandlerService.h"
   608 +#endif  // nsKDEUtils
   754  #include "nsIExternalProtocolService.h"
   609 Index: firefox-115.0/uriloader/exthandler/HandlerServiceParent.cpp
   755  #include "nsStringEnumerator.h"
   610 ===================================================================
   756  #include "nsIMutableArray.h"
   611 --- firefox-115.0.orig/uriloader/exthandler/HandlerServiceParent.cpp
   757  #include "nsCExternalHandlerService.h"
   612 +++ firefox-115.0/uriloader/exthandler/HandlerServiceParent.cpp
       
   613 @@ -18,7 +18,7 @@
   758  #include "nsComponentManagerUtils.h"
   614  #include "nsComponentManagerUtils.h"
   759  #include "nsServiceManagerUtils.h"
   615  #include "nsServiceManagerUtils.h"
   760  #ifdef MOZ_WIDGET_GTK
   616  #ifdef MOZ_WIDGET_GTK
   761 -#  include "unix/nsGNOMERegistry.h"
   617 -#  include "unix/nsGNOMERegistry.h"
   762 +#  include "unix/nsCommonRegistry.h"
   618 +#  include "unix/nsCommonRegistry.h"
   763  #endif
   619  #endif
   764  
   620  
   765  using mozilla::dom::ContentHandlerService;
   621  using mozilla::dom::ContentHandlerService;
   766  using mozilla::dom::HandlerApp;
   622 @@ -310,8 +310,8 @@ mozilla::ipc::IPCResult HandlerServicePa
   767  using mozilla::dom::HandlerInfo;
       
   768  using mozilla::dom::RemoteHandlerApp;
       
   769  
       
   770  namespace {
       
   771 @@ -306,17 +306,17 @@ mozilla::ipc::IPCResult HandlerServicePa
       
   772      const nsACString& aProtocolScheme, bool* aHandlerExists) {
       
   773    if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) {
       
   774      *aHandlerExists = false;
       
   775      return IPC_OK();
       
   776    }
   623    }
   777  #ifdef MOZ_WIDGET_GTK
   624  #ifdef MOZ_WIDGET_GTK
   778    // Check the GNOME registry for a protocol handler
   625    // Check the GNOME registry for a protocol handler
   779    *aHandlerExists =
   626 -  *aHandlerExists =
   780 -      nsGNOMERegistry::HandlerExists(PromiseFlatCString(aProtocolScheme).get());
   627 -      nsGNOMERegistry::HandlerExists(PromiseFlatCString(aProtocolScheme).get());
   781 +      nsCommonRegistry::HandlerExists(PromiseFlatCString(aProtocolScheme).get());
   628 +  *aHandlerExists = nsCommonRegistry::HandlerExists(
       
   629 +      PromiseFlatCString(aProtocolScheme).get());
   782  #else
   630  #else
   783    *aHandlerExists = false;
   631    *aHandlerExists = false;
   784  #endif
   632  #endif
   785    return IPC_OK();
   633 Index: firefox-115.0/uriloader/exthandler/moz.build
   786  }
   634 ===================================================================
   787  
   635 --- firefox-115.0.orig/uriloader/exthandler/moz.build
   788  /*
   636 +++ firefox-115.0/uriloader/exthandler/moz.build
   789   * Check if a handler exists for the provided protocol. Check the datastore
   637 @@ -86,7 +86,9 @@ else:
   790 diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
       
   791 --- a/uriloader/exthandler/moz.build
       
   792 +++ b/uriloader/exthandler/moz.build
       
   793 @@ -81,17 +81,19 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "ui
       
   794  else:
       
   795      # These files can't be built in unified mode because they redefine LOG.
       
   796      SOURCES += [
       
   797          osdir + "/nsOSHelperAppService.cpp",
       
   798      ]
       
   799  
   638  
   800  if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
   639  if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
   801      UNIFIED_SOURCES += [
   640      UNIFIED_SOURCES += [
   802 +        "unix/nsCommonRegistry.cpp",
   641 +        "unix/nsCommonRegistry.cpp",
   803          "unix/nsGNOMERegistry.cpp",
   642          "unix/nsGNOMERegistry.cpp",
   804 +        "unix/nsKDERegistry.cpp",
   643 +        "unix/nsKDERegistry.cpp",
   805          "unix/nsMIMEInfoUnix.cpp",
   644          "unix/nsMIMEInfoUnix.cpp",
   806      ]
   645      ]
   807  elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
   646  elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
   808      UNIFIED_SOURCES += [
   647 @@ -134,6 +136,7 @@ LOCAL_INCLUDES += [
   809          "android/nsMIMEInfoAndroid.cpp",
       
   810      ]
       
   811  elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
       
   812      UNIFIED_SOURCES += [
       
   813 @@ -129,16 +131,17 @@ include("/ipc/chromium/chromium-config.m
       
   814  FINAL_LIBRARY = "xul"
       
   815  
       
   816  LOCAL_INCLUDES += [
       
   817      "/docshell/base",
       
   818      "/dom/base",
       
   819      "/dom/ipc",
   648      "/dom/ipc",
   820      "/netwerk/base",
   649      "/netwerk/base",
   821      "/netwerk/protocol/http",
   650      "/netwerk/protocol/http",
   822 +    "/toolkit/xre",
   651 +    "/toolkit/xre",
   823  ]
   652  ]
   824  
   653  
   825  if CONFIG["MOZ_ENABLE_DBUS"]:
   654  if CONFIG["MOZ_ENABLE_DBUS"]:
   826      CXXFLAGS += CONFIG["MOZ_DBUS_CFLAGS"]
   655 Index: firefox-115.0/uriloader/exthandler/unix/nsCommonRegistry.cpp
   827  
   656 ===================================================================
   828  if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
       
   829      CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
       
   830      CXXFLAGS += CONFIG["MOZ_DBUS_GLIB_CFLAGS"]
       
   831 diff --git a/uriloader/exthandler/unix/nsCommonRegistry.cpp b/uriloader/exthandler/unix/nsCommonRegistry.cpp
       
   832 new file mode 100644
       
   833 --- /dev/null
   657 --- /dev/null
   834 +++ b/uriloader/exthandler/unix/nsCommonRegistry.cpp
   658 +++ firefox-115.0/uriloader/exthandler/unix/nsCommonRegistry.cpp
   835 @@ -0,0 +1,53 @@
   659 @@ -0,0 +1,42 @@
   836 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   660 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   837 +/* This Source Code Form is subject to the terms of the Mozilla Public
   661 +/* This Source Code Form is subject to the terms of the Mozilla Public
   838 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   662 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   839 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   663 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   840 +
   664 +
   843 +#include "nsGNOMERegistry.h"
   667 +#include "nsGNOMERegistry.h"
   844 +#include "nsKDERegistry.h"
   668 +#include "nsKDERegistry.h"
   845 +#include "nsString.h"
   669 +#include "nsString.h"
   846 +#include "nsKDEUtils.h"
   670 +#include "nsKDEUtils.h"
   847 +
   671 +
   848 +/* static */ bool
   672 +/* static */ bool nsCommonRegistry::HandlerExists(const char* aProtocolScheme) {
   849 +nsCommonRegistry::HandlerExists(const char *aProtocolScheme)
   673 +  if (nsKDEUtils::kdeSupport())
   850 +{
   674 +    return nsKDERegistry::HandlerExists(aProtocolScheme);
   851 +    if( nsKDEUtils::kdeSupport())
   675 +  return nsGNOMERegistry::HandlerExists(aProtocolScheme);
   852 +        return nsKDERegistry::HandlerExists( aProtocolScheme );
   676 +}
   853 +    return nsGNOMERegistry::HandlerExists( aProtocolScheme );
   677 +
   854 +}
   678 +/* static */ nsresult nsCommonRegistry::LoadURL(nsIURI* aURL) {
   855 +
   679 +  if (nsKDEUtils::kdeSupport()) return nsKDERegistry::LoadURL(aURL);
   856 +/* static */ nsresult
   680 +  return nsGNOMERegistry::LoadURL(aURL);
   857 +nsCommonRegistry::LoadURL(nsIURI *aURL)
   681 +}
   858 +{
   682 +
   859 +    if( nsKDEUtils::kdeSupport())
   683 +/* static */ void nsCommonRegistry::GetAppDescForScheme(
   860 +        return nsKDERegistry::LoadURL( aURL );
   684 +    const nsACString& aScheme, nsAString& aDesc) {
   861 +    return nsGNOMERegistry::LoadURL( aURL );
   685 +  if (nsKDEUtils::kdeSupport())
   862 +}
   686 +    return nsKDERegistry::GetAppDescForScheme(aScheme, aDesc);
   863 +
   687 +  return nsGNOMERegistry::GetAppDescForScheme(aScheme, aDesc);
   864 +/* static */ void
   688 +}
   865 +nsCommonRegistry::GetAppDescForScheme(const nsACString& aScheme,
       
   866 +                                     nsAString& aDesc)
       
   867 +{
       
   868 +    if( nsKDEUtils::kdeSupport())
       
   869 +        return nsKDERegistry::GetAppDescForScheme( aScheme, aDesc );
       
   870 +    return nsGNOMERegistry::GetAppDescForScheme( aScheme, aDesc );
       
   871 +}
       
   872 +
       
   873 +
   689 +
   874 +/* static */ already_AddRefed<nsMIMEInfoBase>
   690 +/* static */ already_AddRefed<nsMIMEInfoBase>
   875 +nsCommonRegistry::GetFromExtension(const nsACString& aFileExt)
   691 +nsCommonRegistry::GetFromExtension(const nsACString& aFileExt) {
   876 +{
   692 +  if (nsKDEUtils::kdeSupport())
   877 +    if( nsKDEUtils::kdeSupport())
   693 +    return nsKDERegistry::GetFromExtension(aFileExt);
   878 +        return nsKDERegistry::GetFromExtension( aFileExt );
   694 +  return nsGNOMERegistry::GetFromExtension(aFileExt);
   879 +    return nsGNOMERegistry::GetFromExtension( aFileExt );
   695 +}
   880 +}
   696 +
   881 +
   697 +/* static */ already_AddRefed<nsMIMEInfoBase> nsCommonRegistry::GetFromType(
   882 +/* static */ already_AddRefed<nsMIMEInfoBase>
   698 +    const nsACString& aMIMEType) {
   883 +nsCommonRegistry::GetFromType(const nsACString& aMIMEType)
   699 +  if (nsKDEUtils::kdeSupport()) return nsKDERegistry::GetFromType(aMIMEType);
   884 +{
   700 +  return nsGNOMERegistry::GetFromType(aMIMEType);
   885 +    if( nsKDEUtils::kdeSupport())
   701 +}
   886 +        return nsKDERegistry::GetFromType( aMIMEType );
   702 Index: firefox-115.0/uriloader/exthandler/unix/nsCommonRegistry.h
   887 +    return nsGNOMERegistry::GetFromType( aMIMEType );
   703 ===================================================================
   888 +}
       
   889 diff --git a/uriloader/exthandler/unix/nsCommonRegistry.h b/uriloader/exthandler/unix/nsCommonRegistry.h
       
   890 new file mode 100644
       
   891 --- /dev/null
   704 --- /dev/null
   892 +++ b/uriloader/exthandler/unix/nsCommonRegistry.h
   705 +++ firefox-115.0/uriloader/exthandler/unix/nsCommonRegistry.h
   893 @@ -0,0 +1,28 @@
   706 @@ -0,0 +1,28 @@
   894 +/* This Source Code Form is subject to the terms of the Mozilla Public
   707 +/* This Source Code Form is subject to the terms of the Mozilla Public
   895 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   708 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   896 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   709 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   897 +
   710 +
   901 +#include "nsIURI.h"
   714 +#include "nsIURI.h"
   902 +#include "nsCOMPtr.h"
   715 +#include "nsCOMPtr.h"
   903 +
   716 +
   904 +class nsMIMEInfoBase;
   717 +class nsMIMEInfoBase;
   905 +
   718 +
   906 +class nsCommonRegistry
   719 +class nsCommonRegistry {
   907 +{
       
   908 + public:
   720 + public:
   909 +  static bool HandlerExists(const char *aProtocolScheme);
   721 +  static bool HandlerExists(const char* aProtocolScheme);
   910 +
   722 +
   911 +  static nsresult LoadURL(nsIURI *aURL);
   723 +  static nsresult LoadURL(nsIURI* aURL);
   912 +
   724 +
   913 +  static void GetAppDescForScheme(const nsACString& aScheme,
   725 +  static void GetAppDescForScheme(const nsACString& aScheme, nsAString& aDesc);
   914 +                                  nsAString& aDesc);
   726 +
   915 +
   727 +  static already_AddRefed<nsMIMEInfoBase> GetFromExtension(
   916 +  static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
   728 +      const nsACString& aFileExt);
   917 +
   729 +
   918 +  static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
   730 +  static already_AddRefed<nsMIMEInfoBase> GetFromType(
       
   731 +      const nsACString& aMIMEType);
   919 +};
   732 +};
   920 +
   733 +
   921 +#endif
   734 +#endif
   922 diff --git a/uriloader/exthandler/unix/nsKDERegistry.cpp b/uriloader/exthandler/unix/nsKDERegistry.cpp
   735 Index: firefox-115.0/uriloader/exthandler/unix/nsKDERegistry.cpp
   923 new file mode 100644
   736 ===================================================================
   924 --- /dev/null
   737 --- /dev/null
   925 +++ b/uriloader/exthandler/unix/nsKDERegistry.cpp
   738 +++ firefox-115.0/uriloader/exthandler/unix/nsKDERegistry.cpp
   926 @@ -0,0 +1,89 @@
   739 @@ -0,0 +1,75 @@
   927 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   740 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   928 +/* This Source Code Form is subject to the terms of the Mozilla Public
   741 +/* This Source Code Form is subject to the terms of the Mozilla Public
   929 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   742 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   930 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   743 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   931 +
   744 +
   935 +#include "prmem.h"
   748 +#include "prmem.h"
   936 +#include "nsString.h"
   749 +#include "nsString.h"
   937 +#include "nsMIMEInfoUnix.h"
   750 +#include "nsMIMEInfoUnix.h"
   938 +#include "nsKDEUtils.h"
   751 +#include "nsKDEUtils.h"
   939 +
   752 +
   940 +/* static */ bool
   753 +/* static */ bool nsKDERegistry::HandlerExists(const char* aProtocolScheme) {
   941 +nsKDERegistry::HandlerExists(const char *aProtocolScheme)
   754 +  nsTArray<nsCString> command;
   942 +{
   755 +  command.AppendElement("HANDLEREXISTS"_ns);
   943 +    nsTArray<nsCString> command;
   756 +  command.AppendElement(nsAutoCString(aProtocolScheme));
   944 +    command.AppendElement( "HANDLEREXISTS"_ns );
   757 +  return nsKDEUtils::command(command);
   945 +    command.AppendElement( nsAutoCString( aProtocolScheme ));
   758 +}
   946 +    return nsKDEUtils::command( command );
   759 +
   947 +}
   760 +/* static */ nsresult nsKDERegistry::LoadURL(nsIURI* aURL) {
   948 +
   761 +  nsTArray<nsCString> command;
   949 +/* static */ nsresult
   762 +  command.AppendElement("OPEN"_ns);
   950 +nsKDERegistry::LoadURL(nsIURI *aURL)
   763 +  nsCString url;
   951 +{
   764 +  aURL->GetSpec(url);
   952 +    nsTArray<nsCString> command;
   765 +  command.AppendElement(url);
   953 +    command.AppendElement( "OPEN"_ns );
   766 +  bool rv = nsKDEUtils::command(command);
   954 +    nsCString url;
   767 +  if (!rv) return NS_ERROR_FAILURE;
   955 +    aURL->GetSpec( url );
   768 +
   956 +    command.AppendElement( url );
   769 +  return NS_OK;
   957 +    bool rv = nsKDEUtils::command( command );
   770 +}
   958 +    if (!rv)
   771 +
   959 +      return NS_ERROR_FAILURE;
   772 +/* static */ void nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme,
   960 +
   773 +                                                     nsAString& aDesc) {
   961 +    return NS_OK;
   774 +  nsTArray<nsCString> command;
   962 +}
   775 +  command.AppendElement("GETAPPDESCFORSCHEME"_ns);
   963 +
   776 +  command.AppendElement(aScheme);
   964 +/* static */ void
   777 +  nsTArray<nsCString> output;
   965 +nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme,
   778 +  if (nsKDEUtils::command(command, &output) && output.Length() == 1)
   966 +                                     nsAString& aDesc)
   779 +    CopyUTF8toUTF16(output[0], aDesc);
   967 +{
   780 +}
   968 +    nsTArray<nsCString> command;
   781 +
   969 +    command.AppendElement( "GETAPPDESCFORSCHEME"_ns );
   782 +/* static */ already_AddRefed<nsMIMEInfoBase> nsKDERegistry::GetFromExtension(
   970 +    command.AppendElement( aScheme );
   783 +    const nsACString& aFileExt) {
   971 +    nsTArray<nsCString> output;
   784 +  NS_ASSERTION(aFileExt[0] != '.', "aFileExt shouldn't start with a dot");
   972 +    if( nsKDEUtils::command( command, &output ) && output.Length() == 1 )
   785 +  nsTArray<nsCString> command;
   973 +        CopyUTF8toUTF16( output[ 0 ], aDesc );
   786 +  command.AppendElement("GETFROMEXTENSION"_ns);
   974 +}
   787 +  command.AppendElement(aFileExt);
   975 +
   788 +  return GetFromHelper(command);
   976 +
   789 +}
   977 +/* static */ already_AddRefed<nsMIMEInfoBase>
   790 +
   978 +nsKDERegistry::GetFromExtension(const nsACString& aFileExt)
   791 +/* static */ already_AddRefed<nsMIMEInfoBase> nsKDERegistry::GetFromType(
   979 +{
   792 +    const nsACString& aMIMEType) {
   980 +    NS_ASSERTION(aFileExt[0] != '.', "aFileExt shouldn't start with a dot");
   793 +  nsTArray<nsCString> command;
   981 +    nsTArray<nsCString> command;
   794 +  command.AppendElement("GETFROMTYPE"_ns);
   982 +    command.AppendElement( "GETFROMEXTENSION"_ns );
   795 +  command.AppendElement(aMIMEType);
   983 +    command.AppendElement( aFileExt );
   796 +  return GetFromHelper(command);
   984 +    return GetFromHelper( command );
   797 +}
   985 +}
   798 +
   986 +
   799 +/* static */ already_AddRefed<nsMIMEInfoBase> nsKDERegistry::GetFromHelper(
   987 +/* static */ already_AddRefed<nsMIMEInfoBase>
   800 +    const nsTArray<nsCString>& command) {
   988 +nsKDERegistry::GetFromType(const nsACString& aMIMEType)
   801 +  nsTArray<nsCString> output;
   989 +{
   802 +  if (nsKDEUtils::command(command, &output) && output.Length() == 3) {
   990 +    nsTArray<nsCString> command;
   803 +    nsCString mimetype = output[0];
   991 +    command.AppendElement( "GETFROMTYPE"_ns );
   804 +    RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix(mimetype);
   992 +    command.AppendElement( aMIMEType );
   805 +    NS_ENSURE_TRUE(mimeInfo, nullptr);
   993 +    return GetFromHelper( command );
   806 +    nsCString description = output[1];
   994 +}
   807 +    mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
   995 +
   808 +    nsCString handlerAppName = output[2];
   996 +/* static */ already_AddRefed<nsMIMEInfoBase>
   809 +    mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
   997 +nsKDERegistry::GetFromHelper(const nsTArray<nsCString>& command)
   810 +    mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(handlerAppName));
   998 +{
   811 +    return mimeInfo.forget();
   999 +    nsTArray<nsCString> output;
   812 +  }
  1000 +    if( nsKDEUtils::command( command, &output ) && output.Length() == 3 )
   813 +  return nullptr;
  1001 +        {
   814 +}
  1002 +        nsCString mimetype = output[ 0 ];
   815 Index: firefox-115.0/uriloader/exthandler/unix/nsKDERegistry.h
  1003 +        RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix( mimetype );
   816 ===================================================================
  1004 +        NS_ENSURE_TRUE(mimeInfo, nullptr);
       
  1005 +        nsCString description = output[ 1 ];
       
  1006 +        mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
       
  1007 +        nsCString handlerAppName = output[ 2 ];
       
  1008 +        mozilla::StaticPrefs::browser_download_improvements_to_download_panel()
       
  1009 +            ? mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk)
       
  1010 +            : mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
       
  1011 +        mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(handlerAppName));
       
  1012 +        return mimeInfo.forget();
       
  1013 +        }
       
  1014 +    return nullptr;
       
  1015 +}
       
  1016 diff --git a/uriloader/exthandler/unix/nsKDERegistry.h b/uriloader/exthandler/unix/nsKDERegistry.h
       
  1017 new file mode 100644
       
  1018 --- /dev/null
   817 --- /dev/null
  1019 +++ b/uriloader/exthandler/unix/nsKDERegistry.h
   818 +++ firefox-115.0/uriloader/exthandler/unix/nsKDERegistry.h
  1020 @@ -0,0 +1,34 @@
   819 @@ -0,0 +1,35 @@
  1021 +/* This Source Code Form is subject to the terms of the Mozilla Public
   820 +/* This Source Code Form is subject to the terms of the Mozilla Public
  1022 + * License, v. 2.0. If a copy of the MPL was not distributed with this
   821 + * License, v. 2.0. If a copy of the MPL was not distributed with this
  1023 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   822 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  1024 +
   823 +
  1025 +#ifndef nsKDERegistry_h__
   824 +#ifndef nsKDERegistry_h__
  1028 +#include "nsIURI.h"
   827 +#include "nsIURI.h"
  1029 +#include "nsCOMPtr.h"
   828 +#include "nsCOMPtr.h"
  1030 +#include "nsTArray.h"
   829 +#include "nsTArray.h"
  1031 +
   830 +
  1032 +class nsMIMEInfoBase;
   831 +class nsMIMEInfoBase;
  1033 +//class nsAutoCString;
   832 +// class nsAutoCString;
  1034 +//class nsCString;
   833 +// class nsCString;
  1035 +
   834 +
  1036 +class nsKDERegistry
   835 +class nsKDERegistry {
  1037 +{
       
  1038 + public:
   836 + public:
  1039 +  static bool HandlerExists(const char *aProtocolScheme);
   837 +  static bool HandlerExists(const char* aProtocolScheme);
  1040 +
   838 +
  1041 +  static nsresult LoadURL(nsIURI *aURL);
   839 +  static nsresult LoadURL(nsIURI* aURL);
  1042 +
   840 +
  1043 +  static void GetAppDescForScheme(const nsACString& aScheme,
   841 +  static void GetAppDescForScheme(const nsACString& aScheme, nsAString& aDesc);
  1044 +                                  nsAString& aDesc);
   842 +
  1045 +
   843 +  static already_AddRefed<nsMIMEInfoBase> GetFromExtension(
  1046 +  static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
   844 +      const nsACString& aFileExt);
  1047 +
   845 +
  1048 +  static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
   846 +  static already_AddRefed<nsMIMEInfoBase> GetFromType(
       
   847 +      const nsACString& aMIMEType);
       
   848 +
  1049 + private:
   849 + private:
  1050 +  static already_AddRefed<nsMIMEInfoBase> GetFromHelper(const nsTArray<nsCString>& command);
   850 +  static already_AddRefed<nsMIMEInfoBase> GetFromHelper(
  1051 +
   851 +      const nsTArray<nsCString>& command);
  1052 +};
   852 +};
  1053 +
   853 +
  1054 +#endif //nsKDERegistry_h__
   854 +#endif  // nsKDERegistry_h__
  1055 diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
   855 Index: firefox-115.0/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
  1056 --- a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
   856 ===================================================================
  1057 +++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
   857 --- firefox-115.0.orig/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
  1058 @@ -1,48 +1,51 @@
   858 +++ firefox-115.0/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
  1059  /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
   859 @@ -5,16 +5,19 @@
  1060   *
       
  1061   * This Source Code Form is subject to the terms of the Mozilla Public
       
  1062   * License, v. 2.0. If a copy of the MPL was not distributed with this
       
  1063   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   860   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  1064  
   861  
  1065  #include "nsMIMEInfoUnix.h"
   862  #include "nsMIMEInfoUnix.h"
  1066 -#include "nsGNOMERegistry.h"
   863 -#include "nsGNOMERegistry.h"
  1067 +#include "nsCommonRegistry.h"
   864 +#include "nsCommonRegistry.h"
  1070  #include "nsIIOService.h"
   867  #include "nsIIOService.h"
  1071  #ifdef MOZ_ENABLE_DBUS
   868  #ifdef MOZ_ENABLE_DBUS
  1072  #  include "nsDBusHandlerApp.h"
   869  #  include "nsDBusHandlerApp.h"
  1073  #endif
   870  #endif
  1074 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
   871 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
  1075 +#include "nsKDEUtils.h"
   872 +#  include "nsKDEUtils.h"
  1076 +#endif
   873 +#endif
  1077  
   874  
  1078  nsresult nsMIMEInfoUnix::LoadUriInternal(nsIURI* aURI) {
   875  nsresult nsMIMEInfoUnix::LoadUriInternal(nsIURI* aURI) {
  1079 -  return nsGNOMERegistry::LoadURL(aURI);
   876 -  return nsGNOMERegistry::LoadURL(aURI);
  1080 +  return nsCommonRegistry::LoadURL(aURI);
   877 +  return nsCommonRegistry::LoadURL(aURI);
  1081  }
   878  }
  1082  
   879  
  1083  NS_IMETHODIMP
   880  NS_IMETHODIMP
  1084  nsMIMEInfoUnix::GetHasDefaultHandler(bool* _retval) {
   881 @@ -29,15 +32,15 @@ nsMIMEInfoUnix::GetHasDefaultHandler(boo
  1085    // if a default app is set, it means the application has been set from
       
  1086    // either /etc/mailcap or ${HOME}/.mailcap, in which case we don't want to
       
  1087    // give the GNOME answer.
       
  1088    if (GetDefaultApplication()) {
       
  1089      return nsMIMEInfoImpl::GetHasDefaultHandler(_retval);
       
  1090    }
       
  1091  
       
  1092    *_retval = false;
   882    *_retval = false;
  1093  
   883  
  1094    if (mClass == eProtocolInfo) {
   884    if (mClass == eProtocolInfo) {
  1095 -    *_retval = nsGNOMERegistry::HandlerExists(mSchemeOrType.get());
   885 -    *_retval = nsGNOMERegistry::HandlerExists(mSchemeOrType.get());
  1096 +    *_retval = nsCommonRegistry::HandlerExists(mSchemeOrType.get());
   886 +    *_retval = nsCommonRegistry::HandlerExists(mSchemeOrType.get());
  1105 -        mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
   895 -        mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
  1106 +        mimeInfo = nsCommonRegistry::GetFromExtension(ext);
   896 +        mimeInfo = nsCommonRegistry::GetFromExtension(ext);
  1107        }
   897        }
  1108      }
   898      }
  1109      if (mimeInfo) *_retval = true;
   899      if (mimeInfo) *_retval = true;
  1110    }
   900 @@ -59,6 +62,21 @@ nsresult nsMIMEInfoUnix::LaunchDefaultWi
  1111  
       
  1112    if (*_retval) return NS_OK;
       
  1113  
       
  1114    return NS_OK;
       
  1115 @@ -54,16 +57,33 @@ nsresult nsMIMEInfoUnix::LaunchDefaultWi
       
  1116    // give the GNOME answer.
       
  1117    if (GetDefaultApplication()) {
       
  1118      return nsMIMEInfoImpl::LaunchDefaultWithFile(aFile);
       
  1119    }
       
  1120  
       
  1121    nsAutoCString nativePath;
   901    nsAutoCString nativePath;
  1122    aFile->GetNativePath(nativePath);
   902    aFile->GetNativePath(nativePath);
  1123  
   903  
  1124 +  if( nsKDEUtils::kdeSupport()) {
   904 +  if (nsKDEUtils::kdeSupport()) {
  1125 +    bool supports;
   905 +    bool supports;
  1126 +    if( NS_SUCCEEDED( GetHasDefaultHandler( &supports )) && supports ) {
   906 +    if (NS_SUCCEEDED(GetHasDefaultHandler(&supports)) && supports) {
  1127 +      nsTArray<nsCString> command;
   907 +      nsTArray<nsCString> command;
  1128 +      command.AppendElement( "OPEN"_ns );
   908 +      command.AppendElement("OPEN"_ns);
  1129 +      command.AppendElement( nativePath );
   909 +      command.AppendElement(nativePath);
  1130 +      command.AppendElement( "MIMETYPE"_ns );
   910 +      command.AppendElement("MIMETYPE"_ns);
  1131 +      command.AppendElement( mSchemeOrType );
   911 +      command.AppendElement(mSchemeOrType);
  1132 +      if( nsKDEUtils::command( command ))
   912 +      if (nsKDEUtils::command(command)) return NS_OK;
  1133 +        return NS_OK;
       
  1134 +    }
   913 +    }
  1135 +    if (!GetDefaultApplication())
   914 +    if (!GetDefaultApplication()) return NS_ERROR_FILE_NOT_FOUND;
  1136 +      return NS_ERROR_FILE_NOT_FOUND;
       
  1137 +
   915 +
  1138 +    return LaunchWithIProcess(GetDefaultApplication(), nativePath);
   916 +    return LaunchWithIProcess(GetDefaultApplication(), nativePath);
  1139 +  }
   917 +  }
  1140 +
   918 +
  1141    nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
   919    nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  1142    if (!giovfs) {
   920    if (!giovfs) {
  1143      return NS_ERROR_FAILURE;
   921      return NS_ERROR_FAILURE;
  1144    }
   922 Index: firefox-115.0/uriloader/exthandler/unix/nsOSHelperAppService.cpp
  1145  
   923 ===================================================================
  1146    // nsGIOMimeApp->Launch wants a URI string instead of local file
   924 --- firefox-115.0.orig/uriloader/exthandler/unix/nsOSHelperAppService.cpp
  1147    nsresult rv;
   925 +++ firefox-115.0/uriloader/exthandler/unix/nsOSHelperAppService.cpp
  1148    nsCOMPtr<nsIIOService> ioservice =
   926 @@ -10,7 +10,7 @@
  1149 diff --git a/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
       
  1150 --- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp
       
  1151 +++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
       
  1152 @@ -5,17 +5,17 @@
       
  1153   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       
  1154  
       
  1155  #include <sys/types.h>
       
  1156  #include <sys/stat.h>
       
  1157  
       
  1158  #include "nsOSHelperAppService.h"
   927  #include "nsOSHelperAppService.h"
  1159  #include "nsMIMEInfoUnix.h"
   928  #include "nsMIMEInfoUnix.h"
  1160  #ifdef MOZ_WIDGET_GTK
   929  #ifdef MOZ_WIDGET_GTK
  1161 -#  include "nsGNOMERegistry.h"
   930 -#  include "nsGNOMERegistry.h"
  1162 +#  include "nsCommonRegistry.h"
   931 +#  include "nsCommonRegistry.h"
  1163  #  ifdef MOZ_BUILD_APP_IS_BROWSER
   932  #  ifdef MOZ_BUILD_APP_IS_BROWSER
  1164  #    include "nsIToolkitShellService.h"
   933  #    include "nsIToolkitShellService.h"
  1165  #    include "nsIGNOMEShellService.h"
   934  #    include "nsIGNOMEShellService.h"
  1166  #  endif
   935 @@ -1106,7 +1106,7 @@ nsresult nsOSHelperAppService::OSProtoco
  1167  #endif
       
  1168  #include "nsISupports.h"
       
  1169  #include "nsString.h"
       
  1170  #include "nsReadableUtils.h"
       
  1171 @@ -1102,17 +1102,17 @@ nsresult nsOSHelperAppService::GetHandle
       
  1172  
       
  1173  nsresult nsOSHelperAppService::OSProtocolHandlerExists(
       
  1174      const char* aProtocolScheme, bool* aHandlerExists) {
       
  1175    nsresult rv = NS_OK;
       
  1176  
       
  1177    if (!XRE_IsContentProcess()) {
   936    if (!XRE_IsContentProcess()) {
  1178  #ifdef MOZ_WIDGET_GTK
   937  #ifdef MOZ_WIDGET_GTK
  1179      // Check the GNOME registry for a protocol handler
   938      // Check the GNOME registry for a protocol handler
  1180 -    *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
   939 -    *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
  1181 +    *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
   940 +    *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
  1182  #else
   941  #else
  1183      *aHandlerExists = false;
   942      *aHandlerExists = false;
  1184  #endif
   943  #endif
  1185    } else {
   944 @@ -1126,7 +1126,7 @@ nsresult nsOSHelperAppService::OSProtoco
  1186      *aHandlerExists = false;
       
  1187      nsCOMPtr<nsIHandlerService> handlerSvc =
       
  1188          do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv);
       
  1189      if (NS_SUCCEEDED(rv) && handlerSvc) {
       
  1190 @@ -1122,17 +1122,17 @@ nsresult nsOSHelperAppService::OSProtoco
       
  1191    }
       
  1192  
       
  1193    return rv;
       
  1194  }
       
  1195  
       
  1196  NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
   945  NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
  1197      const nsACString& aScheme, nsAString& _retval) {
   946      const nsACString& aScheme, nsAString& _retval) {
  1198  #ifdef MOZ_WIDGET_GTK
   947  #ifdef MOZ_WIDGET_GTK
  1199 -  nsGNOMERegistry::GetAppDescForScheme(aScheme, _retval);
   948 -  nsGNOMERegistry::GetAppDescForScheme(aScheme, _retval);
  1200 +  nsCommonRegistry::GetAppDescForScheme(aScheme, _retval);
   949 +  nsCommonRegistry::GetAppDescForScheme(aScheme, _retval);
  1201    return _retval.IsEmpty() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
   950    return _retval.IsEmpty() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
  1202  #else
   951  #else
  1203    return NS_ERROR_NOT_AVAILABLE;
   952    return NS_ERROR_NOT_AVAILABLE;
  1204  #endif
   953 @@ -1231,7 +1231,7 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel
  1205  }
       
  1206  
       
  1207  NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
       
  1208      const nsACString& aScheme, bool* _retval) {
       
  1209 @@ -1227,17 +1227,17 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel
       
  1210    nsresult rv =
       
  1211        LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt), majorType,
       
  1212                                 minorType, mime_types_description, true);
       
  1213  
       
  1214    if (NS_FAILED(rv) || majorType.IsEmpty()) {
       
  1215  #ifdef MOZ_WIDGET_GTK
   954  #ifdef MOZ_WIDGET_GTK
  1216      LOG("Looking in GNOME registry\n");
   955      LOG("Looking in GNOME registry\n");
  1217      RefPtr<nsMIMEInfoBase> gnomeInfo =
   956      RefPtr<nsMIMEInfoBase> gnomeInfo =
  1218 -        nsGNOMERegistry::GetFromExtension(aFileExt);
   957 -        nsGNOMERegistry::GetFromExtension(aFileExt);
  1219 +        nsCommonRegistry::GetFromExtension(aFileExt);
   958 +        nsCommonRegistry::GetFromExtension(aFileExt);
  1220      if (gnomeInfo) {
   959      if (gnomeInfo) {
  1221        LOG("Got MIMEInfo from GNOME registry\n");
   960        LOG("Got MIMEInfo from GNOME registry\n");
  1222        return gnomeInfo.forget();
   961        return gnomeInfo.forget();
  1223      }
   962 @@ -1344,7 +1344,7 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel
  1224  #endif
       
  1225  
       
  1226      rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt), majorType,
       
  1227                                    minorType, mime_types_description, false);
       
  1228 @@ -1342,17 +1342,17 @@ already_AddRefed<nsMIMEInfoBase> nsOSHel
       
  1229  
       
  1230    // Now look up our extensions
       
  1231    nsAutoString extensions, mime_types_description;
       
  1232    LookUpExtensionsAndDescription(majorType, minorType, extensions,
       
  1233                                   mime_types_description);
       
  1234  
   963  
  1235  #ifdef MOZ_WIDGET_GTK
   964  #ifdef MOZ_WIDGET_GTK
  1236    if (handler.IsEmpty()) {
   965    if (handler.IsEmpty()) {
  1237 -    RefPtr<nsMIMEInfoBase> gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
   966 -    RefPtr<nsMIMEInfoBase> gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
  1238 +    RefPtr<nsMIMEInfoBase> gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType);
   967 +    RefPtr<nsMIMEInfoBase> gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType);
  1239      if (gnomeInfo) {
   968      if (gnomeInfo) {
  1240        LOG("Got MIMEInfo from GNOME registry without extensions; setting them "
   969        LOG("Got MIMEInfo from GNOME registry without extensions; setting them "
  1241            "to %s\n",
   970            "to %s\n",
  1242            NS_LossyConvertUTF16toASCII(extensions).get());
   971 Index: firefox-115.0/widget/gtk/moz.build
  1243  
   972 ===================================================================
  1244        NS_ASSERTION(!gnomeInfo->HasExtensions(), "How'd that happen?");
   973 --- firefox-115.0.orig/widget/gtk/moz.build
  1245        gnomeInfo->SetFileExtensions(NS_ConvertUTF16toUTF8(extensions));
   974 +++ firefox-115.0/widget/gtk/moz.build
  1246        return gnomeInfo.forget();
   975 @@ -149,6 +149,7 @@ LOCAL_INCLUDES += [
  1247 diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build
       
  1248 --- a/widget/gtk/moz.build
       
  1249 +++ b/widget/gtk/moz.build
       
  1250 @@ -142,16 +142,17 @@ FINAL_LIBRARY = "xul"
       
  1251  
       
  1252  LOCAL_INCLUDES += [
       
  1253      "/layout/base",
       
  1254      "/layout/forms",
       
  1255      "/layout/generic",
       
  1256      "/layout/xul",
   976      "/layout/xul",
  1257      "/other-licenses/atk-1.0",
   977      "/other-licenses/atk-1.0",
  1258      "/third_party/cups/include",
   978      "/third_party/cups/include",
  1259 +    "/toolkit/xre",
   979 +    "/toolkit/xre",
  1260      "/widget",
   980      "/widget",
  1261      "/widget/headless",
   981      "/widget/headless",
  1262  ]
   982  ]
  1263  
   983 Index: firefox-115.0/widget/gtk/nsFilePicker.cpp
  1264  if CONFIG["MOZ_X11"] or CONFIG["MOZ_WAYLAND"]:
   984 ===================================================================
  1265      LOCAL_INCLUDES += [
   985 --- firefox-115.0.orig/widget/gtk/nsFilePicker.cpp
  1266          "/widget/x11",
   986 +++ firefox-115.0/widget/gtk/nsFilePicker.cpp
  1267      ]
   987 @@ -5,6 +5,7 @@
  1268 diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp
       
  1269 --- a/widget/gtk/nsFilePicker.cpp
       
  1270 +++ b/widget/gtk/nsFilePicker.cpp
       
  1271 @@ -1,15 +1,16 @@
       
  1272  /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       
  1273  /* This Source Code Form is subject to the terms of the Mozilla Public
       
  1274   * License, v. 2.0. If a copy of the MPL was not distributed with this
       
  1275   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       
  1276  
   988  
  1277  #include <dlfcn.h>
   989  #include <dlfcn.h>
  1278  #include <gtk/gtk.h>
   990  #include <gtk/gtk.h>
  1279 +#include <gdk/gdkx.h>
   991 +#include <gdk/gdkx.h>
  1280  #include <sys/types.h>
   992  #include <sys/types.h>
  1281  #include <sys/stat.h>
   993  #include <sys/stat.h>
  1282  #include <unistd.h>
   994  #include <unistd.h>
  1283  
   995 @@ -28,6 +29,8 @@
  1284  #include "mozilla/Types.h"
       
  1285  #include "nsGtkUtils.h"
       
  1286  #include "nsIFileURL.h"
       
  1287  #include "nsIGIOService.h"
       
  1288 @@ -23,16 +24,18 @@
       
  1289  #include "nsArrayEnumerator.h"
       
  1290  #include "nsEnumeratorUtils.h"
       
  1291  #include "nsNetUtil.h"
       
  1292  #include "nsReadableUtils.h"
       
  1293  #include "MozContainer.h"
       
  1294  #include "WidgetUtilsGtk.h"
   996  #include "WidgetUtilsGtk.h"
  1295  
   997  
  1296  #include "nsFilePicker.h"
   998  #include "nsFilePicker.h"
  1297 +#include "nsKDEUtils.h"
   999 +#include "nsKDEUtils.h"
  1298 +#include "nsURLHelper.h"
  1000 +#include "nsURLHelper.h"
  1299  
  1001  
  1300  #undef LOG
  1002  #undef LOG
  1301  #ifdef MOZ_LOGGING
  1003  #ifdef MOZ_LOGGING
  1302  #  include "mozilla/Logging.h"
  1004 @@ -242,7 +245,8 @@ NS_IMETHODIMP
  1303  #  include "nsTArray.h"
       
  1304  #  include "Units.h"
       
  1305  extern mozilla::LazyLogModule gWidgetLog;
       
  1306  #  define LOG(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
       
  1307 @@ -237,17 +240,19 @@ nsFilePicker::AppendFilters(int32_t aFil
       
  1308    mAllowURLs = !!(aFilterMask & filterAllowURLs);
       
  1309    return nsBaseFilePicker::AppendFilters(aFilterMask);
       
  1310  }
       
  1311  
       
  1312  NS_IMETHODIMP
       
  1313  nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter) {
  1005  nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter) {
  1314    if (aFilter.EqualsLiteral("..apps")) {
  1006    if (aFilter.EqualsLiteral("..apps")) {
  1315      // No platform specific thing we can do here, really....
  1007      // No platform specific thing we can do here, really....
  1316 -    return NS_OK;
  1008 -    return NS_OK;
  1317 +    // Unless it's KDE.
  1009 +    // Unless it's KDE.
  1318 +    if( mMode != modeOpen || !nsKDEUtils::kdeSupport())
  1010 +    if (mMode != modeOpen || !nsKDEUtils::kdeSupport()) return NS_OK;
  1319 +      return NS_OK;
       
  1320    }
  1011    }
  1321  
  1012  
  1322    nsAutoCString filter, name;
  1013    nsAutoCString filter, name;
  1323    CopyUTF16toUTF8(aFilter, filter);
  1014 @@ -352,6 +356,31 @@ nsFilePicker::Open(nsIFilePickerShownCal
  1324    CopyUTF16toUTF8(aTitle, name);
       
  1325  
       
  1326    mFilters.AppendElement(filter);
       
  1327    mFilterNames.AppendElement(name);
       
  1328 @@ -347,16 +352,39 @@ nsresult nsFilePicker::Show(nsIFilePicke
       
  1329    return NS_OK;
       
  1330  }
       
  1331  
       
  1332  NS_IMETHODIMP
       
  1333  nsFilePicker::Open(nsIFilePickerShownCallback* aCallback) {
       
  1334    // Can't show two dialogs concurrently with the same filepicker
  1015    // Can't show two dialogs concurrently with the same filepicker
  1335    if (mRunning) return NS_ERROR_NOT_AVAILABLE;
  1016    if (mRunning) return NS_ERROR_NOT_AVAILABLE;
  1336  
  1017  
  1337 +  // KDE file picker is not handled via callback
  1018 +  // KDE file picker is not handled via callback
  1338 +  if( nsKDEUtils::kdeSupport()) {
  1019 +  if (nsKDEUtils::kdeSupport()) {
  1339 +    mCallback = aCallback;
  1020 +    mCallback = aCallback;
  1340 +    mRunning = true;
  1021 +    mRunning = true;
  1341 +    NS_ADDREF_THIS();
  1022 +    NS_ADDREF_THIS();
  1342 +    g_idle_add([](gpointer data) -> gboolean {
  1023 +    g_idle_add(
  1343 +      nsFilePicker* queuedPicker = (nsFilePicker*) data;
  1024 +        [](gpointer data) -> gboolean {
  1344 +      nsIFilePicker::ResultCode result;
  1025 +          nsFilePicker* queuedPicker = (nsFilePicker*)data;
  1345 +      queuedPicker->kdeFileDialog(&result);
  1026 +          nsIFilePicker::ResultCode result;
  1346 +      if (queuedPicker->mCallback) {
  1027 +          queuedPicker->kdeFileDialog(&result);
  1347 +        queuedPicker->mCallback->Done(result);
  1028 +          if (queuedPicker->mCallback) {
  1348 +        queuedPicker->mCallback = nullptr;
  1029 +            queuedPicker->mCallback->Done(result);
  1349 +      } else {
  1030 +            queuedPicker->mCallback = nullptr;
  1350 +        queuedPicker->mResult = result;
  1031 +          } else {
  1351 +      }
  1032 +            queuedPicker->mResult = result;
  1352 +      queuedPicker->mRunning = false;
  1033 +          }
  1353 +      NS_RELEASE(queuedPicker);
  1034 +          queuedPicker->mRunning = false;
  1354 +      return G_SOURCE_REMOVE;
  1035 +          NS_RELEASE(queuedPicker);
  1355 +    }, this);
  1036 +          return G_SOURCE_REMOVE;
       
  1037 +        },
       
  1038 +        this);
  1356 +
  1039 +
  1357 +    return NS_OK;
  1040 +    return NS_OK;
  1358 +  }
  1041 +  }
  1359 +
  1042 +
  1360    NS_ConvertUTF16toUTF8 title(mTitle);
  1043    NS_ConvertUTF16toUTF8 title(mTitle);
  1361  
  1044  
  1362    GtkWindow* parent_widget =
  1045    GtkWindow* parent_widget =
  1363        GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
  1046 @@ -633,6 +662,205 @@ void nsFilePicker::Done(void* file_choos
  1364  
       
  1365    GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
       
  1366  
       
  1367    const gchar* accept_button;
       
  1368 @@ -628,16 +656,244 @@ void nsFilePicker::Done(void* file_choos
       
  1369      mCallback->Done(result);
       
  1370      mCallback = nullptr;
       
  1371    } else {
       
  1372      mResult = result;
       
  1373    }
       
  1374    NS_RELEASE_THIS();
  1047    NS_RELEASE_THIS();
  1375  }
  1048  }
  1376  
  1049  
  1377 +nsCString nsFilePicker::kdeMakeFilter( int index )
  1050 +nsCString nsFilePicker::kdeMakeFilter(int index) {
  1378 +    {
  1051 +  nsCString buf = mFilters[index];
  1379 +    nsCString buf = mFilters[ index ];
  1052 +  for (PRUint32 i = 0; i < buf.Length(); ++i)
  1380 +    for( PRUint32 i = 0;
  1053 +    if (buf[i] == ';')  // KDE separates just using spaces
  1381 +         i < buf.Length();
  1054 +      buf.SetCharAt(' ', i);
  1382 +         ++i )
  1055 +  if (!mFilterNames[index].IsEmpty()) {
  1383 +        if( buf[ i ] == ';' ) // KDE separates just using spaces
  1056 +    buf += "|";
  1384 +            buf.SetCharAt( ' ', i );
  1057 +    buf += mFilterNames[index].get();
  1385 +    if (!mFilterNames[index].IsEmpty())
  1058 +  }
  1386 +        {
  1059 +  return buf;
  1387 +        buf += "|";
  1060 +}
  1388 +        buf += mFilterNames[index].get();
  1061 +
  1389 +        }
  1062 +static PRInt32 windowToXid(nsIWidget* widget) {
  1390 +    return buf;
  1063 +  GtkWindow* parent_widget =
       
  1064 +      GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
       
  1065 +  GdkWindow* gdk_window =
       
  1066 +      gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(parent_widget)));
       
  1067 +  return GDK_WINDOW_XID(gdk_window);
       
  1068 +}
       
  1069 +
       
  1070 +NS_IMETHODIMP nsFilePicker::kdeFileDialog(nsIFilePicker::ResultCode* aReturn) {
       
  1071 +  NS_ENSURE_ARG_POINTER(aReturn);
       
  1072 +
       
  1073 +  if (mMode == modeOpen && mFilters.Length() == 1 &&
       
  1074 +      mFilters[0].EqualsLiteral("..apps"))
       
  1075 +    return kdeAppsDialog(aReturn);
       
  1076 +
       
  1077 +  nsCString title;
       
  1078 +  title.Adopt(ToNewUTF8String(mTitle));
       
  1079 +
       
  1080 +  const char* arg = NULL;
       
  1081 +  if (mAllowURLs) {
       
  1082 +    switch (mMode) {
       
  1083 +      case nsIFilePicker::modeOpen:
       
  1084 +      case nsIFilePicker::modeOpenMultiple:
       
  1085 +        arg = "GETOPENURL";
       
  1086 +        break;
       
  1087 +      case nsIFilePicker::modeSave:
       
  1088 +        arg = "GETSAVEURL";
       
  1089 +        break;
       
  1090 +      case nsIFilePicker::modeGetFolder:
       
  1091 +        arg = "GETDIRECTORYURL";
       
  1092 +        break;
  1391 +    }
  1093 +    }
  1392 +
  1094 +  } else {
  1393 +static PRInt32 windowToXid( nsIWidget* widget )
  1095 +    switch (mMode) {
  1394 +    {
  1096 +      case nsIFilePicker::modeOpen:
  1395 +    GtkWindow *parent_widget = GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
  1097 +      case nsIFilePicker::modeOpenMultiple:
  1396 +    GdkWindow* gdk_window = gtk_widget_get_window( gtk_widget_get_toplevel( GTK_WIDGET( parent_widget )));
  1098 +        arg = "GETOPENFILENAME";
  1397 +    return GDK_WINDOW_XID( gdk_window );
  1099 +        break;
       
  1100 +      case nsIFilePicker::modeSave:
       
  1101 +        arg = "GETSAVEFILENAME";
       
  1102 +        break;
       
  1103 +      case nsIFilePicker::modeGetFolder:
       
  1104 +        arg = "GETDIRECTORYFILENAME";
       
  1105 +        break;
  1398 +    }
  1106 +    }
  1399 +
  1107 +  }
  1400 +NS_IMETHODIMP nsFilePicker::kdeFileDialog(nsIFilePicker::ResultCode *aReturn)
       
  1401 +    {
       
  1402 +    NS_ENSURE_ARG_POINTER(aReturn);
       
  1403 +
       
  1404 +    if( mMode == modeOpen && mFilters.Length() == 1 && mFilters[ 0 ].EqualsLiteral( "..apps" ))
       
  1405 +        return kdeAppsDialog( aReturn );
       
  1406 +
       
  1407 +    nsCString title;
       
  1408 +    title.Adopt(ToNewUTF8String(mTitle));
       
  1409 +
       
  1410 +    const char* arg = NULL;
       
  1411 +    if( mAllowURLs )
       
  1412 +        {
       
  1413 +        switch( mMode )
       
  1414 +            {
       
  1415 +            case nsIFilePicker::modeOpen:
       
  1416 +            case nsIFilePicker::modeOpenMultiple:
       
  1417 +                arg = "GETOPENURL";
       
  1418 +                break;
       
  1419 +            case nsIFilePicker::modeSave:
       
  1420 +                arg = "GETSAVEURL";
       
  1421 +                break;
       
  1422 +            case nsIFilePicker::modeGetFolder:
       
  1423 +                arg = "GETDIRECTORYURL";
       
  1424 +                break;
       
  1425 +            }
       
  1426 +        }
       
  1427 +    else
       
  1428 +        {
       
  1429 +        switch( mMode )
       
  1430 +            {
       
  1431 +            case nsIFilePicker::modeOpen:
       
  1432 +            case nsIFilePicker::modeOpenMultiple:
       
  1433 +                arg = "GETOPENFILENAME";
       
  1434 +                break;
       
  1435 +            case nsIFilePicker::modeSave:
       
  1436 +                arg = "GETSAVEFILENAME";
       
  1437 +                break;
       
  1438 +            case nsIFilePicker::modeGetFolder:
       
  1439 +                arg = "GETDIRECTORYFILENAME";
       
  1440 +                break;
       
  1441 +            }
       
  1442 +        }
       
  1443 +
  1108 +
  1444 +  nsAutoCString directory;
  1109 +  nsAutoCString directory;
  1445 +  if (mDisplayDirectory) {
  1110 +  if (mDisplayDirectory) {
  1446 +    mDisplayDirectory->GetNativePath(directory);
  1111 +    mDisplayDirectory->GetNativePath(directory);
  1447 +  } else if (mPrevDisplayDirectory) {
  1112 +  } else if (mPrevDisplayDirectory) {
  1448 +    mPrevDisplayDirectory->GetNativePath(directory);
  1113 +    mPrevDisplayDirectory->GetNativePath(directory);
  1449 +  }
  1114 +  }
  1450 +
  1115 +
  1451 +    nsAutoCString startdir;
  1116 +  nsAutoCString startdir;
  1452 +  if (!directory.IsEmpty()) {
  1117 +  if (!directory.IsEmpty()) {
  1453 +    startdir = directory;
  1118 +    startdir = directory;
  1454 +  }
  1119 +  }
  1455 +  if (mMode == nsIFilePicker::modeSave) {
  1120 +  if (mMode == nsIFilePicker::modeSave) {
  1456 +    if( !startdir.IsEmpty())
  1121 +    if (!startdir.IsEmpty()) {
  1457 +      {
       
  1458 +      startdir += "/";
  1122 +      startdir += "/";
  1459 +      startdir += ToNewUTF8String(mDefault);
  1123 +      startdir += ToNewUTF8String(mDefault);
       
  1124 +    } else
       
  1125 +      startdir = ToNewUTF8String(mDefault);
       
  1126 +  }
       
  1127 +
       
  1128 +  nsAutoCString filters;
       
  1129 +  PRInt32 count = mFilters.Length();
       
  1130 +  if (count == 0)  // just in case
       
  1131 +    filters = "*";
       
  1132 +  else {
       
  1133 +    filters = kdeMakeFilter(0);
       
  1134 +    for (PRInt32 i = 1; i < count; ++i) {
       
  1135 +      filters += "\n";
       
  1136 +      filters += kdeMakeFilter(i);
       
  1137 +    }
       
  1138 +  }
       
  1139 +
       
  1140 +  nsTArray<nsCString> command;
       
  1141 +  command.AppendElement(nsAutoCString(arg));
       
  1142 +  command.AppendElement(startdir);
       
  1143 +  if (mMode != nsIFilePicker::modeGetFolder) {
       
  1144 +    command.AppendElement(filters);
       
  1145 +    nsAutoCString selected;
       
  1146 +    selected.AppendInt(mSelectedType);
       
  1147 +    command.AppendElement(selected);
       
  1148 +  }
       
  1149 +  command.AppendElement(title);
       
  1150 +  if (mMode == nsIFilePicker::modeOpenMultiple)
       
  1151 +    command.AppendElement("MULTIPLE"_ns);
       
  1152 +  if (PRInt32 xid = windowToXid(mParentWidget)) {
       
  1153 +    command.AppendElement("PARENT"_ns);
       
  1154 +    nsAutoCString parent;
       
  1155 +    parent.AppendInt(xid);
       
  1156 +    command.AppendElement(parent);
       
  1157 +  }
       
  1158 +
       
  1159 +  nsTArray<nsCString> output;
       
  1160 +  if (nsKDEUtils::commandBlockUi(
       
  1161 +          command,
       
  1162 +          GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)),
       
  1163 +          &output)) {
       
  1164 +    *aReturn = nsIFilePicker::returnOK;
       
  1165 +    mFiles.Clear();
       
  1166 +    if (mMode != nsIFilePicker::modeGetFolder) {
       
  1167 +      mSelectedType = atoi(output[0].get());
       
  1168 +      output.RemoveElementAt(0);
       
  1169 +    }
       
  1170 +    if (mMode == nsIFilePicker::modeOpenMultiple) {
       
  1171 +      mFileURL.Truncate();
       
  1172 +      PRUint32 count = output.Length();
       
  1173 +      for (PRUint32 i = 0; i < count; ++i) {
       
  1174 +        nsCOMPtr<nsIFile> localfile;
       
  1175 +        nsresult rv = NS_NewNativeLocalFile(output[i], PR_FALSE,
       
  1176 +                                            getter_AddRefs(localfile));
       
  1177 +        if (NS_SUCCEEDED(rv)) mFiles.AppendObject(localfile);
  1460 +      }
  1178 +      }
  1461 +    else
  1179 +    } else {
  1462 +      startdir = ToNewUTF8String(mDefault);
  1180 +      if (output.Length() == 0)
  1463 +  }
  1181 +        mFileURL = nsCString();
  1464 +
  1182 +      else if (mAllowURLs)
  1465 +    nsAutoCString filters;
  1183 +        mFileURL = output[0];
  1466 +    PRInt32 count = mFilters.Length();
  1184 +      else  // GetFile() actually requires it to be url even for local files :-/
  1467 +    if( count == 0 ) //just in case
  1185 +      {
  1468 +        filters = "*";
  1186 +        nsCOMPtr<nsIFile> localfile;
  1469 +    else
  1187 +        nsresult rv = NS_NewNativeLocalFile(output[0], PR_FALSE,
  1470 +        {
  1188 +                                            getter_AddRefs(localfile));
  1471 +        filters = kdeMakeFilter( 0 );
  1189 +        if (NS_SUCCEEDED(rv))
  1472 +        for (PRInt32 i = 1; i < count; ++i)
  1190 +          rv = net_GetURLSpecFromActualFile(localfile, mFileURL);
  1473 +            {
  1191 +      }
  1474 +            filters += "\n";
       
  1475 +            filters += kdeMakeFilter( i );
       
  1476 +            }
       
  1477 +        }
       
  1478 +
       
  1479 +    nsTArray<nsCString> command;
       
  1480 +    command.AppendElement( nsAutoCString( arg ));
       
  1481 +    command.AppendElement( startdir );
       
  1482 +    if( mMode != nsIFilePicker::modeGetFolder )
       
  1483 +        {
       
  1484 +        command.AppendElement( filters );
       
  1485 +        nsAutoCString selected;
       
  1486 +        selected.AppendInt( mSelectedType );
       
  1487 +        command.AppendElement( selected );
       
  1488 +        }
       
  1489 +    command.AppendElement( title );
       
  1490 +    if( mMode == nsIFilePicker::modeOpenMultiple )
       
  1491 +        command.AppendElement( "MULTIPLE"_ns );
       
  1492 +    if( PRInt32 xid = windowToXid( mParentWidget ))
       
  1493 +        {
       
  1494 +        command.AppendElement( "PARENT"_ns );
       
  1495 +        nsAutoCString parent;
       
  1496 +        parent.AppendInt( xid );
       
  1497 +        command.AppendElement( parent );
       
  1498 +        }
       
  1499 +
       
  1500 +    nsTArray<nsCString> output;
       
  1501 +    if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
       
  1502 +        {
       
  1503 +        *aReturn = nsIFilePicker::returnOK;
       
  1504 +        mFiles.Clear();
       
  1505 +        if( mMode != nsIFilePicker::modeGetFolder )
       
  1506 +            {
       
  1507 +            mSelectedType = atoi( output[ 0 ].get());
       
  1508 +            output.RemoveElementAt( 0 );
       
  1509 +            }
       
  1510 +        if (mMode == nsIFilePicker::modeOpenMultiple)
       
  1511 +            {
       
  1512 +            mFileURL.Truncate();
       
  1513 +            PRUint32 count = output.Length();
       
  1514 +            for( PRUint32 i = 0;
       
  1515 +                 i < count;
       
  1516 +                 ++i )
       
  1517 +                {
       
  1518 +                nsCOMPtr<nsIFile> localfile;
       
  1519 +                nsresult rv = NS_NewNativeLocalFile( output[ i ],
       
  1520 +                                      PR_FALSE,
       
  1521 +                                      getter_AddRefs(localfile));
       
  1522 +                if (NS_SUCCEEDED(rv))
       
  1523 +                    mFiles.AppendObject(localfile);
       
  1524 +                }
       
  1525 +            }
       
  1526 +        else
       
  1527 +            {
       
  1528 +            if( output.Length() == 0 )
       
  1529 +                mFileURL = nsCString();
       
  1530 +            else if( mAllowURLs )
       
  1531 +                mFileURL = output[ 0 ];
       
  1532 +            else // GetFile() actually requires it to be url even for local files :-/
       
  1533 +                {
       
  1534 +                nsCOMPtr<nsIFile> localfile;
       
  1535 +                nsresult rv = NS_NewNativeLocalFile( output[ 0 ],
       
  1536 +                                   PR_FALSE,
       
  1537 +                                   getter_AddRefs(localfile));
       
  1538 +                if (NS_SUCCEEDED(rv))
       
  1539 +                  rv = net_GetURLSpecFromActualFile(localfile, mFileURL);
       
  1540 +                }
       
  1541 +            }
       
  1542 +  // Remember last used directory.
       
  1543 +  nsCOMPtr<nsIFile> file;
       
  1544 +  GetFile(getter_AddRefs(file));
       
  1545 +  if (file) {
       
  1546 +    nsCOMPtr<nsIFile> dir;
       
  1547 +    file->GetParent(getter_AddRefs(dir));
       
  1548 +    nsCOMPtr<nsIFile> localDir(do_QueryInterface(dir));
       
  1549 +    if (localDir) {
       
  1550 +      localDir.swap(mPrevDisplayDirectory);
       
  1551 +    }
  1192 +    }
  1552 +  }
  1193 +    // Remember last used directory.
  1553 +        if (mMode == nsIFilePicker::modeSave)
  1194 +    nsCOMPtr<nsIFile> file;
  1554 +            {
  1195 +    GetFile(getter_AddRefs(file));
  1555 +            nsCOMPtr<nsIFile> file;
  1196 +    if (file) {
  1556 +            GetFile(getter_AddRefs(file));
  1197 +      nsCOMPtr<nsIFile> dir;
  1557 +            if (file)
  1198 +      file->GetParent(getter_AddRefs(dir));
  1558 +                {
  1199 +      nsCOMPtr<nsIFile> localDir(dir);
  1559 +                bool exists = false;
  1200 +      if (localDir) {
  1560 +                file->Exists(&exists);
  1201 +        localDir.swap(mPrevDisplayDirectory);
  1561 +                if (exists) // TODO do overwrite check in the helper app
  1202 +      }
  1562 +                    *aReturn = nsIFilePicker::returnReplace;
       
  1563 +                }
       
  1564 +            }
       
  1565 +        }
       
  1566 +    else
       
  1567 +        {
       
  1568 +        *aReturn = nsIFilePicker::returnCancel;
       
  1569 +        }
       
  1570 +    return NS_OK;
       
  1571 +    }
  1203 +    }
  1572 +
  1204 +    if (mMode == nsIFilePicker::modeSave) {
  1573 +
  1205 +      nsCOMPtr<nsIFile> file;
  1574 +NS_IMETHODIMP nsFilePicker::kdeAppsDialog(nsIFilePicker::ResultCode *aReturn)
  1206 +      GetFile(getter_AddRefs(file));
  1575 +    {
  1207 +      if (file) {
  1576 +    NS_ENSURE_ARG_POINTER(aReturn);
  1208 +        bool exists = false;
  1577 +
  1209 +        file->Exists(&exists);
  1578 +    nsCString title;
  1210 +        if (exists)  // TODO do overwrite check in the helper app
  1579 +    title.Adopt(ToNewUTF8String(mTitle));
  1211 +          *aReturn = nsIFilePicker::returnReplace;
  1580 +
  1212 +      }
  1581 +    nsTArray<nsCString> command;
       
  1582 +    command.AppendElement( "APPSDIALOG"_ns );
       
  1583 +    command.AppendElement( title );
       
  1584 +    if( PRInt32 xid = windowToXid( mParentWidget ))
       
  1585 +        {
       
  1586 +        command.AppendElement( "PARENT"_ns );
       
  1587 +        nsAutoCString parent;
       
  1588 +        parent.AppendInt( xid );
       
  1589 +        command.AppendElement( parent );
       
  1590 +        }
       
  1591 +
       
  1592 +    nsTArray<nsCString> output;
       
  1593 +    if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
       
  1594 +        {
       
  1595 +        *aReturn = nsIFilePicker::returnOK;
       
  1596 +        mFileURL = output.Length() > 0 ? output[ 0 ] : nsCString();
       
  1597 +        }
       
  1598 +    else
       
  1599 +        {
       
  1600 +        *aReturn = nsIFilePicker::returnCancel;
       
  1601 +        }
       
  1602 +    return NS_OK;
       
  1603 +    }
  1213 +    }
       
  1214 +  } else {
       
  1215 +    *aReturn = nsIFilePicker::returnCancel;
       
  1216 +  }
       
  1217 +  return NS_OK;
       
  1218 +}
       
  1219 +
       
  1220 +NS_IMETHODIMP nsFilePicker::kdeAppsDialog(nsIFilePicker::ResultCode* aReturn) {
       
  1221 +  NS_ENSURE_ARG_POINTER(aReturn);
       
  1222 +
       
  1223 +  nsCString title;
       
  1224 +  title.Adopt(ToNewUTF8String(mTitle));
       
  1225 +
       
  1226 +  nsTArray<nsCString> command;
       
  1227 +  command.AppendElement("APPSDIALOG"_ns);
       
  1228 +  command.AppendElement(title);
       
  1229 +  if (PRInt32 xid = windowToXid(mParentWidget)) {
       
  1230 +    command.AppendElement("PARENT"_ns);
       
  1231 +    nsAutoCString parent;
       
  1232 +    parent.AppendInt(xid);
       
  1233 +    command.AppendElement(parent);
       
  1234 +  }
       
  1235 +
       
  1236 +  nsTArray<nsCString> output;
       
  1237 +  if (nsKDEUtils::commandBlockUi(
       
  1238 +          command,
       
  1239 +          GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)),
       
  1240 +          &output)) {
       
  1241 +    *aReturn = nsIFilePicker::returnOK;
       
  1242 +    mFileURL = output.Length() > 0 ? output[0] : nsCString();
       
  1243 +  } else {
       
  1244 +    *aReturn = nsIFilePicker::returnCancel;
       
  1245 +  }
       
  1246 +  return NS_OK;
       
  1247 +}
  1604 +
  1248 +
  1605  // All below functions available as of GTK 3.20+
  1249  // All below functions available as of GTK 3.20+
  1606  void* nsFilePicker::GtkFileChooserNew(const gchar* title, GtkWindow* parent,
  1250  void* nsFilePicker::GtkFileChooserNew(const gchar* title, GtkWindow* parent,
  1607                                        GtkFileChooserAction action,
  1251                                        GtkFileChooserAction action,
  1608                                        const gchar* accept_label) {
  1252 Index: firefox-115.0/widget/gtk/nsFilePicker.h
  1609    static auto sGtkFileChooserNativeNewPtr =
  1253 ===================================================================
  1610        (void* (*)(const gchar*, GtkWindow*, GtkFileChooserAction, const gchar*,
  1254 --- firefox-115.0.orig/widget/gtk/nsFilePicker.h
  1611                   const gchar*))dlsym(RTLD_DEFAULT,
  1255 +++ firefox-115.0/widget/gtk/nsFilePicker.h
  1612                                       "gtk_file_chooser_native_new");
  1256 @@ -74,6 +74,12 @@ class nsFilePicker : public nsBaseFilePi
  1613 diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h
       
  1614 --- a/widget/gtk/nsFilePicker.h
       
  1615 +++ b/widget/gtk/nsFilePicker.h
       
  1616 @@ -69,16 +69,22 @@ class nsFilePicker : public nsBaseFilePi
       
  1617    nsString mDefaultExtension;
       
  1618  
       
  1619    nsTArray<nsCString> mFilters;
       
  1620    nsTArray<nsCString> mFilterNames;
       
  1621  
       
  1622   private:
  1257   private:
  1623    static nsIFile* mPrevDisplayDirectory;
  1258    static nsIFile* mPrevDisplayDirectory;
  1624  
  1259  
  1625 +  bool kdeRunning();
  1260 +  bool kdeRunning();
  1626 +  bool getKdeRunning();
  1261 +  bool getKdeRunning();
  1627 +  NS_IMETHODIMP kdeFileDialog(nsIFilePicker::ResultCode *aReturn);
  1262 +  NS_IMETHODIMP kdeFileDialog(nsIFilePicker::ResultCode* aReturn);
  1628 +  NS_IMETHODIMP kdeAppsDialog(nsIFilePicker::ResultCode *aReturn);
  1263 +  NS_IMETHODIMP kdeAppsDialog(nsIFilePicker::ResultCode* aReturn);
  1629 +  nsCString kdeMakeFilter( int index );
  1264 +  nsCString kdeMakeFilter(int index);
  1630 +
  1265 +
  1631    void* GtkFileChooserNew(const gchar* title, GtkWindow* parent,
  1266    void* GtkFileChooserNew(const gchar* title, GtkWindow* parent,
  1632                            GtkFileChooserAction action,
  1267                            GtkFileChooserAction action,
  1633                            const gchar* accept_label);
  1268                            const gchar* accept_label);
  1634    void GtkFileChooserShow(void* file_chooser);
  1269 Index: firefox-115.0/xpcom/components/ManifestParser.cpp
  1635    void GtkFileChooserDestroy(void* file_chooser);
  1270 ===================================================================
  1636    void GtkFileChooserSetModal(void* file_chooser, GtkWindow* parent_widget,
  1271 --- firefox-115.0.orig/xpcom/components/ManifestParser.cpp
  1637                                gboolean modal);
  1272 +++ firefox-115.0/xpcom/components/ManifestParser.cpp
  1638  
  1273 @@ -43,6 +43,7 @@
  1639 diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
       
  1640 --- a/xpcom/components/ManifestParser.cpp
       
  1641 +++ b/xpcom/components/ManifestParser.cpp
       
  1642 @@ -38,16 +38,17 @@
       
  1643  #include "nsTextFormatter.h"
       
  1644  #include "nsVersionComparator.h"
       
  1645  #include "nsXPCOMCIDInternal.h"
       
  1646  
       
  1647  #include "nsIConsoleService.h"
       
  1648  #include "nsIScriptError.h"
  1274  #include "nsIScriptError.h"
  1649  #include "nsIXULAppInfo.h"
  1275  #include "nsIXULAppInfo.h"
  1650  #include "nsIXULRuntime.h"
  1276  #include "nsIXULRuntime.h"
  1651 +#include "nsKDEUtils.h"
  1277 +#include "nsKDEUtils.h"
  1652  
  1278  
  1653  using namespace mozilla;
  1279  using namespace mozilla;
  1654  
  1280  
  1655  struct ManifestDirective {
  1281 @@ -394,6 +395,7 @@ void ParseManifest(NSLocationType aType,
  1656    const char* directive;
       
  1657    int argc;
       
  1658  
       
  1659    bool ischrome;
       
  1660 @@ -389,16 +390,17 @@ void ParseManifest(NSLocationType aType,
       
  1661    constexpr auto kRemoteEnabled = u"remoteenabled"_ns;
       
  1662    constexpr auto kRemoteRequired = u"remoterequired"_ns;
       
  1663    constexpr auto kApplication = u"application"_ns;
       
  1664    constexpr auto kAppVersion = u"appversion"_ns;
       
  1665    constexpr auto kGeckoVersion = u"platformversion"_ns;
       
  1666    constexpr auto kOs = u"os"_ns;
  1282    constexpr auto kOs = u"os"_ns;
  1667    constexpr auto kOsVersion = u"osversion"_ns;
  1283    constexpr auto kOsVersion = u"osversion"_ns;
  1668    constexpr auto kABI = u"abi"_ns;
  1284    constexpr auto kABI = u"abi"_ns;
  1669 +  constexpr auto kDesktop = u"desktop"_ns;
  1285 +  constexpr auto kDesktop = u"desktop"_ns;
  1670    constexpr auto kProcess = u"process"_ns;
  1286    constexpr auto kProcess = u"process"_ns;
  1671  #if defined(MOZ_WIDGET_ANDROID)
  1287  #if defined(MOZ_WIDGET_ANDROID)
  1672    constexpr auto kTablet = u"tablet"_ns;
  1288    constexpr auto kTablet = u"tablet"_ns;
  1673  #endif
  1289 @@ -453,6 +455,7 @@ void ParseManifest(NSLocationType aType,
  1674    // You might expect this to be guarded by MOZ_BACKGROUNDTASKS, but it's not
       
  1675    // possible to have conditional manifest contents, so we need to recognize and
       
  1676    // discard these tokens even when MOZ_BACKGROUNDTASKS is not set.
       
  1677    constexpr auto kBackgroundTask = u"backgroundtask"_ns;
       
  1678 @@ -448,39 +450,44 @@ void ParseManifest(NSLocationType aType,
       
  1679          CopyUTF8toUTF16(s, abi);
       
  1680          abi.Insert(char16_t('_'), 0);
       
  1681          abi.Insert(osTarget, 0);
       
  1682        }
       
  1683      }
       
  1684    }
  1290    }
  1685  
  1291  
  1686    nsAutoString osVersion;
  1292    nsAutoString osVersion;
  1687 +  nsAutoString desktop;
  1293 +  nsAutoString desktop;
  1688  #if defined(XP_WIN)
  1294  #if defined(XP_WIN)
  1689  #  pragma warning(push)
  1295  #  pragma warning(push)
  1690  #  pragma warning(disable : 4996)  // VC12+ deprecates GetVersionEx
  1296  #  pragma warning(disable : 4996)  // VC12+ deprecates GetVersionEx
  1691    OSVERSIONINFO info = {sizeof(OSVERSIONINFO)};
  1297 @@ -461,14 +464,17 @@ void ParseManifest(NSLocationType aType,
  1692    if (GetVersionEx(&info)) {
       
  1693      nsTextFormatter::ssprintf(osVersion, u"%ld.%ld", info.dwMajorVersion,
  1298      nsTextFormatter::ssprintf(osVersion, u"%ld.%ld", info.dwMajorVersion,
  1694                                info.dwMinorVersion);
  1299                                info.dwMinorVersion);
  1695    }
  1300    }
  1696 +  desktop = u"win"_ns;
  1301 +  desktop = u"win"_ns;
  1697  #  pragma warning(pop)
  1302  #  pragma warning(pop)
  1705                              gtk_minor_version);
  1310                              gtk_minor_version);
  1706 +  desktop = nsKDEUtils::kdeSession() ? u"kde"_ns : u"gnome"_ns;
  1311 +  desktop = nsKDEUtils::kdeSession() ? u"kde"_ns : u"gnome"_ns;
  1707  #elif defined(MOZ_WIDGET_ANDROID)
  1312  #elif defined(MOZ_WIDGET_ANDROID)
  1708    bool isTablet = false;
  1313    bool isTablet = false;
  1709    if (jni::IsAvailable()) {
  1314    if (jni::IsAvailable()) {
  1710      jni::String::LocalRef release = java::sdk::Build::VERSION::RELEASE();
  1315 @@ -476,6 +482,7 @@ void ParseManifest(NSLocationType aType,
  1711      osVersion.Assign(release->ToString());
  1316      osVersion.Assign(release->ToString());
  1712      isTablet = java::GeckoAppShell::IsTablet();
  1317      isTablet = java::GeckoAppShell::IsTablet();
  1713    }
  1318    }
  1714 +  desktop = u"android"_ns;
  1319 +  desktop = u"android"_ns;
  1715  #endif
  1320  #endif
  1716  
  1321  
  1717    if (XRE_IsContentProcess()) {
  1322    if (XRE_IsContentProcess()) {
  1718      process = kContent;
  1323 @@ -576,6 +583,7 @@ void ParseManifest(NSLocationType aType,
  1719    } else {
       
  1720      process = kMain;
       
  1721    }
       
  1722  
       
  1723 @@ -571,25 +578,27 @@ void ParseManifest(NSLocationType aType,
       
  1724      // When in background task mode, default to not registering
       
  1725      // category directivies unless backgroundtask=1 is specified.
       
  1726      TriState stBackgroundTask = (BackgroundTasks::IsBackgroundTaskMode() &&
       
  1727                                   strcmp("category", directive->directive) == 0)
       
  1728                                      ? eBad
       
  1729                                      : eUnspecified;
  1324                                      : eUnspecified;
  1730  #endif
  1325  #endif
  1731      int flags = 0;
  1326      int flags = 0;
  1732 +    TriState stDesktop = eUnspecified;
  1327 +    TriState stDesktop = eUnspecified;
  1733  
  1328  
  1734      while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
  1329      while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
  1735             ok) {
  1330             ok) {
  1736        ToLowerCase(token);
  1331 @@ -585,6 +593,7 @@ void ParseManifest(NSLocationType aType,
  1737        NS_ConvertASCIItoUTF16 wtoken(token);
       
  1738  
       
  1739        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
  1332        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
  1740            CheckOsFlag(kOs, wtoken, osTarget, stOs) ||
  1333            CheckOsFlag(kOs, wtoken, osTarget, stOs) ||
  1741            CheckStringFlag(kABI, wtoken, abi, stABI) ||
  1334            CheckStringFlag(kABI, wtoken, abi, stABI) ||
  1742 +          CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
  1335 +          CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
  1743            CheckStringFlag(kProcess, wtoken, process, stProcess) ||
  1336            CheckStringFlag(kProcess, wtoken, process, stProcess) ||
  1744            CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
  1337            CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
  1745            CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
  1338            CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
  1746            CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion,
  1339 @@ -644,6 +653,7 @@ void ParseManifest(NSLocationType aType,
  1747                             stGeckoVersion)) {
       
  1748          continue;
       
  1749        }
       
  1750  
       
  1751 @@ -638,17 +647,17 @@ void ParseManifest(NSLocationType aType,
       
  1752        }
       
  1753  
       
  1754        LogMessageWithContext(
       
  1755            aFile, line, "Unrecognized chrome manifest modifier '%s'.", token);
       
  1756        ok = false;
       
  1757      }
       
  1758  
  1340  
  1759      if (!ok || stApp == eBad || stAppVersion == eBad ||
  1341      if (!ok || stApp == eBad || stAppVersion == eBad ||
  1760 -        stGeckoVersion == eBad || stOs == eBad || stOsVersion == eBad ||
  1342          stGeckoVersion == eBad || stOs == eBad || stOsVersion == eBad ||
  1761 +        stGeckoVersion == eBad || stOs == eBad || stOsVersion == eBad || stDesktop == eBad ||
  1343 +        stDesktop == eBad ||
  1762  #ifdef MOZ_WIDGET_ANDROID
  1344  #ifdef MOZ_WIDGET_ANDROID
  1763          stTablet == eBad ||
  1345          stTablet == eBad ||
  1764  #endif
  1346  #endif
  1765  #ifdef MOZ_BACKGROUNDTASKS
  1347 Index: firefox-115.0/xpcom/components/moz.build
  1766          stBackgroundTask == eBad ||
  1348 ===================================================================
  1767  #endif
  1349 --- firefox-115.0.orig/xpcom/components/moz.build
  1768          stABI == eBad || stProcess == eBad) {
  1350 +++ firefox-115.0/xpcom/components/moz.build
  1769        continue;
  1351 @@ -71,6 +71,7 @@ LOCAL_INCLUDES += [
  1770 diff --git a/xpcom/components/moz.build b/xpcom/components/moz.build
       
  1771 --- a/xpcom/components/moz.build
       
  1772 +++ b/xpcom/components/moz.build
       
  1773 @@ -66,16 +66,17 @@ LOCAL_INCLUDES += [
       
  1774      "!..",
       
  1775      "../base",
       
  1776      "../build",
       
  1777      "../ds",
       
  1778      "/chrome",
       
  1779      "/js/xpconnect/loader",
  1352      "/js/xpconnect/loader",
  1780      "/layout/build",
  1353      "/layout/build",
  1781      "/modules/libjar",
  1354      "/modules/libjar",
  1782 +    "/toolkit/xre",
  1355 +    "/toolkit/xre",
  1783  ]
  1356  ]
  1784  
  1357  
  1785  if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
  1358  if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
  1786      CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
  1359 Index: firefox-115.0/xpcom/io/nsLocalFileUnix.cpp
  1787      if CONFIG["MOZ_ENABLE_DBUS"]:
  1360 ===================================================================
  1788          CXXFLAGS += CONFIG["MOZ_DBUS_GLIB_CFLAGS"]
  1361 --- firefox-115.0.orig/xpcom/io/nsLocalFileUnix.cpp
  1789  
  1362 +++ firefox-115.0/xpcom/io/nsLocalFileUnix.cpp
  1790  include("/ipc/chromium/chromium-config.mozbuild")
  1363 @@ -51,6 +51,7 @@
  1791 diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
       
  1792 --- a/xpcom/io/nsLocalFileUnix.cpp
       
  1793 +++ b/xpcom/io/nsLocalFileUnix.cpp
       
  1794 @@ -46,16 +46,17 @@
       
  1795  #include "nsString.h"
       
  1796  #include "nsIDirectoryEnumerator.h"
       
  1797  #include "nsSimpleEnumerator.h"
       
  1798  #include "private/pprio.h"
       
  1799  #include "prlink.h"
       
  1800  
  1364  
  1801  #ifdef MOZ_WIDGET_GTK
  1365  #ifdef MOZ_WIDGET_GTK
  1802  #  include "nsIGIOService.h"
  1366  #  include "nsIGIOService.h"
  1803 +#  include "nsKDEUtils.h"
  1367 +#  include "nsKDEUtils.h"
  1804  #endif
  1368  #endif
  1805  
  1369  
  1806  #ifdef MOZ_WIDGET_COCOA
  1370  #ifdef MOZ_WIDGET_COCOA
  1807  #  include <Carbon/Carbon.h>
  1371 @@ -2172,10 +2173,18 @@ nsLocalFile::Reveal() {
  1808  #  include "CocoaFileUtils.h"
       
  1809  #  include "prmem.h"
       
  1810  #  include "plbase64.h"
       
  1811  
       
  1812 @@ -2167,20 +2168,29 @@ nsLocalFile::SetPersistentDescriptor(con
       
  1813  
       
  1814  NS_IMETHODIMP
       
  1815  nsLocalFile::Reveal() {
       
  1816    if (!FilePreferences::IsAllowedPath(mPath)) {
       
  1817      return NS_ERROR_FILE_ACCESS_DENIED;
       
  1818    }
  1372    }
  1819  
  1373  
  1820  #ifdef MOZ_WIDGET_GTK
  1374  #ifdef MOZ_WIDGET_GTK
  1821 +  nsAutoCString url;
  1375 +  nsAutoCString url;
  1822    nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  1376    nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  1823 -  if (!giovfs) {
  1377 -  if (!giovfs) {
       
  1378 -    return NS_ERROR_FAILURE;
  1824 +  url = mPath;
  1379 +  url = mPath;
  1825 +  if(nsKDEUtils::kdeSupport()) {
  1380 +  if (nsKDEUtils::kdeSupport()) {
  1826 +    nsTArray<nsCString> command;
  1381 +    nsTArray<nsCString> command;
  1827 +    command.AppendElement( "REVEAL"_ns );
  1382 +    command.AppendElement("REVEAL"_ns);
  1828 +    command.AppendElement( mPath );
  1383 +    command.AppendElement(mPath);
  1829 +    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
  1384 +    return nsKDEUtils::command(command) ? NS_OK : NS_ERROR_FAILURE;
  1830 +  }
  1385    }
  1831 +
  1386 +
  1832 +  if (!giovfs)
  1387 +  if (!giovfs) return NS_ERROR_FAILURE;
  1833      return NS_ERROR_FAILURE;
       
  1834 -  }
       
  1835 +
  1388 +
  1836    return giovfs->RevealFile(this);
  1389    return giovfs->RevealFile(this);
  1837  #elif defined(MOZ_WIDGET_COCOA)
  1390  #elif defined(MOZ_WIDGET_COCOA)
  1838    CFURLRef url;
  1391    CFURLRef url;
  1839    if (NS_SUCCEEDED(GetCFURL(&url))) {
  1392 @@ -2197,6 +2206,13 @@ nsLocalFile::Launch() {
  1840      nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
       
  1841      ::CFRelease(url);
       
  1842      return rv;
       
  1843    }
  1393    }
  1844 @@ -2192,16 +2202,23 @@ nsLocalFile::Reveal() {
       
  1845  
       
  1846  NS_IMETHODIMP
       
  1847  nsLocalFile::Launch() {
       
  1848    if (!FilePreferences::IsAllowedPath(mPath)) {
       
  1849      return NS_ERROR_FILE_ACCESS_DENIED;
       
  1850    }
       
  1851  
  1394  
  1852  #ifdef MOZ_WIDGET_GTK
  1395  #ifdef MOZ_WIDGET_GTK
  1853 +  if( nsKDEUtils::kdeSupport()) {
  1396 +  if (nsKDEUtils::kdeSupport()) {
  1854 +    nsTArray<nsCString> command;
  1397 +    nsTArray<nsCString> command;
  1855 +    command.AppendElement( "OPEN"_ns );
  1398 +    command.AppendElement("OPEN"_ns);
  1856 +    command.AppendElement( mPath );
  1399 +    command.AppendElement(mPath);
  1857 +    return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
  1400 +    return nsKDEUtils::command(command) ? NS_OK : NS_ERROR_FAILURE;
  1858 +  }
  1401 +  }
  1859 +
  1402 +
  1860    nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  1403    nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  1861    if (!giovfs) {
  1404    if (!giovfs) {
  1862      return NS_ERROR_FAILURE;
  1405      return NS_ERROR_FAILURE;
  1863    }
       
  1864  
       
  1865    return giovfs->LaunchFile(mPath);
       
  1866  #elif defined(MOZ_WIDGET_ANDROID)
       
  1867    // Not supported on GeckoView