Bug 469880 - Implement callback support for libnotify notifications, and fall back to XUL notifications if the server doesn't support callbacks. r+sr=roc

This commit is contained in:
Michael Ventnor 2009-05-04 10:11:11 +02:00
Родитель 31343a5e86
Коммит 7b6ec343ea
9 изменённых файлов: 203 добавлений и 14 удалений

Просмотреть файл

@ -5282,13 +5282,15 @@ dnl ========================================================
dnl = libnotify support
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(libnotify,
[ --enable-libnotify Enable libnotify support ],
MOZ_ENABLE_LIBNOTIFY=1,
MOZ_ENABLE_LIBNOTIFY=)
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)

Просмотреть файл

@ -57,5 +57,9 @@ DIRS += \
$(NULL)
endif
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -76,13 +76,16 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
{
// Check if there is an optional service that handles system-level notifications
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
if (sysAlerts)
return sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aAlertName);
nsresult rv;
if (sysAlerts) {
rv = sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aAlertName);
if (NS_SUCCEEDED(rv))
return rv;
}
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
nsCOMPtr<nsIDOMWindow> newWindow;
nsresult rv;
nsCOMPtr<nsISupportsArray> argsArray;
rv = NS_NewISupportsArray(getter_AddRefs(argsArray));

Просмотреть файл

@ -0,0 +1,55 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = toolkit/components/alerts/test
include $(DEPTH)/config/autoconf.mk
# Mochitest tests
MOCHI_TESTS = \
test_alerts.html \
$(NULL)
include $(topsrcdir)/config/rules.mk
libs:: $(MOCHI_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Alerts Service</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
Alerts service mochitest<br/>
Did an alert appear anywhere?<br/>
If so, the test will finish once the alert disappears. If not, the test will time out.<br/>
<pre id="test">
<script class="testbody" type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var observer = {
observe: function (aSubject, aTopic, aData) {
if (aTopic != "alertclickcallback") // Did someone click the alert while running mochitests?...
is(aTopic, "alertfinished", "Checking the topic for a finished notification");
is(aData, "foobarcookie", "Checking whether the alert cookie was passed correctly");
SimpleTest.finish();
}
};
const Cc = Components.classes;
const Ci = Components.interfaces;
try {
var notifier = Cc["@mozilla.org/alerts-service;1"].
getService(Ci.nsIAlertsService);
notifier.showAlertNotification(null, "Notification test", "Surprise! I'm here to test notifications!",
false, "foobarcookie", observer);
SimpleTest.waitForExplicitFinish();
} catch (ex) {
// Alerts service doesn't exist
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -56,6 +56,8 @@ REQUIRES = \
imglib2 \
intl \
widget \
thebes \
cairo \
$(NULL)
CPPSRCS = \

Просмотреть файл

@ -46,6 +46,26 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libnotify/notify.h>
#include <gdk/gdk.h>
static PRBool gHasActions = PR_FALSE;
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_cb(NotifyNotification *notification,
gpointer user_data)
{
g_object_unref(notification);
nsAlertsIconListener* alert = static_cast<nsAlertsIconListener*> (user_data);
alert->SendClosed();
NS_RELEASE(alert);
}
NS_IMPL_ISUPPORTS2(nsAlertsIconListener, imgIContainerObserver, imgIDecoderObserver)
@ -193,9 +213,17 @@ nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
if (aPixbuf)
notify_notification_set_icon_from_pixbuf(notify, aPixbuf);
notify_notification_set_timeout(notify, NOTIFY_EXPIRES_DEFAULT);
NS_ADDREF(this);
if (mAlertHasAction) {
// What we put as the label doesn't matter here, if the action
// string is "default" then that makes the entire bubble clickable
// rather than creating a button.
notify_notification_add_action(notify, "default", "Activate",
notify_action_cb, this, NULL);
}
g_signal_connect(notify, "closed", G_CALLBACK(notify_closed_cb), this);
gboolean result = notify_notification_show(notify, NULL);
g_object_unref(notify);
return result ? NS_OK : NS_ERROR_FAILURE;
}
@ -223,10 +251,25 @@ nsAlertsIconListener::StartRequest(const nsAString & aImageUrl)
getter_AddRefs(mIconRequest));
}
void
nsAlertsIconListener::SendCallback()
{
mAlertListener->Observe(NULL, "alertclickcallback", mAlertCookie.get());
}
void
nsAlertsIconListener::SendClosed()
{
mAlertListener->Observe(NULL, "alertfinished", mAlertCookie.get());
}
nsresult
nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
const nsAString & aAlertTitle,
const nsAString & aAlertText)
const nsAString & aAlertText,
PRBool aAlertTextClickable,
const nsAString & aAlertCookie,
nsIObserver * aAlertListener)
{
if (!notify_is_initted()) {
// Give the name of this application to libnotify
@ -254,10 +297,30 @@ nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
if (!notify_init(appShortName.get()))
return NS_ERROR_FAILURE;
GList *server_caps = notify_get_server_caps();
if (server_caps) {
for (GList* cap = server_caps; cap != NULL; cap = cap->next) {
if (!strcmp((char*) cap->data, "actions")) {
gHasActions = PR_TRUE;
break;
}
}
g_list_foreach(server_caps, (GFunc)g_free, NULL);
g_list_free(server_caps);
}
}
if (!gHasActions && aAlertTextClickable)
return NS_ERROR_FAILURE; // No good, fallback to XUL
mAlertTitle = NS_ConvertUTF16toUTF8(aAlertTitle);
mAlertText = NS_ConvertUTF16toUTF8(aAlertText);
mAlertHasAction = aAlertTextClickable;
mAlertListener = aAlertListener;
mAlertCookie = aAlertCookie;
return StartRequest(aImageUrl);
}

Просмотреть файл

@ -41,6 +41,7 @@
#include "nsCOMPtr.h"
#include "imgIDecoderObserver.h"
#include "nsStringAPI.h"
#include "nsIObserver.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
@ -58,14 +59,24 @@ public:
nsresult InitAlertAsync(const nsAString & aImageUrl,
const nsAString & aAlertTitle,
const nsAString & aAlertText);
const nsAString & aAlertText,
PRBool aAlertTextClickable,
const nsAString & aAlertCookie,
nsIObserver * aAlertListener);
void SendCallback();
void SendClosed();
protected:
nsCOMPtr<imgIRequest> mIconRequest;
nsCString mAlertTitle;
nsCString mAlertText;
nsCOMPtr<nsIObserver> mAlertListener;
nsString mAlertCookie;
PRPackedBool mLoadedFrame;
PRPackedBool mAlertHasAction;
nsresult StartRequest(const nsAString & aImageUrl);
nsresult ShowAlert(GdkPixbuf* aPixbuf);

Просмотреть файл

@ -68,5 +68,6 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
if (!alertListener)
return NS_ERROR_OUT_OF_MEMORY;
return alertListener->InitAlertAsync(aImageUrl, aAlertTitle, aAlertText);
return alertListener->InitAlertAsync(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener);
}