Bug 402742 - "Stock icons will not display if libgnomeui is not present" [p=ventnor.bugzilla@yahoo.com.au (Michael Ventnor) r+sr=roc a=blocking1.9+]
authorreed@reedloden.com
Tue, 04 Dec 2007 14:08:41 -0800
changeset 8693 5c5038a0fa77e2ce76f6d3f875b55d73bb16596e
parent 8692 88c3c0416d15d2ab87104b274197bf2fd64f04fe
child 8694 7ad4601a2f66a721bcc3a3dce6ccd476153b0719
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherderautoland@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblocking1.9
bugs402742
milestone1.9b2pre
Bug 402742 - "Stock icons will not display if libgnomeui is not present" [p=ventnor.bugzilla@yahoo.com.au (Michael Ventnor) r+sr=roc a=blocking1.9+]
modules/libpr0n/decoders/icon/Makefile.in
modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp
--- a/modules/libpr0n/decoders/icon/Makefile.in
+++ b/modules/libpr0n/decoders/icon/Makefile.in
@@ -45,17 +45,22 @@ include $(DEPTH)/config/autoconf.mk
 MODULE		= imgicon
 LIBRARY_NAME	= imgicon
 IS_COMPONENT	= 1
 MODULE_NAME	= nsIconDecoderModule
 
 PACKAGE_FILE = imgicon.pkg
 
 ifdef MOZ_ENABLE_GNOMEUI
-EXTRA_DSO_LDOPTS = $(MOZ_GNOMEUI_LIBS)
+EXTRA_DSO_LDOPTS = \
+                   $(MOZ_GNOMEVFS_LIBS) \
+                   $(MOZ_LIBGNOME_LIBS) \
+                   $(MOZ_GTK2_LIBS) \
+                   $(NULL)
+
 PLATFORM = gtk
 FORCE_SHARED_LIB = 1
 else
 LIBXUL_LIBRARY = 1
 EXPORT_LIBRARY = 1
 endif
 
 ifeq ($(OS_ARCH),WINNT)
--- a/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp
@@ -38,17 +38,16 @@
 #include <stdlib.h>
 #include <unistd.h>
 
 // Older versions of these headers seem to be missing an extern "C"
 extern "C" {
 #include <libgnome/libgnome.h>
 #include <libgnomeui/gnome-icon-theme.h>
 #include <libgnomeui/gnome-icon-lookup.h>
-#include <libgnomeui/gnome-ui-init.h>
 
 #include <libgnomevfs/gnome-vfs-file-info.h>
 #include <libgnomevfs/gnome-vfs-ops.h>
 }
 
 #include <gtk/gtkwidget.h>
 #include <gtk/gtkiconfactory.h>
 #include <gtk/gtkimage.h>
@@ -57,23 +56,43 @@ extern "C" {
 #include <gtk/gtkversion.h>
 
 #include "nsIMIMEService.h"
 
 #include "nsIStringBundle.h"
 
 #include "nsNetUtil.h"
 #include "nsIURL.h"
+#include "prlink.h"
 
 #include "nsIconChannel.h"
 
 NS_IMPL_ISUPPORTS2(nsIconChannel,
                    nsIRequest,
                    nsIChannel)
 
+// These let us have a soft dependency on libgnomeui rather than a hard one. These are just basically the prototypes
+// of the functions in the libraries.
+typedef char* (*_GnomeIconLookup_fn)(GtkIconTheme *icon_theme, GnomeThumbnailFactory *thumbnail_factory,
+                                     const char *file_uri, const char *custom_icon, GnomeVFSFileInfo *file_info,
+                                     const char *mime_type, GnomeIconLookupFlags flags, GnomeIconLookupResultFlags *result);
+typedef GnomeIconTheme* (*_GnomeIconThemeNew_fn)(void);
+typedef char* (*_GnomeIconThemeLookupIcon_fn)(GnomeIconTheme *theme, const char *icon_name, int size,
+                                              const GnomeIconData **icon_data, int *base_size);
+typedef int (*_GnomeInit_fn)(const char *app_id, const char *app_version, int argc, char **argv, const struct poptOption *options,
+                             int flags, poptContext *return_ctx);
+
+static PRLibrary* gLibGnomeUI = nsnull;
+static PRBool gTriedToLoadLibGnomeUI = PR_FALSE;
+
+static _GnomeIconLookup_fn _gnome_icon_lookup = nsnull;
+static _GnomeIconThemeNew_fn _gnome_icon_theme_new = nsnull;
+static _GnomeIconThemeLookupIcon_fn _gnome_icon_theme_lookup_icon = nsnull;
+static _GnomeInit_fn _gnome_init = nsnull;
+
 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 &&
                  gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB &&
@@ -163,16 +182,45 @@ ensure_icon_factory()
   if (!gIconFactory) {
     gIconFactory = gtk_icon_factory_new();
     gtk_icon_factory_add_default(gIconFactory);
     g_object_unref(gIconFactory);
   }
 }
 #endif
 
