diff options
author | Kyle K <kylek389@gmail.com> | 2020-01-30 16:07:31 -0600 |
---|---|---|
committer | Kyle K <kylek389@gmail.com> | 2020-01-30 16:07:31 -0600 |
commit | 085fd7b7925a028c989e6d18e3bc3d4cdb4c2780 (patch) | |
tree | 410b63bdf79e0ced324c5ab57dcb1bb1b6525846 /patches/www-client/firefox/mozilla-kde.patch | |
parent | fb028220dbcc5dc2a1d4078b1ecd7b2749700014 (diff) | |
download | gentoox-085fd7b7925a028c989e6d18e3bc3d4cdb4c2780.tar.gz gentoox-085fd7b7925a028c989e6d18e3bc3d4cdb4c2780.tar.bz2 gentoox-085fd7b7925a028c989e6d18e3bc3d4cdb4c2780.zip |
begin theming, patch firefox for KDE global menu
Diffstat (limited to 'patches/www-client/firefox/mozilla-kde.patch')
-rw-r--r-- | patches/www-client/firefox/mozilla-kde.patch | 1940 |
1 files changed, 1940 insertions, 0 deletions
diff --git a/patches/www-client/firefox/mozilla-kde.patch b/patches/www-client/firefox/mozilla-kde.patch new file mode 100644 index 0000000..281f29b --- /dev/null +++ b/patches/www-client/firefox/mozilla-kde.patch @@ -0,0 +1,1940 @@ +# HG changeset patch +# User msirringhaus@suse.de +# Date 1559294891 -7200 +# Fri May 31 11:28:11 2019 +0200 +# Node ID c2aa7198fb925e7fde96abf65b6f68b9b755f112 +# Parent 52a515e07938d75f7c33e7b724845ce6dc315c0c +Description: Add KDE integration to Firefox (toolkit parts) +Author: Wolfgang Rosenauer <wolfgang@rosenauer.org> +Author: Lubos Lunak <lunak@suse.com> +Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751 + https://bugzilla.novell.com/show_bug.cgi?id=170055 + +diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp +--- a/modules/libpref/Preferences.cpp ++++ b/modules/libpref/Preferences.cpp +@@ -88,16 +88,17 @@ + #include "nsXPCOM.h" + #include "nsXULAppAPI.h" + #include "nsZipArchive.h" + #include "plbase64.h" + #include "PLDHashTable.h" + #include "plstr.h" + #include "prlink.h" + #include "xpcpublic.h" ++#include "nsKDEUtils.h" + + #ifdef DEBUG + # include <map> + #endif + + #ifdef MOZ_MEMORY + # include "mozmemory.h" + #endif +@@ -4543,25 +4544,37 @@ nsresult Preferences::InitInitialObjects + // application pref files for backwards compatibility. + static const char* specialFiles[] = { + #if defined(XP_MACOSX) + "macprefs.js" + #elif defined(XP_WIN) + "winpref.js" + #elif defined(XP_UNIX) + "unix.js" ++ , "" // placeholder for KDE (empty is otherwise harmless) + # if defined(_AIX) + , + "aix.js" + # endif + #elif defined(XP_BEOS) + "beos.js" + #endif + }; + ++ if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper? ++ for(int i = 0; ++ i < MOZ_ARRAY_LENGTH(specialFiles); ++ ++i ) { ++ if( *specialFiles[ i ] == '\0' ) { ++ specialFiles[ i ] = "kde.js"; ++ break; ++ } ++ } ++ } ++ + rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, + ArrayLength(specialFiles)); + if (NS_FAILED(rv)) { + NS_WARNING("Error parsing application default preferences."); + } + + // Load jar:$app/omni.jar!/defaults/preferences/*.js + // or jar:$gre/omni.jar!/defaults/preferences/*.js. +@@ -4607,17 +4620,17 @@ nsresult Preferences::InitInitialObjects + } + + nsCOMPtr<nsIFile> path = do_QueryInterface(elem); + if (!path) { + continue; + } + + // Do we care if a file provided by this process fails to load? +- pref_LoadPrefsInDir(path, nullptr, 0); ++ pref_LoadPrefsInDir(path, specialFiles, ArrayLength(specialFiles)); + } + } + + if (XRE_IsParentProcess()) { + SetupTelemetryPref(); + } + + NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr, +diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build +--- a/modules/libpref/moz.build ++++ b/modules/libpref/moz.build +@@ -113,16 +113,20 @@ EXPORTS.mozilla += [ + ] + EXPORTS.mozilla += sorted(['!' + g for g in gen_h]) + + UNIFIED_SOURCES += [ + 'Preferences.cpp', + 'SharedPrefMap.cpp', + ] + ++LOCAL_INCLUDES += [ ++ '/toolkit/xre' ++] ++ + gen_all_tuple = tuple(gen_h + gen_cpp + gen_rs) + + GENERATED_FILES += [gen_all_tuple] + + static_pref_list = GENERATED_FILES[gen_all_tuple] + static_pref_list.script = 'init/generate_static_pref_list.py:emit_code' + static_pref_list.inputs = ['init/StaticPrefList.yaml'] + +diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py +--- a/python/mozbuild/mozpack/chrome/flags.py ++++ b/python/mozbuild/mozpack/chrome/flags.py +@@ -227,16 +227,17 @@ class Flags(OrderedDict): + 'contentaccessible': Flag, + 'os': StringFlag, + 'osversion': VersionFlag, + 'abi': StringFlag, + 'platform': Flag, + 'xpcnativewrappers': Flag, + 'tablet': Flag, + 'process': StringFlag, ++ 'desktop': StringFlag, + } + RE = re.compile(r'([!<>=]+)') + + def __init__(self, *flags): + ''' + Initialize a set of flags given in string form. + flags = Flags('contentaccessible=yes', 'appversion>=3.5') + ''' +diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py +--- a/python/mozbuild/mozpack/chrome/manifest.py ++++ b/python/mozbuild/mozpack/chrome/manifest.py +@@ -36,16 +36,17 @@ class ManifestEntry(object): + 'platformversion', + 'os', + 'osversion', + 'abi', + 'xpcnativewrappers', + 'tablet', + 'process', + 'contentaccessible', ++ 'desktop', + ] + + def __init__(self, base, *flags): + ''' + Initialize a manifest entry with the given base path and flags. + ''' + self.base = base + self.flags = Flags(*flags) +diff --git a/toolkit/components/downloads/moz.build b/toolkit/components/downloads/moz.build +--- a/toolkit/components/downloads/moz.build ++++ b/toolkit/components/downloads/moz.build +@@ -41,10 +41,14 @@ XPCOM_MANIFESTS += [ + + if CONFIG['MOZ_PLACES']: + EXTRA_JS_MODULES += [ + 'DownloadHistory.jsm', + ] + + FINAL_LIBRARY = 'xul' + ++LOCAL_INCLUDES += [ ++ '/toolkit/xre' ++] ++ + with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Downloads API') +diff --git a/toolkit/mozapps/downloads/HelperAppDlg.jsm b/toolkit/mozapps/downloads/HelperAppDlg.jsm +--- a/toolkit/mozapps/downloads/HelperAppDlg.jsm ++++ b/toolkit/mozapps/downloads/HelperAppDlg.jsm +@@ -1199,36 +1199,66 @@ nsUnknownContentTypeDialog.prototype = { + params.handlerApp && + params.handlerApp.executable && + params.handlerApp.executable.isFile() + ) { + // Remember the file they chose to run. + this.chosenApp = params.handlerApp; + } + } else if ("@mozilla.org/applicationchooser;1" in Cc) { +- var nsIApplicationChooser = Ci.nsIApplicationChooser; +- var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance( +- nsIApplicationChooser +- ); +- appChooser.init( +- this.mDialog, +- this.dialogElement("strings").getString("chooseAppFilePickerTitle") +- ); +- var contentTypeDialogObj = this; +- let appChooserCallback = function appChooserCallback_done(aResult) { +- if (aResult) { +- contentTypeDialogObj.chosenApp = aResult.QueryInterface( +- Ci.nsILocalHandlerApp +- ); +- } +- contentTypeDialogObj.finishChooseApp(); +- }; +- appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback); +- // The finishChooseApp is called from appChooserCallback +- return; ++ // handle the KDE case which is implemented in the filepicker ++ // therefore falling back to Gtk2 like behaviour if KDE is running ++ // FIXME this should be better handled in the nsIApplicationChooser ++ // interface ++ var env = Components.classes["@mozilla.org/process/environment;1"] ++ .getService(Components.interfaces.nsIEnvironment); ++ if (env.get('KDE_FULL_SESSION') == "true") ++ { ++ var nsIFilePicker = Ci.nsIFilePicker; ++ var fp = Cc["@mozilla.org/filepicker;1"] ++ .createInstance(nsIFilePicker); ++ fp.init(this.mDialog, ++ this.dialogElement("strings").getString("chooseAppFilePickerTitle"), ++ nsIFilePicker.modeOpen); ++ ++ fp.appendFilters(nsIFilePicker.filterApps); ++ ++ fp.open(aResult => { ++ if (aResult == nsIFilePicker.returnOK && fp.file) { ++ // Remember the file they chose to run. ++ var localHandlerApp = ++ Cc["@mozilla.org/uriloader/local-handler-app;1"]. ++ createInstance(Ci.nsILocalHandlerApp); ++ localHandlerApp.executable = fp.file; ++ this.chosenApp = localHandlerApp; ++ } ++ this.finishChooseApp(); ++ }); ++ } else { ++ var nsIApplicationChooser = Ci.nsIApplicationChooser; ++ var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance( ++ nsIApplicationChooser ++ ); ++ appChooser.init( ++ this.mDialog, ++ this.dialogElement("strings").getString("chooseAppFilePickerTitle") ++ ); ++ var contentTypeDialogObj = this; ++ let appChooserCallback = function appChooserCallback_done(aResult) { ++ if (aResult) { ++ contentTypeDialogObj.chosenApp = aResult.QueryInterface( ++ Ci.nsILocalHandlerApp ++ ); ++ } ++ contentTypeDialogObj.finishChooseApp(); ++ }; ++ appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback); ++ // The finishChooseApp is called from appChooserCallback ++ return; ++ } + } else { + var nsIFilePicker = Ci.nsIFilePicker; + var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); + fp.init( + this.mDialog, + this.dialogElement("strings").getString("chooseAppFilePickerTitle"), + nsIFilePicker.modeOpen + ); +diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp +--- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp ++++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp +@@ -14,16 +14,17 @@ + #include "nsPrintfCString.h" + #include "nsNetCID.h" + #include "nsNetUtil.h" + #include "nsISupportsPrimitives.h" + #include "nsIGSettingsService.h" + #include "nsInterfaceHashtable.h" + #include "mozilla/Attributes.h" + #include "nsIURI.h" ++#include "nsKDEUtils.h" + + using namespace mozilla; + + class nsUnixSystemProxySettings final : public nsISystemProxySettings { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISYSTEMPROXYSETTINGS + +@@ -37,16 +38,18 @@ class nsUnixSystemProxySettings final : + nsCOMPtr<nsIGSettingsCollection> mProxySettings; + nsInterfaceHashtable<nsCStringHashKey, nsIGSettingsCollection> + mSchemeProxySettings; + nsresult GetProxyFromGSettings(const nsACString& aScheme, + const nsACString& aHost, int32_t aPort, + nsACString& aResult); + nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, + nsACString& aResult); ++ nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost, ++ PRInt32 aPort, nsACString& aResult); + }; + + NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings) + + NS_IMETHODIMP + nsUnixSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) { + // dbus prevents us from being threadsafe, but this routine should not block + // anyhow +@@ -381,21 +384,50 @@ nsresult nsUnixSystemProxySettings::GetP + return NS_OK; + } + + nsresult nsUnixSystemProxySettings::GetProxyForURI(const nsACString& aSpec, + const nsACString& aScheme, + const nsACString& aHost, + const int32_t aPort, + nsACString& aResult) { ++ if (nsKDEUtils::kdeSupport()) ++ return GetProxyFromKDE(aScheme, aHost, aPort, aResult); ++ + if (mProxySettings) { + nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult); + if (NS_SUCCEEDED(rv)) return rv; + } + + return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult); + } + ++nsresult ++nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme, ++ const nsACString& aHost, ++ PRInt32 aPort, ++ nsACString& aResult) ++{ ++ nsAutoCString url; ++ url = aScheme; ++ url += "://"; ++ url += aHost; ++ if( aPort >= 0 ) ++ { ++ url += ":"; ++ url += nsPrintfCString("%d", aPort); ++ } ++ nsTArray<nsCString> command; ++ command.AppendElement( NS_LITERAL_CSTRING( "GETPROXY" )); ++ command.AppendElement( url ); ++ nsTArray<nsCString> result; ++ if( !nsKDEUtils::command( command, &result ) || result.Length() != 1 ) ++ return NS_ERROR_FAILURE; ++ aResult = result[0]; ++ return NS_OK; ++} ++ ++ + NS_IMPL_COMPONENT_FACTORY(nsUnixSystemProxySettings) { + auto result = MakeRefPtr<nsUnixSystemProxySettings>(); + result->Init(); + return result.forget().downcast<nsISupports>(); + } +diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build +--- a/toolkit/xre/moz.build ++++ b/toolkit/xre/moz.build +@@ -87,17 +87,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co + '../components/printingui', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit': + UNIFIED_SOURCES += [ + 'nsNativeAppSupportDefault.cpp', + 'UIKitDirProvider.mm', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': ++ EXPORTS += ['nsKDEUtils.h'] + UNIFIED_SOURCES += [ ++ 'nsKDEUtils.cpp', + 'nsNativeAppSupportUnix.cpp', + ] + else: + UNIFIED_SOURCES += [ + 'nsNativeAppSupportDefault.cpp', + ] + + if CONFIG['MOZ_HAS_REMOTE']: +diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp +new file mode 100644 +--- /dev/null ++++ b/toolkit/xre/nsKDEUtils.cpp +@@ -0,0 +1,344 @@ ++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "nsKDEUtils.h" ++#include "nsIWidget.h" ++#include "nsISupportsPrimitives.h" ++#include "nsIMutableArray.h" ++#include "nsComponentManagerUtils.h" ++#include "nsArrayUtils.h" ++ ++#include <gtk/gtk.h> ++ ++#include <limits.h> ++#include <stdio.h> ++#include <sys/wait.h> ++#include <sys/resource.h> ++#include <unistd.h> ++#include <X11/Xlib.h> ++// copied from X11/X.h as a hack since for an unknown ++// reason it's not picked up from X11/X.h ++#ifndef None ++#define None 0L /* universal null resource or null atom */ ++#endif ++ ++//#define DEBUG_KDE ++#ifdef DEBUG_KDE ++#define KMOZILLAHELPER "kmozillahelper" ++#else ++// not need for lib64, it's a binary ++#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper" ++#endif ++ ++#define KMOZILLAHELPER_VERSION 6 ++#define MAKE_STR2( n ) #n ++#define MAKE_STR( n ) MAKE_STR2( n ) ++ ++static bool getKdeSession() ++ { ++ Display* dpy = XOpenDisplay( NULL ); ++ if( dpy == NULL ) ++ return false; ++ Atom kde_full_session = XInternAtom( dpy, "KDE_FULL_SESSION", true ); ++ bool kde = false; ++ if( kde_full_session != None ) ++ { ++ int cnt; ++ if( Atom* props = XListProperties( dpy, DefaultRootWindow( dpy ), &cnt )) ++ { ++ for( int i = 0; ++ i < cnt; ++ ++i ) ++ { ++ if( props[ i ] == kde_full_session ) ++ { ++ kde = true; ++#ifdef DEBUG_KDE ++ fprintf( stderr, "KDE SESSION %d\n", kde ); ++#endif ++ break; ++ } ++ } ++ XFree( props ); ++ } ++ } ++ XCloseDisplay( dpy ); ++ return kde; ++ } ++ ++static bool getKdeSupport() ++ { ++ nsTArray<nsCString> command; ++ command.AppendElement( NS_LITERAL_CSTRING( "CHECK" )); ++ command.AppendElement( NS_LITERAL_CSTRING( MAKE_STR( KMOZILLAHELPER_VERSION ))); ++ bool kde = nsKDEUtils::command( command ); ++#ifdef DEBUG_KDE ++ fprintf( stderr, "KDE RUNNING %d\n", kde ); ++#endif ++ return kde; ++ } ++ ++nsKDEUtils::nsKDEUtils() ++ : commandFile( NULL ) ++ , replyFile( NULL ) ++ { ++ } ++ ++nsKDEUtils::~nsKDEUtils() ++ { ++// closeHelper(); not actually useful, exiting will close the fd too ++ } ++ ++nsKDEUtils* nsKDEUtils::self() ++ { ++ static nsKDEUtils s; ++ return &s; ++ } ++ ++static bool helperRunning = false; ++static bool helperFailed = false; ++ ++bool nsKDEUtils::kdeSession() ++ { ++ static bool session = getKdeSession(); ++ return session; ++ } ++ ++bool nsKDEUtils::kdeSupport() ++ { ++ static bool support = kdeSession() && getKdeSupport(); ++ return support && helperRunning; ++ } ++ ++struct nsKDECommandData ++ { ++ FILE* file; ++ nsTArray<nsCString>* output; ++ GMainLoop* loop; ++ bool success; ++ }; ++ ++static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data ) ++ { ++ nsKDECommandData* p = static_cast< nsKDECommandData* >( data ); ++ char buf[ 8192 ]; // TODO big enough ++ bool command_done = false; ++ bool command_failed = false; ++ while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL ) ++ { // TODO what if the kernel splits a line into two chunks? ++//#ifdef DEBUG_KDE ++// fprintf( stderr, "READ: %s %d\n", buf, feof( p->file )); ++//#endif ++ if( char* eol = strchr( buf, '\n' )) ++ *eol = '\0'; ++ command_done = ( strcmp( buf, "\\1" ) == 0 ); ++ command_failed = ( strcmp( buf, "\\0" ) == 0 ); ++ nsAutoCString line( buf ); ++ line.ReplaceSubstring( "\\n", "\n" ); ++ line.ReplaceSubstring( "\\" "\\", "\\" ); // \\ -> \ , i.e. unescape ++ if( p->output && !( command_done || command_failed )) ++ p->output->AppendElement( nsCString( buf )); // TODO utf8? ++ } ++ bool quit = false; ++ if( feof( p->file ) || command_failed ) ++ { ++ quit = true; ++ p->success = false; ++ } ++ if( command_done ) ++ { // reading one reply finished ++ quit = true; ++ p->success = true; ++ } ++ if( quit ) ++ { ++ if( p->loop ) ++ g_main_loop_quit( p->loop ); ++ return FALSE; ++ } ++ return TRUE; ++ } ++ ++bool nsKDEUtils::command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output ) ++ { ++ return self()->internalCommand( command, NULL, false, output ); ++ } ++ ++bool nsKDEUtils::command( nsIArray* command, nsIArray** output) ++ { ++ nsTArray<nsCString> in; ++ PRUint32 length; ++ command->GetLength( &length ); ++ for ( PRUint32 i = 0; i < length; i++ ) ++ { ++ nsCOMPtr<nsISupportsCString> str = do_QueryElementAt( command, i ); ++ if( str ) ++ { ++ nsAutoCString s; ++ str->GetData( s ); ++ in.AppendElement( s ); ++ } ++ } ++ ++ nsTArray<nsCString> out; ++ bool ret = self()->internalCommand( in, NULL, false, &out ); ++ ++ if ( !output ) return ret; ++ ++ nsCOMPtr<nsIMutableArray> result = do_CreateInstance( NS_ARRAY_CONTRACTID ); ++ if ( !result ) return false; ++ ++ for ( PRUint32 i = 0; i < out.Length(); i++ ) ++ { ++ nsCOMPtr<nsISupportsCString> rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID ); ++ if ( !rstr ) return false; ++ ++ rstr->SetData( out[i] ); ++ result->AppendElement( rstr ); ++ } ++ ++ NS_ADDREF( *output = result); ++ return ret; ++ } ++ ++ ++bool nsKDEUtils::commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output ) ++ { ++ return self()->internalCommand( command, parent, true, output ); ++ } ++ ++bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool blockUi, ++ nsTArray<nsCString>* output ) ++ { ++ if( !startHelper()) ++ return false; ++ feedCommand( command ); ++ // do not store the data in 'this' but in extra structure, just in case there ++ // is reentrancy (can there be? the event loop is re-entered) ++ nsKDECommandData data; ++ data.file = replyFile; ++ data.output = output; ++ data.success = false; ++ if( blockUi ) ++ { ++ data.loop = g_main_loop_new( NULL, FALSE ); ++ GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); ++ if( parent && gtk_window_get_group(parent) ) ++ gtk_window_group_add_window( gtk_window_get_group(parent), GTK_WINDOW( window )); ++ gtk_widget_realize( window ); ++ gtk_widget_set_sensitive( window, TRUE ); ++ gtk_grab_add( window ); ++ GIOChannel* channel = g_io_channel_unix_new( fileno( data.file )); ++ g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data ); ++ g_io_channel_unref( channel ); ++ g_main_loop_run( data.loop ); ++ g_main_loop_unref( data.loop ); ++ gtk_grab_remove( window ); ++ gtk_widget_destroy( window ); ++ } ++ else ++ { ++ data.loop = NULL; ++ while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data )) ++ ; ++ } ++ return data.success; ++ } ++ ++bool nsKDEUtils::startHelper() ++ { ++ if( helperRunning ) ++ return true; ++ if( helperFailed ) ++ return false; ++ helperFailed = true; ++ int fdcommand[ 2 ]; ++ int fdreply[ 2 ]; ++ if( pipe( fdcommand ) < 0 ) ++ return false; ++ if( pipe( fdreply ) < 0 ) ++ { ++ close( fdcommand[ 0 ] ); ++ close( fdcommand[ 1 ] ); ++ return false; ++ } ++ char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL }; ++ switch( fork()) ++ { ++ case -1: ++ { ++ close( fdcommand[ 0 ] ); ++ close( fdcommand[ 1 ] ); ++ close( fdreply[ 0 ] ); ++ close( fdreply[ 1 ] ); ++ return false; ++ } ++ case 0: // child ++ { ++ if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 ) ++ _exit( 1 ); ++ if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 ) ++ _exit( 1 ); ++ int maxfd = 1024; // close all other fds ++ struct rlimit rl; ++ if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 ) ++ maxfd = rl.rlim_max; ++ for( int i = 3; ++ i < maxfd; ++ ++i ) ++ close( i ); ++#ifdef DEBUG_KDE ++ execvp( KMOZILLAHELPER, args ); ++#else ++ execv( KMOZILLAHELPER, args ); ++#endif ++ _exit( 1 ); // failed ++ } ++ default: // parent ++ { ++ commandFile = fdopen( fdcommand[ 1 ], "w" ); ++ replyFile = fdopen( fdreply[ 0 ], "r" ); ++ close( fdcommand[ 0 ] ); ++ close( fdreply[ 1 ] ); ++ if( commandFile == NULL || replyFile == NULL ) ++ { ++ closeHelper(); ++ return false; ++ } ++ // ok, helper ready, getKdeRunning() will check if it works ++ } ++ } ++ helperFailed = false; ++ helperRunning = true; ++ return true; ++ } ++ ++void nsKDEUtils::closeHelper() ++ { ++ if( commandFile != NULL ) ++ fclose( commandFile ); // this will also make the helper quit ++ if( replyFile != NULL ) ++ fclose( replyFile ); ++ helperRunning = false; ++ } ++ ++void nsKDEUtils::feedCommand( const nsTArray<nsCString>& command ) ++ { ++ for( int i = 0; ++ i < command.Length(); ++ ++i ) ++ { ++ nsCString line = command[ i ]; ++ line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape ++ line.ReplaceSubstring( "\n", "\\n" ); ++#ifdef DEBUG_KDE ++ fprintf( stderr, "COMM: %s\n", line.get()); ++#endif ++ fputs( line.get(), commandFile ); ++ fputs( "\n", commandFile ); ++ } ++ fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data ++ fflush( commandFile ); ++ } +diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h +new file mode 100644 +--- /dev/null ++++ b/toolkit/xre/nsKDEUtils.h +@@ -0,0 +1,48 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef nsKDEUtils_h__ ++#define nsKDEUtils_h__ ++ ++#include "nsString.h" ++#include "nsTArray.h" ++#include <stdio.h> ++ ++typedef struct _GtkWindow GtkWindow; ++ ++class nsIArray; ++ ++class NS_EXPORT nsKDEUtils ++ { ++ public: ++ /* Returns true if running inside a KDE session (regardless of whether there is KDE ++ support available for Firefox). This should be used e.g. when determining ++ dialog button order but not for code that requires the KDE support. */ ++ static bool kdeSession(); ++ /* Returns true if running inside a KDE session and KDE support is available ++ for Firefox. This should be used everywhere where the external helper is needed. */ ++ static bool kdeSupport(); ++ /* Executes the given helper command, returns true if helper returned success. */ ++ static bool command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output = NULL ); ++ static bool command( nsIArray* command, nsIArray** output = NULL ); ++ /* Like command(), but additionally blocks the parent widget like if there was ++ a modal dialog shown and enters the event loop (i.e. there are still paint updates, ++ this is for commands that take long). */ ++ static bool commandBlockUi( const nsTArray<nsCString>& command, GtkWindow* parent, nsTArray<nsCString>* output = NULL ); ++ ++ private: ++ nsKDEUtils(); ++ ~nsKDEUtils(); ++ static nsKDEUtils* self(); ++ bool startHelper(); ++ void closeHelper(); ++ void feedCommand( const nsTArray<nsCString>& command ); ++ bool internalCommand( const nsTArray<nsCString>& command, GtkWindow* parent, bool isParent, ++ nsTArray<nsCString>* output ); ++ FILE* commandFile; ++ FILE* replyFile; ++ }; ++ ++#endif // nsKDEUtils +diff --git a/uriloader/exthandler/HandlerServiceParent.cpp b/uriloader/exthandler/HandlerServiceParent.cpp +--- a/uriloader/exthandler/HandlerServiceParent.cpp ++++ b/uriloader/exthandler/HandlerServiceParent.cpp +@@ -7,17 +7,17 @@ + #include "mozilla/ipc/ProtocolUtils.h" + #include "mozilla/Logging.h" + #include "HandlerServiceParent.h" + #include "nsIHandlerService.h" + #include "nsIMIMEInfo.h" + #include "ContentHandlerService.h" + #include "nsStringEnumerator.h" + #ifdef MOZ_WIDGET_GTK +-# include "unix/nsGNOMERegistry.h" ++# include "unix/nsCommonRegistry.h" + #endif + + using mozilla::dom::ContentHandlerService; + using mozilla::dom::HandlerApp; + using mozilla::dom::HandlerInfo; + using mozilla::dom::RemoteHandlerApp; + + namespace { +@@ -288,17 +288,17 @@ mozilla::ipc::IPCResult HandlerServicePa + mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocolOS( + const nsCString& aProtocolScheme, bool* aHandlerExists) { + if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) { + *aHandlerExists = false; + return IPC_OK(); + } + #ifdef MOZ_WIDGET_GTK + // Check the GNOME registry for a protocol handler +- *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme.get()); ++ *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme.get()); + #else + *aHandlerExists = false; + #endif + return IPC_OK(); + } + + /* + * Check if a handler exists for the provided protocol. Check the datastore +@@ -317,17 +317,17 @@ mozilla::ipc::IPCResult HandlerServicePa + nsCOMPtr<nsIExternalProtocolService> protoSvc = + do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + *aHandlerExists = false; + return IPC_OK(); + } + rv = protoSvc->ExternalProtocolHandlerExists(aProtocolScheme.get(), + aHandlerExists); +- ++## + if (NS_WARN_IF(NS_FAILED(rv))) { + *aHandlerExists = false; + } + #else + MOZ_RELEASE_ASSERT(false, "No implementation on this platform."); + *aHandlerExists = false; + #endif + return IPC_OK(); +diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build +--- a/uriloader/exthandler/moz.build ++++ b/uriloader/exthandler/moz.build +@@ -85,17 +85,19 @@ else: + SOURCES += [ + osdir + '/nsOSHelperAppService.cpp', + ] + if CONFIG['CC_TYPE'] in ('clang', 'gcc'): + CXXFLAGS += ['-Wno-error=shadow'] + + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': + UNIFIED_SOURCES += [ ++ 'unix/nsCommonRegistry.cpp', + 'unix/nsGNOMERegistry.cpp', ++ 'unix/nsKDERegistry.cpp', + 'unix/nsMIMEInfoUnix.cpp', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + UNIFIED_SOURCES += [ + 'android/nsAndroidHandlerApp.cpp', + 'android/nsExternalURLHandlerService.cpp', + 'android/nsMIMEInfoAndroid.cpp', + ] +@@ -135,16 +137,17 @@ include('/ipc/chromium/chromium-config.m + FINAL_LIBRARY = 'xul' + + LOCAL_INCLUDES += [ + '/docshell/base', + '/dom/base', + '/dom/ipc', + '/netwerk/base', + '/netwerk/protocol/http', ++ '/toolkit/xre', + ] + + if CONFIG['MOZ_ENABLE_DBUS']: + CXXFLAGS += CONFIG['TK_CFLAGS'] + CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS'] + + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': + CXXFLAGS += CONFIG['TK_CFLAGS'] +diff --git a/uriloader/exthandler/unix/nsCommonRegistry.cpp b/uriloader/exthandler/unix/nsCommonRegistry.cpp +new file mode 100644 +--- /dev/null ++++ b/uriloader/exthandler/unix/nsCommonRegistry.cpp +@@ -0,0 +1,53 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "nsCommonRegistry.h" ++ ++#include "nsGNOMERegistry.h" ++#include "nsKDERegistry.h" ++#include "nsString.h" ++#include "nsKDEUtils.h" ++ ++/* static */ bool ++nsCommonRegistry::HandlerExists(const char *aProtocolScheme) ++{ ++ if( nsKDEUtils::kdeSupport()) ++ return nsKDERegistry::HandlerExists( aProtocolScheme ); ++ return nsGNOMERegistry::HandlerExists( aProtocolScheme ); ++} ++ ++/* static */ nsresult ++nsCommonRegistry::LoadURL(nsIURI *aURL) ++{ ++ if( nsKDEUtils::kdeSupport()) ++ return nsKDERegistry::LoadURL( aURL ); ++ return nsGNOMERegistry::LoadURL( aURL ); ++} ++ ++/* static */ void ++nsCommonRegistry::GetAppDescForScheme(const nsACString& aScheme, ++ nsAString& aDesc) ++{ ++ if( nsKDEUtils::kdeSupport()) ++ return nsKDERegistry::GetAppDescForScheme( aScheme, aDesc ); ++ return nsGNOMERegistry::GetAppDescForScheme( aScheme, aDesc ); ++} ++ ++ ++/* static */ already_AddRefed<nsMIMEInfoBase> ++nsCommonRegistry::GetFromExtension(const nsACString& aFileExt) ++{ ++ if( nsKDEUtils::kdeSupport()) ++ return nsKDERegistry::GetFromExtension( aFileExt ); ++ return nsGNOMERegistry::GetFromExtension( aFileExt ); ++} ++ ++/* static */ already_AddRefed<nsMIMEInfoBase> ++nsCommonRegistry::GetFromType(const nsACString& aMIMEType) ++{ ++ if( nsKDEUtils::kdeSupport()) ++ return nsKDERegistry::GetFromType( aMIMEType ); ++ return nsGNOMERegistry::GetFromType( aMIMEType ); ++} +diff --git a/uriloader/exthandler/unix/nsCommonRegistry.h b/uriloader/exthandler/unix/nsCommonRegistry.h +new file mode 100644 +--- /dev/null ++++ b/uriloader/exthandler/unix/nsCommonRegistry.h +@@ -0,0 +1,28 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef nsCommonRegistry_h__ ++#define nsCommonRegistry_h__ ++ ++#include "nsIURI.h" ++#include "nsCOMPtr.h" ++ ++class nsMIMEInfoBase; ++ ++class nsCommonRegistry ++{ ++ public: ++ static bool HandlerExists(const char *aProtocolScheme); ++ ++ static nsresult LoadURL(nsIURI *aURL); ++ ++ static void GetAppDescForScheme(const nsACString& aScheme, ++ nsAString& aDesc); ++ ++ static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt); ++ ++ static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType); ++}; ++ ++#endif +diff --git a/uriloader/exthandler/unix/nsKDERegistry.cpp b/uriloader/exthandler/unix/nsKDERegistry.cpp +new file mode 100644 +--- /dev/null ++++ b/uriloader/exthandler/unix/nsKDERegistry.cpp +@@ -0,0 +1,87 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "nsKDERegistry.h" ++#include "prlink.h" ++#include "prmem.h" ++#include "nsString.h" ++#include "nsMIMEInfoUnix.h" ++#include "nsAutoPtr.h" ++#include "nsKDEUtils.h" ++ ++/* static */ bool ++nsKDERegistry::HandlerExists(const char *aProtocolScheme) ++{ ++ nsTArray<nsCString> command; ++ command.AppendElement( NS_LITERAL_CSTRING( "HANDLEREXISTS" )); ++ command.AppendElement( nsAutoCString( aProtocolScheme )); ++ return nsKDEUtils::command( command ); ++} ++ ++/* static */ nsresult ++nsKDERegistry::LoadURL(nsIURI *aURL) ++{ ++ nsTArray<nsCString> command; ++ command.AppendElement( NS_LITERAL_CSTRING( "OPEN" )); ++ nsCString url; ++ aURL->GetSpec( url ); ++ command.AppendElement( url ); ++ bool rv = nsKDEUtils::command( command ); ++ if (!rv) ++ return NS_ERROR_FAILURE; ++ ++ return NS_OK; ++} ++ ++/* static */ void ++nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme, ++ |