Bug 858919 - Add support for libnotify calls which was removed for new notification API. r=karlt
authorMartin Stransky <stransky@redhat.com>
Fri, 14 Nov 2014 04:04:00 +0100
changeset 215781 616a7e93b73e4f3522f8308c6d3137b8172ebf1e
parent 215780 91fa670781830e500dbd503405381c2d316ceddc
child 215782 80dc5596d1585fb397316efc7bf45c10aa9f7965
push id27826
push userryanvm@gmail.com
push dateFri, 14 Nov 2014 22:30:56 +0000
treeherdermozilla-central@dfe8756ccd94 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs858919
milestone36.0a1
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 858919 - Add support for libnotify calls which was removed for new notification API. r=karlt
toolkit/components/alerts/nsAlertsService.cpp
toolkit/system/gnome/moz.build
toolkit/system/gnome/nsAlertsIconListener.cpp
toolkit/system/gnome/nsAlertsIconListener.h
toolkit/system/gnome/nsGnomeModule.cpp
toolkit/system/gnome/nsSystemAlertsService.cpp
toolkit/system/gnome/nsSystemAlertsService.h
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -95,20 +95,22 @@ NS_IMETHODIMP nsAlertsService::ShowAlert
   mozilla::AndroidBridge::Bridge()->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertCookie,
                                                           aAlertListener, aAlertName);
   return NS_OK;
 #else
   // Check if there is an optional service that handles system-level notifications
   nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
   nsresult rv;
   if (sysAlerts) {
-    return sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
-                                            aAlertCookie, aAlertListener, aAlertName,
-                                            aBidi, aLang, aData,
-                                            IPC::Principal(aPrincipal));
+    rv = sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
+                                          aAlertCookie, aAlertListener, aAlertName,
+                                          aBidi, aLang, aData,
+                                          IPC::Principal(aPrincipal));
+    if (NS_SUCCEEDED(rv))
+      return NS_OK;
   }
 
   if (!ShouldShowAlert()) {
     // Do not display the alert. Instead call alertfinished and get out.
     if (aAlertListener)
       aAlertListener->Observe(nullptr, "alertfinished", PromiseFlatString(aAlertCookie).get());
     return NS_OK;
   }
--- a/toolkit/system/gnome/moz.build
+++ b/toolkit/system/gnome/moz.build
@@ -1,16 +1,18 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SOURCES += [
+    'nsAlertsIconListener.cpp',
     'nsGnomeModule.cpp',
+    'nsSystemAlertsService.cpp',
 ]
 
 if CONFIG['MOZ_ENABLE_GCONF']:
     SOURCES += [
         'nsGConfService.cpp',
     ]
 
 if CONFIG['MOZ_ENABLE_GNOMEVFS']:
--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -46,16 +46,31 @@ static void notify_closed_marshal(GClosu
   NS_ABORT_IF_FALSE(n_param_values >= 1, "No object in params");
 
   nsAlertsIconListener* alert =
     static_cast<nsAlertsIconListener*>(closure->data);
   alert->SendClosed();
   NS_RELEASE(alert);
 }
 
+static GdkPixbuf*
+GetPixbufFromImgRequest(imgIRequest* aRequest)
+{
+  nsCOMPtr<imgIContainer> image;
+  nsresult rv = aRequest->GetImage(getter_AddRefs(image));
+  if (NS_FAILED(rv)) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
+    do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
+
+  return imgToPixbuf->ConvertImageToPixbuf(image);
+}
+
 NS_IMPL_ISUPPORTS(nsAlertsIconListener, imgINotificationObserver,
                   nsIObserver, nsISupportsWeakReference)
 
 nsAlertsIconListener::nsAlertsIconListener()
 : mLoadedFrame(false),
   mNotification(nullptr)
 {
   if (!libNotifyHandle && !libNotifyNotAvail) {
@@ -101,57 +116,55 @@ nsAlertsIconListener::Notify(imgIRequest
   }
 
   return NS_OK;
 }
 
 nsresult
 nsAlertsIconListener::OnStopRequest(imgIRequest* aRequest)
 {
+  NS_ASSERTION(mIconRequest == aRequest, "aRequest does not match!");
+
   uint32_t imgStatus = imgIRequest::STATUS_ERROR;
   nsresult rv = aRequest->GetImageStatus(&imgStatus);
   NS_ENSURE_SUCCESS(rv, rv);
   if ((imgStatus & imgIRequest::STATUS_ERROR) && !mLoadedFrame) {
     // We have an error getting the image. Display the notification with no icon.
     ShowAlert(nullptr);
-  }
 
-  if (mIconRequest) {
+    // Cancel any pending request
     mIconRequest->Cancel(NS_BINDING_ABORTED);
     mIconRequest = nullptr;
   }
+
   return NS_OK;
 }
 
 nsresult
 nsAlertsIconListener::OnStopFrame(imgIRequest* aRequest)
 {
-  if (aRequest != mIconRequest)
-    return NS_ERROR_FAILURE;
+  NS_ASSERTION(mIconRequest == aRequest, "aRequest does not match!");
 
   if (mLoadedFrame)
     return NS_OK; // only use one frame
 
-  nsCOMPtr<imgIContainer> image;
-  nsresult rv = aRequest->GetImage(getter_AddRefs(image));
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
-    do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
-
-  GdkPixbuf* imagePixbuf = imgToPixbuf->ConvertImageToPixbuf(image);
-  if (!imagePixbuf)
-    return NS_ERROR_FAILURE;
-
-  ShowAlert(imagePixbuf);
-
-  g_object_unref(imagePixbuf);
+  GdkPixbuf* imagePixbuf = GetPixbufFromImgRequest(aRequest);
+  if (!imagePixbuf) {
+    ShowAlert(nullptr);
+  } else {
+    ShowAlert(imagePixbuf);
+    g_object_unref(imagePixbuf);
+  }
 
   mLoadedFrame = true;
+
+  // Cancel any pending request (multipart image loading/decoding for instance)
+  mIconRequest->Cancel(NS_BINDING_ABORTED);
+  mIconRequest = nullptr;
+
   return NS_OK;
 }
 
 nsresult
 nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
 {
   mNotification = notify_notification_new(mAlertTitle.get(), mAlertText.get(),
                                           nullptr, nullptr);
@@ -175,16 +188,19 @@ nsAlertsIconListener::ShowAlert(GdkPixbu
   // different signature, so a marshaller is used instead of a C callback to
   // get the user_data (this) in a parseable format.  |closure| is created
   // with a floating reference, which gets sunk by g_signal_connect_closure().
   GClosure* closure = g_closure_new_simple(sizeof(GClosure), this);
   g_closure_set_marshal(closure, notify_closed_marshal);
   mClosureHandler = g_signal_connect_closure(mNotification, "closed", closure, FALSE);
   gboolean result = notify_notification_show(mNotification, nullptr);
 
+  if (result && mAlertListener)
+    mAlertListener->Observe(nullptr, "alertshow", mAlertCookie.get());
+
   return result ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsAlertsIconListener::StartRequest(const nsAString & aImageUrl)
 {
   if (mIconRequest) {
     // Another icon request is already in flight.  Kill it.
@@ -196,19 +212,25 @@ nsAlertsIconListener::StartRequest(const
   NS_NewURI(getter_AddRefs(imageUri), aImageUrl);
   if (!imageUri)
     return ShowAlert(nullptr);
 
   nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1"));
   if (!il)
     return ShowAlert(nullptr);
 
-  return il->LoadImageXPCOM(imageUri, nullptr, nullptr, nullptr, nullptr,
-                            this, nullptr, nsIRequest::LOAD_NORMAL, nullptr,
-                            nullptr, getter_AddRefs(mIconRequest));
+  nsresult rv = il->LoadImageXPCOM(imageUri, nullptr, nullptr, nullptr, nullptr,
+                                   this, nullptr, nsIRequest::LOAD_NORMAL, nullptr,
+                                   0 /* use default */, getter_AddRefs(mIconRequest));
+  if (NS_FAILED(rv))
+    return rv;
+
+  mIconRequest->StartDecoding();
+
+  return NS_OK;
 }
 
 void
 nsAlertsIconListener::SendCallback()
 {
   if (mAlertListener)
     mAlertListener->Observe(nullptr, "alertclickcallback", mAlertCookie.get());
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/system/gnome/nsAlertsIconListener.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsAlertsIconListener_h__
+#define nsAlertsIconListener_h__
+
+#include "nsCOMPtr.h"
+#include "imgINotificationObserver.h"
+#include "nsStringAPI.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+class imgIRequest;
+
+struct NotifyNotification;
+
+class nsAlertsIconListener : public imgINotificationObserver,
+                             public nsIObserver,
+                             public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IMGINOTIFICATIONOBSERVER
+  NS_DECL_NSIOBSERVER
+
+  nsAlertsIconListener();
+
+  nsresult InitAlertAsync(const nsAString & aImageUrl,
+                          const nsAString & aAlertTitle, 
+                          const nsAString & aAlertText,
+                          bool aAlertTextClickable,
+                          const nsAString & aAlertCookie,
+                          nsIObserver * aAlertListener);
+
+  void SendCallback();
+  void SendClosed();
+
+protected:
+  virtual ~nsAlertsIconListener();
+
+  nsresult OnStopRequest(imgIRequest* aRequest);
+  nsresult OnStopFrame(imgIRequest* aRequest);
+
+  /**
+   * 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,53 +17,58 @@ 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
+#include "nsSystemAlertsService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemAlertsService, Init)
 
 #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
+NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID);
 
 static const mozilla::Module::CIDEntry kGnomeCIDs[] = {
 #ifdef MOZ_ENABLE_GCONF
   { &kNS_GCONFSERVICE_CID, false, nullptr, nsGConfServiceConstructor },
 #endif
 #ifdef MOZ_ENABLE_GNOMEVFS
   { &kNS_GNOMEVFSSERVICE_CID, false, nullptr, nsGnomeVFSServiceConstructor },
 #endif
 #ifdef MOZ_ENABLE_GIO
   { &kNS_GIOSERVICE_CID, false, nullptr, nsGIOServiceConstructor },
   { &kNS_GSETTINGSSERVICE_CID, false, nullptr, nsGSettingsServiceConstructor },
 #endif
+  { &kNS_SYSTEMALERTSSERVICE_CID, false, nullptr, nsSystemAlertsServiceConstructor },
   { nullptr }
 };
 
 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
+  { NS_SYSTEMALERTSERVICE_CONTRACTID, &kNS_SYSTEMALERTSSERVICE_CID },
   { nullptr }
 };
 
 static nsresult
 InitGType ()
 {
   g_type_init();
   return NS_OK;
new file mode 100644
--- /dev/null
+++ b/toolkit/system/gnome/nsSystemAlertsService.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsXULAppAPI.h"
+#include "nsSystemAlertsService.h"
+#include "nsAlertsIconListener.h"
+#include "nsAutoPtr.h"
+
+NS_IMPL_ADDREF(nsSystemAlertsService)
+NS_IMPL_RELEASE(nsSystemAlertsService)
+
+NS_INTERFACE_MAP_BEGIN(nsSystemAlertsService)
+   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAlertsService)
+   NS_INTERFACE_MAP_ENTRY(nsIAlertsService)
+NS_INTERFACE_MAP_END_THREADSAFE
+
+nsSystemAlertsService::nsSystemAlertsService()
+{
+}
+
+nsSystemAlertsService::~nsSystemAlertsService()
+{}
+
+nsresult
+nsSystemAlertsService::Init()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsSystemAlertsService::ShowAlertNotification(const nsAString & aImageUrl, const nsAString & aAlertTitle, 
+                                                           const nsAString & aAlertText, bool aAlertTextClickable,
+                                                           const nsAString & aAlertCookie,
+                                                           nsIObserver * aAlertListener,
+                                                           const nsAString & aAlertName,
+                                                           const nsAString & aBidi,
+                                                           const nsAString & aLang,
+                                                           const nsAString & aData,
+                                                           nsIPrincipal * aPrincipal)
+{
+  nsRefPtr<nsAlertsIconListener> alertListener = new nsAlertsIconListener();
+  if (!alertListener)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  return alertListener->InitAlertAsync(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
+                                       aAlertCookie, aAlertListener);
+}
+
+NS_IMETHODIMP nsSystemAlertsService::CloseAlert(const nsAString& aAlertName,
+                                                nsIPrincipal* aPrincipal)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/system/gnome/nsSystemAlertsService.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsSystemAlertsService_h__
+#define nsSystemAlertsService_h__
+
+#include "nsIAlertsService.h"
+#include "nsCOMPtr.h"
+
+class nsSystemAlertsService : public nsIAlertsService
+{
+public:
+  NS_DECL_NSIALERTSSERVICE
+  NS_DECL_ISUPPORTS
+
+  nsSystemAlertsService();
+
+  nsresult Init();
+
+protected:
+  virtual ~nsSystemAlertsService();
+
+};
+
+#endif /* nsSystemAlertsService_h__ */