File notification-daemon-svn3017.patch of Package notification-daemon
Index: configure.ac
===================================================================
--- configure.ac (révision 2976)
+++ configure.ac (copie de travail)
@@ -67,13 +67,13 @@ AC_EXEEXT
AM_PROG_LIBTOOL
AC_PROG_INTLTOOL
-ALL_LINGUAS="de nl sv"
+ALL_LINGUAS="ar de it nl pl sv"
GETTEXT_PACKAGE=notification-daemon
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
AM_GLIB_GNU_GETTEXT
-REQ_GTK_VERSION=2.4.0
+REQ_GTK_VERSION=2.10.0
REQ_GLIB_VERSION=$REQ_GTK_VERSION
REQ_SEXY_VERSION=0.1.3
REQ_DBUS_VERSION=0.36
@@ -162,6 +162,34 @@ fi
AC_SUBST(CFLAGS)
dnl ################################################################
+dnl # Sound Support
+dnl ################################################################
+
+AC_ARG_ENABLE(sound,
+ [[ --enable-sound=[auto,gstreamer,no] Sound support (default=auto)]] )
+
+if test x$enable_sound != xno -a x$enable_sound != xgstreamer; then
+ enable_sound=auto
+fi
+
+if test x$enable_sound != xno; then
+ gstreampkg="gstreamer-0.10"
+
+ if test x$enable_sound = xauto; then
+ PKG_CHECK_MODULES(GSTREAMER, $gstreampkg,
+ [enable_sound=gstreamer], [enable_sound=no])
+ else
+ PKG_CHECK_MODULES(GSTREAMER, $gstreampkg, [enable_sound=gstreamer])
+ fi
+
+ if test x$enable_sound = xgstreamer; then
+ AC_DEFINE([HAVE_GSTREAMER], 1, [Defined if Gstreamer is detected])
+ AC_SUBST(GSTREAMER_CFLAGS)
+ AC_SUBST(GSTREAMER_LIBS)
+ fi
+fi
+
+dnl ################################################################
dnl # Output the Makefiles
dnl ################################################################
AC_CONFIG_FILES([
@@ -184,6 +212,7 @@ echo
echo prefix............... : $prefix
echo dbus-1 system.d dir.. : $DBUS_SYS_DIR
echo dbus-1 services dir.. : $DBUS_SERVICES_DIR
+echo sound support........ : $enable_sound
echo
echo "Now type make to compile"
echo "Then su to root and type: make install"
Index: AUTHORS
===================================================================
--- AUTHORS (révision 2976)
+++ AUTHORS (copie de travail)
@@ -3,13 +3,20 @@ Authors:
John (J5) Palmieri <johnp@redhat.com>
Contributors:
+ driehuis@playbeing.org
Ed Catmur <ed@catmur.co.uk>
felix@hsgheli.de
+ Jim Ramsay <i.am@jimramsay.com>
+ Luca Cavalli <luca.cavelli@gmail.com>
Matt Walton <matthew@matthew-walton.co.uk>
Pawel Worach <pawel.worach@gmail.com>
Rodney Dawes <dobey@novell.com>
+ Jonh Wendell <wendell@bani.com.br>
Translators:
+ Arabic - Djihed Afifi <djihed@gmail.com>
Dutch - Wouter Bolsterlee <uws+gnome@xs4all.nl>
German - Florian Steinel <steinel@pootle.wordforge.org.flonet.net>
+ Italian - Luca Ferretti <elle.uca@libero.it>
+ Polish - Raven <piotrdrag@gmail.com>
Swedish - Daniel Nylander <po@danielnylander.se>
Index: ChangeLog
===================================================================
--- ChangeLog (révision 2976)
+++ ChangeLog (copie de travail)
@@ -1,3 +1,133 @@
+Thu Sep 25 18:53:21 PDT 2008 Christian Hammond <chipx86@chipx86.com>
+
+ * src/capplet/notification-properties.glade:
+ - Prevent duplicate mnemonics between "Position" and "Preview."
+
+Thu Sep 25 18:52:05 PDT 2008 Christian Hammond <chipx86@chipx86.com>
+
+ * src/capplet/notification-properties.c:
+ - Some bullet-proofing to prevent crashes with multiple preview
+ notifications.
+
+Thu Sep 25 18:25:36 PDT 2008 Christian Hammond <chipx86@chipx86.com>
+
+ * src/daemon/daemon.c:
+ * NEWS:
+ - Added better support for attaching context notifications to an icon on
+ the system tray, even when it moves. Patch by Colin Walters.
+
+Tue Mar 18 21:39:53 PDT 2008 Christian Hammond <chipx86@chipx86.com>
+
+ * src/daemon/daemon.c:
+ - Patch by parasti to prevent our notification blocking when the
+ fullscreen window is not on the current workspace. Fixes bug #142.
+
+Tue Mar 18 20:55:27 PDT 2008 Christian Hammond <chipx86@chipx86.com>
+
+ * src/themes/bubble/eggnotificationbubblewidget.c:
+ * src/themes/standard/theme.c:
+ - Patch by maniac to set the NOTIFICATION type hint for the notification
+ windows. Fixes bug #161.
+
+Sat Aug 25 21:42:50 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/capplet/notification-properties.c:
+ A po/notification-daemon.it.po:
+ * AUTHORS:
+ * NEWS:
+ * configure.ac:
+ - Added an Italian translation by Luca Ferretti.
+
+Sat Aug 25 19:42:05 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/themes/standard/theme.c:
+ - Escape the text in the summary so that & and < don't cause problems.
+ Fixes bug #132.
+
+Sat Aug 25 19:31:16 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/daemon/daemon.c:
+ - Show notifications if a fullscreen window isn't the active window.
+ This fixes problems if a fullscreen window is hidden or minimized.
+ This fixes bug #142.
+
+Sat Aug 25 19:10:18 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/themes/standard/theme.c:
+ - Only set the urgency in the standard theme if the value is actually a
+ uchar. We were assuming it would be, but that made it easy to crash
+ things. Now we make sure. Fixes bug #135.
+
+Sat Aug 25 18:55:34 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/daemon/daemon.c:
+ * src/daemon/daemon.h:
+ - Send the reason the notification closed when emitting
+ the NotificationClosed signal, as per the spec. Fixes bug #137.
+ - Bump spec compliance to 1.0.
+
+Sat Aug 25 18:15:02 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ A po/ar.po:
+ * AUTHORS:
+ * configure.ac:
+ - Added an Arabic translation courtesy of Djihed Afifi. Closes
+ ticket #131.
+
+Sat Aug 25 17:58:35 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/daemon/daemon.c:
+ * src/daemon/daemon.h:
+ - Return an error when attempting to close a notification of ID 0.
+
+Wed Jun 13 03:12:31 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/themes/standard/theme.c:
+ - Patch by M.S. to fix a bug where notifications with arrows were
+ crossing the monitor on multihead setups instead of staying on their
+ head. (Bug #5)
+
+Wed Jun 13 02:58:07 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * po/POTFILES.in:
+ * src/capplet/Makefile.am:
+ * src/capplet/notification-properties.c:
+ A src/capplet/notification-properties.glade:
+ * src/Makefile.am:
+ * AUTHORS:
+ * configure.ac:
+ - Patch by Jonh Wendell (and some code changes and dialog tweaks by me)
+ to add a control panel applet for specifying the theme and
+ notification position. This is not complete. We need to support actual
+ querying of theme engine names. Works for now, though.
+ Closes ticket #126.
+
+Sun Apr 29 03:43:13 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * data/notification-daemon.schemas.in:
+ * src/daemon/daemon.c:
+ * src/daemon/daemon.h:
+ * src/daemon/Makefile.am:
+ * AUTHORS:
+ * NEWS:
+ * configure.ac:
+ - Added support for playing sounds when the "sound-file" hint is set or
+ when the default_sound GConf key is set, as well as support for the
+ "suppress-sound" hint. Patch by Jim Ramsay. (Ticket #111)
+
+Sun Apr 29 02:38:12 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/themes/standard/theme.c:
+ - Fix the close button size so that it's not stretched. This fixes (at
+ least partially) bug #127. Patch by Luca Cavelli.
+
+Sun Apr 29 01:02:12 PDT 2007 Christian Hammond <chipx86@chipx86.com>
+
+ * src/daemon/engines.c:
+ - Patch by driehuis to prevent quitting on theme engine failure. We now
+ spit out an error and then fall back to the default theme. Closes
+ ticket #128.
+
==================== 0.3.7 ====================
Tue Feb 27 23:19:00 PST 2007 Christian Hammond <chipx86@chipx86.com>
Index: src/daemon/sound.c
===================================================================
--- src/daemon/sound.c (révision 0)
+++ src/daemon/sound.c (révision 3018)
@@ -0,0 +1,80 @@
+/*
+ * sound.c - Sound support portion of the destop notification spec
+ *
+ * Copyright (C) 2007 Jim Ramsay <i.am@jimramsay.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "config.h"
+
+#include "sound.h"
+
+#ifdef HAVE_GSTREAMER
+#include <gst/gst.h>
+
+static GstElement *player;
+
+static void
+sound_play_uri(const gchar* uri)
+{
+ /*
+ * TODO: Fade out the current sound and then start the new sound?
+ * Right now we just cut off the existing sound, which is kind of
+ * abrupt
+ */
+
+ /* Stop the pipeline */
+ gst_element_set_state(player, GST_STATE_NULL);
+
+ /* Set the input to a local file uri */
+ g_object_set(G_OBJECT(player), "uri", uri, NULL);
+
+ /* Start the pipeline again */
+ gst_element_set_state(player, GST_STATE_PLAYING);
+}
+#endif /* HAVE_GSTREAMER */
+
+void
+sound_init(void)
+{
+#ifdef HAVE_GSTREAMER
+ gst_init(NULL, NULL);
+
+ player = gst_element_factory_make("playbin", "Notification Player");
+
+ /*
+ * Instead of using the default audiosink, use the gconfaudiosink,
+ * which will respect the defaults in gstreamer-properties
+ */
+ g_object_set(G_OBJECT(player), "audio-sink",
+ gst_element_factory_make("gconfaudiosink", "GconfAudioSink"),
+ NULL);
+
+#endif /* HAVE_GSTREAMER */
+}
+
+void
+sound_play(const gchar* filename)
+{
+ /* We are guaranteed here that the file exists */
+#ifdef HAVE_GSTREAMER
+ /* gstreamer's playbin takes uris, so make a file:// uri */
+ gchar* uri = g_strdup_printf("file://%s", filename);
+ sound_play_uri(uri);
+ g_free(uri);
+#endif /* HAVE_GSTREAMER */
+}
+
Index: src/daemon/sound.h
===================================================================
--- src/daemon/sound.h (révision 0)
+++ src/daemon/sound.h (révision 3018)
@@ -0,0 +1,30 @@
+/*
+ * sound.h - Sound support portion of the destop notification spec
+ *
+ * Copyright (C) 2007 Jim Ramsay <i.am@jimramsay.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef _SOUND_H
+#define _SOUND_H
+
+#include <glib.h>
+
+void sound_init(void);
+
+void sound_play(const gchar *filename);
+
+#endif /* _SOUND_H */
Index: src/daemon/daemon.c
===================================================================
--- src/daemon/daemon.c (révision 2976)
+++ src/daemon/daemon.c (copie de travail)
@@ -45,6 +45,7 @@
#include "daemon.h"
#include "engines.h"
#include "stack.h"
+#include "sound.h"
#include "notificationdaemon-dbus-glue.h"
#define IMAGE_SIZE 48
@@ -82,13 +83,15 @@ typedef struct
gboolean paused;
guint id;
GtkWindow *nw;
-
+ Window src_window_xid;
} NotifyTimeout;
struct _NotifyDaemonPrivate
{
guint next_id;
guint timeout_source;
+ GHashTable *idle_reposition_notify_ids;
+ GHashTable *monitored_window_hash;
GHashTable *notification_hash;
gboolean url_clicked_lock;
NotifyStack **stacks;
@@ -115,10 +118,19 @@ struct _DBusGMethodInvocation
static void notify_daemon_finalize(GObject *object);
static void _close_notification(NotifyDaemon *daemon, guint id,
- gboolean hide_notification);
-static void _emit_closed_signal(GtkWindow *nw);
+ gboolean hide_notification,
+ NotifydClosedReason reason);
+static GdkFilterReturn _notify_x11_filter(GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer user_data);
+static void _emit_closed_signal(GtkWindow *nw, NotifydClosedReason reason);
static void _action_invoked_cb(GtkWindow *nw, const char *key);
static NotifyStackLocation get_stack_location_from_string(const char *slocation);
+static void sync_notification_position(NotifyDaemon *daemon, GtkWindow *nw,
+ Window source);
+static void monitor_notification_source_windows(NotifyDaemon *daemon,
+ NotifyTimeout *nt,
+ Window source);
G_DEFINE_TYPE(NotifyDaemon, notify_daemon, G_TYPE_OBJECT);
@@ -165,6 +177,10 @@ notify_daemon_init(NotifyDaemon *daemon)
daemon->priv->stacks_size = gdk_screen_get_n_monitors(screen);
daemon->priv->stacks = g_new0(NotifyStack *, daemon->priv->stacks_size);
+ daemon->priv->idle_reposition_notify_ids = g_hash_table_new(NULL, NULL);
+ daemon->priv->monitored_window_hash = g_hash_table_new(NULL, NULL);
+ gdk_window_add_filter(NULL, _notify_x11_filter, daemon);
+
for (i = 0; i < daemon->priv->stacks_size; i++)
{
daemon->priv->stacks[i] = notify_stack_new(daemon, screen,
@@ -182,6 +198,8 @@ notify_daemon_finalize(GObject *object)
NotifyDaemon *daemon = NOTIFY_DAEMON(object);
GObjectClass *parent_class = G_OBJECT_CLASS(notify_daemon_parent_class);
+ g_hash_table_destroy(daemon->priv->monitored_window_hash);
+ g_hash_table_destroy(daemon->priv->idle_reposition_notify_ids);
g_hash_table_destroy(daemon->priv->notification_hash);
g_free(daemon->priv);
@@ -248,19 +266,23 @@ _action_invoked_cb(GtkWindow *nw, const
dbus_connection_send(dbus_conn, message, NULL);
dbus_message_unref(message);
- _close_notification(daemon, id, TRUE);
+ _close_notification(daemon, id, TRUE, NOTIFYD_CLOSED_USER);
}
static void
-_emit_closed_signal(GtkWindow *nw)
+_emit_closed_signal(GtkWindow *nw, NotifydClosedReason reason)
{
DBusMessage *message = create_signal(nw, "NotificationClosed");
+ dbus_message_append_args(message,
+ DBUS_TYPE_UINT32, &reason,
+ DBUS_TYPE_INVALID);
dbus_connection_send(dbus_conn, message, NULL);
dbus_message_unref(message);
}
static void
-_close_notification(NotifyDaemon *daemon, guint id, gboolean hide_notification)
+_close_notification(NotifyDaemon *daemon, guint id,
+ gboolean hide_notification, NotifydClosedReason reason)
{
NotifyDaemonPrivate *priv = daemon->priv;
NotifyTimeout *nt;
@@ -269,7 +291,7 @@ _close_notification(NotifyDaemon *daemon
if (nt != NULL)
{
- _emit_closed_signal(nt->nw);
+ _emit_closed_signal(nt->nw, reason);
if (hide_notification)
theme_hide_notification(nt->nw);
@@ -281,7 +303,118 @@ _close_notification(NotifyDaemon *daemon
static void
_notification_destroyed_cb(GtkWindow *nw, NotifyDaemon *daemon)
{
- _close_notification(daemon, NW_GET_NOTIFY_ID(nw), FALSE);
+ /*
+ * This usually won't happen, but can if notification-daemon dies before
+ * all notifications are closed. Mark them as expired.
+ */
+ _close_notification(daemon, NW_GET_NOTIFY_ID(nw), FALSE,
+ NOTIFYD_CLOSED_EXPIRED);
+}
+
+typedef struct
+{
+ NotifyDaemon *daemon;
+ gint id;
+} IdleRepositionData;
+
+static gboolean
+idle_reposition_notification(gpointer datap)
+{
+ IdleRepositionData *data = (IdleRepositionData *)datap;
+ NotifyDaemon *daemon = data->daemon;
+ NotifyTimeout *nt;
+ gint notify_id;
+
+ notify_id = data->id;
+
+ /* Look up the timeout, if it's completed we don't need to do anything */
+ nt = (NotifyTimeout *)g_hash_table_lookup(daemon->priv->notification_hash,
+ ¬ify_id);
+ if (nt != NULL) {
+ sync_notification_position(daemon, nt->nw, nt->src_window_xid);
+ }
+
+ g_hash_table_remove(daemon->priv->idle_reposition_notify_ids,
+ GINT_TO_POINTER(notify_id));
+ g_object_unref(daemon);
+ g_free(data);
+
+ return FALSE;
+}
+
+static void
+_queue_idle_reposition_notification(NotifyDaemon *daemon, gint notify_id)
+{
+ IdleRepositionData *data;
+ gpointer orig_key;
+ gpointer value;
+ guint idle_id;
+
+ /* Do we already have an idle update pending? */
+ if (g_hash_table_lookup_extended(daemon->priv->idle_reposition_notify_ids,
+ GINT_TO_POINTER(notify_id),
+ &orig_key, &value))
+ {
+ return;
+ }
+
+ data = g_new0(IdleRepositionData, 1);
+ data->daemon = g_object_ref(daemon);
+ data->id = notify_id;
+
+ /* We do this as a short timeout to avoid repositioning spam */
+ idle_id = g_timeout_add_full(G_PRIORITY_LOW, 50,
+ idle_reposition_notification, data, NULL);
+ g_hash_table_insert(daemon->priv->idle_reposition_notify_ids,
+ GINT_TO_POINTER(notify_id), GUINT_TO_POINTER(idle_id));
+}
+
+static GdkFilterReturn
+_notify_x11_filter(GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ NotifyDaemon *daemon = NOTIFY_DAEMON(user_data);
+ XEvent *xev = (XEvent *)xevent;
+ gpointer orig_key;
+ gpointer value;
+ gint notify_id;
+ NotifyTimeout *nt;
+
+ if (xev->xany.type == DestroyNotify)
+ {
+ g_hash_table_remove(daemon->priv->monitored_window_hash,
+ GUINT_TO_POINTER(xev->xany.window));
+ return GDK_FILTER_CONTINUE;
+ }
+
+ if (!g_hash_table_lookup_extended(daemon->priv->monitored_window_hash,
+ GUINT_TO_POINTER(xev->xany.window), &orig_key, &value))
+ return GDK_FILTER_CONTINUE;
+
+ notify_id = GPOINTER_TO_INT(value);
+
+ if (xev->xany.type == ConfigureNotify || xev->xany.type == MapNotify)
+ {
+ _queue_idle_reposition_notification(daemon, notify_id);
+ }
+ else if (xev->xany.type == ReparentNotify)
+ {
+ nt = (NotifyTimeout *)g_hash_table_lookup(
+ daemon->priv->notification_hash, ¬ify_id);
+
+ if (nt == NULL)
+ return GDK_FILTER_CONTINUE;
+
+ /*
+ * If the window got reparented, we need to start monitoring the
+ * new parents.
+ */
+ monitor_notification_source_windows(daemon, nt, nt->src_window_xid);
+ sync_notification_position(daemon, nt->nw, nt->src_window_xid);
+ }
+
+ return GDK_FILTER_CONTINUE;
}
static void
@@ -349,7 +482,7 @@ _is_expired(gpointer key, gpointer value
if (now_time > expiration_time)
{
theme_notification_tick(nt->nw, 0);
- _emit_closed_signal(nt->nw);
+ _emit_closed_signal(nt->nw, NOTIFYD_CLOSED_EXPIRED);
return TRUE;
}
else if (nt->paused)
@@ -425,7 +558,7 @@ _calculate_timeout(NotifyDaemon *daemon,
}
}
-static guint
+static NotifyTimeout *
_store_notification(NotifyDaemon *daemon, GtkWindow *nw, int timeout)
{
NotifyDaemonPrivate *priv = daemon->priv;
@@ -455,7 +588,7 @@ _store_notification(NotifyDaemon *daemon
g_hash_table_insert(priv->notification_hash,
g_memdup(&id, sizeof(guint)), nt);
- return id;
+ return nt;
}
static gboolean
@@ -623,7 +756,8 @@ _notify_daemon_process_icon_data(NotifyD
if (expected_len != tmp_array->len)
{
g_warning("_notify_daemon_process_icon_data expected image "
- "data to be of length %i but got a length of %i",
+ "data to be of length %" G_GSIZE_FORMAT " but got a "
+ "length of %u",
expected_len, tmp_array->len);
return FALSE;
}
@@ -650,7 +784,8 @@ window_clicked_cb(GtkWindow *nw, GdkEven
}
_action_invoked_cb(nw, "default");
- _close_notification(daemon, NW_GET_NOTIFY_ID(nw), TRUE);
+ _close_notification(daemon, NW_GET_NOTIFY_ID(nw), TRUE,
+ NOTIFYD_CLOSED_USER);
}
static void
@@ -772,19 +907,24 @@ static gboolean
fullscreen_window_exists(GtkWidget *nw)
{
WnckScreen *wnck_screen;
+ WnckWorkspace *wnck_workspace;
GList *l;
wnck_screen = wnck_screen_get(GDK_SCREEN_XNUMBER(
gdk_drawable_get_screen(GDK_DRAWABLE(GTK_WIDGET(nw)->window))));
wnck_screen_force_update(wnck_screen);
+ wnck_workspace = wnck_screen_get_active_workspace(wnck_screen);
+
for (l = wnck_screen_get_windows_stacked(wnck_screen);
l != NULL;
l = l->next)
{
WnckWindow *wnck_win = (WnckWindow *)l->data;
- if (wnck_window_is_fullscreen(wnck_win))
+ if (wnck_window_is_on_workspace(wnck_win, wnck_workspace) &&
+ wnck_window_is_fullscreen(wnck_win) &&
+ wnck_window_is_active(wnck_win))
{
/*
* Sanity check if the window is _really_ fullscreen to
@@ -805,6 +945,113 @@ fullscreen_window_exists(GtkWidget *nw)
return FALSE;
}
+static Window
+get_window_parent(Display *display,
+ Window window,
+ Window *root)
+{
+ Window parent;
+ Window *children = NULL;
+ guint nchildren;
+ gboolean result;
+
+ gdk_error_trap_push();
+ result = XQueryTree(display, window, root, &parent, &children, &nchildren);
+ if (gdk_error_trap_pop() || !result)
+ return None;
+
+ if (children)
+ XFree(children);
+
+ return parent;
+}
+
+/*
+ * Recurse over X Window and parents, up to root, and start watching them
+ * for position changes.
+ */
+static void
+monitor_notification_source_windows(NotifyDaemon *daemon,
+ NotifyTimeout *nt,
+ Window source)
+{
+ Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ Window root = None;
+ Window parent;
+
+ /* Store the window in the timeout */
+ g_assert(nt != NULL);
+ nt->src_window_xid = source;
+
+ for (parent = get_window_parent(display, source, &root);
+ parent != None && root != parent;
+ parent = get_window_parent(display, parent, &root)) {
+
+ XSelectInput(display, parent, StructureNotifyMask);
+ g_hash_table_insert(daemon->priv->monitored_window_hash,
+ GUINT_TO_POINTER(parent), GINT_TO_POINTER(nt->id));
+ }
+}
+
+/* Use a source X Window ID to reposition a notification. */
+static void
+sync_notification_position(NotifyDaemon *daemon,
+ GtkWindow *nw,
+ Window source)
+{
+ Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ Status result;
+ Window root;
+ Window child;
+ int x, y;
+ unsigned int width, height;
+ unsigned int border_width, depth;
+
+ gdk_error_trap_push();
+
+ /* Get the root for this window */
+ result = XGetGeometry(display, source, &root, &x, &y,
+ &width, &height, &border_width, &depth);
+ if (gdk_error_trap_pop() || !result)
+ return;
+
+ /*
+ * Now calculate the offset coordinates for the source window from
+ * the root.
+ */
+ gdk_error_trap_push ();
+ result = XTranslateCoordinates(display, source, root, 0, 0,
+ &x, &y, &child);
+ if (gdk_error_trap_pop() || !result)
+ return;
+
+ x += width / 2;
+ y += height / 2;
+
+ theme_set_notification_arrow(nw, TRUE, x, y);
+ theme_move_notification(nw, x, y);
+ theme_show_notification(nw);
+
+ /*
+ * We need to manually queue a draw here as the default theme recalculates
+ * its position in the draw handler and moves the window (which seems
+ * fairly broken), so just calling move/show above isn't enough to cause
+ * its position to be calculated.
+ */
+ gtk_widget_queue_draw(GTK_WIDGET(nw));
+}
+
+GQuark
+notify_daemon_error_quark(void)
+{
+ static GQuark q = 0;
+
+ if (q == 0)
+ q = g_quark_from_static_string("notification-daemon-error-quark");
+
+ return q;
+}
+
gboolean
notify_daemon_notify_handler(NotifyDaemon *daemon,
const gchar *app_name,
@@ -824,8 +1071,11 @@ notify_daemon_notify_handler(NotifyDaemo
gboolean new_notification = FALSE;
gint x = 0;
gint y = 0;
+ Window window_xid = None;
guint return_id;
gchar *sender;
+ gchar *sound_file = NULL;
+ gboolean sound_enabled;
gint i;
if (id > 0)
@@ -867,8 +1117,13 @@ notify_daemon_notify_handler(NotifyDaemo
*XXX This needs to handle file URIs and all that.
*/
+
+ if ((data = (GValue *)g_hash_table_lookup(hints, "window-xid")) != NULL)
+ {
+ window_xid = (Window)g_value_get_uint(data);
+ }
/* deal with x, and y hints */
- if ((data = (GValue *)g_hash_table_lookup(hints, "x")) != NULL)
+ else if ((data = (GValue *)g_hash_table_lookup(hints, "x")) != NULL)
{
x = g_value_get_int(data);
@@ -879,6 +1134,63 @@ notify_daemon_notify_handler(NotifyDaemo
}
}
+ /* Deal with sound hints */
+ sound_enabled = gconf_client_get_bool(gconf_client,
+ GCONF_KEY_SOUND_ENABLED, NULL);
+ data = (GValue *)g_hash_table_lookup(hints, "suppress-sound");
+
+ if (data != NULL)
+ {
+ if (G_VALUE_HOLDS_BOOLEAN(data))
+ sound_enabled = !g_value_get_boolean(data);
+ else if (G_VALUE_HOLDS_INT(data))
+ sound_enabled = (g_value_get_int(data) != 0);
+ else
+ {
+ g_warning("suppress-sound is of type %s (expected bool or int)\n",
+ g_type_name(G_VALUE_TYPE(data)));
+ }
+ }
+
+ if (sound_enabled)
+ {
+ data = (GValue *)g_hash_table_lookup(hints, "sound-file");
+
+ if (data != NULL)
+ {
+ sound_file = g_value_dup_string(data);
+
+ if (*sound_file == '\0' ||
+ !g_file_test(sound_file, G_FILE_TEST_EXISTS))
+ {
+ g_free(sound_file);
+ sound_file = NULL;
+ }
+ }
+
+ /*
+ * TODO: If we don't have a sound_file yet, get the urgency hint, then
+ * get the corresponding system event sound
+ *
+ * We will need to parse /etc/sound/events/gnome-2.soundlist
+ * and ~/.gnome2/sound/events/gnome-2.soundlist.
+ */
+
+ /* If we don't have a sound file yet, use our gconf default */
+ if (sound_file == NULL)
+ {
+ sound_file = gconf_client_get_string(gconf_client,
+ GCONF_KEY_DEFAULT_SOUND, NULL);
+ if (sound_file != NULL &&
+ (*sound_file == '\0' ||
+ !g_file_test(sound_file, G_FILE_TEST_EXISTS)))
+ {
+ g_free(sound_file);
+ sound_file = NULL;
+ }
+ }
+ }
+
/* set up action buttons */
for (i = 0; actions[i] != NULL; i += 2)
{
@@ -957,7 +1269,15 @@ notify_daemon_notify_handler(NotifyDaemo
}
}
- if (use_pos_data)
+
+ if (window_xid != None)
+ {
+ /*
+ * Do nothing here if we were passed an XID; we'll call
+ * sync_notification_position later.
+ */
+ }
+ else if (use_pos_data)
{
/*
* Typically, the theme engine will set its own position based on
@@ -983,13 +1303,34 @@ notify_daemon_notify_handler(NotifyDaemo
notify_stack_add_window(priv->stacks[monitor], nw, new_notification);
}
+ if (id == 0)
+ {
+ nt = _store_notification(daemon, nw, timeout);
+ return_id = nt->id;
+ }
+ else
+ return_id = id;
+
+ /*
+ * If we have a source Window XID, start monitoring the tree
+ * for changes, and reposition the window based on the source
+ * window. We need to do this after return_id is calculated.
+ */
+ if (window_xid != None)
+ {
+ monitor_notification_source_windows(daemon, nt, window_xid);
+ sync_notification_position(daemon, nw, window_xid);
+ }
+
if (!screensaver_active(GTK_WIDGET(nw)) &&
!fullscreen_window_exists(GTK_WIDGET(nw)))
{
theme_show_notification(nw);
+ if (sound_file != NULL)
+ sound_play(sound_file);
}
- return_id = (id == 0 ? _store_notification(daemon, nw, timeout) : id);
+ g_free(sound_file);
#if CHECK_DBUS_VERSION(0, 60)
sender = dbus_g_method_get_sender(context);
@@ -1015,9 +1356,15 @@ gboolean
notify_daemon_close_notification_handler(NotifyDaemon *daemon,
guint id, GError **error)
{
- _close_notification(daemon, id, TRUE);
-
- return TRUE;
+ if (id == 0)
+ {
+ g_set_error(error, notify_daemon_error_quark(), 100,
+ _("%u is not a valid notification ID"), id);
+ return FALSE;
+ } else {
+ _close_notification(daemon, id, TRUE, NOTIFYD_CLOSED_API);
+ return TRUE;
+ }
}
gboolean
@@ -1045,7 +1392,7 @@ notify_daemon_get_server_information(Not
*out_name = g_strdup("Notification Daemon");
*out_vendor = g_strdup("Galago Project");
*out_version = g_strdup(VERSION);
- *out_spec_ver = g_strdup("0.9");
+ *out_spec_ver = g_strdup("1.0");
return TRUE;
}
@@ -1067,6 +1414,8 @@ main(int argc, char **argv)
g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+ sound_init();
+
gtk_init(&argc, &argv);
gconf_init(argc, argv, NULL);
Index: src/daemon/Makefile.am
===================================================================
--- src/daemon/Makefile.am (révision 2976)
+++ src/daemon/Makefile.am (copie de travail)
@@ -6,9 +6,11 @@ notification_daemon_SOURCES = \
engines.c \
engines.h \
stack.c \
- stack.h
+ stack.h \
+ sound.c \
+ sound.h
-notification_daemon_LDADD = $(NOTIFICATION_DAEMON_LIBS)
+notification_daemon_LDADD = $(NOTIFICATION_DAEMON_LIBS) $(GSTREAMER_LIBS)
BUILT_SOURCES = notificationdaemon-dbus-glue.h
@@ -19,6 +21,7 @@ notificationdaemon-dbus-glue.h: notifica
INCLUDES = \
-I$(top_srcdir) \
$(NOTIFICATION_DAEMON_CFLAGS) \
+ $(GSTREAMER_CFLAGS) \
-DENGINES_DIR=\"$(libdir)/notification-daemon-1.0/engines\"
EXTRA_DIST = notificationdaemon.xml
Index: src/daemon/daemon.h
===================================================================
--- src/daemon/daemon.h (révision 2976)
+++ src/daemon/daemon.h (copie de travail)
@@ -32,6 +32,8 @@
#define GCONF_KEY_DAEMON "/apps/notification-daemon"
#define GCONF_KEY_THEME GCONF_KEY_DAEMON "/theme"
#define GCONF_KEY_POPUP_LOCATION GCONF_KEY_DAEMON "/popup_location"
+#define GCONF_KEY_SOUND_ENABLED GCONF_KEY_DAEMON "/sound_enabled"
+#define GCONF_KEY_DEFAULT_SOUND GCONF_KEY_DAEMON "/default_sound"
#define NOTIFY_TYPE_DAEMON (notify_daemon_get_type())
#define NOTIFY_DAEMON(obj) \
@@ -47,6 +49,22 @@
#define NOTIFY_DAEMON_DEFAULT_TIMEOUT 7000
+enum
+{
+ URGENCY_LOW,
+ URGENCY_NORMAL,
+ URGENCY_CRITICAL
+};
+
+typedef enum
+{
+ NOTIFYD_CLOSED_EXPIRED = 1,
+ NOTIFYD_CLOSED_USER = 2,
+ NOTIFYD_CLOSED_API = 3,
+ NOTIFYD_CLOSED_RESERVED = 4
+
+} NotifydClosedReason;
+
typedef struct _NotifyDaemon NotifyDaemon;
typedef struct _NotifyDaemonClass NotifyDaemonClass;
typedef struct _NotifyDaemonPrivate NotifyDaemonPrivate;
@@ -64,17 +82,11 @@ struct _NotifyDaemonClass
GObjectClass parent_class;
};
-enum _NotifyDaemonError
-{
- NOTIFY_DAEMON_ERROR_GENERIC = 0,
-};
-
G_BEGIN_DECLS
GType notify_daemon_get_type(void);
-NotifyDaemon *notify_daemon_new(void)
- G_GNUC_MALLOC;
+GQuark notify_daemon_error_quark(void);
gboolean notify_daemon_notify_handler(NotifyDaemon *daemon,
const gchar *app_name,
Index: src/daemon/engines.c
===================================================================
--- src/daemon/engines.c (révision 2976)
+++ src/daemon/engines.c (copie de travail)
@@ -60,7 +60,7 @@ load_theme_engine(const char *name)
if (!g_module_symbol(engine->module, #name, (gpointer *)&engine->name)) \
{ \
/* Too harsh! Fall back to default. */ \
- g_error("Theme doesn't provide the required function '%s'", #name); \
+ g_warning("Theme doesn't provide the required function '%s'", #name); \
goto error; \
}
Index: src/themes/standard/theme.c
===================================================================
--- src/themes/standard/theme.c (révision 2976)
+++ src/themes/standard/theme.c (copie de travail)
@@ -80,16 +80,11 @@ enum
#define BACKGROUND_OPACITY 0.92
#define BOTTOM_GRADIENT_HEIGHT 30
-#if GTK_CHECK_VERSION(2, 8, 0)
-# define USE_CAIRO
-#endif
-
#if GTK_CHECK_VERSION(2, 10, 0)
# define USE_COMPOSITE
#endif
-#ifdef USE_CAIRO
static void
fill_background(GtkWidget *widget, WindowData *windata, cairo_t *cr)
{
@@ -131,21 +126,7 @@ fill_background(GtkWidget *widget, Windo
cairo_pattern_destroy(gradient);
#endif
}
-#else /* !USE_CAIRO */
-static void
-fill_background(GtkWidget *widget, WindowData *windata)
-{
- GtkStyle *style = gtk_widget_get_style(windata->win);
-
- gdk_draw_rectangle(GDK_DRAWABLE(widget->window),
- style->base_gc[GTK_STATE_NORMAL], TRUE,
- 0, 0,
- widget->allocation.width,
- widget->allocation.height);
-}
-#endif
-#ifdef USE_CAIRO
static void
draw_stripe(GtkWidget *widget, WindowData *windata, cairo_t *cr)
{
@@ -193,57 +174,22 @@ draw_stripe(GtkWidget *widget, WindowDat
cairo_fill(cr);
#endif
}
-#else /* !USE_CAIRO */
-static void
-draw_stripe(GtkWidget *widget, WindowData *windata)
-{
- GtkStyle *style = gtk_widget_get_style(widget);
- gboolean custom_gc = FALSE;
- GdkColor color;
- GdkGC *gc;
-
- switch (windata->urgency)
- {
- case URGENCY_LOW: // LOW
- gc = style->bg_gc[GTK_STATE_NORMAL];
- break;
-
- case URGENCY_CRITICAL: // CRITICAL
- custom_gc = TRUE;
- gc = gdk_gc_new(GDK_DRAWABLE(widget->window));
- gdk_color_parse("#CC0000", &color);
- gdk_gc_set_rgb_fg_color(gc, &color);
- break;
-
- case URGENCY_NORMAL: // NORMAL
- default:
- gc = style->bg_gc[GTK_STATE_SELECTED];
- break;
- }
-
-
- gdk_draw_rectangle(widget->window, gc, TRUE,
- windata->main_hbox->allocation.x + 1,
- windata->main_hbox->allocation.y + 1,
- STRIPE_WIDTH,
- windata->main_hbox->allocation.height - 2);
-
- if (custom_gc)
- g_object_unref(G_OBJECT(gc));
-}
-#endif
static GtkArrowType
get_notification_arrow_type(GtkWidget *nw)
{
WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
- int screen_height;
+ GdkScreen *screen;
+ GdkRectangle monitor_geometry;
+ int monitor;
- screen_height = gdk_screen_get_height(
- gdk_drawable_get_screen(GDK_DRAWABLE(nw->window)));
+ screen = gdk_drawable_get_screen(GDK_DRAWABLE(nw->window));
+ monitor = gdk_screen_get_monitor_at_point(screen, windata->point_x,
+ windata->point_y);
+ gdk_screen_get_monitor_geometry(screen, monitor, &monitor_geometry);
- if (windata->point_y + windata->height + DEFAULT_ARROW_HEIGHT >
- screen_height)
+ if (windata->point_y - monitor_geometry.y + windata->height +
+ DEFAULT_ARROW_HEIGHT > monitor_geometry.height)
{
return GTK_ARROW_DOWN;
}
@@ -268,63 +214,71 @@ create_border_with_arrow(GtkWidget *nw,
int width;
int height;
int y;
+ int norm_point_x;
+ int norm_point_y;
GtkArrowType arrow_type;
GdkScreen *screen;
- int screen_width;
- int screen_height;
int arrow_side1_width = DEFAULT_ARROW_WIDTH / 2;
int arrow_side2_width = DEFAULT_ARROW_WIDTH / 2;
int arrow_offset = DEFAULT_ARROW_OFFSET;
GdkPoint *shape_points = NULL;
int i = 0;
+ int monitor;
+ GdkRectangle monitor_geometry;
width = windata->width;
height = windata->height;
- screen = gdk_drawable_get_screen(GDK_DRAWABLE(nw->window));
- screen_width = gdk_screen_get_width(screen);
- screen_height = gdk_screen_get_height(screen);
+ screen = gdk_drawable_get_screen(GDK_DRAWABLE(nw->window));
+ monitor = gdk_screen_get_monitor_at_point(screen,
+ windata->point_x,
+ windata->point_y);
+ gdk_screen_get_monitor_geometry(screen, monitor, &monitor_geometry);
windata->num_border_points = 5;
arrow_type = get_notification_arrow_type(windata->win);
+ norm_point_x = windata->point_x - monitor_geometry.x;
+ norm_point_y = windata->point_y - monitor_geometry.y;
+
/* Handle the offset and such */
switch (arrow_type)
{
case GTK_ARROW_UP:
case GTK_ARROW_DOWN:
- if (windata->point_x < arrow_side1_width)
+ if (norm_point_x < arrow_side1_width)
{
arrow_side1_width = 0;
arrow_offset = 0;
}
- else if (windata->point_x > screen_width - arrow_side2_width)
+ else if (norm_point_x > monitor_geometry.width - arrow_side2_width)
{
arrow_side2_width = 0;
arrow_offset = width - arrow_side1_width;
}
else
{
- if (windata->point_x - arrow_side2_width + width >=
- screen_width)
+ if (norm_point_x - arrow_side2_width + width >=
+ monitor_geometry.width)
{
arrow_offset =
width - arrow_side1_width - arrow_side2_width -
- (screen_width - MAX(windata->point_x +
- arrow_side1_width,
- screen_width -
- DEFAULT_ARROW_OFFSET));
+ monitor_geometry.width -
+ MAX(norm_point_x + arrow_side1_width,
+ monitor_geometry.width - DEFAULT_ARROW_OFFSET);
}
else
{
- arrow_offset = MIN(windata->point_x - arrow_side1_width,
+ arrow_offset = MIN(norm_point_x - arrow_side1_width,
DEFAULT_ARROW_OFFSET);
}
if (arrow_offset == 0 ||
arrow_offset == width - arrow_side1_width)
+ {
windata->num_border_points++;
+ }
else
windata->num_border_points += 2;
}
@@ -439,15 +393,15 @@ create_border_with_arrow(GtkWidget *nw,
case GTK_ARROW_LEFT:
case GTK_ARROW_RIGHT:
- if (windata->point_y < arrow_side1_width)
+ if (norm_point_y < arrow_side1_width)
{
arrow_side1_width = 0;
- arrow_offset = windata->point_y;
+ arrow_offset = norm_point_y;
}
- else if (windata->point_y > screen_height - arrow_side2_width)
+ else if (norm_point_y > monitor_geometry.height - arrow_side2_width)
{
arrow_side2_width = 0;
- arrow_offset = windata->point_y - arrow_side1_width;
+ arrow_offset = norm_point_y - arrow_side1_width;
}
break;
@@ -463,7 +417,6 @@ create_border_with_arrow(GtkWidget *nw,
g_free(shape_points);
}
-#ifdef USE_CAIRO
static void
draw_border(GtkWidget *widget, WindowData *windata, cairo_t *cr)
{
@@ -501,56 +454,21 @@ draw_border(GtkWidget *widget, WindowDat
cairo_stroke(cr);
}
-#else /* !USE_CAIRO */
-static void
-draw_border(GtkWidget *widget,
- WindowData *windata)
-{
- if (windata->gc == NULL)
- {
- GdkColor color;
-
- windata->gc = gdk_gc_new(widget->window);
- gdk_color_parse("black", &color);
- gdk_gc_set_rgb_fg_color(windata->gc, &color);
- }
-
- if (windata->has_arrow)
- {
- create_border_with_arrow(windata->win, windata);
-
- gdk_draw_polygon(widget->window, windata->gc, FALSE,
- windata->border_points, windata->num_border_points);
- gdk_window_shape_combine_region(windata->win->window,
- windata->window_region,
- 0, 0);
- g_free(windata->border_points);
- windata->border_points = NULL;
- }
- else
- {
- gdk_draw_rectangle(widget->window, windata->gc, FALSE,
- 0, 0, windata->width - 1, windata->height - 1);
- }
-
-}
-#endif
static gboolean
paint_window(GtkWidget *widget,
GdkEventExpose *event,
WindowData *windata)
{
+ cairo_t *context;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
if (windata->width == 0) {
windata->width = windata->win->allocation.width;
windata->height = windata->win->allocation.height;
}
-#ifdef USE_CAIRO
- cairo_t *context;
- cairo_surface_t *surface;
- cairo_t *cr;
-
context = gdk_cairo_create(widget->window);
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
@@ -569,11 +487,6 @@ paint_window(GtkWidget *widget,
cairo_paint(context);
cairo_surface_destroy(surface);
cairo_destroy(context);
-#else /* !USE_CAIRO */
- fill_background(widget, windata);
- draw_border(widget, windata);
- draw_stripe(widget, windata);
-#endif
return FALSE;
}
@@ -666,6 +579,7 @@ create_notification(UrlClickedCb url_cli
GtkWidget *image;
GtkWidget *alignment;
AtkObject *atkobj;
+ GtkRcStyle *rcstyle;
WindowData *windata;
#ifdef USE_COMPOSITE
GdkColormap *colormap;
@@ -692,6 +606,8 @@ create_notification(UrlClickedCb url_cli
#endif
gtk_window_set_title(GTK_WINDOW(win), "Notification");
+ gtk_window_set_type_hint(GTK_WINDOW(win),
+ GDK_WINDOW_TYPE_HINT_NOTIFICATION);
gtk_widget_add_events(win, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
gtk_widget_realize(win);
gtk_widget_set_size_request(win, WIDTH, -1);
@@ -762,15 +678,24 @@ create_notification(UrlClickedCb url_cli
atk_object_set_description(atkobj, "Notification summary text.");
/* Add the close button */
+ alignment = gtk_alignment_new(1, 0, 0, 0);
+ gtk_widget_show(alignment);
+ gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0);
+
close_button = gtk_button_new();
gtk_widget_show(close_button);
- gtk_box_pack_start(GTK_BOX(hbox), close_button, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(alignment), close_button);
gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
gtk_container_set_border_width(GTK_CONTAINER(close_button), 0);
- gtk_widget_set_size_request(close_button, 20, 20);
+ //gtk_widget_set_size_request(close_button, 20, 20);
g_signal_connect_swapped(G_OBJECT(close_button), "clicked",
G_CALLBACK(gtk_widget_destroy), win);
+ rcstyle = gtk_rc_style_new();
+ rcstyle->xthickness = rcstyle->ythickness = 0;
+ gtk_widget_modify_style(close_button, rcstyle);
+ gtk_rc_style_unref(rcstyle);
+
atkobj = gtk_widget_get_accessible(close_button);
atk_action_set_description(ATK_ACTION(atkobj), 0,
"Closes the notification.");
@@ -829,7 +754,7 @@ set_notification_hints(GtkWindow *nw, GH
value = (GValue *)g_hash_table_lookup(hints, "urgency");
- if (value != NULL)
+ if (value != NULL && G_VALUE_HOLDS_UCHAR(value))
{
windata->urgency = g_value_get_uchar(value);
@@ -866,11 +791,14 @@ notification_tick(GtkWindow *nw, glong r
void
set_notification_text(GtkWindow *nw, const char *summary, const char *body)
{
- char *str;
+ char *str, *quoted;
WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
g_assert(windata != NULL);
- str = g_strdup_printf("<b><big>%s</big></b>", summary);
+ quoted = g_markup_escape_text(summary, -1);
+ str = g_strdup_printf("<b><big>%s</big></b>", quoted);
+ g_free(quoted);
+
gtk_label_set_markup(GTK_LABEL(windata->summary_label), str);
g_free(str);
@@ -933,11 +861,10 @@ countdown_expose_cb(GtkWidget *pie, GdkE
WindowData *windata)
{
GtkStyle *style = gtk_widget_get_style(windata->win);
-
-#ifdef USE_CAIRO
cairo_t *context;
cairo_surface_t *surface;
cairo_t *cr;
+
context = gdk_cairo_create(GDK_DRAWABLE(windata->pie_countdown->window));
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
surface = cairo_surface_create_similar(
@@ -948,15 +875,11 @@ countdown_expose_cb(GtkWidget *pie, GdkE
cr = cairo_create(surface);
fill_background(pie, windata, cr);
-#else /* !USE_CAIRO */
- fill_background(pie, windata);
-#endif
if (windata->timeout > 0)
{
gdouble pct = (gdouble)windata->remaining / (gdouble)windata->timeout;
-#ifdef USE_CAIRO
gdk_cairo_set_source_color(cr, &style->bg[GTK_STATE_ACTIVE]);
cairo_move_to(cr, PIE_RADIUS, PIE_RADIUS);
@@ -964,21 +887,13 @@ countdown_expose_cb(GtkWidget *pie, GdkE
-G_PI_2, -(pct * G_PI * 2) - G_PI_2);
cairo_line_to(cr, PIE_RADIUS, PIE_RADIUS);
cairo_fill(cr);
-#else /* !USE_CAIRO */
- gdk_draw_arc(GDK_DRAWABLE(windata->pie_countdown->window),
- style->bg_gc[GTK_STATE_ACTIVE], TRUE,
- 0, 0, PIE_WIDTH, PIE_HEIGHT,
- 90 * 64, pct * 360.0 * 64.0);
-#endif
}
-#ifdef USE_CAIRO
cairo_destroy(cr);
cairo_set_source_surface(context, surface, 0, 0);
cairo_paint(context);
cairo_surface_destroy(surface);
cairo_destroy(context);
-#endif
return TRUE;
}
Index: src/themes/bubble/eggnotificationbubblewidget.c
===================================================================
--- src/themes/bubble/eggnotificationbubblewidget.c (révision 2976)
+++ src/themes/bubble/eggnotificationbubblewidget.c (copie de travail)
@@ -1125,6 +1125,7 @@ egg_notification_bubble_widget_new (void
{
return g_object_new (EGG_TYPE_NOTIFICATION_BUBBLE_WIDGET,
"type", GTK_WINDOW_POPUP,
+ "type-hint", GDK_WINDOW_TYPE_HINT_NOTIFICATION,
NULL);
}
Index: data/notification-daemon.schemas.in
===================================================================
--- data/notification-daemon.schemas.in (révision 2976)
+++ data/notification-daemon.schemas.in (copie de travail)
@@ -25,5 +25,29 @@
</locale>
</schema>
+ <schema>
+ <key>/schemas/apps/notification-daemon/sound_enabled</key>
+ <applyto>/apps/notification-daemon/sound_enabled</applyto>
+ <owner>notification-daemon</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Sound Enabled</short>
+ <long>Turns on and off sound support for notifications.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/notification-daemon/default_sound</key>
+ <applyto>/apps/notification-daemon/default_sound</applyto>
+ <owner>notification-daemon</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Default Sound</short>
+ <long>The default sound file used unless a notification supplies the 'sound-file' or 'suppress-sound' hint. Leave empty for no default sound.</long>
+ </locale>
+ </schema>
+
</schemalist>
</gconfschemafile>
Index: NEWS
===================================================================
--- NEWS (révision 2976)
+++ NEWS (copie de travail)
@@ -1,3 +1,37 @@
+version 0.3.8:
+ * Bumped up the required minimum version of GTK+ to 2.10.0.
+ * Bump the notification spec version we're compliant with to 1.0.
+ * Send the reason code along with the NotificationClosed signal in order
+ to indicate why the notification was closed. (Bug #137)
+ * Send an error if the user attempts to close an already closed
+ notification.
+ * Text is now escaped in the summary in the Standard theme so that
+ ampersands and other special characters show up instead of disappearing.
+ (Bug #132)
+ * Set the type hint for notifications to TYPE_NOTIFICATION. (Bug #146)
+ * Added support for playing sounds when the "sound-file" hint is set or
+ when the default_sound GConf key is set, as well as support for the
+ "suppress-sound" hint. Patch by Jim Ramsay. (Ticket #111)
+ * Added a control panel applet for controlling such things as the
+ notification theme and popup positions. Patch by John Wendell.
+ (Ticket #126)
+ * Added better support for attaching context notifications to an icon on
+ the system tray, even when it moves. Patch by Colin Walters.
+ * Added an Arabic translation. Patch by Djihed Afifi. (Ticket #131)
+ * Added an Italian translation. Patch by Luca Ferretti.
+ * Fixed a bug where notifications weren't displayed if a fullscreen
+ window was minimized. (Bug #142)
+ * Fixed a bug where we were quitting on theme engine failure, instead of
+ falling back to the default theme engine. Patch by
+ driehuis-at-playbeing.org. (Ticket #128)
+ * Fixed a bug where notifications with arrows were crossing the monitor
+ on multihead setups instead of staying on their head. Patch by M.S.
+ (Bug #5)
+ * Fixed the close button size on the notifications so that they don't
+ stretch. Patch by Luca Cavelli. (Bug #127)
+ * Fixed a crash when an unsupported value type was passed in for the
+ urgency when using the standard theme. (Bug #135)
+
version 0.3.7 (27-February-2007):
* Fixed a compatibility issue with dbus-glib 0.72. Patch by Pawel Worach.
(Bug #95)
Index: po/ar.po
===================================================================
--- po/ar.po (révision 0)
+++ po/ar.po (révision 3018)
@@ -0,0 +1,42 @@
+# Arabic translations for notification-daemon package.
+# Copyright (C) 2007 THE notification-daemon'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the notification-daemon package.
+# Djihed Afifi <djihed@gmail.com>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: notification-daemon 0.3.7\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-02-15 03:02-0800\n"
+"PO-Revision-Date: 2007-04-21 04:33+0100\n"
+"Last-Translator: Djihed Afifi <djihed@gmail.com>\n"
+"Language-Team: Arabeyes <doc@arabeyes.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Arabic\n"
+
+#: ../data/notification-daemon.schemas.in.h:1
+msgid "Current theme"
+msgstr "النسق الحالي"
+
+#: ../data/notification-daemon.schemas.in.h:2
+msgid "Default popup location on the workspace for stack notifications. Allowed values: \"top_left\",\"top_right\",\"bottom_left\" and \"bottom_right\""
+msgstr "الموضع الافتراضي للتنبيهات على مساحة العمل لصف التنبيهات. القيم الممكنة هي: \"top_left\",\"top_right\",\"bottom_left\" و \"bottom_right\""
+
+#: ../data/notification-daemon.schemas.in.h:3
+msgid "Popup location"
+msgstr "موقع التنبيه"
+
+#: ../data/notification-daemon.schemas.in.h:4
+msgid "The theme used when displaying notifications."
+msgstr "النسق المستخدم عند عرض التنبيهات"
+
+#: ../src/capplet/notification-properties.desktop.in.h:1
+msgid "Pop-Up Notifications"
+msgstr "تنبيهات منبثقة"
+
+#: ../src/capplet/notification-properties.desktop.in.h:2
+msgid "Set your pop-up notification preferences"
+msgstr "حدد تفضيلات التنبيهات"
+
Index: po/pl.po
===================================================================
--- po/pl.po (révision 0)
+++ po/pl.po (révision 3018)
@@ -0,0 +1,43 @@
+# translation of pl.po to Polish
+# Piotr Drąg <piotrdrag@gmail.com>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-02-15 03:02-0800\n"
+"PO-Revision-Date: 2008-03-19 16:03-0700\n"
+"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
+"Language-Team: Polish <pl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../data/notification-daemon.schemas.in.h:1
+msgid "Current theme"
+msgstr "Obecny motyw"
+
+#: ../data/notification-daemon.schemas.in.h:2
+msgid ""
+"Default popup location on the workspace for stack notifications. Allowed "
+"values: \"top_left\",\"top_right\",\"bottom_left\" and \"bottom_right\""
+msgstr ""
+"Domyślne położenie wyskakującego okna na obszarze roboczym dla stosu "
+"powiadomień. Dozwolone wartości: \"top_left\",\"top_right\",\"bottom_left\" "
+"i \"bottom_right\""
+
+#: ../data/notification-daemon.schemas.in.h:3
+msgid "Popup location"
+msgstr "Położenie wyskakującego okna"
+
+#: ../data/notification-daemon.schemas.in.h:4
+msgid "The theme used when displaying notifications."
+msgstr "Motyw używany podczas wyświetlania powiadomień."
+
+#: ../src/capplet/notification-properties.desktop.in.h:1
+msgid "Pop-Up Notifications"
+msgstr "Wyskakujące powiadomienia"
+
+#: ../src/capplet/notification-properties.desktop.in.h:2
+msgid "Set your pop-up notification preferences"
+msgstr "Preferencje wyskakujących powiadomień"
Index: po/it.po
===================================================================
--- po/it.po (révision 0)
+++ po/it.po (révision 3018)
@@ -0,0 +1,136 @@
+# Italian translation for notification-daemon package.
+# Copyright (C) 2007 Free Software Foundation, Inc.
+# This file is distributed under the same license as the notification-daemon package.
+# Luca Ferretti <elle.uca@libero.it>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: notification-daemon\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-07-17 10:07+0200\n"
+"PO-Revision-Date: 2007-07-17 10:10+0200\n"
+"Last-Translator: Luca Ferretti <elle.uca@libero.it>\n"
+"Language-Team: Italian <tp@lists.linux.it>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: data/notification-daemon.schemas.in.h:1
+msgid "Current theme"
+msgstr "Tema attuale"
+
+#: data/notification-daemon.schemas.in.h:2
+msgid "Default Sound"
+msgstr "Suono predefinito"
+
+#: data/notification-daemon.schemas.in.h:3
+msgid ""
+"Default popup location on the workspace for stack notifications. Allowed "
+"values: \"top_left\",\"top_right\",\"bottom_left\" and \"bottom_right\""
+msgstr ""
+"Posizione predefinita di comparsa sull'area di lavoro per impilare le "
+"notifiche. Valori ammessi: \"top_left\", \"top_right\", \"bottom_left\" e "
+"\"bottom_right\""
+
+#: data/notification-daemon.schemas.in.h:4
+msgid "Popup location"
+msgstr "Posizione popup"
+
+#: data/notification-daemon.schemas.in.h:5
+msgid "Sound Enabled"
+msgstr "Suono abilitato"
+
+#: data/notification-daemon.schemas.in.h:6
+msgid ""
+"The default sound file used unless a notification supplies the 'sound-file' "
+"or 'suppress-sound' hint. Leave empty for no default sound."
+msgstr ""
+"Il file audio predefinito usato, a meno che una notifica non fornisca l'hint "
+"'sound-file' o 'suppress-sound'. Lasciare in bianco per non usare alcun "
+"suono predefinito."
+
+#: data/notification-daemon.schemas.in.h:7
+msgid "The theme used when displaying notifications."
+msgstr "Il tema usato nel mostrare le notifiche."
+
+#: data/notification-daemon.schemas.in.h:8
+msgid "Turns on and off sound support for notifications."
+msgstr "Attiva e disattiva il supporto audio alle notifiche."
+
+#: src/capplet/notification-properties.c:79
+msgid "Top Left"
+msgstr "Alto - sinistra"
+
+#: src/capplet/notification-properties.c:80
+msgid "Top Right"
+msgstr "Alto - destra"
+
+#: src/capplet/notification-properties.c:81
+msgid "Bottom Left"
+msgstr "Basso - sinistra"
+
+#: src/capplet/notification-properties.c:82
+msgid "Bottom Right"
+msgstr "Basso - destra"
+
+#: src/capplet/notification-properties.c:327
+msgid "Ubuntu theme"
+msgstr "Tema di Ubuntu"
+
+#: src/capplet/notification-properties.c:329
+msgid "Standard theme"
+msgstr "Tema predefinito"
+
+#: src/capplet/notification-properties.c:422
+msgid "Error initializing libnotify"
+msgstr "Errore nell'inizializzare libnotify"
+
+#: src/capplet/notification-properties.c:436
+msgid "Notification Test"
+msgstr "Controllo notifica"
+
+#: src/capplet/notification-properties.c:437
+msgid "Just a test"
+msgstr "Solo un controllo"
+
+#: src/capplet/notification-properties.c:444
+#, c-format
+msgid "Error while displaying notification: %s"
+msgstr "Errore durante la visualizzazione della notifica: %s"
+
+#: src/capplet/notification-properties.c:501
+#, c-format
+msgid "Unable to locate glade file '%s'"
+msgstr "Impossibile localizzare il file glade «%s»"
+
+#: src/capplet/notification-properties.desktop.in.h:1
+msgid "Pop-Up Notifications"
+msgstr "Notifiche a comparsa"
+
+#: src/capplet/notification-properties.desktop.in.h:2
+msgid "Set your pop-up notification preferences"
+msgstr "Imposta le preferenze delle notifiche a comparsa (o popup)"
+
+#: src/capplet/notification-properties.glade.h:1
+msgid " "
+msgstr " "
+
+#: src/capplet/notification-properties.glade.h:2
+msgid "<b>General Options</b>"
+msgstr "<b>Opzioni generali</b>"
+
+#: src/capplet/notification-properties.glade.h:3
+msgid "Notification Settings"
+msgstr "Impostazioni di notifiche"
+
+#: src/capplet/notification-properties.glade.h:4
+msgid "_Position:"
+msgstr "_Posizione:"
+
+#: src/capplet/notification-properties.glade.h:5
+msgid "_Preview"
+msgstr "_Anteprima"
+
+#: src/capplet/notification-properties.glade.h:6
+msgid "_Theme:"
+msgstr "_Tema:"
Index: po/ChangeLog
===================================================================
--- po/ChangeLog (révision 2976)
+++ po/ChangeLog (copie de travail)
@@ -1,3 +1,8 @@
+Tue Mar 18 20:50:08 PDT 2008 Christian Hammond <chipx86@chipx86.com>
+
+ A pl.po:
+ - Added a Polish translation by Raven.
+
Thu Feb 15 03:03:07 PST 2007 Christian Hammond <chipx86@chipx86.com>
* POTFILES.in: