Bug 467168 - migrate libgnome and libgnomeui to GTK/GIO functions, r=karlt
authorjhorak@redhat.com
Fri, 17 Jun 2011 03:05:00 -0700
changeset 71288 78ed4ddb5fbd0715fe35bafa3de9417b5b93a18b
parent 71287 3a59f48381adfa7e03ad709061e240dd128d0cae
child 71289 2cc9093cdd2399744acab52c47350c5bd62e6690
push idunknown
push userunknown
push dateunknown
reviewerskarlt
bugs467168
milestone7.0a1
Bug 467168 - migrate libgnome and libgnomeui to GTK/GIO functions, r=karlt
configure.in
modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp
modules/libpr0n/decoders/icon/gtk/nsIconChannel.h
--- a/configure.in
+++ b/configure.in
@@ -122,17 +122,17 @@ PYTHON_VERSION=2.5
 CAIRO_VERSION=1.10
 PANGO_VERSION=1.14.0
 GTK2_VERSION=2.10.0
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.8
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
-GIO_VERSION=2.0
+GIO_VERSION=2.18
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
 SQLITE_VERSION=3.7.5
 LIBNOTIFY_VERSION=0.4
 
 MSMANIFEST_TOOL=
 
 dnl Set various checks
@@ -5451,16 +5451,18 @@ then
     dnl ========================================================
     MOZ_ARG_ENABLE_BOOL(gio,
     [  --enable-gio            Enable GIO support (default: disabled)],
         MOZ_ENABLE_GIO=force,
         MOZ_ENABLE_GIO=)
 
     if test "$MOZ_ENABLE_GIO" -a "$MOZ_ENABLE_GTK2"
     then
+        PKG_CHECK_MODULES(_GTKCHECK, gtk+-2.0 >= 2.14, , 
+                          [AC_MSG_ERROR([* * * Could not find gtk+-2.0 > 2.14. Required for build with gio.])])
         PKG_CHECK_MODULES(MOZ_GIO, gio-2.0 >= $GIO_VERSION,[
             MOZ_GIO_LIBS=`echo $MOZ_GIO_LIBS | sed 's/-llinc\>//'`
             MOZ_ENABLE_GIO=1
             AC_DEFINE(MOZ_ENABLE_GIO)
         ],[
             if test "$MOZ_ENABLE_GIO" = "force"
             then
                 AC_MSG_ERROR([* * * Could not find gio-2.0 >= $GIO_VERSION])
--- a/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp
@@ -45,16 +45,19 @@ extern "C" {
 #include <libgnome/libgnome.h>
 #include <libgnomeui/gnome-icon-theme.h>
 #include <libgnomeui/gnome-icon-lookup.h>
 
 #include <libgnomevfs/gnome-vfs-file-info.h>
 #include <libgnomevfs/gnome-vfs-ops.h>
 }
 #endif
+#ifdef MOZ_ENABLE_GIO
+#include <gio/gio.h>
+#endif
 
 #include <gtk/gtk.h>
 
 #include "nsIMIMEService.h"
 
 #include "nsIStringBundle.h"
 
 #include "nsNetUtil.h"
@@ -86,17 +89,17 @@ static PRLibrary* gLibGnomeVFS = nsnull;
 static PRBool gTriedToLoadGnomeLibs = PR_FALSE;
 
 static _GnomeIconLookup_fn _gnome_icon_lookup = nsnull;
 static _GnomeIconThemeNew_fn _gnome_icon_theme_new = nsnull;
 static _GnomeInit_fn _gnome_init = nsnull;
 static _GnomeProgramGet_fn _gnome_program_get = nsnull;
 static _GnomeVFSGetFileInfo_fn _gnome_vfs_get_file_info = nsnull;
 static _GnomeVFSFileInfoClear_fn _gnome_vfs_file_info_clear = nsnull;
-#endif
+#endif //MOZ_ENABLE_GNOMEUI
 
 static nsresult
 moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI *aURI,
                           nsIChannel **aChannel)
 {
   int width = gdk_pixbuf_get_width(aPixbuf);
   int height = gdk_pixbuf_get_height(aPixbuf);
   NS_ENSURE_TRUE(height < 256 && width < 256 && height > 0 && width > 0 &&
@@ -156,17 +159,17 @@ moz_gdk_pixbuf_to_channel(GdkPixbuf* aPi
                                 NS_LITERAL_CSTRING("image/icon"));
   return rv;
 }
 
 static GtkWidget *gProtoWindow = nsnull;
 static GtkWidget *gStockImageWidget = nsnull;
 #ifdef MOZ_ENABLE_GNOMEUI
 static GnomeIconTheme *gIconTheme = nsnull;
-#endif
+#endif //MOZ_ENABLE_GNOMEUI
 
 static void
 ensure_stock_image_widget()
 {
   // Only the style of the GtkImage needs to be used, but the widget is kept
   // to track dynamic style changes.
   if (!gProtoWindow) {
     gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP);
@@ -247,17 +250,17 @@ ensure_libgnomevfs()
     }
   }
 
   if (!gLibGnomeVFS)
     return NS_ERROR_NOT_AVAILABLE;
 
   return NS_OK;
 }
-#endif
+#endif //MOZ_ENABLE_GNOMEUI
 
 static GtkIconSize
 moz_gtk_icon_size(const char *name)
 {
   if (strcmp(name, "button") == 0)
     return GTK_ICON_SIZE_BUTTON;
 
   if (strcmp(name, "menu") == 0)
@@ -273,16 +276,54 @@ moz_gtk_icon_size(const char *name)
     return GTK_ICON_SIZE_DND;
 
   if (strcmp(name, "dialog") == 0)
     return GTK_ICON_SIZE_DIALOG;
 
   return GTK_ICON_SIZE_MENU;
 }
 
+static PRInt32
+GetIconSize(nsIMozIconURI *aIconURI)
+{
+  nsCAutoString iconSizeString;
+
+  aIconURI->GetIconSize(iconSizeString);
+  if (iconSizeString.IsEmpty()) {
+    PRUint32 size;
+    nsresult rv = aIconURI->GetImageSize(&size);
+    NS_ASSERTION(NS_SUCCEEDED(rv), "GetImageSize failed");
+    return size; 
+  } else {
+    int size;
+
+    GtkIconSize icon_size = moz_gtk_icon_size(iconSizeString.get());
+    gtk_icon_size_lookup(icon_size, &size, NULL);
+    return size;
+  }
+}
+
+/* Scale icon buffer to preferred size */
+static nsresult
+ScaleIconBuf(GdkPixbuf **aBuf, PRInt32 iconSize)
+{
+  // Scale buffer only if width or height differ from preferred size
+  if (gdk_pixbuf_get_width(*aBuf)  != iconSize &&
+      gdk_pixbuf_get_height(*aBuf) != iconSize) {
+    GdkPixbuf *scaled = gdk_pixbuf_scale_simple(*aBuf, iconSize, iconSize,
+                                                GDK_INTERP_BILINEAR);
+    // replace original buffer by scaled
+    g_object_unref(*aBuf);
+    *aBuf = scaled;
+    if (!scaled)
+      return NS_ERROR_OUT_OF_MEMORY;
+  }
+  return NS_OK;
+}
+
 #ifdef MOZ_ENABLE_GNOMEUI
 nsresult
 nsIconChannel::InitWithGnome(nsIMozIconURI *aIconURI)
 {
   nsresult rv;
 
   if (NS_FAILED(ensure_libgnomeui()) || NS_FAILED(ensure_libgnome()) || NS_FAILED(ensure_libgnomevfs())) {
     gTriedToLoadGnomeLibs = PR_TRUE;
@@ -312,32 +353,17 @@ nsIconChannel::InitWithGnome(nsIMozIconU
       NS_WARNING("brand.properties not present, using default application name");
       appName.Assign(NS_LITERAL_STRING("Gecko"));
     }
 
     char* empty[] = { "" };
     _gnome_init(NS_ConvertUTF16toUTF8(appName).get(), "1.0", 1, empty, NULL, 0, NULL);
   }
 
-  nsCAutoString iconSizeString;
-  aIconURI->GetIconSize(iconSizeString);
-
-  PRUint32 iconSize;
-
-  if (iconSizeString.IsEmpty()) {
-    rv = aIconURI->GetImageSize(&iconSize);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "GetImageSize failed");
-  } else {
-    int size;
-    
-    GtkIconSize icon_size = moz_gtk_icon_size(iconSizeString.get());
-    gtk_icon_size_lookup(icon_size, &size, NULL);
-    iconSize = size;
-  }
-
+  PRUint32 iconSize = GetIconSize(aIconURI);
   nsCAutoString type;
   aIconURI->GetContentType(type);
 
   GnomeVFSFileInfo fileInfo = {0};
   fileInfo.refcount = 1; // In case some GnomeVFS function addrefs and releases it
 
   nsCAutoString spec;
   nsCOMPtr<nsIURL> url;
@@ -362,17 +388,16 @@ nsIconChannel::InitWithGnome(nsIMozIconU
 
       if (!type.IsEmpty()) {
         fileInfo.valid_fields = GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
         fileInfo.mime_type = g_strdup(type.get());
       }
     }
   }
 
-
   if (type.IsEmpty()) {
     nsCOMPtr<nsIMIMEService> ms(do_GetService("@mozilla.org/mime;1"));
     if (ms) {
       nsCAutoString fileExt;
       aIconURI->GetFileExtension(fileExt);
       if (!fileExt.IsEmpty()) {
         ms->GetTypeFromExtension(fileExt, type);
       }
@@ -402,59 +427,153 @@ nsIconChannel::InitWithGnome(nsIMozIconU
   if (!theme) {
     g_free(name);
     return NS_ERROR_UNEXPECTED;
   }
 
   GError *err = nsnull;
   GdkPixbuf* buf = gtk_icon_theme_load_icon(theme, name, iconSize, (GtkIconLookupFlags)0, &err);
   g_free(name);
-  
+
   if (!buf) {
     if (err)
       g_error_free(err);
     return NS_ERROR_UNEXPECTED;
   }
 
-  GdkPixbuf* scaled = buf;
-  if (PRUint32(gdk_pixbuf_get_width(buf))  != iconSize &&
-      PRUint32(gdk_pixbuf_get_height(buf)) != iconSize) {
-    // scale...
-    scaled = gdk_pixbuf_scale_simple(buf, iconSize, iconSize,
-                                     GDK_INTERP_BILINEAR);
-    g_object_unref(buf);
-    if (!scaled)
-      return NS_ERROR_OUT_OF_MEMORY;
+  rv = ScaleIconBuf(&buf, iconSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = moz_gdk_pixbuf_to_channel(buf, aIconURI,
+                                 getter_AddRefs(mRealChannel));
+  g_object_unref(buf);
+  return rv;
+}
+#endif // MOZ_ENABLE_GNOMEUI
+
+#ifdef MOZ_ENABLE_GIO
+nsresult
+nsIconChannel::InitWithGIO(nsIMozIconURI *aIconURI)
+{
+  nsresult rv;
+
+  GIcon *icon = NULL;
+  nsCOMPtr<nsIURL> fileURI;
+
+  // Read icon content
+  aIconURI->GetIconURL(getter_AddRefs(fileURI));
+
+  // Get icon for file specified by URI
+  if (fileURI) {
+    PRBool isFile;
+    nsCAutoString spec;
+    fileURI->GetAsciiSpec(spec);
+    if (NS_SUCCEEDED(fileURI->SchemeIs("file", &isFile)) && isFile) {
+      GFile *file = g_file_new_for_uri(spec.get());
+      GFileInfo *fileInfo = g_file_query_info(file,
+                                              G_FILE_ATTRIBUTE_STANDARD_ICON,
+                                              G_FILE_QUERY_INFO_NONE, NULL, NULL);
+      g_object_unref(file);
+      if (fileInfo) {
+        // icon from g_content_type_get_icon doesn't need unref
+        icon = g_file_info_get_icon(fileInfo);
+        if (icon)
+          g_object_ref(icon);
+        g_object_unref(fileInfo);
+      }
+    }
+  }
+  
+  // Try to get icon by using MIME type
+  if (!icon) {
+    nsCAutoString type;
+    aIconURI->GetContentType(type);
+    // Try to get MIME type from file extension by using nsIMIMEService
+    if (type.IsEmpty()) {
+      nsCOMPtr<nsIMIMEService> ms(do_GetService("@mozilla.org/mime;1"));
+      if (ms) {
+        nsCAutoString fileExt;
+        aIconURI->GetFileExtension(fileExt);
+        ms->GetTypeFromExtension(fileExt, type);
+      }
+    }
+    char *ctype = NULL; // character representation of content type
+    if (!type.IsEmpty()) {
+      ctype = g_content_type_from_mime_type(type.get());
+    }
+    if (ctype) {
+      icon = g_content_type_get_icon(ctype);
+      g_free(ctype);
+    }
   }
 
-  // XXX Respect icon state
+  // Get default icon theme
+  GtkIconTheme *iconTheme = gtk_icon_theme_get_default();  
+  GtkIconInfo *iconInfo = NULL;
+  // Get icon size
+  PRInt32 iconSize = GetIconSize(aIconURI);
+
+  if (icon) {
+    NS_SUCCEEDED(rv);
+
+    // Use icon and theme to get GtkIconInfo
+    iconInfo = gtk_icon_theme_lookup_by_gicon(iconTheme,
+                                              icon, iconSize,
+                                              (GtkIconLookupFlags)0);
+    g_object_unref(icon);
+  }
   
-  rv = moz_gdk_pixbuf_to_channel(scaled, aIconURI,
+  if (!iconInfo) {
+    // Mozilla's mimetype lookup failed. Try the "unknown" icon.
+    iconInfo = gtk_icon_theme_lookup_icon(iconTheme,
+                                          "unknown", iconSize,
+                                          (GtkIconLookupFlags)0);
+    if (!iconInfo) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+  }
+  
+  // Create a GdkPixbuf buffer containing icon and scale it
+  GdkPixbuf* buf = gtk_icon_info_load_icon(iconInfo, NULL);
+  gtk_icon_info_free(iconInfo);
+  if (!buf) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  
+  rv = ScaleIconBuf(&buf, iconSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = moz_gdk_pixbuf_to_channel(buf, aIconURI,
                                  getter_AddRefs(mRealChannel));
-  g_object_unref(scaled);
+  g_object_unref(buf);
   return rv;
 }
-#endif
+#endif // MOZ_ENABLE_GIO
 
 nsresult
 nsIconChannel::Init(nsIURI* aURI)
 {
   nsCOMPtr<nsIMozIconURI> iconURI = do_QueryInterface(aURI);
   NS_ASSERTION(iconURI, "URI is not an nsIMozIconURI");
 
   nsCAutoString stockIcon;
   iconURI->GetStockIcon(stockIcon);
   if (stockIcon.IsEmpty()) {
 #ifdef MOZ_ENABLE_GNOMEUI
     return InitWithGnome(iconURI);
+#else 
+#ifdef MOZ_ENABLE_GIO
+    return InitWithGIO(iconURI);
 #else
     return NS_ERROR_NOT_AVAILABLE;
 #endif
+#endif
   }
 
+  // Search for stockIcon
   nsCAutoString iconSizeString;
   iconURI->GetIconSize(iconSizeString);
 
   nsCAutoString iconStateString;
   iconURI->GetIconState(iconStateString);
 
   GtkIconSize icon_size = moz_gtk_icon_size(iconSizeString.get());
   GtkStateType state = iconStateString.EqualsLiteral("disabled") ?
@@ -566,10 +685,10 @@ nsIconChannel::Shutdown() {
   if (gLibGnome) {
     PR_UnloadLibrary(gLibGnome);
     gLibGnome = nsnull;
   }
   if (gLibGnomeVFS) {
     PR_UnloadLibrary(gLibGnomeVFS);
     gLibGnomeVFS = nsnull;
   }
-#endif
+#endif //MOZ_ENABLE_GNOMEUI
 }
--- a/modules/libpr0n/decoders/icon/gtk/nsIconChannel.h
+++ b/modules/libpr0n/decoders/icon/gtk/nsIconChannel.h
@@ -71,11 +71,12 @@ class nsIconChannel : public nsIChannel 
      * Will always be non-null after a successful Init.
      */
     nsCOMPtr<nsIChannel> mRealChannel;
 
     /**
      * Called by Init if we need to use the gnomeui library.
      */
     nsresult InitWithGnome(nsIMozIconURI *aURI);
+    nsresult InitWithGIO(nsIMozIconURI *aIconURI);
 };
 
 #endif