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 231995 616a7e93b73e4f3522f8308c6d3137b8172ebf1e
parent 231994 91fa670781830e500dbd503405381c2d316ceddc
child 231996 80dc5596d1585fb397316efc7bf45c10aa9f7965
push id7326
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:58:42 +0000
treeherdermozilla-aurora@d3a3b2a0f2f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs858919
milestone36.0a1
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__ */