Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
DISCONTINUED:openSUSE:11.1:Update
notification-daemon
notification-daemon-svn3017.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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:
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor