Bug 783765 - Use libnotify as a dynamic library. r=glandium
authorMarco Castelluccio <mar.castelluccio@studenti.unina.it>
Sat, 25 Aug 2012 08:54:16 +0200
changeset 105413 d7fb23a822dd7ce3d641dcaa7ca485ee96fafb0e
parent 105412 542e9ac22e76fc3d462add927c788063b940cd9d
child 105414 8056f890ce791be8e9b8d4b55fd21203171e83fd
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersglandium
bugs783765
milestone17.0a1
Bug 783765 - Use libnotify as a dynamic library. r=glandium
config/system-headers
configure.in
js/src/config/system-headers
toolkit/system/gnome/Makefile.in
toolkit/system/gnome/nsAlertsIconListener.cpp
toolkit/system/gnome/nsAlertsIconListener.h
toolkit/system/gnome/nsGnomeModule.cpp
--- a/config/system-headers
+++ b/config/system-headers
@@ -399,17 +399,16 @@ libgnomevfs/gnome-vfs-file-info.h
 libgnomevfs/gnome-vfs.h
 libgnomevfs/gnome-vfs-init.h
 libgnomevfs/gnome-vfs-mime.h
 libgnomevfs/gnome-vfs-mime-handlers.h
 libgnomevfs/gnome-vfs-mime-utils.h
 libgnomevfs/gnome-vfs-ops.h
 libgnomevfs/gnome-vfs-standard-callbacks.h
 lib$routines.h
-libnotify/notify.h
 limits
 limits.h
 link.h
 linux/kernel.h
 linux/limits.h
 linux/rtc.h
 linux/version.h
 list
--- a/configure.in
+++ b/configure.in
@@ -69,17 +69,16 @@ WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 GIO_VERSION=2.18
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
 SQLITE_VERSION=3.7.13
-LIBNOTIFY_VERSION=0.4
 
 MSMANIFEST_TOOL=
 
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 AC_PROG_AWK
 
@@ -4924,61 +4923,22 @@ then
         AC_DEFINE(MOZ_ENABLE_LIBPROXY)
     fi
 fi
 AC_SUBST(MOZ_ENABLE_LIBPROXY)
 AC_SUBST(MOZ_LIBPROXY_CFLAGS)
 AC_SUBST(MOZ_LIBPROXY_LIBS)
 
 dnl ========================================================
-dnl = libnotify support
+dnl = GNOME component (mozgnome)
 dnl ========================================================
 
 if test "$MOZ_ENABLE_GTK2"
 then
-    MOZ_ENABLE_LIBNOTIFY=1
-
-    MOZ_ARG_DISABLE_BOOL(libnotify,
-    [  --disable-libnotify     Disable libnotify support ],
-    MOZ_ENABLE_LIBNOTIFY=,
-    MOZ_ENABLE_LIBNOTIFY=1)
-
-    if test "$MOZ_ENABLE_LIBNOTIFY"
-    then
-        AC_DEFINE(MOZ_ENABLE_LIBNOTIFY)
-    fi
-fi
-
-if test -z "$SKIP_LIBRARY_CHECKS"
-then
-    if test "$MOZ_ENABLE_GTK2"
-    then
-        if test "$MOZ_ENABLE_LIBNOTIFY"
-        then
-            PKG_CHECK_MODULES(MOZ_LIBNOTIFY, libnotify >= $LIBNOTIFY_VERSION)
-        fi
-    fi
-fi
-AC_SUBST(MOZ_ENABLE_LIBNOTIFY)
-AC_SUBST(MOZ_LIBNOTIFY_CFLAGS)
-AC_SUBST(MOZ_LIBNOTIFY_LIBS)
-
-dnl ========================================================
-dnl = GNOME component (mozgnome)
-dnl ========================================================
-
-# The GNOME component is built if one of
-# gnome-vfs, gio, gconf or libnotify is available.
-if test "$MOZ_ENABLE_GCONF" -o \
-   "$MOZ_ENABLE_GNOMEVFS" -o \
-   "$MOZ_ENABLE_GIO" -o \
-   "$MOZ_ENABLE_LIBNOTIFY"; then
     MOZ_ENABLE_GNOME_COMPONENT=1
-else
-    MOZ_ENABLE_GNOME_COMPONENT=
 fi
 AC_SUBST(MOZ_ENABLE_GNOME_COMPONENT)
 
 dnl ========================================================
 dnl = libgnomeui support module
 dnl ========================================================
 
 if test "$MOZ_ENABLE_GTK2"
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -399,17 +399,16 @@ libgnomevfs/gnome-vfs-file-info.h
 libgnomevfs/gnome-vfs.h
 libgnomevfs/gnome-vfs-init.h
 libgnomevfs/gnome-vfs-mime.h
 libgnomevfs/gnome-vfs-mime-handlers.h
 libgnomevfs/gnome-vfs-mime-utils.h
 libgnomevfs/gnome-vfs-ops.h
 libgnomevfs/gnome-vfs-standard-callbacks.h
 lib$routines.h
-libnotify/notify.h
 limits
 limits.h
 link.h
 linux/kernel.h
 linux/limits.h
 linux/rtc.h
 linux/version.h
 list
--- a/toolkit/system/gnome/Makefile.in
+++ b/toolkit/system/gnome/Makefile.in
@@ -10,18 +10,22 @@ VPATH	  = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= mozgnome
 LIBRARY_NAME	= mozgnome
 FORCE_SHARED_LIB = 1
 IS_COMPONENT	= 1
 
 
-CPPSRCS = nsGnomeModule.cpp
-	
+CPPSRCS = \
+  nsGnomeModule.cpp \
+  nsAlertsService.cpp \
+  nsAlertsIconListener.cpp \
+  $(NULL)
+
 ifdef MOZ_ENABLE_GCONF
 CPPSRCS += \
   nsGConfService.cpp \
   $(NULL)
 endif
 
 ifdef MOZ_ENABLE_GNOMEVFS
 CPPSRCS += \
@@ -31,38 +35,29 @@ endif
 
 ifdef MOZ_ENABLE_GIO
 CPPSRCS += \
 	nsGIOService.cpp \
 	nsGSettingsService.cpp \
 	$(NULL)
 endif
 
-ifdef MOZ_ENABLE_LIBNOTIFY
-CPPSRCS += \
-	nsAlertsService.cpp \
-	nsAlertsIconListener.cpp \
-	$(NULL)
-endif
-
 EXTRA_DSO_LDOPTS += \
 		$(XPCOM_GLUE_LDOPTS) \
 		$(XPCOM_FROZEN_LDOPTS) \
 		$(NSPR_LIBS) \
 		$(MOZ_GCONF_LIBS) \
 		$(MOZ_GNOMEVFS_LIBS) \
 		$(GLIB_LIBS) \
-		$(MOZ_LIBNOTIFY_LIBS) \
 		$(MOZ_GIO_LIBS) \
 		$(NULL)
 
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/build/
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += \
 	$(MOZ_GCONF_CFLAGS) \
 	$(MOZ_GNOMEVFS_CFLAGS) \
 	$(MOZ_GIO_CFLAGS) \
 	$(GLIB_CFLAGS) \
-	$(MOZ_LIBNOTIFY_CFLAGS) \
 	$(MOZ_GTK2_CFLAGS) \
 	$(NULL)
--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -8,26 +8,32 @@
 #include "imgILoader.h"
 #include "imgIRequest.h"
 #include "nsNetUtil.h"
 #include "nsIImageToPixbuf.h"
 #include "nsIStringBundle.h"
 #include "nsIObserverService.h"
 #include "nsCRT.h"
 
+#include <dlfcn.h>
 #include <gdk/gdk.h>
 
-// Compatibility macro for <libnotify-0.7
-#ifndef NOTIFY_CHECK_VERSION
-#define NOTIFY_CHECK_VERSION(x,y,z) 0
-#endif
-
 static bool gHasActions = false;
 static bool gHasCaps = false;
 
+void* nsAlertsIconListener::libNotifyHandle = nullptr;
+bool nsAlertsIconListener::libNotifyNotAvail = false;
+nsAlertsIconListener::notify_is_initted_t nsAlertsIconListener::notify_is_initted = nullptr;
+nsAlertsIconListener::notify_init_t nsAlertsIconListener::notify_init = nullptr;
+nsAlertsIconListener::notify_get_server_caps_t nsAlertsIconListener::notify_get_server_caps = nullptr;
+nsAlertsIconListener::notify_notification_new_t nsAlertsIconListener::notify_notification_new = nullptr;
+nsAlertsIconListener::notify_notification_show_t nsAlertsIconListener::notify_notification_show = nullptr;
+nsAlertsIconListener::notify_notification_set_icon_from_pixbuf_t nsAlertsIconListener::notify_notification_set_icon_from_pixbuf = nullptr;
+nsAlertsIconListener::notify_notification_add_action_t nsAlertsIconListener::notify_notification_add_action = nullptr;
+
 static void notify_action_cb(NotifyNotification *notification,
                              gchar *action, gpointer user_data)
 {
   nsAlertsIconListener* alert = static_cast<nsAlertsIconListener*> (user_data);
   alert->SendCallback();
 }
 
 static void notify_closed_marshal(GClosure* closure,
@@ -47,22 +53,45 @@ static void notify_closed_marshal(GClosu
 
 NS_IMPL_ISUPPORTS4(nsAlertsIconListener, imgIContainerObserver,
                    imgIDecoderObserver, nsIObserver, nsISupportsWeakReference)
 
 nsAlertsIconListener::nsAlertsIconListener()
 : mLoadedFrame(false),
   mNotification(NULL)
 {
+  if (!libNotifyHandle && !libNotifyNotAvail) {
+    libNotifyHandle = dlopen("libnotify.so.4", RTLD_LAZY);
+    if (!libNotifyHandle) {
+      libNotifyHandle = dlopen("libnotify.so.1", RTLD_LAZY);
+      if (!libNotifyHandle) {
+        libNotifyNotAvail = true;
+        return;
+      }
+    }
+
+    notify_is_initted = (notify_is_initted_t)dlsym(libNotifyHandle, "notify_is_initted");
+    notify_init = (notify_init_t)dlsym(libNotifyHandle, "notify_init");
+    notify_get_server_caps = (notify_get_server_caps_t)dlsym(libNotifyHandle, "notify_get_server_caps");
+    notify_notification_new = (notify_notification_new_t)dlsym(libNotifyHandle, "notify_notification_new");
+    notify_notification_show = (notify_notification_show_t)dlsym(libNotifyHandle, "notify_notification_show");
+    notify_notification_set_icon_from_pixbuf = (notify_notification_set_icon_from_pixbuf_t)dlsym(libNotifyHandle, "notify_notification_set_icon_from_pixbuf");
+    notify_notification_add_action = (notify_notification_add_action_t)dlsym(libNotifyHandle, "notify_notification_add_action");
+    if (!notify_is_initted || !notify_init || !notify_get_server_caps || !notify_notification_new || !notify_notification_show || !notify_notification_set_icon_from_pixbuf || !notify_notification_add_action) {
+      dlclose(libNotifyHandle);
+      libNotifyHandle = nullptr;
+    }
+  }
 }
 
 nsAlertsIconListener::~nsAlertsIconListener()
 {
   if (mIconRequest)
     mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
+  // Don't dlclose libnotify as it uses atexit().
 }
 
 NS_IMETHODIMP
 nsAlertsIconListener::OnStartRequest(imgIRequest* aRequest)
 {
   return NS_OK;
 }
 
@@ -180,24 +209,17 @@ nsAlertsIconListener::OnStopFrame(imgIRe
 
   mLoadedFrame = true;
   return NS_OK;
 }
 
 nsresult
 nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
 {
-  mNotification = notify_notification_new(mAlertTitle.get(),
-                                          mAlertText.get(),
-                                          NULL
-// >=libnotify-0.7.0 has no support for attaching to widgets
-#if !NOTIFY_CHECK_VERSION(0,7,0)
-                                          , NULL
-#endif
-                                          );
+  mNotification = notify_notification_new(mAlertTitle.get(), mAlertText.get(), NULL, NULL);
 
   if (!mNotification)
     return NS_ERROR_OUT_OF_MEMORY;
 
   if (aPixbuf)
     notify_notification_set_icon_from_pixbuf(mNotification, aPixbuf);
 
   NS_ADDREF(this);
@@ -279,16 +301,19 @@ nsAlertsIconListener::Observe(nsISupport
 nsresult
 nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
                                      const nsAString & aAlertTitle, 
                                      const nsAString & aAlertText,
                                      bool aAlertTextClickable,
                                      const nsAString & aAlertCookie,
                                      nsIObserver * aAlertListener)
 {
+  if (!libNotifyHandle)
+    return NS_ERROR_FAILURE;
+
   if (!notify_is_initted()) {
     // Give the name of this application to libnotify
     nsCOMPtr<nsIStringBundleService> bundleService = 
       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
 
     nsCAutoString appShortName;
     if (bundleService) {
       nsCOMPtr<nsIStringBundle> bundle;
--- a/toolkit/system/gnome/nsAlertsIconListener.h
+++ b/toolkit/system/gnome/nsAlertsIconListener.h
@@ -8,20 +8,21 @@
 
 #include "nsCOMPtr.h"
 #include "imgIDecoderObserver.h"
 #include "nsStringAPI.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
-#include <libnotify/notify.h>
 
 class imgIRequest;
 
+struct NotifyNotification;
+
 class nsAlertsIconListener : public imgIDecoderObserver,
                              public nsIObserver,
                              public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_IMGICONTAINEROBSERVER
   NS_DECL_IMGIDECODEROBSERVER
@@ -36,26 +37,50 @@ public:
                           bool aAlertTextClickable,
                           const nsAString & aAlertCookie,
                           nsIObserver * aAlertListener);
 
   void SendCallback();
   void SendClosed();
 
 protected:
+  /**
+   * The only difference between libnotify.so.4 and libnotify.so.1 for these symbols
+   * is that notify_notification_new takes three arguments in libnotify.so.4 and
+   * four in libnotify.so.1.
+   * Passing the fourth argument as NULL is binary compatible.
+   */
+  typedef void (*NotifyActionCallback)(NotifyNotification*, char*, gpointer);
+  typedef bool (*notify_is_initted_t)(void);
+  typedef bool (*notify_init_t)(const char*);
+  typedef GList* (*notify_get_server_caps_t)(void);
+  typedef NotifyNotification* (*notify_notification_new_t)(const char*, const char*, const char*, const char*);
+  typedef bool (*notify_notification_show_t)(void*, char*);
+  typedef void (*notify_notification_set_icon_from_pixbuf_t)(void*, GdkPixbuf*);
+  typedef void (*notify_notification_add_action_t)(void*, const char*, const char*, NotifyActionCallback, gpointer, GFreeFunc);
+
   nsCOMPtr<imgIRequest> mIconRequest;
   nsCString mAlertTitle;
   nsCString mAlertText;
 
   nsCOMPtr<nsIObserver> mAlertListener;
   nsString mAlertCookie;
 
   bool mLoadedFrame;
   bool mAlertHasAction;
 
+  static void* libNotifyHandle;
+  static bool libNotifyNotAvail;
+  static notify_is_initted_t notify_is_initted;
+  static notify_init_t notify_init;
+  static notify_get_server_caps_t notify_get_server_caps;
+  static notify_notification_new_t notify_notification_new;
+  static notify_notification_show_t notify_notification_show;
+  static notify_notification_set_icon_from_pixbuf_t notify_notification_set_icon_from_pixbuf;
+  static notify_notification_add_action_t notify_notification_add_action;
   NotifyNotification* mNotification;
   gulong mClosureHandler;
 
   nsresult StartRequest(const nsAString & aImageUrl);
   nsresult ShowAlert(GdkPixbuf* aPixbuf);
 };
 
 #endif
--- a/toolkit/system/gnome/nsGnomeModule.cpp
+++ b/toolkit/system/gnome/nsGnomeModule.cpp
@@ -17,67 +17,59 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGC
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGnomeVFSService, Init)
 #endif
 #ifdef MOZ_ENABLE_GIO
 #include "nsGIOService.h"
 #include "nsGSettingsService.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIOService)
 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 nsresult
 InitGType ()
 {
   g_type_init();
   return NS_OK;