From 3e05834b4c23a5d5951403719b8594ff3d9fe30b Mon Sep 17 00:00:00 2001 From: Glynn Foster Date: Mon, 13 Sep 2004 07:51:51 +0000 Subject: [PATCH] Add new notification icon. Update for new files. Restructure code a little 2004-09-13 Glynn Foster * data/Makefile.am, data/zenity-notification.png: Add new notification icon. * src/Makefile.am: Update for new files. * src/about.c, src/calendar.c, src/entry.c, src/fileselection.c, src/progress.c, src/text.c, src/tree.c, src/msg.c: Restructure code a little bit for new utility functions for setting window icons. * src/eggtrayicon.c, src/eggtrayicon.h: New files for notification area support. * src/main.c, src/notification.c, src/util.c, src/util.h, src/zenity.h: Add support for notification area. * data/zenity.1, help/*: Update docs for notification and new file selection changes. --- ChangeLog | 15 + data/Makefile.am | 3 +- data/zenity-notification.png | Bin 0 -> 898 bytes data/zenity.1 | 14 + .../zenity-notification-screenshot.png | Bin 0 -> 3104 bytes help/C/l10n_scripts/notification.sh | 5 + help/C/zenity.xml | 70 ++- src/Makefile.am | 3 + src/about.c | 4 +- src/calendar.c | 5 +- src/eggtrayicon.c | 468 ++++++++++++++++++ src/eggtrayicon.h | 77 +++ src/entry.c | 5 +- src/fileselection.c | 5 +- src/main.c | 67 ++- src/msg.c | 34 +- src/notification.c | 129 +++++ src/progress.c | 5 +- src/text.c | 5 +- src/tree.c | 5 +- src/util.c | 73 ++- src/util.h | 10 +- src/zenity.h | 6 + 23 files changed, 917 insertions(+), 91 deletions(-) create mode 100644 data/zenity-notification.png create mode 100644 help/C/figures/zenity-notification-screenshot.png create mode 100755 help/C/l10n_scripts/notification.sh create mode 100644 src/eggtrayicon.c create mode 100644 src/eggtrayicon.h create mode 100644 src/notification.c diff --git a/ChangeLog b/ChangeLog index 3801b06..aaa250b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2004-09-13 Glynn Foster + + * data/Makefile.am, data/zenity-notification.png: Add new + notification icon. + * src/Makefile.am: Update for new files. + * src/about.c, src/calendar.c, src/entry.c, src/fileselection.c, + src/progress.c, src/text.c, src/tree.c, src/msg.c: Restructure code a + little bit for new utility functions for setting window icons. + * src/eggtrayicon.c, src/eggtrayicon.h: New files for notification area + support. + * src/main.c, src/notification.c, src/util.c, src/util.h, src/zenity.h: + Add support for notification area. + * data/zenity.1, help/*: Update docs for notification and new file + selection changes. + 2004-09-13 Glynn Foster * THANKS: Update diff --git a/data/Makefile.am b/data/Makefile.am index aade652..fd71b4e 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -14,7 +14,8 @@ images_DATA = \ zenity-file.png \ zenity-progress.png \ zenity-text.png \ - zenity-entry.png + zenity-entry.png \ + zenity-notification.png man_MANS = zenity.1 diff --git a/data/zenity-notification.png b/data/zenity-notification.png new file mode 100644 index 0000000000000000000000000000000000000000..6b44ef9bcbdc931342f2bc93f5b499d77115aa1f GIT binary patch literal 898 zcmV-|1AY97P) zbQ8!_SJ|}SLb@qPR(7YDl{>r9f`W@$yHY|Mbu&goDNYNqlaVnpV@&8IZ{~g6b6vcT zyo?h=7cRsLhxd5g_y3*yzvrF{|A$cpJ_j0rA4MbjR^9JsYaijcGgC9A@`;laiwDVN zGZg)cwh!P2+$z~w<9dzkoZ=c<=3%*GmJrt;PgGZj!Ws- z3ykIqmDZzr5xD(NfNHsN>b(myvveJo#&7FrEm%r{WpU-LH#l8+o`u@a7-N!fJ)hjz zA&l3nY_wYqU^y041Aw`y=~?<-K=b!Mv6aHMZEU4bN-=TZDJI4WSe6w=I#WBtGv!wS z=Jr}a^~}`F#TQ?iq`4Mmu9U*gWRgtp{!r)Z@9*OU!LAjENcfH+H=VIG7#u#)Y_Q92D3i%uWZ(jWftu;h|q+*oK_~D}fXXC0$TQpfL9%SS3 zHbw*yL5rZZMvJhx^e~y2WS{!kM1btbD8S^fJvfrfX6SDB5D`S{P&|rHzxr-REVd*S zL?L1Tj>L1*7GaE`?|LYu!ivA(8Jg0Ma@LL8*}jw0eEFBqE8omSydNCjhMz z@fak=g!>X{4Fl9Vop#Aq7J-&9`#k_U7EOs85wz#xyAD8Y*dE-xS6ifz&+d311iPN` za6LaM0ujN85cnQ}_Gvfk05^vLuHU(JW7W1K0R*Y%XYaqAO#EX09kkYoRaykk?ISv% zv3z$m-S`HZUG>@HuYCOS>GNzk?%$eJ`d}rth~PR~1ir`0(l@jl_b;XagS}{ZeeKuc zXueR%jU5849nnZIEgtwDZqGpnK5HvK(Rxsu2d?ecO>egz)r-dKRSFYNV~E6~`VRu1 z!1wX{4xZOX2OhutxDbn9e&P$~xytLM@xw>Sj*NzfD5@skb!a#1vFCeUIRE;U`QIOZ Y0XNiBQ{*{=5&!@I07*qoM6N<$g2{xe6#xJL literal 0 HcmV?d00001 diff --git a/data/zenity.1 b/data/zenity.1 index 17f6eab..3949899 100644 --- a/data/zenity.1 +++ b/data/zenity.1 @@ -43,6 +43,9 @@ Display info dialog .B \-\-list Display list dialog .TP +.B \-\-notification +Display notification icon +.TP .B \-\-progress Display progress indication dialog .TP @@ -152,6 +155,13 @@ Allow changes to text Specify what column to print to standard output. The default is to return the first column. 'ALL' may be used to print all columns. +.PP +Notification options + +.TP +.B \-\-text=STRING +Set the notification text + .PP Progress options @@ -230,6 +240,10 @@ and the text \fIFinding all header files...\fP. .IP find . -name '*.h' | zenity --title "Search Results" --text "Finding all header files.." --column "Files" .PP +Show an icon in the notification area +.IP +zenity --notification --window-icon=update.png --text "System update necessary!" +.PP Display a weekly shopping list in a check list dialog with \fIApples\fP and \fIOranges\fP pre selected .IP zenity --list --checklist --column "Buy" --column "Item" TRUE Apples TRUE Oranges FALSE Pears FALSE Toothpaste diff --git a/help/C/figures/zenity-notification-screenshot.png b/help/C/figures/zenity-notification-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b2c9a15641f24976c8a12acd5c672bcc7eda31 GIT binary patch literal 3104 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 File selection List + Notification Message Error @@ -248,7 +249,10 @@ =icon_path - Specifies the icon that is displayed in the window frame of the dialog. + Specifies the icon that is displayed in the window frame of the dialog. There are + 4 stock icons also available by providing the following keywords - 'info', 'warning', 'question' and + 'error'. + @@ -435,7 +439,8 @@ File Selection Dialog - Use the option to create a file selection dialog. &app; returns the selected files or directories to standard error. + Use the option to create a file selection dialog. &app; returns the selected files or directories to standard + error. The default mode of the file selection dialog is open. The file selection dialog supports the following options: @@ -457,6 +462,20 @@ + + + + Allows only selection of directories in the file selection dialog. + + + + + + + Set the file selection dialog into save mode. + + + =separator @@ -501,6 +520,53 @@ + + + Notification Icon + + + + + + + + =text + + Specifies the text that is displayed in the notification area. + + + + + + + + The following example script shows how to create a notification icon: + + #!/bin/sh + + zenity --notification\ + --window-icon="info" \ + --text="There are system updates necessary!" + + + + +
+ Notification Icon Example + + + + + + + &app; notification icon example + + + +
+ +
+ diff --git a/src/Makefile.am b/src/Makefile.am index c5c9fcd..310cb56 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,9 @@ zenity_SOURCES = \ text.c \ progress.c \ tree.c \ + notification.c \ + eggtrayicon.c \ + eggtrayicon.h \ about.c \ util.h \ util.c diff --git a/src/about.c b/src/about.c index 60cb570..d6fc908 100644 --- a/src/about.c +++ b/src/about.c @@ -300,7 +300,7 @@ zenity_create_boutique (void) window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - zenity_util_set_window_icon (window, ZENITY_IMAGE_FULLPATH ("zenity.png")); + zenity_util_set_window_icon (window, NULL, ZENITY_IMAGE_FULLPATH ("zenity.png")); canvas = zenity_create_monk (); gtk_container_add (GTK_CONTAINER (window), canvas); @@ -383,7 +383,7 @@ zenity_about (ZenityData *data) g_signal_connect (G_OBJECT (dialog), "key_press_event", G_CALLBACK (zenity_zen_wisdom), glade_dialog); - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity.png")); + zenity_util_set_window_icon (dialog, NULL, ZENITY_IMAGE_FULLPATH ("zenity.png")); image = glade_xml_get_widget (glade_dialog, "zenity_about_image"); diff --git a/src/calendar.c b/src/calendar.c index 5936aef..9da633e 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -58,10 +58,7 @@ zenity_calendar (ZenityData *data, ZenityCalendarData *cal_data) if (data->dialog_title) gtk_window_set_title (GTK_WINDOW (dialog), data->dialog_title); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity-calendar.png")); + zenity_util_set_window_icon (dialog, data->window_icon, ZENITY_IMAGE_FULLPATH ("zenity-calendar.png")); if (data->width > -1 || data->height > -1) gtk_window_set_default_size (GTK_WINDOW (dialog), data->width, data->height); diff --git a/src/eggtrayicon.c b/src/eggtrayicon.c new file mode 100644 index 0000000..c4aa3e6 --- /dev/null +++ b/src/eggtrayicon.c @@ -0,0 +1,468 @@ +/* -*- 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, 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 new file mode 100644 index 0000000..007f4c1 --- /dev/null +++ b/src/eggtrayicon.h @@ -0,0 +1,77 @@ +/* -*- 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/entry.c b/src/entry.c index 4d24216..46672f8 100644 --- a/src/entry.c +++ b/src/entry.c @@ -54,10 +54,7 @@ zenity_entry (ZenityData *data, ZenityEntryData *entry_data) if (data->dialog_title) gtk_window_set_title (GTK_WINDOW (dialog), data->dialog_title); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity-entry.png")); + zenity_util_set_window_icon (dialog, data->window_icon, ZENITY_IMAGE_FULLPATH ("zenity-entry.png")); if (data->width > -1 || data->height > -1) gtk_window_set_default_size (GTK_WINDOW (dialog), data->width, data->height); diff --git a/src/fileselection.c b/src/fileselection.c index fdd40fd..4d50fb7 100644 --- a/src/fileselection.c +++ b/src/fileselection.c @@ -60,10 +60,7 @@ void zenity_fileselection (ZenityData *data, ZenityFileData *file_data) if (data->dialog_title) gtk_window_set_title (GTK_WINDOW (dialog), data->dialog_title); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity-file.png")); + zenity_util_set_window_icon (dialog, data->window_icon, ZENITY_IMAGE_FULLPATH ("zenity-file.png")); if (file_data->uri) { dir = g_path_get_dirname (file_data->uri); diff --git a/src/main.c b/src/main.c index 09b1519..4d8c607 100644 --- a/src/main.c +++ b/src/main.c @@ -42,6 +42,7 @@ typedef enum { MODE_TEXTINFO, MODE_WARNING, MODE_INFO, + MODE_NOTIFICATION, MODE_ABOUT, MODE_LAST } ZenityDialogMode; @@ -64,6 +65,7 @@ typedef struct { ZenityProgressData *progress_data; ZenityTextData *text_data; ZenityTreeData *tree_data; + ZenityNotificationData *notification_data; } ZenityParsingOptions; enum { @@ -79,6 +81,7 @@ enum { OPTION_TEXTINFO, OPTION_TEXTEDIT, OPTION_WARNING, + OPTION_NOTIFICATION, OPTION_TITLE, OPTION_ICON, OPTION_WIDTH, @@ -110,6 +113,8 @@ enum { OPTION_PRINTCOLUMN, OPTION_QUESTIONTEXT, OPTION_WARNINGTEXT, + OPTION_NOTIFICATIONICON, + OPTION_NOTIFICATIONTEXT, OPTION_ABOUT, OPTION_VERSION, OPTION_LAST, @@ -185,6 +190,15 @@ struct poptOption options[] = { N_("Display list dialog"), NULL }, + { + "notification", + '\0', + POPT_ARG_NONE, + NULL, + OPTION_NOTIFICATION, + N_("Display notification"), + NULL + }, { "progress", '\0', @@ -548,6 +562,28 @@ struct poptOption list_options[] = { POPT_TABLEEND }; +struct poptOption notification_options[] = { + { + NULL, + '\0', + POPT_ARG_CALLBACK | POPT_CBFLAG_POST, + zenity_parse_options_callback, + 0, + NULL, + NULL + }, + { + "text", + '\0', + POPT_ARG_STRING, + NULL, + OPTION_NOTIFICATIONTEXT, + N_("Set the notification text"), + NULL + }, + POPT_TABLEEND +}; + struct poptOption progress_options[] = { { NULL, @@ -896,6 +932,15 @@ struct poptOption application_options[] = { N_("List options"), NULL }, + { + NULL, + '\0', + POPT_ARG_INCLUDE_TABLE, + notification_options, + 0, + N_("Notication options"), + NULL + }, { NULL, '\0', @@ -979,6 +1024,7 @@ zenity_init_parsing_options (void) { results->progress_data = g_new0 (ZenityProgressData, 1); results->text_data = g_new0 (ZenityTextData, 1); results->tree_data = g_new0 (ZenityTreeData, 1); + results->notification_data = g_new0 (ZenityNotificationData, 1); /* Give some sensible defaults */ results->data->width = -1; @@ -1056,6 +1102,10 @@ zenity_free_parsing_options (void) { if (results->tree_data->print_column) g_free (results->tree_data->print_column); break; + case MODE_NOTIFICATION: + if (results->notification_data->notification_text) + g_free (results->notification_data->notification_text); + break; default: break; } @@ -1125,6 +1175,9 @@ main (gint argc, gchar **argv) { results->tree_data->data = poptGetArgs (ctx); zenity_tree (results->data, results->tree_data); break; + case MODE_NOTIFICATION: + zenity_notification (results->data, results->notification_data); + break; case MODE_PROGRESS: zenity_progress (results->data, results->progress_data); break; @@ -1229,6 +1282,12 @@ zenity_parse_options_callback (poptContext ctx, results->mode = MODE_LIST; break; + case OPTION_NOTIFICATION: + if (results->mode != MODE_LAST) + zenity_error (NULL, ERROR_DIALOG); + + results->mode = MODE_NOTIFICATION; + break; case OPTION_PROGRESS: if (results->mode != MODE_LAST) zenity_error (NULL, ERROR_DIALOG); @@ -1286,13 +1345,13 @@ zenity_parse_options_callback (poptContext ctx, case OPTION_PROGRESSTEXT: case OPTION_LISTTEXT: case OPTION_WARNINGTEXT: - + case OPTION_NOTIFICATIONTEXT: /* FIXME: This is an ugly hack because of the way the poptOptions are * ordered above. When you try and use an --option more than once * parse_options_callback gets called for each option. Suckage */ - if (parse_option_text > 7) + if (parse_option_text > 8) zenity_error ("--text", ERROR_DUPLICATE); switch (results->mode) { @@ -1319,6 +1378,10 @@ zenity_parse_options_callback (poptContext ctx, results->tree_data->dialog_text = g_locale_to_utf8 (g_strcompress (arg), -1, NULL, NULL, NULL); break; + case MODE_NOTIFICATION: + results->notification_data->notification_text = g_locale_to_utf8 (g_strcompress (arg), + -1, NULL, NULL, NULL); + break; default: zenity_error ("--text", ERROR_SUPPORT); } diff --git a/src/msg.c b/src/msg.c index 2728447..ffb2e53 100644 --- a/src/msg.c +++ b/src/msg.c @@ -83,29 +83,25 @@ zenity_msg (ZenityData *data, ZenityMsgData *msg_data) if (data->dialog_title) gtk_window_set_title (GTK_WINDOW (dialog), data->dialog_title); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else { - switch (msg_data->mode) { - case ZENITY_MSG_WARNING: - zenity_util_set_window_icon_from_stock (dialog, GTK_STOCK_DIALOG_WARNING); - break; + switch (msg_data->mode) { + case ZENITY_MSG_WARNING: + zenity_util_set_window_icon_from_stock (dialog, data->window_icon, GTK_STOCK_DIALOG_WARNING); + break; - case ZENITY_MSG_QUESTION: - zenity_util_set_window_icon_from_stock (dialog, GTK_STOCK_DIALOG_QUESTION); - break; + case ZENITY_MSG_QUESTION: + zenity_util_set_window_icon_from_stock (dialog, data->window_icon, GTK_STOCK_DIALOG_QUESTION); + break; - case ZENITY_MSG_ERROR: - zenity_util_set_window_icon_from_stock (dialog, GTK_STOCK_DIALOG_ERROR); - break; + case ZENITY_MSG_ERROR: + zenity_util_set_window_icon_from_stock (dialog, data->window_icon, GTK_STOCK_DIALOG_ERROR); + break; - case ZENITY_MSG_INFO: - zenity_util_set_window_icon_from_stock (dialog, GTK_STOCK_DIALOG_INFO); - break; + case ZENITY_MSG_INFO: + zenity_util_set_window_icon_from_stock (dialog, data->window_icon, GTK_STOCK_DIALOG_INFO); + break; - default: - break; - } + default: + break; } if (data->width > -1 || data->height > -1) diff --git a/src/notification.c b/src/notification.c new file mode 100644 index 0000000..42f72c5 --- /dev/null +++ b/src/notification.c @@ -0,0 +1,129 @@ +/* + * notification.c + * + * Copyright (C) 2002 Sun Microsystems, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * Authors: Glynn Foster + */ + +#include +#include +#include "zenity.h" +#include "eggtrayicon.h" +#include "util.h" + +EggTrayIcon *tray_icon; + +static gboolean +zenity_notification_icon_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + ZenityData *zen_data; + + zen_data = data; + + zen_data->exit_code = zenity_util_return_exit_code (ZENITY_OK); + gtk_main_quit (); +} + +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 gboolean +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 (); +} + +void +zenity_notification (ZenityData *data, ZenityNotificationData *notification_data) +{ + GtkWidget *icon_image; + GtkWidget *icon_event_box; + GtkTooltips *tooltips; + GdkPixbuf *pixbuf = NULL; + + 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 (); + + if (pixbuf) { + icon_image = gtk_image_new_from_pixbuf (pixbuf); + gdk_pixbuf_unref (pixbuf); + } else { + g_warning ("Could not load notification icon : %s", ZENITY_IMAGE_FULLPATH ("zenity-notification.png")); + return; + } + + gtk_container_add (GTK_CONTAINER (icon_event_box), icon_image); + + 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, "button_press_event", + G_CALLBACK (zenity_notification_icon_press_callback), data); + + 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); + + gtk_widget_show_all (GTK_WIDGET (tray_icon)); + + /* Does nothing at the moment */ + gtk_main (); +} diff --git a/src/progress.c b/src/progress.c index 373c5b8..ed727ca 100644 --- a/src/progress.c +++ b/src/progress.c @@ -191,10 +191,7 @@ zenity_progress (ZenityData *data, ZenityProgressData *progress_data) if (data->dialog_title) gtk_window_set_title (GTK_WINDOW (dialog), data->dialog_title); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity-progress.png")); + zenity_util_set_window_icon (dialog, data->window_icon, ZENITY_IMAGE_FULLPATH ("zenity-progress.png")); if (data->width > -1 || data->height > -1) gtk_window_set_default_size (GTK_WINDOW (dialog), data->width, data->height); diff --git a/src/text.c b/src/text.c index b70bed0..acd1739 100644 --- a/src/text.c +++ b/src/text.c @@ -128,10 +128,7 @@ zenity_text (ZenityData *data, ZenityTextData *text_data) if (data->dialog_title) gtk_window_set_title (GTK_WINDOW (dialog), data->dialog_title); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity-text.png")); + zenity_util_set_window_icon (dialog, data->window_icon, ZENITY_IMAGE_FULLPATH ("zenity-text.png")); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); diff --git a/src/tree.c b/src/tree.c index fed58e2..436f632 100644 --- a/src/tree.c +++ b/src/tree.c @@ -320,10 +320,7 @@ zenity_tree (ZenityData *data, ZenityTreeData *tree_data) if (tree_data->dialog_text) gtk_label_set_text (GTK_LABEL (text), tree_data->dialog_text); - if (data->window_icon) - zenity_util_set_window_icon (dialog, data->window_icon); - else - zenity_util_set_window_icon (dialog, ZENITY_IMAGE_FULLPATH ("zenity-list.png")); + zenity_util_set_window_icon (dialog, data->window_icon, ZENITY_IMAGE_FULLPATH ("zenity-list.png")); if (data->width > -1 || data->height > -1) gtk_window_set_default_size (GTK_WINDOW (dialog), data->width, data->height); diff --git a/src/util.c b/src/util.c index 3364e30..b839d42 100644 --- a/src/util.c +++ b/src/util.c @@ -143,56 +143,53 @@ zenity_util_fill_file_buffer (GtkTextBuffer *buffer, const gchar *filename) return TRUE; } -static GList * -zenity_util_list_from_char_array (const char **s) +GdkPixbuf * +zenity_util_pixbuf_new_from_file (GtkWidget *widget, gchar *filename) { - GList *list = NULL; - gint i; - - for (i = 0; s[i]; i++) { - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new_from_file (s[i], NULL); - if (pixbuf) - list = g_list_prepend (list, pixbuf); - } - - return list; -} - -static void -zenity_util_free_list (GList *list) -{ - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); + if (!strcmp (g_strdown (filename), "warning")) + return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_BUTTON, NULL); + if (!strcmp (g_strdown (filename), "info")) + return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_BUTTON, NULL); + if (!strcmp (g_strdown (filename), "question")) + return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_BUTTON, NULL); + if (!strcmp (g_strdown (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); } void -zenity_util_set_window_icon (GtkWidget *widget, const gchar *filename) +zenity_util_set_window_icon (GtkWidget *widget, const gchar *filename, const gchar *default_file) { - const gchar *filenames[2] = { NULL}; - GList *list; + GdkPixbuf *pixbuf; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_WINDOW (widget)); + if (filename != NULL) + pixbuf = zenity_util_pixbuf_new_from_file (widget, (gchar *) filename); + else + pixbuf = gdk_pixbuf_new_from_file (default_file, NULL); - if (filename == NULL) - return; - - filenames[0] = filename; - list = zenity_util_list_from_char_array (filenames); - gtk_window_set_icon_list (GTK_WINDOW (widget), list); - zenity_util_free_list (list); + if (pixbuf != NULL) { + gtk_window_set_icon (GTK_WINDOW (widget), pixbuf); + g_object_unref (pixbuf); + } } void -zenity_util_set_window_icon_from_stock (GtkWidget *widget, const gchar *stock_id) +zenity_util_set_window_icon_from_stock (GtkWidget *widget, const gchar *filename, const gchar *default_stock_id) { GdkPixbuf *pixbuf; - - pixbuf = gtk_widget_render_icon (widget, stock_id, (GtkIconSize) -1, NULL); - gtk_window_set_icon (GTK_WINDOW (widget), pixbuf); - g_object_unref (pixbuf); + + if (filename != NULL) { + pixbuf = zenity_util_pixbuf_new_from_file (widget, (gchar *) filename); + } + else { + pixbuf = gtk_widget_render_icon (widget, default_stock_id, GTK_ICON_SIZE_BUTTON, NULL); + } + + if (pixbuf != NULL) { + gtk_window_set_icon (GTK_WINDOW (widget), pixbuf); + g_object_unref (pixbuf); + } } void diff --git a/src/util.h b/src/util.h index 69ec912..4e3c214 100644 --- a/src/util.h +++ b/src/util.h @@ -15,10 +15,14 @@ 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); -void zenity_util_set_window_icon (GtkWidget *widget, - const gchar *filename); +void zenity_util_set_window_icon (GtkWidget *widget, + const gchar *filename, + const gchar *default_file); void zenity_util_set_window_icon_from_stock (GtkWidget *widget, - const gchar *stock_id); + const gchar *filename, + const gchar *default_stock_id); +GdkPixbuf * zenity_util_pixbuf_new_from_file (GtkWidget *widget, + gchar *filename); void zenity_util_show_help (GError **error); gint zenity_util_return_exit_code (ZenityExitCode value); void zenity_util_show_dialog (GtkWidget *widget); diff --git a/src/zenity.h b/src/zenity.h index d9aff43..3d4eeea 100644 --- a/src/zenity.h +++ b/src/zenity.h @@ -98,6 +98,10 @@ typedef struct { const gchar **data; } ZenityTreeData; +typedef struct { + gchar *notification_text; +} ZenityNotificationData; + void zenity_calendar (ZenityData *data, ZenityCalendarData *calendar_data); void zenity_msg (ZenityData *data, @@ -112,6 +116,8 @@ void zenity_text (ZenityData *data, ZenityTextData *text_data); void zenity_tree (ZenityData *data, ZenityTreeData *tree_data); +void zenity_notification (ZenityData *data, + ZenityNotificationData *notification_data); void zenity_about (ZenityData *data); G_END_DECLS