From 086d512e9a6596948d08aef6286e39a3ff6815d8 Mon Sep 17 00:00:00 2001 From: "bryner%brianryner.com" Date: Mon, 29 Sep 2003 22:04:05 +0000 Subject: [PATCH] Use GNOME application associations for GTK2 builds (bug 128668). r=bzbarsky, sr=blizzard. git-svn-id: svn://10.0.0.236/trunk@147448 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/docshell/build/Makefile.in | 3 + mozilla/uriloader/exthandler/Makefile.in | 10 +- .../exthandler/unix/nsGNOMERegistry.cpp | 289 ++++++++++++++++++ .../exthandler/unix/nsGNOMERegistry.h | 54 ++++ .../exthandler/unix/nsOSHelperAppService.cpp | 67 +++- 5 files changed, 406 insertions(+), 17 deletions(-) create mode 100644 mozilla/uriloader/exthandler/unix/nsGNOMERegistry.cpp create mode 100644 mozilla/uriloader/exthandler/unix/nsGNOMERegistry.h diff --git a/mozilla/docshell/build/Makefile.in b/mozilla/docshell/build/Makefile.in index b96d88ce37d..598191d4177 100644 --- a/mozilla/docshell/build/Makefile.in +++ b/mozilla/docshell/build/Makefile.in @@ -107,3 +107,6 @@ ifeq ($(OS_ARCH),WINNT) OS_LIBS += $(call EXPAND_LIBNAME, shell32) endif +ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) +EXTRA_DSO_LDOPTS += $(TK_LIBS) +endif diff --git a/mozilla/uriloader/exthandler/Makefile.in b/mozilla/uriloader/exthandler/Makefile.in index ab55e73cdf9..9f6b9959e73 100644 --- a/mozilla/uriloader/exthandler/Makefile.in +++ b/mozilla/uriloader/exthandler/Makefile.in @@ -82,6 +82,10 @@ OSHELPER += nsInternetConfig.cpp \ $(NULL) endif +ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) +OSHELPER += nsGNOMERegistry.cpp +endif + EXPORTS = nsExternalHelperAppService.h \ nsExternalProtocolHandler.h \ $(OSDIR)/nsOSHelperAppService.h \ @@ -93,7 +97,7 @@ XPIDLSRCS = \ nsIExternalProtocolService.idl \ nsIExternalHelperAppService.idl \ $(NULL) - + ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) XPIDLSRCS += nsIInternetConfigService.idl endif @@ -114,6 +118,10 @@ FORCE_STATIC_LIB = 1 SRCS_IN_OBJDIR = 1 include $(topsrcdir)/config/rules.mk +ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) +CXXFLAGS += $(TK_CFLAGS) +endif + # the use of multiple VPATH dirs is broken in cygwin make ifeq ($(OS_ARCH),WINNT) export:: $(OSDIR)/nsOSHelperAppService.cpp diff --git a/mozilla/uriloader/exthandler/unix/nsGNOMERegistry.cpp b/mozilla/uriloader/exthandler/unix/nsGNOMERegistry.cpp new file mode 100644 index 00000000000..9d8321d2fb4 --- /dev/null +++ b/mozilla/uriloader/exthandler/unix/nsGNOMERegistry.cpp @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the GNOME helper app implementation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsGNOMERegistry.h" +#include "prlink.h" +#include "prmem.h" +#include "nsString.h" +#include "nsIComponentManager.h" +#include "nsILocalFile.h" + +#include +#include + +static PRLibrary *gconfLib; +static PRLibrary *gnomeLib; +static PRLibrary *vfsLib; + +typedef struct _GConfClient GConfClient; +typedef struct _GnomeProgram GnomeProgram; +typedef struct _GnomeModuleInfo GnomeModuleInfo; + +typedef struct { + char *id; + char *name; + char *command; + /* there is more here, but we don't need it */ +} GnomeVFSMimeApplication; + +typedef GConfClient * (*_gconf_client_get_default_fn)(); +typedef gchar * (*_gconf_client_get_string_fn)(GConfClient *, + const char *, GError **); +typedef gboolean (*_gnome_url_show_fn)(const char *, GError **); +typedef const char * (*_gnome_vfs_mime_type_from_name_fn)(const char *); +typedef GList * (*_gnome_vfs_mime_get_extensions_list_fn)(const char *); +typedef void (*_gnome_vfs_mime_extensions_list_free_fn)(GList *); +typedef const char * (*_gnome_vfs_mime_get_description_fn)(const char *); +typedef GnomeVFSMimeApplication * (*_gnome_vfs_mime_get_default_application_fn) + (const char *); +typedef void (*_gnome_vfs_mime_application_free_fn)(GnomeVFSMimeApplication *); +typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *, + const GnomeModuleInfo *, int, + char **, const char *, ...); +typedef const GnomeModuleInfo * (*_libgnome_module_info_get_fn)(); + +#define DECL_FUNC_PTR(func) static _##func##_fn _##func + +DECL_FUNC_PTR(gconf_client_get_default); +DECL_FUNC_PTR(gconf_client_get_string); +DECL_FUNC_PTR(gnome_url_show); +DECL_FUNC_PTR(gnome_vfs_mime_type_from_name); +DECL_FUNC_PTR(gnome_vfs_mime_get_extensions_list); +DECL_FUNC_PTR(gnome_vfs_mime_extensions_list_free); +DECL_FUNC_PTR(gnome_vfs_mime_get_description); +DECL_FUNC_PTR(gnome_vfs_mime_get_default_application); +DECL_FUNC_PTR(gnome_vfs_mime_application_free); +DECL_FUNC_PTR(gnome_program_init); +DECL_FUNC_PTR(libgnome_module_info_get); + +static void +CleanUp() +{ + // Unload all libraries + if (gnomeLib) + PR_UnloadLibrary(gnomeLib); + if (gconfLib) + PR_UnloadLibrary(gconfLib); + if (vfsLib) + PR_UnloadLibrary(vfsLib); + + gnomeLib = gconfLib = vfsLib = nsnull; +} + +/* static */ void +nsGNOMERegistry::Startup() +{ + #define GET_LIB_FUNCTION(lib, func) \ + PR_BEGIN_MACRO \ + _##func = (_##func##_fn) PR_FindFunctionSymbol(lib##Lib, #func); \ + if (!_##func) { \ + PR_Free(libName); \ + CleanUp(); \ + return; \ + } \ + PR_END_MACRO + + // Attempt to open libgconf + char *libName = PR_GetLibraryName(nsnull, "gconf-2"); + gconfLib = PR_LoadLibrary(libName); + + if (gconfLib) { + GET_LIB_FUNCTION(gconf, gconf_client_get_default); + GET_LIB_FUNCTION(gconf, gconf_client_get_string); + } + + PR_Free(libName); + + // Attempt to open libgnome + libName = PR_GetLibraryName(nsnull, "gnome-2"); + gnomeLib = PR_LoadLibrary(libName); + + if (gnomeLib) { + GET_LIB_FUNCTION(gnome, gnome_url_show); + GET_LIB_FUNCTION(gnome, gnome_program_init); + GET_LIB_FUNCTION(gnome, libgnome_module_info_get); + } + + PR_Free(libName); + + // Attempt to open libgnomevfs + libName = PR_GetLibraryName(nsnull, "gnomevfs-2"); + vfsLib = PR_LoadLibrary(libName); + + if (vfsLib) { + GET_LIB_FUNCTION(vfs, gnome_vfs_mime_type_from_name); + GET_LIB_FUNCTION(vfs, gnome_vfs_mime_get_extensions_list); + GET_LIB_FUNCTION(vfs, gnome_vfs_mime_extensions_list_free); + GET_LIB_FUNCTION(vfs, gnome_vfs_mime_get_description); + GET_LIB_FUNCTION(vfs, gnome_vfs_mime_get_default_application); + GET_LIB_FUNCTION(vfs, gnome_vfs_mime_application_free); + } + + PR_Free(libName); + + // Initialize GNOME, if it's not already initialized. It's not + // necessary to tell GNOME about our actual command line arguments. + + char *argv[1] = { "gecko" }; + _gnome_program_init("Gecko", "1.0", _libgnome_module_info_get(), + 1, argv, NULL); + + // Note: after GNOME has been initialized, do not ever unload these + // libraries. They register atexit handlers, so if they are unloaded, we'll + // crash on exit. +} + +/* static */ PRBool +nsGNOMERegistry::HandlerExists(const char *aProtocolScheme) +{ + if (!gconfLib) + return PR_FALSE; + + GConfClient *client = _gconf_client_get_default(); + NS_ASSERTION(client, "no gconf client"); + + nsCAutoString gconfPath(NS_LITERAL_CSTRING("/desktop/gnome/url-handlers/") + + nsDependentCString(aProtocolScheme) + + NS_LITERAL_CSTRING("/command")); + + gchar *app = _gconf_client_get_string(client, gconfPath.get(), NULL); + g_object_unref(G_OBJECT(client)); + + if (app) { + g_free(app); + return PR_TRUE; + } + + return PR_FALSE; +} + +/* static */ nsresult +nsGNOMERegistry::LoadURL(nsIURI *aURL) +{ + if (!gconfLib) + return NS_ERROR_FAILURE; + + nsCAutoString spec; + aURL->GetAsciiSpec(spec); + + // XXX what if gnome_url_show() uses the default handler and that's us? + + if (_gnome_url_show(spec.get(), NULL)) + return NS_OK; + + return NS_ERROR_FAILURE; +} + +/* static */ already_AddRefed +nsGNOMERegistry::GetFromExtension(const char *aFileExt) +{ + if (!gconfLib) + return nsnull; + + // Get the MIME type from the extension, then call GetFromType to + // fill in the MIMEInfo. + + nsCAutoString fileExtToUse; + if (aFileExt && aFileExt[0] != '.') + fileExtToUse = '.'; + + fileExtToUse.Append(aFileExt); + + const char *mimeType = _gnome_vfs_mime_type_from_name(fileExtToUse.get()); + if (!strcmp(mimeType, "application/octet-stream")) + return nsnull; + + return GetFromType(mimeType); +} + +/* static */ already_AddRefed +nsGNOMERegistry::GetFromType(const char *aMIMEType) +{ + if (!gconfLib) + return nsnull; + + nsCOMPtr mimeInfo; + + GnomeVFSMimeApplication *handlerApp = _gnome_vfs_mime_get_default_application(aMIMEType); + if (!handlerApp) + return nsnull; + + mimeInfo = do_CreateInstance(NS_MIMEINFO_CONTRACTID); + NS_ENSURE_TRUE(mimeInfo, nsnull); + + mimeInfo->SetMIMEType(aMIMEType); + + // Get the list of extensions and append then to the mimeInfo. + GList *extensions = _gnome_vfs_mime_get_extensions_list(aMIMEType); + for (GList *extension = extensions; extension; extension = extension->next) + mimeInfo->AppendExtension((const char *) extension->data); + + _gnome_vfs_mime_extensions_list_free(extensions); + + const char *description = _gnome_vfs_mime_get_description(aMIMEType); + mimeInfo->SetDescription(NS_ConvertUTF8toUCS2(description).get()); + + // Convert UTF-8 registry value to filesystem encoding, which + // g_find_program_in_path() uses. + + gchar *nativeCommand = g_filename_from_utf8(handlerApp->command, + -1, NULL, NULL, NULL); + if (!nativeCommand) { + NS_ERROR("Could not convert helper app command to filesystem encoding"); + return nsnull; + } + + gchar *commandPath = g_find_program_in_path(nativeCommand); + + g_free(nativeCommand); + + nsCOMPtr appFile; + NS_NewNativeLocalFile(nsDependentCString(commandPath), PR_TRUE, + getter_AddRefs(appFile)); + if (appFile) { + mimeInfo->SetDefaultApplicationHandler(appFile); + mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUCS2(handlerApp->name).get()); + mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault); + } + + _gnome_vfs_mime_application_free(handlerApp); + + nsIMIMEInfo* retval; + NS_ADDREF((retval = mimeInfo)); + return retval; +} diff --git a/mozilla/uriloader/exthandler/unix/nsGNOMERegistry.h b/mozilla/uriloader/exthandler/unix/nsGNOMERegistry.h new file mode 100644 index 00000000000..92237b87c55 --- /dev/null +++ b/mozilla/uriloader/exthandler/unix/nsGNOMERegistry.h @@ -0,0 +1,54 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the GNOME helper app implementation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIURI.h" +#include "nsIMIMEInfo.h" +#include "nsCOMPtr.h" + +class nsGNOMERegistry +{ + public: + static void Startup(); + + static PRBool HandlerExists(const char *aProtocolScheme); + + static nsresult LoadURL(nsIURI *aURL); + + static already_AddRefed GetFromExtension(const char *aFileExt); + + static already_AddRefed GetFromType(const char *aMIMEType); +}; diff --git a/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp index a0dd0ecbed0..907c74d8d34 100644 --- a/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp @@ -22,6 +22,9 @@ */ #include "nsOSHelperAppService.h" +#ifdef MOZ_WIDGET_GTK2 +#include "nsGNOMERegistry.h" +#endif #include "nsISupports.h" #include "nsString.h" #include "nsReadableUtils.h" @@ -63,6 +66,9 @@ IsNetscapeFormat(const nsAString& aBuffer); nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() { +#ifdef MOZ_WIDGET_GTK2 + nsGNOMERegistry::Startup(); +#endif } nsOSHelperAppService::~nsOSHelperAppService() @@ -1262,6 +1268,13 @@ NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * a *aHandlerExists = (NS_SUCCEEDED(rv1) && exists && NS_SUCCEEDED(rv2) && isExecutable); LOG((" handler exists: %s\n", *aHandlerExists ? "yes" : "no")); } + +#ifdef MOZ_WIDGET_GTK2 + // Check the GConf registry for a protocol handler + if (!*aHandlerExists) + *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme); +#endif + return NS_OK; } @@ -1278,26 +1291,31 @@ NS_IMETHODIMP nsOSHelperAppService::LoadUrl(nsIURI * aURI) nsCOMPtr appFile; rv = GetHandlerAppFromPrefs(scheme.get(), getter_AddRefs(appFile)); - if (NS_FAILED(rv)) - return rv; + if (NS_SUCCEEDED(rv)) { + // Let's not support passing arguments for now + nsCOMPtr proc(do_CreateInstance("@mozilla.org/process/util;1", &rv)); + if (NS_FAILED(rv)) + return rv; - // Let's not support passing arguments for now - nsCOMPtr proc(do_CreateInstance("@mozilla.org/process/util;1", &rv)); - if (NS_FAILED(rv)) - return rv; + rv = proc->Init(appFile); + if (NS_FAILED(rv)) + return rv; - rv = proc->Init(appFile); - if (NS_FAILED(rv)) - return rv; + nsCAutoString spec; + rv = aURI->GetAsciiSpec(spec); + if (NS_FAILED(rv)) + return rv; - nsCAutoString spec; - rv = aURI->GetAsciiSpec(spec); - if (NS_FAILED(rv)) - return rv; + const char* args[] = { spec.get() }; + PRUint32 tmp; + return proc->Run(/*blocking*/PR_FALSE, args, NS_ARRAY_LENGTH(args), &tmp); + } - const char* args[] = { spec.get() }; - PRUint32 tmp; - return proc->Run(/*blocking*/PR_FALSE, args, NS_ARRAY_LENGTH(args), &tmp); +#ifdef MOZ_WIDGET_GTK2 + return nsGNOMERegistry::LoadURL(aURI); +#else + return rv; +#endif } nsresult nsOSHelperAppService::GetFileTokenForPath(const PRUnichar * platformAppPath, nsIFile ** aFile) @@ -1370,6 +1388,14 @@ nsOSHelperAppService::GetFromExtension(const char *aFileExt) { LOG(("Here we do an extension lookup for '%s'\n", aFileExt)); +#ifdef MOZ_WIDGET_GTK2 + nsIMIMEInfo *gnomeInfo = nsGNOMERegistry::GetFromExtension(aFileExt).get(); + if (gnomeInfo) { + LOG(("Got MIMEInfo from GNOME registry\n")); + return gnomeInfo; + } +#endif + nsAutoString mimeType, majorType, minorType, mime_types_description, mailcap_description, handler, mozillaFlags; @@ -1444,6 +1470,15 @@ nsOSHelperAppService::GetFromType(const char *aMIMEType) { return nsnull; LOG(("Here we do a mimetype lookup for '%s'\n", aMIMEType)); + +#ifdef MOZ_WIDGET_GTK2 + nsIMIMEInfo *gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType).get(); + if (gnomeInfo) { + LOG(("Got MIMEInfo from GNOME registry\n")); + return gnomeInfo; + } +#endif + // extract the major and minor types NS_ConvertASCIItoUTF16 mimeType(aMIMEType); nsAString::const_iterator start_iter, end_iter,