Bug 611953 - Part 3: GNOME 3.0 readiness; r=roc,karlt
authorChris Coulson <chrisccoulson@ubuntu.com>
Tue, 12 Apr 2011 16:11:20 -0400
changeset 68072 fdd8cf56674f2991cab501b05c93c5b4f5d829e5
parent 68071 1c4241b5a0d4ef16348b3f1721cf6c95b240d597
child 68073 0f251ed101927d0083751daa2cf06c29ae120489
push id19495
push usereakhgari@mozilla.com
push dateWed, 13 Apr 2011 18:01:10 +0000
treeherdermozilla-central@800bb4e93950 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, karlt
bugs611953
milestone2.2a1pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 611953 - Part 3: GNOME 3.0 readiness; r=roc,karlt
browser/components/shell/src/nsGNOMEShellService.cpp
browser/components/shell/src/nsGNOMEShellService.h
toolkit/system/gnome/nsGIOService.cpp
xpcom/system/nsIGIOService.idl
--- 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<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
   nsCOMPtr<nsIGIOService> 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<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
+  nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
 
   PRBool enabled;
   nsCAutoString handler;
+  nsCOMPtr<nsIGIOMimeApp> 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);
-
-    // 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 (gconf) {
+      handler.Truncate();
+      gconf->GetAppForProtocol(nsDependentCString(appProtocols[i].name),
+                               &enabled, handler);
 
-    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<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
+  nsCOMPtr<nsIGIOService> 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<nsIGIOService> giovfs =
-      do_GetService(NS_GIOSERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, NS_OK);
-
     nsCOMPtr<nsIStringBundleService> bundleService =
       do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIStringBundle> 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<nsIGIOMimeApp> 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<nsIGConfService> 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<nsIGConfService> 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<nsIGConfService> 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<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
+  if (giovfs) {
+    nsCOMPtr<nsIGIOMimeApp> gioApp;
+    giovfs->GetAppForURIScheme(scheme, getter_AddRefs(gioApp));
+    if (gioApp)
+      return gioApp->Launch(EmptyCString());
+  }
+
   nsCOMPtr<nsIGConfService> 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;
 
--- 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;
 };
 
--- 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;
--- 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 */