+static nsresult
+ensure_libgnomeui()
+{
+  // Attempt to get the libgnomeui symbol references. We do it this way so that stock icons from Init()
+  // don't get held back by InitWithGnome()'s libgnomeui dependency.
+  if (!gTriedToLoadLibGnomeUI) {
+    gLibGnomeUI = PR_LoadLibrary("libgnomeui-2.so.0");
+    gTriedToLoadLibGnomeUI = PR_TRUE;
+    if (!gLibGnomeUI)
+      return NS_ERROR_NOT_AVAILABLE;
+
+    _gnome_init = (_GnomeInit_fn)PR_FindFunctionSymbol(gLibGnomeUI, "gnome_init_with_popt_table");
+    _gnome_icon_theme_new = (_GnomeIconThemeNew_fn)PR_FindFunctionSymbol(gLibGnomeUI, "gnome_icon_theme_new");
+    _gnome_icon_lookup = (_GnomeIconLookup_fn)PR_FindFunctionSymbol(gLibGnomeUI, "gnome_icon_lookup");
+    _gnome_icon_theme_lookup_icon = (_GnomeIconThemeLookupIcon_fn)PR_FindFunctionSymbol(gLibGnomeUI, "gnome_icon_theme_lookup_icon");
+
+    if (!_gnome_init || !_gnome_icon_theme_new || !gnome_icon_lookup || !_gnome_icon_theme_lookup_icon) {
+      PR_UnloadLibrary(gLibGnomeUI);
+      gLibGnomeUI = nsnull;
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+  }
+
+  if (!gLibGnomeUI)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  return NS_OK;
+}
+
 static GtkIconSize
 moz_gtk_icon_size(const char *name)
 {
   if (strcmp(name, "button") == 0)
     return GTK_ICON_SIZE_BUTTON;
 
   if (strcmp(name, "menu") == 0)
     return GTK_ICON_SIZE_MENU;
@@ -188,16 +236,19 @@ moz_gtk_icon_size(const char *name)
 
   return GTK_ICON_SIZE_MENU;
 }
 
 nsresult
 nsIconChannel::InitWithGnome(nsIMozIconURI *aIconURI)
 {
   nsresult rv;
+
+  if (NS_FAILED(ensure_libgnomeui()))
+    return NS_ERROR_NOT_AVAILABLE;
   
   if (!gnome_program_get()) {
     // Get the brandShortName from the string bundle to pass to GNOME
     // as the application name.  This may be used for things such as
     // the title of grouped windows in the panel.
     nsCOMPtr<nsIStringBundleService> bundleService = 
       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
 
@@ -212,17 +263,17 @@ nsIconChannel::InitWithGnome(nsIMozIconU
       bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
                                 getter_Copies(appName));
     } else {
       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);
+    _gnome_init(NS_ConvertUTF16toUTF8(appName).get(), "1.0", 1, empty, NULL, 0, NULL);
   }
 
   nsCAutoString iconSizeString;
   aIconURI->GetIconSize(iconSizeString);
 
   PRUint32 iconSize;
 
   if (iconSizeString.IsEmpty()) {
@@ -282,33 +333,34 @@ nsIconChannel::InitWithGnome(nsIMozIconU
       nsCAutoString fileExt;
       aIconURI->GetFileExtension(fileExt);
       ms->GetTypeFromExtension(fileExt, type);
     }
   }
 
   // Get the icon theme
   if (!gIconTheme) {
-    gIconTheme = gnome_icon_theme_new();
+    gIconTheme = _gnome_icon_theme_new();
+
     if (!gIconTheme) {
       gnome_vfs_file_info_clear(&fileInfo);
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
-  char* name = gnome_icon_lookup(gIconTheme, NULL, spec.get(), NULL, &fileInfo,
-                                 type.get(), GNOME_ICON_LOOKUP_FLAGS_NONE,
-                                 NULL);
+  char* name = _gnome_icon_lookup(gIconTheme, NULL, spec.get(), NULL, &fileInfo,
+                                  type.get(), GNOME_ICON_LOOKUP_FLAGS_NONE,
+                                  NULL);
+
   gnome_vfs_file_info_clear(&fileInfo);
-  if (!name) {
+  if (!name)
     return NS_ERROR_NOT_AVAILABLE;
-  }
- 
-  char* file = gnome_icon_theme_lookup_icon(gIconTheme, name, iconSize,
-                                            NULL, NULL);
+
+  char* file = _gnome_icon_theme_lookup_icon(gIconTheme, name, iconSize,
+                                             NULL, NULL);
   g_free(name);
   if (!file)
     return NS_ERROR_NOT_AVAILABLE;
 
   // Create a GdkPixbuf buffer and scale it
   GError *err = nsnull;
   GdkPixbuf* buf = gdk_pixbuf_new_from_file(file, &err);
   g_free(file);
@@ -399,9 +451,14 @@ nsIconChannel::Shutdown() {
     gtk_widget_destroy(gProtoWindow);
     gProtoWindow = nsnull;
     gStockImageWidget = nsnull;
   }
   if (gIconTheme) {
     g_object_unref(G_OBJECT(gIconTheme));
     gIconTheme = nsnull;
   }
+  if (gLibGnomeUI) {
+    PR_UnloadLibrary(gLibGnomeUI);
+    gLibGnomeUI = nsnull;
+    gTriedToLoadLibGnomeUI = PR_FALSE;
+  }
 }