diff --git a/ChangeLog b/ChangeLog index c25ac14..2c6b0af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2006-07-27 Lucas Rocha + + * src/notification.c (-set_scaled_pixbuf, + +zenity_notification_icon_update, + -zenity_notification_icon_press_callback, + +zenity_notification_icon_size_changed_cb, + -zenity_notification_icon_expose_callback, + -zenity_notification_icon_destroy_callback, + +zenity_notification_icon_activate_cb, + zenity_notification_handle_stdin, zenity_notification), + src/util.[ch] (+zenity_util_stock_from_filename, + zenity_util_pixbuf_new_from_file), Makefile.am, configure.in: + + Migration to gtk_status_icon (Fixes bug #341451). Patch from + Christian Persch . + + * src/eggtrayicon.[ch]: removed. + 2006-07-27 Lucas Rocha * src/text.c (zenity_text_handle_stdin): correctly stdin input for diff --git a/configure.in b/configure.in index 87c243d..4acf5b7 100644 --- a/configure.in +++ b/configure.in @@ -16,7 +16,7 @@ IT_PROG_INTLTOOL([0.34.90]) AC_PROG_CC -GTK_REQUIRED=2.9.0 +GTK_REQUIRED=2.9.2 PKG_CHECK_MODULES([ZENITY],[gtk+-2.0 >= $GTK_REQUIRED libglade-2.0 libgnomecanvas-2.0 glib-2.0]) AC_SUBST([ZENITY_CFLAGS]) @@ -32,7 +32,7 @@ AC_PATH_PROG([PERL],[perl],) # libnotify check # ******************************* -LIBNOTIFY_REQUIRED=0.3.2 +LIBNOTIFY_REQUIRED=0.4.1 PKG_CHECK_MODULES([LIBNOTIFY],[libnotify >= $LIBNOTIFY_REQUIRED], [HAVE_LIBNOTIFY="yes"],[HAVE_LIBNOTIFY="no"]) AC_SUBST([LIBNOTIFY_CFLAGS]) diff --git a/src/Makefile.am b/src/Makefile.am index 192dc3b..e70a51b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,24 +3,22 @@ bin_PROGRAMS = zenity bin_SCRIPTS = gdialog zenity_SOURCES = \ + about.c \ + calendar.c \ + entry.c \ + fileselection.c \ main.c \ + msg.c \ + notification.c \ option.c \ option.h \ - zenity.h \ - calendar.c \ - msg.c \ - scale.c \ - fileselection.c \ - entry.c \ - text.c \ progress.c \ + scale.c \ + text.c \ tree.c \ - eggtrayicon.h \ - eggtrayicon.c \ - notification.c \ - about.c \ + util.c \ util.h \ - util.c + zenity.h zenity_CPPFLAGS = \ -I$(includedir) \ diff --git a/src/eggtrayicon.c b/src/eggtrayicon.c deleted file mode 100644 index 1e6d5bd..0000000 --- a/src/eggtrayicon.c +++ /dev/null @@ -1,468 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* eggtrayicon.c - * Copyright (C) 2002 Anders Carlsson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include - -#include "eggtrayicon.h" - -#include -#include - -#ifndef EGG_COMPILATION -#ifndef _ -#define _(x) dgettext (GETTEXT_PACKAGE, x) -#define N_(x) x -#endif -#else -#define _(x) x -#define N_(x) x -#endif - -#define SYSTEM_TRAY_REQUEST_DOCK 0 -#define SYSTEM_TRAY_BEGIN_MESSAGE 1 -#define SYSTEM_TRAY_CANCEL_MESSAGE 2 - -#define SYSTEM_TRAY_ORIENTATION_HORZ 0 -#define SYSTEM_TRAY_ORIENTATION_VERT 1 - -enum { - PROP_0, - PROP_ORIENTATION -}; - -static GtkPlugClass *parent_class = NULL; - -static void egg_tray_icon_init (EggTrayIcon *icon); -static void egg_tray_icon_class_init (EggTrayIconClass *klass); - -static void egg_tray_icon_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static void egg_tray_icon_realize (GtkWidget *widget); -static void egg_tray_icon_unrealize (GtkWidget *widget); - -static void egg_tray_icon_update_manager_window (EggTrayIcon *icon); - -GType -egg_tray_icon_get_type (void) -{ - static GType our_type = 0; - - if (our_type == 0) - { - static const GTypeInfo our_info = - { - sizeof (EggTrayIconClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) egg_tray_icon_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EggTrayIcon), - 0, /* n_preallocs */ - (GInstanceInitFunc) egg_tray_icon_init - }; - - our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0); - } - - return our_type; -} - -static void -egg_tray_icon_init (EggTrayIcon *icon) -{ - icon->stamp = 1; - icon->orientation = GTK_ORIENTATION_HORIZONTAL; - - gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK); -} - -static void -egg_tray_icon_class_init (EggTrayIconClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *)klass; - GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->get_property = egg_tray_icon_get_property; - - widget_class->realize = egg_tray_icon_realize; - widget_class->unrealize = egg_tray_icon_unrealize; - - g_object_class_install_property (gobject_class, - PROP_ORIENTATION, - g_param_spec_enum ("orientation", - _("Orientation"), - _("The orientation of the tray."), - GTK_TYPE_ORIENTATION, - GTK_ORIENTATION_HORIZONTAL, - G_PARAM_READABLE)); -} - -static void -egg_tray_icon_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EggTrayIcon *icon = EGG_TRAY_ICON (object); - - switch (prop_id) - { - case PROP_ORIENTATION: - g_value_set_enum (value, icon->orientation); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -egg_tray_icon_get_orientation_property (EggTrayIcon *icon) -{ - Display *xdisplay; - Atom type; - int format; - union { - gulong *prop; - guchar *prop_ch; - } prop = { NULL }; - gulong nitems; - gulong bytes_after; - int error, result; - - g_assert (icon->manager_window != None); - - xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); - - gdk_error_trap_push (); - type = None; - result = XGetWindowProperty (xdisplay, - icon->manager_window, - icon->orientation_atom, - 0, G_MAXLONG, FALSE, - XA_CARDINAL, - &type, &format, &nitems, - &bytes_after, &(prop.prop_ch)); - error = gdk_error_trap_pop (); - - if (error || result != Success) - return; - - if (type == XA_CARDINAL) - { - GtkOrientation orientation; - - orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ? - GTK_ORIENTATION_HORIZONTAL : - GTK_ORIENTATION_VERTICAL; - - if (icon->orientation != orientation) - { - icon->orientation = orientation; - - g_object_notify (G_OBJECT (icon), "orientation"); - } - } - - if (prop.prop) - XFree (prop.prop); -} - -static GdkFilterReturn -egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data) -{ - EggTrayIcon *icon = user_data; - XEvent *xev = (XEvent *)xevent; - - if (xev->xany.type == ClientMessage && - xev->xclient.message_type == icon->manager_atom && - xev->xclient.data.l[1] == icon->selection_atom) - { - egg_tray_icon_update_manager_window (icon); - } - else if (xev->xany.window == icon->manager_window) - { - if (xev->xany.type == PropertyNotify && - xev->xproperty.atom == icon->orientation_atom) - { - egg_tray_icon_get_orientation_property (icon); - } - if (xev->xany.type == DestroyNotify) - { - egg_tray_icon_update_manager_window (icon); - } - } - - return GDK_FILTER_CONTINUE; -} - -static void -egg_tray_icon_unrealize (GtkWidget *widget) -{ - EggTrayIcon *icon = EGG_TRAY_ICON (widget); - GdkWindow *root_window; - - if (icon->manager_window != None) - { - GdkWindow *gdkwin; - - gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget), - icon->manager_window); - - gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); - } - - root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); - - gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon); - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); -} - -static void -egg_tray_icon_send_manager_message (EggTrayIcon *icon, - long message, - Window window, - long data1, - long data2, - long data3) -{ - XClientMessageEvent ev; - Display *display; - - ev.type = ClientMessage; - ev.window = window; - ev.message_type = icon->system_tray_opcode_atom; - ev.format = 32; - ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window); - ev.data.l[1] = message; - ev.data.l[2] = data1; - ev.data.l[3] = data2; - ev.data.l[4] = data3; - - display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); - - gdk_error_trap_push (); - XSendEvent (display, - icon->manager_window, False, NoEventMask, (XEvent *)&ev); - XSync (display, False); - gdk_error_trap_pop (); -} - -static void -egg_tray_icon_send_dock_request (EggTrayIcon *icon) -{ - egg_tray_icon_send_manager_message (icon, - SYSTEM_TRAY_REQUEST_DOCK, - icon->manager_window, - gtk_plug_get_id (GTK_PLUG (icon)), - 0, 0); -} - -static void -egg_tray_icon_update_manager_window (EggTrayIcon *icon) -{ - Display *xdisplay; - - xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); - - if (icon->manager_window != None) - { - GdkWindow *gdkwin; - - gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), - icon->manager_window); - - gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); - } - - XGrabServer (xdisplay); - - icon->manager_window = XGetSelectionOwner (xdisplay, - icon->selection_atom); - - if (icon->manager_window != None) - XSelectInput (xdisplay, - icon->manager_window, StructureNotifyMask|PropertyChangeMask); - - XUngrabServer (xdisplay); - XFlush (xdisplay); - - if (icon->manager_window != None) - { - GdkWindow *gdkwin; - - gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), - icon->manager_window); - - gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon); - - /* Send a request that we'd like to dock */ - egg_tray_icon_send_dock_request (icon); - - egg_tray_icon_get_orientation_property (icon); - } -} - -static void -egg_tray_icon_realize (GtkWidget *widget) -{ - EggTrayIcon *icon = EGG_TRAY_ICON (widget); - GdkScreen *screen; - GdkDisplay *display; - Display *xdisplay; - char buffer[256]; - GdkWindow *root_window; - - if (GTK_WIDGET_CLASS (parent_class)->realize) - GTK_WIDGET_CLASS (parent_class)->realize (widget); - - screen = gtk_widget_get_screen (widget); - display = gdk_screen_get_display (screen); - xdisplay = gdk_x11_display_get_xdisplay (display); - - /* Now see if there's a manager window around */ - g_snprintf (buffer, sizeof (buffer), - "_NET_SYSTEM_TRAY_S%d", - gdk_screen_get_number (screen)); - - icon->selection_atom = XInternAtom (xdisplay, buffer, False); - - icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False); - - icon->system_tray_opcode_atom = XInternAtom (xdisplay, - "_NET_SYSTEM_TRAY_OPCODE", - False); - - icon->orientation_atom = XInternAtom (xdisplay, - "_NET_SYSTEM_TRAY_ORIENTATION", - False); - - egg_tray_icon_update_manager_window (icon); - - root_window = gdk_screen_get_root_window (screen); - - /* Add a root window filter so that we get changes on MANAGER */ - gdk_window_add_filter (root_window, - egg_tray_icon_manager_filter, icon); -} - -EggTrayIcon * -egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) -{ - g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); - - return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL); -} - -EggTrayIcon* -egg_tray_icon_new (const gchar *name) -{ - return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL); -} - -guint -egg_tray_icon_send_message (EggTrayIcon *icon, - gint timeout, - const gchar *message, - gint len) -{ - guint stamp; - - g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0); - g_return_val_if_fail (timeout >= 0, 0); - g_return_val_if_fail (message != NULL, 0); - - if (icon->manager_window == None) - return 0; - - if (len < 0) - len = strlen (message); - - stamp = icon->stamp++; - - /* Get ready to send the message */ - egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE, - (Window)gtk_plug_get_id (GTK_PLUG (icon)), - timeout, len, stamp); - - /* Now to send the actual message */ - gdk_error_trap_push (); - while (len > 0) - { - XClientMessageEvent ev; - Display *xdisplay; - - xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); - - ev.type = ClientMessage; - ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon)); - ev.format = 8; - ev.message_type = XInternAtom (xdisplay, - "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); - if (len > 20) - { - memcpy (&ev.data, message, 20); - len -= 20; - message += 20; - } - else - { - memcpy (&ev.data, message, len); - len = 0; - } - - XSendEvent (xdisplay, - icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev); - XSync (xdisplay, False); - } - gdk_error_trap_pop (); - - return stamp; -} - -void -egg_tray_icon_cancel_message (EggTrayIcon *icon, - guint id) -{ - g_return_if_fail (EGG_IS_TRAY_ICON (icon)); - g_return_if_fail (id > 0); - - egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE, - (Window)gtk_plug_get_id (GTK_PLUG (icon)), - id, 0, 0); -} - -GtkOrientation -egg_tray_icon_get_orientation (EggTrayIcon *icon) -{ - g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL); - - return icon->orientation; -} diff --git a/src/eggtrayicon.h b/src/eggtrayicon.h deleted file mode 100644 index 007f4c1..0000000 --- a/src/eggtrayicon.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* eggtrayicon.h - * Copyright (C) 2002 Anders Carlsson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __EGG_TRAY_ICON_H__ -#define __EGG_TRAY_ICON_H__ - -#include -#include - -G_BEGIN_DECLS - -#define EGG_TYPE_TRAY_ICON (egg_tray_icon_get_type ()) -#define EGG_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon)) -#define EGG_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass)) -#define EGG_IS_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON)) -#define EGG_IS_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON)) -#define EGG_TRAY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass)) - -typedef struct _EggTrayIcon EggTrayIcon; -typedef struct _EggTrayIconClass EggTrayIconClass; - -struct _EggTrayIcon -{ - GtkPlug parent_instance; - - guint stamp; - - Atom selection_atom; - Atom manager_atom; - Atom system_tray_opcode_atom; - Atom orientation_atom; - Window manager_window; - - GtkOrientation orientation; -}; - -struct _EggTrayIconClass -{ - GtkPlugClass parent_class; -}; - -GType egg_tray_icon_get_type (void); - -EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen *screen, - const gchar *name); - -EggTrayIcon *egg_tray_icon_new (const gchar *name); - -guint egg_tray_icon_send_message (EggTrayIcon *icon, - gint timeout, - const char *message, - gint len); -void egg_tray_icon_cancel_message (EggTrayIcon *icon, - guint id); - -GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon); - -G_END_DECLS - -#endif /* __EGG_TRAY_ICON_H__ */ diff --git a/src/notification.c b/src/notification.c index 6d5f8dd..222fbc8 100644 --- a/src/notification.c +++ b/src/notification.c @@ -2,6 +2,7 @@ * notification.c * * Copyright (C) 2002 Sun Microsystems, Inc. + * Copyright (C) 2006 Christian Persch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,6 +24,7 @@ #include +#include #include #include #include @@ -32,101 +34,71 @@ #endif #include "zenity.h" -#include "eggtrayicon.h" #include "util.h" -static EggTrayIcon *tray_icon; -static GtkWidget *icon_image; -static GtkWidget *icon_event_box; -static GtkTooltips *tooltips; - +static GtkStatusIcon *status_icon; +static gchar *icon_file; +static const gchar *icon_stock; +static gint icon_size; static void -set_scaled_pixbuf (GtkImage *image, GdkPixbuf *pixbuf, GtkIconSize icon_size) +zenity_notification_icon_update (void) { - GdkScreen *screen; - GtkSettings *settings; - int width, height, desired_width, desired_height; - GdkPixbuf *new_pixbuf; + GdkPixbuf *pixbuf; + GError *error = NULL; - screen = gtk_widget_get_screen (GTK_WIDGET (image)); - settings = gtk_settings_get_for_screen (screen); - if (!gtk_icon_size_lookup_for_settings (settings, icon_size, - &desired_width, &desired_height)) - return; + pixbuf = gdk_pixbuf_new_from_file_at_scale (icon_file, icon_size, icon_size, TRUE, &error); + if (error) { + g_warning ("Could not load notification icon '%s': %s", + icon_file, error->message); + g_clear_error (&error); + } + if (!pixbuf) { + pixbuf = gdk_pixbuf_new_from_file_at_scale (ZENITY_IMAGE_FULLPATH ("zenity-notification.png"), + icon_size, icon_size, TRUE, NULL); + } - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - if (height > desired_height || width > desired_width) { - if (width * desired_height / height > desired_width) - desired_height = height * desired_width / width; - else - desired_width = width * desired_height / height; + gtk_status_icon_set_from_pixbuf (status_icon, pixbuf); - new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, - desired_width, - desired_height, - GDK_INTERP_BILINEAR); - gtk_image_set_from_pixbuf (image, new_pixbuf); - g_object_unref (new_pixbuf); - } else { - gtk_image_set_from_pixbuf (image, pixbuf); + if (pixbuf) { + g_object_unref (pixbuf); } } static gboolean -zenity_notification_icon_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer data) +zenity_notification_icon_size_changed_cb (GtkStatusIcon *icon, + gint size, + gpointer user_data) { - ZenityData *zen_data; + icon_size = size; - zen_data = data; + /* If we're displaying not a stock icon but a custom pixbuf, + * we need to update the icon for the new size. + */ + if (!icon_stock) { + zenity_notification_icon_update (); + + return TRUE; + } + + return FALSE; +} + +static gboolean +zenity_notification_icon_activate_cb (GtkWidget *widget, + ZenityData *data) +{ + data->exit_code = zenity_util_return_exit_code (ZENITY_OK); - zen_data->exit_code = zenity_util_return_exit_code (ZENITY_OK); gtk_main_quit (); + return TRUE; } static gboolean -zenity_notification_icon_expose_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - if (GTK_WIDGET_HAS_FOCUS (widget)) { - gint focus_width, focus_pad; - gint x, y, width, height; - - gtk_widget_style_get (widget, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - NULL); - x = widget->allocation.x + focus_pad; - y = widget->allocation.y + focus_pad; - width = widget->allocation.width - 2 * focus_pad; - height = widget->allocation.height - 2 * focus_pad; - - gtk_paint_focus (widget->style, widget->window, - GTK_WIDGET_STATE (widget), - &event->area, widget, "button", - x, y, width, height); - } - - return FALSE; -} - -static void -zenity_notification_icon_destroy_callback (GtkWidget *widget, gpointer data) -{ - ZenityData *zen_data; - - zen_data = data; - gtk_widget_destroy (GTK_WIDGET (tray_icon)); - - zen_data->exit_code = zenity_util_return_exit_code (ZENITY_ESC); - gtk_main_quit (); -} - -static gboolean -zenity_notification_handle_stdin (GIOChannel *channel, +zenity_notification_handle_stdin (GIOChannel *channel, GIOCondition condition, - gpointer user_data) + gpointer user_data) { ZenityData *zen_data; @@ -137,7 +109,7 @@ zenity_notification_handle_stdin (GIOChannel *channel, GError *error = NULL; string = g_string_new (NULL); - while (channel->is_readable != TRUE) + while (channel->is_readable == FALSE) ; do { gint status; @@ -167,60 +139,72 @@ zenity_notification_handle_stdin (GIOChannel *channel, continue; } /* split off the command and value */ - command = g_strndup (string->str, colon - string->str); - command = g_strstrip (command); - g_strdown (command); + command = g_strstrip (g_strndup (string->str, colon - string->str)); value = colon + 1; while (*value && g_ascii_isspace (*value)) value++; - if (!strcmp (command, "icon")) { - GdkPixbuf *pixbuf; + if (!g_ascii_strcasecmp (command, "icon")) { + icon_stock = zenity_util_stock_from_filename (value); - pixbuf = zenity_util_pixbuf_new_from_file (GTK_WIDGET (tray_icon), - value); - if (pixbuf != NULL) { - set_scaled_pixbuf (GTK_IMAGE (icon_image), pixbuf, - GTK_ICON_SIZE_BUTTON); - gdk_pixbuf_unref (pixbuf); - } else { - g_warning ("Could not load notification icon : %s", value); - } - } else if (!strcmp (command, "message")) { + g_free (icon_file); + icon_file = g_strdup (value); + + if (icon_stock) { + gtk_status_icon_set_from_stock (status_icon, icon_stock); + } else if (gtk_status_icon_get_visible (status_icon) && + gtk_status_icon_is_embedded (status_icon)) { + zenity_notification_icon_update (); + } + } else if (!g_ascii_strcasecmp (command, "message")) { #ifdef HAVE_LIBNOTIFY - /* display a notification bubble */ - if (notify_is_initted ()) { - GError *error = NULL; - NotifyNotification *n; - GdkPixbuf *icon; + /* display a notification bubble */ + if (!g_utf8_validate (value, -1, NULL)) { + g_warning ("Invalid UTF-8 in input!"); + } else if (notify_is_initted ()) { + GError *error = NULL; + NotifyNotification *notif; + const gchar *icon = NULL; + gchar *freeme = NULL; + gchar *message; - n = notify_notification_new (g_strcompress (value), NULL, NULL, - GTK_WIDGET (tray_icon)); + message = g_strcompress (value); - icon = gtk_image_get_pixbuf (GTK_IMAGE (icon_image)); + if (icon_stock) { + icon = icon_stock; + } else if (icon_file) { + icon = freeme = g_filename_to_uri (icon_file, NULL, NULL); + } - notify_notification_set_icon_from_pixbuf (n, icon); + notif = notify_notification_new_with_status_icon (message, NULL /* summary */, + icon, status_icon); + g_free (message); + g_free (freeme); - notify_notification_show (n, &error); + notify_notification_show (notif, &error); if (error) { - g_warning (error->message); + g_warning ("Error showing notification: %s", error->message); g_error_free (error); } - g_object_unref (G_OBJECT (n)); + g_object_unref (notif); } else { #else { /* this brace is for balance */ #endif g_warning ("Notification framework not available"); } - } else if (!strcmp (command, "tooltip")) { - gtk_tooltips_set_tip (tooltips, icon_event_box, value, value); - } else if (!strcmp (command, "visible")) { - if (!strcasecmp (value, "false")) { - gtk_widget_hide (GTK_WIDGET (tray_icon)); - } else { - gtk_widget_show (GTK_WIDGET (tray_icon)); + } else if (!g_ascii_strcasecmp (command, "tooltip")) { + if (g_utf8_validate (value, -1, NULL)) { + gtk_status_icon_set_tooltip (status_icon, value); + } else { + g_warning ("Invalid UTF-8 in input!"); + } + } else if (!g_ascii_strcasecmp (command, "visible")) { + if (!g_ascii_strcasecmp (value, "false")) { + gtk_status_icon_set_visible (status_icon, FALSE); + } else { + gtk_status_icon_set_visible (status_icon, TRUE); } } else { g_warning ("Unknown command '%s'", command); @@ -256,64 +240,47 @@ zenity_notification_listen_on_stdin (ZenityData *data) void zenity_notification (ZenityData *data, ZenityNotificationData *notification_data) { - GdkPixbuf *pixbuf = NULL; + status_icon = gtk_status_icon_new (); + g_signal_connect (status_icon, "size-changed", + G_CALLBACK (zenity_notification_icon_size_changed_cb), data); - tray_icon = egg_tray_icon_new (_("Zenity notification")); - tooltips = gtk_tooltips_new (); - - if (data->window_icon != NULL) - pixbuf = zenity_util_pixbuf_new_from_file (GTK_WIDGET (tray_icon), data->window_icon); - else - pixbuf = gdk_pixbuf_new_from_file (ZENITY_IMAGE_FULLPATH ("zenity-notification.png"), NULL); - - icon_event_box = gtk_event_box_new (); - icon_image = gtk_image_new (); - - if (pixbuf) { - set_scaled_pixbuf (GTK_IMAGE (icon_image), pixbuf, - GTK_ICON_SIZE_BUTTON); - gdk_pixbuf_unref (pixbuf); + if (notification_data->notification_text) { + gtk_status_icon_set_tooltip (status_icon, notification_data->notification_text); } else { - if (data->window_icon != NULL) { - g_warning ("Could not load notification icon : %s", data->window_icon); - } - else - g_warning ("Could not load notification icon : %s", ZENITY_IMAGE_FULLPATH ("zenity-notification.png")); - return; + gtk_status_icon_set_tooltip (status_icon, _("Zenity notification")); } - gtk_container_add (GTK_CONTAINER (icon_event_box), icon_image); + icon_file = g_strdup (data->window_icon); + icon_stock = zenity_util_stock_from_filename (data->window_icon); - if (notification_data->notification_text) - gtk_tooltips_set_tip (tooltips, icon_event_box, notification_data->notification_text, notification_data->notification_text); - else - gtk_tooltips_set_tip (tooltips, icon_event_box, _("Zenity notification"), _("Zenity notification")); - - gtk_widget_add_events (GTK_WIDGET (tray_icon), GDK_BUTTON_PRESS_MASK | GDK_FOCUS_CHANGE_MASK); - gtk_container_add (GTK_CONTAINER (tray_icon), icon_event_box); - - g_signal_connect (tray_icon, "destroy", - G_CALLBACK (zenity_notification_icon_destroy_callback), data); - - g_signal_connect (tray_icon, "expose_event", - G_CALLBACK (zenity_notification_icon_expose_callback), data); - - if (notification_data->listen) { - zenity_notification_listen_on_stdin (data); - } else { - /* if we aren't listening for changes, then close on button_press */ - g_signal_connect (tray_icon, "button_press_event", - G_CALLBACK (zenity_notification_icon_press_callback), data); + /* Only set the stock icon here; if we're going to display a + * custom pixbuf we wait for the size-changed signal to load + * it at the right size. + */ + if (icon_stock) { + gtk_status_icon_set_from_stock (status_icon, icon_stock); } #ifdef HAVE_LIBNOTIFY /* create the notification widget */ - if (!notify_is_initted ()) - notify_init (_("Zenity notification")); + if (!notify_is_initted ()) { + notify_init (_("Zenity notification")); + } #endif - - gtk_widget_show_all (GTK_WIDGET (tray_icon)); - - /* Does nothing at the moment */ + + if (notification_data->listen) { + zenity_notification_listen_on_stdin (data); + } else { + /* if we aren't listening for changes, then close on activate (left-click) */ + g_signal_connect (status_icon, "activate", + G_CALLBACK (zenity_notification_icon_activate_cb), data); + } + + /* Show icon and wait */ + gtk_status_icon_set_visible (status_icon, TRUE); gtk_main (); + + /* Cleanup */ + g_object_unref (status_icon); + g_free (icon_file); } diff --git a/src/util.c b/src/util.c index 4fc7f8d..41c7c55 100644 --- a/src/util.c +++ b/src/util.c @@ -145,19 +145,33 @@ zenity_util_fill_file_buffer (GtkTextBuffer *buffer, const gchar *filename) return TRUE; } -GdkPixbuf * -zenity_util_pixbuf_new_from_file (GtkWidget *widget, gchar *filename) +const gchar * +zenity_util_stock_from_filename (const gchar *filename) { - if (!strcasecmp (filename, "warning")) - return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_BUTTON, NULL); - if (!strcasecmp (filename, "info")) - return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_BUTTON, NULL); - if (!strcasecmp (filename, "question")) - return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_BUTTON, NULL); - if (!strcasecmp (filename, "error")) - return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_BUTTON, NULL); - else - return gdk_pixbuf_new_from_file (filename, NULL); + if (!filename || !filename[0]) + return GTK_STOCK_DIALOG_WARNING; /* default */ + + if (!g_ascii_strcasecmp (filename, "warning")) + return GTK_STOCK_DIALOG_WARNING; + if (!g_ascii_strcasecmp (filename, "info")) + return GTK_STOCK_DIALOG_INFO; + if (!g_ascii_strcasecmp (filename, "question")) + return GTK_STOCK_DIALOG_QUESTION; + if (!g_ascii_strcasecmp (filename, "error")) + return GTK_STOCK_DIALOG_ERROR; + return NULL; +} + +GdkPixbuf * +zenity_util_pixbuf_new_from_file (GtkWidget *widget, const gchar *filename) +{ + const gchar *stock; + + stock = zenity_util_stock_from_filename (filename); + if (stock) + return gtk_widget_render_icon (widget, stock, GTK_ICON_SIZE_BUTTON, NULL); + + return gdk_pixbuf_new_from_file (filename, NULL); } void diff --git a/src/util.h b/src/util.h index cbf96ab..7535275 100644 --- a/src/util.h +++ b/src/util.h @@ -15,6 +15,7 @@ GladeXML* zenity_util_load_glade_file (const gchar *widge gchar * zenity_util_strip_newline (gchar *string); gboolean zenity_util_fill_file_buffer (GtkTextBuffer *buffer, const gchar *filename); +const gchar * zenity_util_stock_from_filename (const gchar *filename); void zenity_util_set_window_icon (GtkWidget *widget, const gchar *filename, const gchar *default_file); @@ -22,7 +23,7 @@ void zenity_util_set_window_icon_from_stock (GtkWidget *widge const gchar *filename, const gchar *default_stock_id); GdkPixbuf * zenity_util_pixbuf_new_from_file (GtkWidget *widget, - gchar *filename); + const gchar *filename); void zenity_util_show_help (GError **error); gint zenity_util_return_exit_code (ZenityExitCode value); void zenity_util_show_dialog (GtkWidget *widget);