diff --git a/toolkit/system/gnome/nsGIOService.cpp b/toolkit/system/gnome/nsGIOService.cpp --- a/toolkit/system/gnome/nsGIOService.cpp +++ b/toolkit/system/gnome/nsGIOService.cpp @@ -101,25 +101,25 @@ nsGIOMimeApp::GetName(nsACString& aName) return NS_OK; } NS_IMETHODIMP nsGIOMimeApp::GetCommand(nsACString& aCommand) { get_commandline_t g_app_info_get_commandline_ptr; - void *libHandle = dlopen("libgio-2.0.so", RTLD_LAZY); + void *libHandle = dlopen("libgio-2.0.so.0", RTLD_LAZY); if (!libHandle) { return NS_ERROR_FAILURE; } dlerror(); /* clear any existing error */ g_app_info_get_commandline_ptr = (get_commandline_t) dlsym(libHandle, "g_app_info_get_commandline"); - if (dlerror() != NULL) { - const char cmd = *g_app_info_get_commandline_ptr(mApp); + if (dlerror() == NULL) { + const char *cmd = g_app_info_get_commandline_ptr(mApp); if (!cmd) { dlclose(libHandle); return NS_ERROR_FAILURE; } aCommand.Assign(cmd); } dlclose(libHandle); return NS_OK; @@ -414,75 +414,46 @@ nsGIOService::CreateAppFromCommand(nsACS nsIGIOMimeApp** appInfo) { GError *error = NULL; *appInfo = nsnull; GAppInfo *app_info = NULL, *app_info_from_list = NULL; GList *apps = g_app_info_get_all(); GList *apps_p = apps; - get_commandline_t g_app_info_get_commandline_ptr; - - void *libHandle = dlopen("libgio-2.0.so", RTLD_LAZY); - if (!libHandle) { - return NS_ERROR_FAILURE; - } - dlerror(); /* clear any existing error */ - g_app_info_get_commandline_ptr = - (get_commandline_t) dlsym(libHandle, "g_app_info_get_commandline"); - if (dlerror() != NULL) { - g_app_info_get_commandline_ptr = NULL; - } // Try to find relevant and existing GAppInfo in all installed application + // We do this by comparing each GAppInfo's executable with out own while (apps_p) { app_info_from_list = (GAppInfo*) apps_p->data; - /* This is a silly test. It just compares app names but not - * commands. This is due to old version of Glib/Gio. The required - * function which allows to do a regular check of existence of desktop file - * is possible by using function g_app_info_get_commandline. This function - * has been introduced in Glib 2.20. */ - if (app_info_from_list && strcmp(g_app_info_get_name(app_info_from_list), - PromiseFlatCString(appName).get()) == 0 ) - { - if (g_app_info_get_commandline_ptr) - { - /* Following test is only possible with Glib >= 2.20. - * Compare path only by using strncmp */ - if (strncmp(g_app_info_get_commandline_ptr(app_info_from_list), - PromiseFlatCString(cmd).get(), - strlen(PromiseFlatCString(cmd).get())) == 0) - { - app_info = app_info_from_list; - break; - } else { - g_object_unref(app_info_from_list); - } - } else { + if (!app_info) { + // If the executable is not absolute, get it's full path + char *executable = g_find_program_in_path(g_app_info_get_executable(app_info_from_list)); + + if (executable && strcmp(executable, PromiseFlatCString(cmd).get()) == 0) { + g_object_ref (app_info_from_list); app_info = app_info_from_list; - break; } - } else { - g_object_unref(app_info_from_list); + g_free(executable); } + + g_object_unref(app_info_from_list); apps_p = apps_p->next; } g_list_free(apps); if (!app_info) { app_info = g_app_info_create_from_commandline(PromiseFlatCString(cmd).get(), PromiseFlatCString(appName).get(), G_APP_INFO_CREATE_SUPPORTS_URIS, &error); } if (!app_info) { g_warning("Cannot create application info from command: %s", error->message); g_error_free(error); - dlclose(libHandle); return NS_ERROR_FAILURE; } nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info); NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY); NS_ADDREF(*appInfo = mozApp); - dlclose(libHandle); return NS_OK; } diff --git a/browser/components/shell/src/nsGNOMEShellService.cpp b/browser/components/shell/src/nsGNOMEShellService.cpp --- a/browser/components/shell/src/nsGNOMEShellService.cpp +++ b/browser/components/shell/src/nsGNOMEShellService.cpp @@ -101,24 +101,24 @@ static const char kDesktopOptionsKey[] = static const char kDesktopDrawBGKey[] = DG_BACKGROUND "/draw_background"; static const char kDesktopColorKey[] = DG_BACKGROUND "/primary_color"; nsresult nsGNOMEShellService::Init() { nsresult rv; - // GConf _must_ be available, or we do not allow + // GConf or GIO _must_ be available, or we do not allow // CreateInstance to succeed. nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); nsCOMPtr giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); - if (!gconf) + if (!gconf && !giovfs) return NS_ERROR_NOT_AVAILABLE; // Check G_BROKEN_FILENAMES. If it's set, then filenames in glib use // the locale encoding. If it's not set, they use UTF-8. mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nsnull; if (GetAppPathFromLauncher()) return NS_OK; @@ -189,50 +189,77 @@ nsGNOMEShellService::KeyMatchesAppName(c if (!commandPath) return PR_FALSE; PRBool matches = mAppPath.Equals(commandPath); g_free(commandPath); return matches; } +PRBool +nsGNOMEShellService::CheckHandlerMatchesAppName(const nsACString &handler) const +{ + gint argc; + gchar **argv; + nsCAutoString command(handler); + + // The string will be something of the form: [/path/to/]browser "%s" + // We want to remove all of the parameters and get just the binary name. + + if (g_shell_parse_argv(command.get(), &argc, &argv, NULL) && argc > 0) { + command.Assign(argv[0]); + g_strfreev(argv); + } + + if (!KeyMatchesAppName(command.get())) + return PR_FALSE; // the handler is set to another app + + return PR_TRUE; +} + NS_IMETHODIMP nsGNOMEShellService::IsDefaultBrowser(PRBool aStartupCheck, PRBool* aIsDefaultBrowser) { *aIsDefaultBrowser = PR_FALSE; if (aStartupCheck) mCheckedThisSession = PR_TRUE; nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); + nsCOMPtr giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); PRBool enabled; nsCAutoString handler; + nsCOMPtr gioApp; for (unsigned int i = 0; i < NS_ARRAY_LENGTH(appProtocols); ++i) { if (!appProtocols[i].essential) continue; - handler.Truncate(); - gconf->GetAppForProtocol(nsDependentCString(appProtocols[i].name), - &enabled, handler); + if (gconf) { + handler.Truncate(); + gconf->GetAppForProtocol(nsDependentCString(appProtocols[i].name), + &enabled, handler); - // The string will be something of the form: [/path/to/]browser "%s" - // We want to remove all of the parameters and get just the binary name. - - gint argc; - gchar **argv; - - if (g_shell_parse_argv(handler.get(), &argc, &argv, NULL) && argc > 0) { - handler.Assign(argv[0]); - g_strfreev(argv); + if (!CheckHandlerMatchesAppName(handler) || !enabled) + return NS_OK; // the handler is disabled or set to another app } - if (!KeyMatchesAppName(handler.get()) || !enabled) - return NS_OK; // the handler is disabled or set to another app + if (giovfs) { + handler.Truncate(); + giovfs->GetAppForURIScheme(nsDependentCString(appProtocols[i].name), + getter_AddRefs(gioApp)); + if (!gioApp) + return NS_OK; + + gioApp->GetCommand(handler); + + if (!CheckHandlerMatchesAppName(handler)) + return NS_OK; // the handler is set to another app + } } *aIsDefaultBrowser = PR_TRUE; return NS_OK; } NS_IMETHODIMP @@ -240,19 +267,20 @@ nsGNOMEShellService::SetDefaultBrowser(P PRBool aForAllUsers) { #ifdef DEBUG if (aForAllUsers) NS_WARNING("Setting the default browser for all users is not yet supported"); #endif nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); + nsCOMPtr giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); if (gconf) { nsCAutoString appKeyValue; - if(mAppIsInPath) { + if (mAppIsInPath) { // mAppPath is in the users path, so use only the basename as the launcher gchar *tmp = g_path_get_basename(mAppPath.get()); appKeyValue = tmp; g_free(tmp); } else { appKeyValue = mAppPath; } @@ -261,23 +289,18 @@ nsGNOMEShellService::SetDefaultBrowser(P for (unsigned int i = 0; i < NS_ARRAY_LENGTH(appProtocols); ++i) { if (appProtocols[i].essential || aClaimAllTypes) { gconf->SetAppForProtocol(nsDependentCString(appProtocols[i].name), appKeyValue); } } } - // set handler for .html and xhtml files and MIME types: - if (aClaimAllTypes) { + if (giovfs) { nsresult rv; - nsCOMPtr giovfs = - do_GetService(NS_GIOSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, NS_OK); - nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr brandBundle; rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle)); NS_ENSURE_SUCCESS(rv, rv); @@ -290,20 +313,30 @@ nsGNOMEShellService::SetDefaultBrowser(P // use brandShortName as the application id. NS_ConvertUTF16toUTF8 id(brandShortName); nsCOMPtr appInfo; rv = giovfs->CreateAppFromCommand(mAppPath, id, getter_AddRefs(appInfo)); NS_ENSURE_SUCCESS(rv, rv); - // Add mime types for html, xhtml extension and set app to just created appinfo. - for (unsigned int i = 0; i < NS_ARRAY_LENGTH(appTypes); ++i) { - appInfo->SetAsDefaultForMimeType(nsDependentCString(appTypes[i].mimeType)); - appInfo->SetAsDefaultForFileExtensions(nsDependentCString(appTypes[i].extensions)); + // set handler for the protocols + for (unsigned int i = 0; i < NS_ARRAY_LENGTH(appProtocols); ++i) { + if (appProtocols[i].essential || aClaimAllTypes) { + appInfo->SetAsDefaultForURIScheme(nsDependentCString(appProtocols[i].name)); + } + } + + // set handler for .html and xhtml files and MIME types: + if (aClaimAllTypes) { + // Add mime types for html, xhtml extension and set app to just created appinfo. + for (unsigned int i = 0; i < NS_ARRAY_LENGTH(appTypes); ++i) { + appInfo->SetAsDefaultForMimeType(nsDependentCString(appTypes[i].mimeType)); + appInfo->SetAsDefaultForFileExtensions(nsDependentCString(appTypes[i].extensions)); + } } } return NS_OK; } NS_IMETHODIMP nsGNOMEShellService::GetShouldCheckDefaultBrowser(PRBool* aResult) @@ -403,48 +436,52 @@ nsGNOMEShellService::SetDesktopBackgroun filePath.Append("_wallpaper.png"); // write the image to a file in the home dir rv = WriteImage(filePath, container); // if the file was written successfully, set it as the system wallpaper nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); - nsCAutoString options; - if (aPosition == BACKGROUND_TILE) - options.Assign("wallpaper"); - else if (aPosition == BACKGROUND_STRETCH) - options.Assign("stretched"); - else - options.Assign("centered"); + if (gconf) { + nsCAutoString options; + if (aPosition == BACKGROUND_TILE) + options.Assign("wallpaper"); + else if (aPosition == BACKGROUND_STRETCH) + options.Assign("stretched"); + else + options.Assign("centered"); - gconf->SetString(NS_LITERAL_CSTRING(kDesktopOptionsKey), options); + gconf->SetString(NS_LITERAL_CSTRING(kDesktopOptionsKey), options); - // Set the image to an empty string first to force a refresh - // (since we could be writing a new image on top of an existing - // Firefox_wallpaper.png and nautilus doesn't monitor the file for changes) - gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), - EmptyCString()); + // Set the image to an empty string first to force a refresh + // (since we could be writing a new image on top of an existing + // Firefox_wallpaper.png and nautilus doesn't monitor the file for changes) + gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), + EmptyCString()); - gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), filePath); - gconf->SetBool(NS_LITERAL_CSTRING(kDesktopDrawBGKey), PR_TRUE); + gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), filePath); + gconf->SetBool(NS_LITERAL_CSTRING(kDesktopDrawBGKey), PR_TRUE); + } return rv; } #define COLOR_16_TO_8_BIT(_c) ((_c) >> 8) #define COLOR_8_TO_16_BIT(_c) ((_c) << 8 | (_c)) NS_IMETHODIMP nsGNOMEShellService::GetDesktopBackgroundColor(PRUint32 *aColor) { nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); nsCAutoString background; - gconf->GetString(NS_LITERAL_CSTRING(kDesktopColorKey), background); + if (gconf) { + gconf->GetString(NS_LITERAL_CSTRING(kDesktopColorKey), background); + } if (background.IsEmpty()) { *aColor = 0; return NS_OK; } GdkColor color; gboolean success = gdk_color_parse(background.get(), &color); @@ -473,36 +510,48 @@ ColorToCString(PRUint32 aColor, nsCStrin } NS_IMETHODIMP nsGNOMEShellService::SetDesktopBackgroundColor(PRUint32 aColor) { NS_ASSERTION(aColor <= 0xffffff, "aColor has extra bits"); nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); - nsCAutoString colorString; - ColorToCString(aColor, colorString); + if (gconf) { + nsCAutoString colorString; + ColorToCString(aColor, colorString); - gconf->SetString(NS_LITERAL_CSTRING(kDesktopColorKey), colorString); + gconf->SetString(NS_LITERAL_CSTRING(kDesktopColorKey), colorString); + } return NS_OK; } NS_IMETHODIMP nsGNOMEShellService::OpenApplication(PRInt32 aApplication) { nsCAutoString scheme; if (aApplication == APPLICATION_MAIL) scheme.Assign("mailto"); else if (aApplication == APPLICATION_NEWS) scheme.Assign("news"); else return NS_ERROR_NOT_AVAILABLE; + nsCOMPtr giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); + if (giovfs) { + nsCOMPtr gioApp; + giovfs->GetAppForURIScheme(scheme, getter_AddRefs(gioApp)); + if (gioApp) + return gioApp->Launch(EmptyCString()); + } + nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); + if (!gconf) + return NS_ERROR_FAILURE; PRBool enabled; nsCAutoString appCommand; gconf->GetAppForProtocol(scheme, &enabled, appCommand); if (!enabled) return NS_ERROR_FAILURE; diff --git a/browser/components/shell/src/nsGNOMEShellService.h b/browser/components/shell/src/nsGNOMEShellService.h --- a/browser/components/shell/src/nsGNOMEShellService.h +++ b/browser/components/shell/src/nsGNOMEShellService.h @@ -49,16 +49,17 @@ public: NS_DECL_NSISHELLSERVICE nsresult Init() NS_HIDDEN; private: ~nsGNOMEShellService() {} NS_HIDDEN_(PRBool) KeyMatchesAppName(const char *aKeyValue) const; + NS_HIDDEN_(PRBool) CheckHandlerMatchesAppName(const nsACString& handler) const; NS_HIDDEN_(PRBool) GetAppPathFromLauncher(); PRPackedBool mCheckedThisSession; PRPackedBool mUseLocaleFilenames; nsCString mAppPath; PRPackedBool mAppIsInPath; }; diff --git a/toolkit/system/gnome/nsGIOService.cpp b/toolkit/system/gnome/nsGIOService.cpp --- a/toolkit/system/gnome/nsGIOService.cpp +++ b/toolkit/system/gnome/nsGIOService.cpp @@ -277,16 +277,43 @@ nsGIOMimeApp::SetAsDefaultForFileExtensi } else { *ext_pos = '\0'; } } g_free(extensions); return NS_OK; } +/** + * Set default application for URI's of a particular scheme + * @param aURIScheme string containing the URI scheme + * @return NS_OK when application was set as default for URI scheme, + * NS_ERROR_FAILURE otherwise + */ +NS_IMETHODIMP +nsGIOMimeApp::SetAsDefaultForURIScheme(nsACString const& aURIScheme) +{ + GError *error = NULL; + nsCAutoString contentType("x-scheme-handler/"); + contentType.Append(aURIScheme); + + g_app_info_set_as_default_for_type(mApp, + contentType.get(), + &error); + if (error) { + g_warning("Cannot set application as default for URI scheme (%s): %s", + PromiseFlatCString(aURIScheme).get(), + error->message); + g_error_free(error); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + nsresult nsGIOService::Init() { // do nothing, gvfs/gio does not init. return NS_OK; } NS_IMPL_ISUPPORTS1(nsGIOService, nsIGIOService) @@ -317,16 +344,33 @@ nsGIOService::GetMimeTypeFromExtension(c g_free(mime_type); g_free(content_type); return NS_OK; } // used in nsGNOMERegistry // ----------------------------------------------------------------------------- NS_IMETHODIMP +nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme, + nsIGIOMimeApp** aApp) +{ + *aApp = nsnull; + + GAppInfo *app_info = g_app_info_get_default_for_uri_scheme( + PromiseFlatCString(aURIScheme).get()); + if (app_info) { + nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info); + NS_ADDREF(*aApp = mozApp); + } else { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP nsGIOService::GetAppForMimeType(const nsACString& aMimeType, nsIGIOMimeApp** aApp) { *aApp = nsnull; char *content_type = get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get()); if (!content_type) return NS_ERROR_FAILURE; diff --git a/xpcom/system/nsIGIOService.idl b/xpcom/system/nsIGIOService.idl --- a/xpcom/system/nsIGIOService.idl +++ b/xpcom/system/nsIGIOService.idl @@ -41,57 +41,61 @@ interface nsIUTF8StringEnumerator; interface nsIURI; /* nsIGIOMimeApp holds information about an application that is looked up with nsIGIOService::GetAppForMimeType. */ // 66009894-9877-405b-9321-bf30420e34e6 prev uuid -[scriptable, uuid(e77021b4-4012-407d-b686-7a1f18050109)] +[scriptable, uuid(ca6bad0c-8a48-48ac-82c7-27bb8f510fbe)] interface nsIGIOMimeApp : nsISupports { const long EXPECTS_URIS = 0; const long EXPECTS_PATHS = 1; const long EXPECTS_URIS_FOR_NON_FILES = 2; readonly attribute AUTF8String id; readonly attribute AUTF8String name; readonly attribute AUTF8String command; readonly attribute long expectsURIs; // see constants above readonly attribute nsIUTF8StringEnumerator supportedURISchemes; void launch(in AUTF8String uri); void setAsDefaultForMimeType(in AUTF8String mimeType); void setAsDefaultForFileExtensions(in AUTF8String extensions); + void setAsDefaultForURIScheme(in AUTF8String uriScheme); }; /* * The VFS service makes use of two distinct registries. * * The application registry holds information about applications (uniquely * identified by id), such as which MIME types and URI schemes they are * capable of handling, whether they run in a terminal, etc. * * The MIME registry holds information about MIME types, such as which * extensions map to a given MIME type. The MIME registry also stores the * id of the application selected to handle each MIME type. */ // prev id dea20bf0-4e4d-48c5-b932-dc3e116dc64b -[scriptable, uuid(47e372c2-78bb-4899-8114-56aa7d9cdac5)] +[scriptable, uuid(eda22a30-84e1-4e16-9ca0-cd1553c2b34a)] interface nsIGIOService : nsISupports { /*** MIME registry methods ***/ /* Obtain the MIME type registered for an extension. The extension should not include a leading dot. */ AUTF8String getMimeTypeFromExtension(in AUTF8String extension); + /* Obtain the preferred application for opening a given URI scheme */ + nsIGIOMimeApp getAppForURIScheme(in AUTF8String aURIScheme); + /* Obtain the preferred application for opening a given MIME type */ nsIGIOMimeApp getAppForMimeType(in AUTF8String mimeType); /* Obtain the preferred application for opening a given MIME type */ nsIGIOMimeApp createAppFromCommand(in AUTF8String cmd, in AUTF8String appName); /* Obtain a description for the given MIME type */ diff --git a/toolkit/system/gnome/Makefile.in b/toolkit/system/gnome/Makefile.in --- a/toolkit/system/gnome/Makefile.in +++ b/toolkit/system/gnome/Makefile.in @@ -60,16 +60,17 @@ ifdef MOZ_ENABLE_GNOMEVFS CPPSRCS += \ nsGnomeVFSService.cpp \ $(NULL) endif ifdef MOZ_ENABLE_GIO CPPSRCS += \ nsGIOService.cpp \ + nsGSettingsService.cpp \ $(NULL) endif ifdef MOZ_ENABLE_LIBNOTIFY CPPSRCS += \ nsAlertsService.cpp \ nsAlertsIconListener.cpp \ $(NULL) diff --git a/toolkit/system/gnome/nsGSettingsService.cpp b/toolkit/system/gnome/nsGSettingsService.cpp new file mode 100644 --- /dev/null +++ b/toolkit/system/gnome/nsGSettingsService.cpp @@ -0,0 +1,238 @@ +/* -*- 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 Mozilla GNOME integration code. + * + * The Initial Developer of the Original Code is + * Canonical Ltd. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Coulson + * + * 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 "nsGSettingsService.h" +#include "nsStringAPI.h" +#include "nsCOMPtr.h" +#include "prlink.h" +#include "nsComponentManagerUtils.h" + +#include +#include + +typedef struct _GSettings GSettings; + +typedef GSettings * (*_g_settings_new_fn) (const char* schema); +typedef const char * const* (*_g_settings_list_schemas_fn) (void); +typedef gboolean (*_g_settings_set_string_fn) (GSettings* settings, + const char* key, + const char* value); +typedef gboolean (*_g_settings_set_boolean_fn) (GSettings* settings, + const char* key, + gboolean value); +typedef gboolean (*_g_settings_set_int_fn) (GSettings* settings, + const char* key, + int value); +typedef char * (*_g_settings_get_string_fn) (GSettings* settings, + const char* key); +typedef gboolean (*_g_settings_get_boolean_fn) (GSettings* settings, + const char* key); +typedef int (*_g_settings_get_int_fn) (GSettings* settings, + const char* key); + +static _g_settings_new_fn _g_settings_new; +static _g_settings_list_schemas_fn _g_settings_list_schemas; +static PRLibrary *gioLib = nsnull; + +class nsGSettingsCollection : public nsIGSettingsCollection +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIGSETTINGSCOLLECTION + + nsGSettingsCollection(GSettings* aSettings) : mSettings(aSettings) {} + ~nsGSettingsCollection() { g_object_unref(mSettings); } + +private: + GSettings *mSettings; +}; + +NS_IMPL_ISUPPORTS1(nsGSettingsCollection, nsIGSettingsCollection) + +NS_IMETHODIMP +nsGSettingsCollection::SetString(const nsACString& aKey, + const nsACString& aValue) +{ + _g_settings_set_string_fn _g_settings_set_string = + (_g_settings_set_string_fn) PR_FindFunctionSymbol(gioLib, + "g_settings_set_string"); + if (!_g_settings_set_string) + return NS_ERROR_FAILURE; + + gboolean res = _g_settings_set_string(mSettings, + PromiseFlatCString(aKey).get(), + PromiseFlatCString(aValue).get()); + + return res ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsGSettingsCollection::SetBoolean(const nsACString& aKey, + PRBool aValue) +{ + _g_settings_set_boolean_fn _g_settings_set_boolean = + (_g_settings_set_boolean_fn) PR_FindFunctionSymbol(gioLib, + "g_settings_set_boolean"); + if (!_g_settings_set_boolean) + return NS_ERROR_FAILURE; + + gboolean res = _g_settings_set_boolean(mSettings, + PromiseFlatCString(aKey).get(), + aValue); + + return res ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsGSettingsCollection::SetInt(const nsACString& aKey, + PRInt32 aValue) +{ + _g_settings_set_int_fn _g_settings_set_int = + (_g_settings_set_int_fn) PR_FindFunctionSymbol(gioLib, + "g_settings_set_int"); + if (!_g_settings_set_int) + return NS_ERROR_FAILURE; + + gboolean res = _g_settings_set_int(mSettings, + PromiseFlatCString(aKey).get(), + aValue); + + return res ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsGSettingsCollection::GetString(const nsACString& aKey, + nsACString& aResult) +{ + _g_settings_get_string_fn _g_settings_get_string = + (_g_settings_get_string_fn) PR_FindFunctionSymbol(gioLib, + "g_settings_get_string"); + if (!_g_settings_get_string) + return NS_ERROR_FAILURE; + + char *result = _g_settings_get_string(mSettings, + PromiseFlatCString(aKey).get()); + if (!result) + return NS_ERROR_FAILURE; + + aResult.Assign(result); + g_free(result); + return NS_OK; +} + +NS_IMETHODIMP +nsGSettingsCollection::GetBoolean(const nsACString& aKey, + PRBool* aResult) +{ + _g_settings_get_boolean_fn _g_settings_get_boolean = + (_g_settings_get_boolean_fn) PR_FindFunctionSymbol(gioLib, + "g_settings_get_boolean"); + if (!_g_settings_get_boolean) + return NS_ERROR_FAILURE; + + gboolean res = _g_settings_get_boolean(mSettings, + PromiseFlatCString(aKey).get()); + *aResult = res ? PR_TRUE : PR_FALSE; + + return NS_OK; +} + +NS_IMETHODIMP +nsGSettingsCollection::GetInt(const nsACString& aKey, + PRInt32* aResult) +{ + _g_settings_get_int_fn _g_settings_get_int = + (_g_settings_get_int_fn) PR_FindFunctionSymbol(gioLib, + "g_settings_get_int"); + if (!_g_settings_get_int) + return NS_ERROR_FAILURE; + + *aResult = _g_settings_get_int(mSettings, + PromiseFlatCString(aKey).get()); + + return NS_OK; +} + +nsresult +nsGSettingsService::Init() +{ + if (!gioLib) { + gioLib = PR_LoadLibrary("libgio-2.0.so.0"); + } + + _g_settings_new = (_g_settings_new_fn) + PR_FindFunctionSymbol(gioLib, "g_settings_new"); + _g_settings_list_schemas = (_g_settings_list_schemas_fn) + PR_FindFunctionSymbol(gioLib, "g_settings_list_schemas"); + + if (!_g_settings_new || !_g_settings_list_schemas) { + PR_UnloadLibrary(gioLib); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(nsGSettingsService, nsIGSettingsService) + +nsGSettingsService::~nsGSettingsService() +{ + if (gioLib) { + PR_UnloadLibrary(gioLib); + gioLib = nsnull; + } +} + +NS_IMETHODIMP +nsGSettingsService::GetCollectionForSchema(const nsACString& schema, + nsIGSettingsCollection** collection) +{ + const char * const *schemas = _g_settings_list_schemas(); + unsigned int i = 0; + + for (i = 0; schemas[i] != NULL; i++) { + if (strcmp(schemas[i], PromiseFlatCString(schema).get()) == 0) { + GSettings *settings = _g_settings_new(PromiseFlatCString(schema).get()); + nsGSettingsCollection *mozGSettings = new nsGSettingsCollection(settings); + NS_ADDREF(*collection = mozGSettings); + return NS_OK; + } + } + + return NS_ERROR_FAILURE; +} diff --git a/toolkit/system/gnome/nsGSettingsService.h b/toolkit/system/gnome/nsGSettingsService.h new file mode 100644 --- /dev/null +++ b/toolkit/system/gnome/nsGSettingsService.h @@ -0,0 +1,60 @@ +/* -*- 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 Mozilla GNOME integration code. + * + * The Initial Developer of the Original Code is + * Canonical Ltd. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Coulson + * + * 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 ***** */ + +#ifndef nsGSettingsService_h_ +#define nsGSettingsService_h_ + +#include "nsIGSettingsService.h" + +#define NS_GSETTINGSSERVICE_CID \ +{0xbfd4a9d8, 0xd886, 0x4161, {0x81, 0xef, 0x88, 0x68, 0xda, 0x11, 0x41, 0x70}} + +class nsGSettingsService : public nsIGSettingsService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIGSETTINGSSERVICE + + NS_HIDDEN_(nsresult) Init(); + +private: + ~nsGSettingsService(); +}; + +#endif + diff --git a/toolkit/system/gnome/nsGnomeModule.cpp b/toolkit/system/gnome/nsGnomeModule.cpp --- a/toolkit/system/gnome/nsGnomeModule.cpp +++ b/toolkit/system/gnome/nsGnomeModule.cpp @@ -44,62 +44,67 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGConfService, Init) #endif #ifdef MOZ_ENABLE_GNOMEVFS #include "nsGnomeVFSService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGnomeVFSService, Init) #endif #ifdef MOZ_ENABLE_GIO #include "nsGIOService.h" +#include "nsGSettingsService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGIOService, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGSettingsService, Init) #endif #ifdef MOZ_ENABLE_LIBNOTIFY #include "nsAlertsService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAlertsService, Init) #endif #ifdef MOZ_ENABLE_GCONF NS_DEFINE_NAMED_CID(NS_GCONFSERVICE_CID); #endif #ifdef MOZ_ENABLE_GNOMEVFS NS_DEFINE_NAMED_CID(NS_GNOMEVFSSERVICE_CID); #endif #ifdef MOZ_ENABLE_GIO NS_DEFINE_NAMED_CID(NS_GIOSERVICE_CID); +NS_DEFINE_NAMED_CID(NS_GSETTINGSSERVICE_CID); #endif #ifdef MOZ_ENABLE_LIBNOTIFY NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID); #endif static const mozilla::Module::CIDEntry kGnomeCIDs[] = { #ifdef MOZ_ENABLE_GCONF { &kNS_GCONFSERVICE_CID, false, NULL, nsGConfServiceConstructor }, #endif #ifdef MOZ_ENABLE_GNOMEVFS { &kNS_GNOMEVFSSERVICE_CID, false, NULL, nsGnomeVFSServiceConstructor }, #endif #ifdef MOZ_ENABLE_GIO { &kNS_GIOSERVICE_CID, false, NULL, nsGIOServiceConstructor }, + { &kNS_GSETTINGSSERVICE_CID, false, NULL, nsGSettingsServiceConstructor }, #endif #ifdef MOZ_ENABLE_LIBNOTIFY { &kNS_SYSTEMALERTSSERVICE_CID, false, NULL, nsAlertsServiceConstructor }, #endif { NULL } }; static const mozilla::Module::ContractIDEntry kGnomeContracts[] = { #ifdef MOZ_ENABLE_GCONF { NS_GCONFSERVICE_CONTRACTID, &kNS_GCONFSERVICE_CID }, #endif #ifdef MOZ_ENABLE_GNOMEVFS { NS_GNOMEVFSSERVICE_CONTRACTID, &kNS_GNOMEVFSSERVICE_CID }, #endif #ifdef MOZ_ENABLE_GIO { NS_GIOSERVICE_CONTRACTID, &kNS_GIOSERVICE_CID }, + { NS_GSETTINGSSERVICE_CONTRACTID, &kNS_GSETTINGSSERVICE_CID }, #endif #ifdef MOZ_ENABLE_LIBNOTIFY { NS_SYSTEMALERTSERVICE_CONTRACTID, &kNS_SYSTEMALERTSSERVICE_CID }, #endif { NULL } }; static const mozilla::Module kGnomeModule = { diff --git a/xpcom/system/Makefile.in b/xpcom/system/Makefile.in --- a/xpcom/system/Makefile.in +++ b/xpcom/system/Makefile.in @@ -47,16 +47,17 @@ XPIDL_MODULE = xpcom_system XPIDLSRCS = \ nsIXULAppInfo.idl \ nsIXULRuntime.idl \ nsIGConfService.idl \ nsIGnomeVFSService.idl \ nsIBlocklistService.idl \ nsIGIOService.idl \ + nsIGSettingsService.idl \ nsIAccelerometer.idl \ nsIGeolocationProvider.idl \ nsIHapticFeedback.idl \ $(NULL) ifdef MOZ_CRASHREPORTER XPIDLSRCS += nsICrashReporter.idl endif diff --git a/xpcom/system/nsIGSettingsService.idl b/xpcom/system/nsIGSettingsService.idl new file mode 100644 --- /dev/null +++ b/xpcom/system/nsIGSettingsService.idl @@ -0,0 +1,61 @@ +/* -*- Mode: IDL; 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 Mozilla GNOME integration code. + * + * The Initial Developer of the Original Code is + * Canonical Ltd. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Coulson + * + * 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 "nsISupports.idl" +#include "nsIArray.idl" + +[scriptable, uuid(09637d3c-3c07-40b4-aff9-1d2a0f046f3c)] +interface nsIGSettingsCollection : nsISupports +{ + void setString(in AUTF8String key, in AUTF8String value); + void setBoolean(in AUTF8String key, in boolean value); + void setInt(in AUTF8String key, in long value); + AUTF8String getString(in AUTF8String key); + boolean getBoolean(in AUTF8String key); + long getInt(in AUTF8String key); +}; + +[scriptable, uuid(849c088b-57d1-4f24-b7b2-3dc4acb04c0a)] +interface nsIGSettingsService : nsISupports +{ + nsIGSettingsCollection getCollectionForSchema(in AUTF8String schema); +}; + +%{C++ +#define NS_GSETTINGSSERVICE_CONTRACTID "@mozilla.org/gsettings-service;1" +%} diff --git a/browser/components/shell/src/nsGNOMEShellService.cpp b/browser/components/shell/src/nsGNOMEShellService.cpp --- a/browser/components/shell/src/nsGNOMEShellService.cpp +++ b/browser/components/shell/src/nsGNOMEShellService.cpp @@ -41,16 +41,17 @@ #include "nsILocalFile.h" #include "nsIProperties.h" #include "nsDirectoryServiceDefs.h" #include "nsIPrefService.h" #include "prenv.h" #include "nsStringAPI.h" #include "nsIGConfService.h" #include "nsIGIOService.h" +#include "nsIGSettingsService.h" #include "nsIStringBundle.h" #include "nsIOutputStream.h" #include "nsIProcess.h" #include "nsNetUtil.h" #include "nsIDOMHTMLImageElement.h" #include "nsIImageLoadingContent.h" #include "imgIRequest.h" #include "imgIContainer.h" @@ -96,29 +97,37 @@ static const char kDocumentIconPath[] = // GConf registry key constants #define DG_BACKGROUND "/desktop/gnome/background" static const char kDesktopImageKey[] = DG_BACKGROUND "/picture_filename"; static const char kDesktopOptionsKey[] = DG_BACKGROUND "/picture_options"; static const char kDesktopDrawBGKey[] = DG_BACKGROUND "/draw_background"; static const char kDesktopColorKey[] = DG_BACKGROUND "/primary_color"; +static const char kDesktopBGSchema[] = "org.gnome.desktop.background"; +static const char kDesktopImageGSKey[] = "picture-uri"; +static const char kDesktopOptionGSKey[] = "picture-options"; +static const char kDesktopDrawBGGSKey[] = "draw-background"; +static const char kDesktopColorGSKey[] = "primary-color"; + nsresult nsGNOMEShellService::Init() { nsresult rv; - // GConf or GIO _must_ be available, or we do not allow + // GConf, GSettings or GIO _must_ be available, or we do not allow // CreateInstance to succeed. nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); nsCOMPtr giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); + nsCOMPtr gsettings = + do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); - if (!gconf && !giovfs) + if (!gconf && !giovfs && !gsettings) return NS_ERROR_NOT_AVAILABLE; // Check G_BROKEN_FILENAMES. If it's set, then filenames in glib use // the locale encoding. If it's not set, they use UTF-8. mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nsnull; if (GetAppPathFromLauncher()) return NS_OK; @@ -434,27 +443,47 @@ nsGNOMEShellService::SetDesktopBackgroun filePath.Append('/'); filePath.Append(NS_ConvertUTF16toUTF8(brandName)); filePath.Append("_wallpaper.png"); // write the image to a file in the home dir rv = WriteImage(filePath, container); // if the file was written successfully, set it as the system wallpaper + nsCAutoString options; + if (aPosition == BACKGROUND_TILE) + options.Assign("wallpaper"); + else if (aPosition == BACKGROUND_STRETCH) + options.Assign("stretched"); + else + options.Assign("centered"); + + // Try GSettings first. If we don't have GSettings or the right schema, fall back + // to using GConf instead. Note that if GSettings works ok, the changes get + // mirrored to GConf by the gsettings->gconf bridge in gnome-settings-daemon + nsCOMPtr gsettings = + do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); + if (gsettings) { + nsCOMPtr background_settings; + gsettings->GetCollectionForSchema( + NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings)); + if (background_settings) { + filePath.Insert("file://", 0); + background_settings->SetString(NS_LITERAL_CSTRING(kDesktopOptionGSKey), + options); + background_settings->SetString(NS_LITERAL_CSTRING(kDesktopImageGSKey), + filePath); + background_settings->SetBoolean(NS_LITERAL_CSTRING(kDesktopDrawBGGSKey), + PR_TRUE); + return rv; + } + } + nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); - if (gconf) { - nsCAutoString options; - if (aPosition == BACKGROUND_TILE) - options.Assign("wallpaper"); - else if (aPosition == BACKGROUND_STRETCH) - options.Assign("stretched"); - else - options.Assign("centered"); - gconf->SetString(NS_LITERAL_CSTRING(kDesktopOptionsKey), options); // Set the image to an empty string first to force a refresh // (since we could be writing a new image on top of an existing // Firefox_wallpaper.png and nautilus doesn't monitor the file for changes) gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), EmptyCString()); @@ -466,21 +495,33 @@ nsGNOMEShellService::SetDesktopBackgroun } #define COLOR_16_TO_8_BIT(_c) ((_c) >> 8) #define COLOR_8_TO_16_BIT(_c) ((_c) << 8 | (_c)) NS_IMETHODIMP nsGNOMEShellService::GetDesktopBackgroundColor(PRUint32 *aColor) { - nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); + nsCOMPtr gsettings = + do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); + nsCOMPtr background_settings; + nsCAutoString background; + if (gsettings) { + gsettings->GetCollectionForSchema( + NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings)); + if (background_settings) { + background_settings->GetString(NS_LITERAL_CSTRING(kDesktopColorGSKey), + background); + } + } - nsCAutoString background; - if (gconf) { - gconf->GetString(NS_LITERAL_CSTRING(kDesktopColorKey), background); + if (!background_settings) { + nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); + if (gconf) + gconf->GetString(NS_LITERAL_CSTRING(kDesktopColorKey), background); } if (background.IsEmpty()) { *aColor = 0; return NS_OK; } GdkColor color; @@ -508,22 +548,35 @@ ColorToCString(PRUint32 aColor, nsCStrin PR_snprintf(buf, 14, "#%04x%04x%04x", red, green, blue); } NS_IMETHODIMP nsGNOMEShellService::SetDesktopBackgroundColor(PRUint32 aColor) { NS_ASSERTION(aColor <= 0xffffff, "aColor has extra bits"); + + nsCAutoString colorString; + ColorToCString(aColor, colorString); + + nsCOMPtr gsettings = + do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); + if (gsettings) { + nsCOMPtr background_settings; + gsettings->GetCollectionForSchema( + NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings)); + if (background_settings) { + background_settings->SetString(NS_LITERAL_CSTRING(kDesktopColorGSKey), + colorString); + return NS_OK; + } + } + nsCOMPtr gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); - if (gconf) { - nsCAutoString colorString; - ColorToCString(aColor, colorString); - gconf->SetString(NS_LITERAL_CSTRING(kDesktopColorKey), colorString); } return NS_OK; } NS_IMETHODIMP nsGNOMEShellService::OpenApplication(PRInt32 aApplication)