Hello All, Hi All, Here is my proposed solution. It solves the problem with no extra functionality but should be easy to expand. We have a new GObject: EmNotify, singleton, that is created when the MailComponent is created, it also gets destroyed with the latter. This objects takes care of the configuration (listening to GConf) and does the notifications. The notifications however are still triggered in mail-folder-cache.c:real_flush_update() The "notification type" is no longer an exclusive radio button but allows all the three possibilities together (tray icon, beep and sound). The GConf schema is not changed, we just store an int and read it as flags. Possible improvements: - Allow watching selected folders (this means extend the em-mailer-prefs.c to allow such selection), for this we need mail-folder-cache.c:real_flush_update() to pass a richer data structure to em_notify_notify() containing the URI or some kind of ID of the folder that is being notified (not too hard). - Show a GTK_WINDOW_POPUP for a moment near the notification icon mail has arrived. (with perhaps some information about the folder or something like that) Anyway this is the future and for now we have the Outlook-like functionality, that I was quite missing, in fact. -- Stéphane Konstantaropoulos - Research Student, Computer Science -- University of York, http://www-users.cs.york.ac.uk/~stephane
Index: mail/Makefile.am =================================================================== RCS file: /cvs/gnome/evolution/mail/Makefile.am,v retrieving revision 1.259 diff -u -u -r1.259 Makefile.am --- mail/Makefile.am 25 Jan 2005 02:26:33 -0000 1.259 +++ mail/Makefile.am 6 Apr 2005 01:40:17 -0000 @@ -180,7 +180,9 @@ message-tag-editor.c \ message-tag-editor.h \ message-tag-followup.c \ - message-tag-followup.h + message-tag-followup.h \ + em-notify.c \ + em-notify.h if ENABLE_SMIME SMIME_LIB=$(top_builddir)/smime/gui/libevolution-smime.la Index: mail/em-mailer-prefs.c =================================================================== RCS file: /cvs/gnome/evolution/mail/em-mailer-prefs.c,v retrieving revision 1.29 diff -u -u -r1.29 em-mailer-prefs.c --- mail/em-mailer-prefs.c 2 Mar 2005 05:23:45 -0000 1.29 +++ mail/em-mailer-prefs.c 6 Apr 2005 01:40:23 -0000 @@ -28,6 +28,7 @@ #include "em-mailer-prefs.h" #include "em-format.h" +#include "em-notify.h" #include <libedataserver/e-iconv.h> #include <gtkhtml/gtkhtml-properties.h> @@ -639,14 +640,14 @@ static void notify_type_changed (GtkWidget *widget, EMMailerPrefs *prefs) { - int type; + int type = 0; - if (gtk_toggle_button_get_active (prefs->notify_not)) - type = MAIL_CONFIG_NOTIFY_NOT; - else if (gtk_toggle_button_get_active (prefs->notify_beep)) - type = MAIL_CONFIG_NOTIFY_BEEP; - else - type = MAIL_CONFIG_NOTIFY_PLAY_SOUND; + if (gtk_toggle_button_get_active (prefs->notify_tray)) + type |= MAIL_NOTIFY_TYPE_TRAY; + if (gtk_toggle_button_get_active (prefs->notify_beep)) + type |= MAIL_NOTIFY_TYPE_BEEP; + if (gtk_toggle_button_get_active (prefs->notify_play_sound)) + type |= MAIL_NOTIFY_TYPE_SOUND; gconf_client_set_int (prefs->gconf, "/apps/evolution/mail/notify/type", type, NULL); } @@ -775,20 +776,21 @@ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/notify/type", NULL); val = gconf_client_get_int (prefs->gconf, "/apps/evolution/mail/notify/type", NULL); - prefs->notify_not = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radNotifyNot")); - gtk_toggle_button_set_active (prefs->notify_not, val == MAIL_CONFIG_NOTIFY_NOT); - g_signal_connect (prefs->notify_not, "toggled", G_CALLBACK (notify_type_changed), prefs); - if (locked) - gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_not, FALSE); - prefs->notify_beep = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radNotifyBeep")); - gtk_toggle_button_set_active (prefs->notify_beep, val == MAIL_CONFIG_NOTIFY_BEEP); + prefs->notify_tray = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "checkNotifyTray")); + gtk_toggle_button_set_active (prefs->notify_tray, val & MAIL_NOTIFY_TYPE_TRAY); + g_signal_connect (prefs->notify_tray, "toggled", G_CALLBACK (notify_type_changed), prefs); + if (locked) + gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_tray, FALSE); + + prefs->notify_beep = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "checkNotifyBeep")); + gtk_toggle_button_set_active (prefs->notify_beep, val & MAIL_NOTIFY_TYPE_BEEP); g_signal_connect (prefs->notify_beep, "toggled", G_CALLBACK (notify_type_changed), prefs); if (locked) gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_beep, FALSE); - prefs->notify_play_sound = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radNotifyPlaySound")); - gtk_toggle_button_set_active (prefs->notify_play_sound, val == MAIL_CONFIG_NOTIFY_PLAY_SOUND); + prefs->notify_play_sound = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "checkNotifySound")); + gtk_toggle_button_set_active (prefs->notify_play_sound, val & MAIL_NOTIFY_TYPE_SOUND); g_signal_connect (prefs->notify_play_sound, "toggled", G_CALLBACK (notify_type_changed), prefs); if (locked) gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_play_sound, FALSE); Index: mail/em-mailer-prefs.h =================================================================== RCS file: /cvs/gnome/evolution/mail/em-mailer-prefs.h,v retrieving revision 1.12 diff -u -u -r1.12 em-mailer-prefs.h --- mail/em-mailer-prefs.h 3 May 2004 10:30:59 -0000 1.12 +++ mail/em-mailer-prefs.h 6 Apr 2005 01:40:24 -0000 @@ -84,7 +84,7 @@ struct _GtkToggleButton *confirm_expunge; /* New Mail Notification */ - struct _GtkToggleButton *notify_not; + struct _GtkToggleButton *notify_tray; struct _GtkToggleButton *notify_beep; struct _GtkToggleButton *notify_play_sound; struct _GnomeFileEntry *notify_sound_file; Index: mail/mail-component-factory.c =================================================================== RCS file: /cvs/gnome/evolution/mail/mail-component-factory.c,v retrieving revision 1.15 diff -u -u -r1.15 mail-component-factory.c --- mail/mail-component-factory.c 8 Dec 2004 01:58:48 -0000 1.15 +++ mail/mail-component-factory.c 6 Apr 2005 01:40:24 -0000 @@ -42,6 +42,8 @@ #include "em-format-hook.h" #include "em-format-html-display.h" +#include "em-notify.h" + #include "importers/mail-importer.h" #include <bonobo-activation/bonobo-activation.h> @@ -63,6 +65,10 @@ if (strcmp (component_id, COMPONENT_ID) == 0) { MailComponent *component = mail_component_peek (); + EmNotify *notify = em_notify_peek (); + + g_object_weak_ref(G_OBJECT(component), + (GWeakNotify) g_object_unref, notify); bonobo_object_ref (BONOBO_OBJECT (component)); return BONOBO_OBJECT (component); Index: mail/mail-config.glade =================================================================== RCS file: /cvs/gnome/evolution/mail/mail-config.glade,v retrieving revision 1.158 diff -u -u -r1.158 mail-config.glade --- mail/mail-config.glade 30 Mar 2005 07:57:45 -0000 1.158 +++ mail/mail-config.glade 6 Apr 2005 01:40:50 -0000 @@ -376,7 +376,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -503,7 +503,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -574,7 +574,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -761,7 +761,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -807,7 +807,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -1174,7 +1174,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -1195,7 +1195,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -1240,7 +1240,6 @@ <property name="directory_entry">False</property> <property name="modal">False</property> <property name="use_filechooser">True</property> - <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property> <child internal-child="entry"> <widget class="GtkEntry" id="source_path"> @@ -1251,7 +1250,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> </child> @@ -1901,7 +1900,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -2287,7 +2286,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -2872,7 +2871,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -2988,7 +2987,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -3195,7 +3194,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -3389,7 +3388,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -3410,7 +3409,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -4926,10 +4925,10 @@ <property name="spacing">6</property> <child> - <widget class="GtkRadioButton" id="radNotifyNot"> + <widget class="GtkCheckButton" id="checkNotifyTray"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="label" translatable="yes">_Do not notify me when new mail arrives</property> + <property name="label" translatable="yes">Show icon in the system tray</property> <property name="use_underline">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> @@ -4945,7 +4944,7 @@ </child> <child> - <widget class="GtkRadioButton" id="radNotifyBeep"> + <widget class="GtkCheckButton" id="checkNotifyBeep"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">Beep w_hen new mail arrives</property> @@ -4955,7 +4954,6 @@ <property name="active">False</property> <property name="inconsistent">False</property> <property name="draw_indicator">True</property> - <property name="group">radNotifyNot</property> </widget> <packing> <property name="padding">0</property> @@ -4965,7 +4963,7 @@ </child> <child> - <widget class="GtkRadioButton" id="radNotifyPlaySound"> + <widget class="GtkCheckButton" id="checkNotifySound"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">Play sound file when new mail arri_ves</property> @@ -4975,7 +4973,6 @@ <property name="active">False</property> <property name="inconsistent">False</property> <property name="draw_indicator">True</property> - <property name="group">radNotifyNot</property> </widget> <packing> <property name="padding">0</property> @@ -5031,7 +5027,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> </child> @@ -5550,7 +5546,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes">Important</property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -5572,7 +5568,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes">Work</property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -5594,7 +5590,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes">Personal</property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -5616,7 +5612,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes">To Do</property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -5638,7 +5634,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes">Later</property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -5793,7 +5789,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -5821,7 +5817,7 @@ <property name="reorderable">False</property> <property name="enable_search">True</property> <accessibility> - <atkproperty name="AtkObject::accessible_name" translatable="yes">Mail Headers Table</atkproperty> + <atkproperty name="AtkObject::accessible_name" translatable="yes">Mail Headers Table</atkproperty> </accessibility> </widget> </child> @@ -6403,7 +6399,7 @@ <child> <widget class="GtkAlignment" id="alignment25"> <property name="visible">True</property> - <property name="xalign">7.45058015283e-09</property> + <property name="xalign">7.45058e-09</property> <property name="yalign">0.5</property> <property name="xscale">0</property> <property name="yscale">1</property> @@ -7337,7 +7333,7 @@ <property name="enable_search">True</property> <accessibility> <atkproperty name="AtkObject::accessible_name" translatable="yes">Languages Table</atkproperty> - </accessibility> + </accessibility> </widget> </child> </widget> @@ -8075,7 +8071,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> <packing> @@ -8095,7 +8091,6 @@ <property name="directory_entry">False</property> <property name="modal">False</property> <property name="use_filechooser">True</property> - <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property> <child internal-child="entry"> <widget class="GtkEntry" id="combo-entry2"> @@ -8106,7 +8101,7 @@ <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> - <property name="invisible_char">*</property> + <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">False</property> </widget> </child> Index: mail/mail-folder-cache.c =================================================================== RCS file: /cvs/gnome/evolution/mail/mail-folder-cache.c,v retrieving revision 1.99 diff -u -u -r1.99 mail-folder-cache.c --- mail/mail-folder-cache.c 6 Jan 2005 22:12:57 -0000 1.99 +++ mail/mail-folder-cache.c 6 Apr 2005 01:40:55 -0000 @@ -54,6 +54,7 @@ #include "mail-autofilter.h" #include "mail-config.h" #include "em-folder-tree-model.h" +#include "em-notify.h" #include "em-event.h" @@ -98,6 +99,7 @@ int unread; CamelStore *store; + CamelFolder *folder; }; struct _store_info { @@ -117,9 +119,6 @@ static guint ping_id = 0; static gboolean ping_cb (gpointer user_data); -static guint notify_id = 0; -static int notify_type = -1; - static time_t last_notify = 0; static guint notify_idle_id = 0; static gboolean notify_idle_cb (gpointer user_data); @@ -151,25 +150,9 @@ static gboolean notify_idle_cb (gpointer user_data) { - GConfClient *gconf; - char *filename; - - gconf = mail_config_get_gconf_client (); - - switch (notify_type) { - case MAIL_CONFIG_NOTIFY_PLAY_SOUND: - filename = gconf_client_get_string (gconf, "/apps/evolution/mail/notify/sound", NULL); - if (filename != NULL) { - gnome_sound_play (filename); - g_free (filename); - } - break; - case MAIL_CONFIG_NOTIFY_BEEP: - gdk_beep (); - break; - default: - break; - } + EmNotify *n = em_notify_peek(); + em_notify_notify(n, GPOINTER_TO_INT(user_data)); + g_object_unref(n); time (&last_notify); @@ -179,15 +162,9 @@ } static void -notify_type_changed (GConfClient *client, guint cnxn_id, - GConfEntry *entry, gpointer user_data) -{ - notify_type = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL); -} - -static void real_flush_updates(void *o, void *event_data, void *data) { + static GSList *folders_with_new = NULL; struct _MailComponent *component; struct _EMFolderTreeModel *model; struct _folder_update *up; @@ -225,22 +202,16 @@ /* update unread counts */ em_folder_tree_model_set_unread_count (model, up->store, up->full_name, up->unread); - /* new mail notification */ - if (notify_type == -1) { - /* need to track the user's new-mail-notification settings... */ - GConfClient *gconf; - - gconf = mail_config_get_gconf_client (); - gconf_client_add_dir (gconf, "/apps/evolution/mail/notify", - GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); - notify_id = gconf_client_notify_add (gconf, "/apps/evolution/mail/notify", - notify_type_changed, NULL, NULL, NULL); - notify_type = gconf_client_get_int (gconf, "/apps/evolution/mail/notify/type", NULL); - } - time (&now); - if (notify_type != 0 && up->new && notify_idle_id == 0 && (now - last_notify >= 5)) - notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb, NULL, NULL); + if(up->new) + if(!g_slist_find(folders_with_new, up->folder)) + folders_with_new = g_slist_append(folders_with_new, up->folder); + + if (notify_idle_id == 0 && (now - last_notify >= 5)){ + if(g_slist_find(folders_with_new, up->folder)) + notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb, + GINT_TO_POINTER((gint32) up->new), NULL); + } if (up->uri) { EMEvent *e = em_event_peek(); @@ -375,6 +346,7 @@ up->new = new ? 1 : 0; up->store = mfi->store_info->store; up->uri = g_strdup(mfi->uri); + up->folder = folder; camel_object_ref(up->store); e_dlist_addtail(&updates, (EDListNode *)up); flush_updates(); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ mail/em-notify.c 2005-04-06 01:34:36.882140072 +0000 @@ -0,0 +1,372 @@ +/* Evolution new mail notification + * + * Copyright (C) 2005 Stéphane Konstantaropoulos + * + * Author: Stéphane Konstantaropoulos <stephane cs york ac uk> + * + * This is a GObject that handles notification of new mails. + * Callers obtain a reference with em_notify_peek() as this is supposed + * to be singleton + * + * Notification is done at em_notify_notify(), that receives one parameter + * new or not. Simple as it is. + * + * This can be extended to receive some more complex parameter like a + * CamelFolder and allow for notification of only selected folders or + * accounts... + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + */ + +#define selfp (self->_priv) + +#include "em-notify.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mail-config.h" +#include <e-util/e-icon-factory.h> +#include <gtk/gtk.h> +#include <gconf/gconf-client.h> +#include <libgnome/libgnome.h> + +static const GFlagsValue _em_notify_flags_values[] = { + { MAIL_NOTIFY_TYPE_BEEP, (char *)"MAIL_NOTIFY_TYPE_BEEP", (char *)"beep" }, + { MAIL_NOTIFY_TYPE_SOUND, (char *)"MAIL_NOTIFY_TYPE_SOUND", (char *)"sound" }, + { MAIL_NOTIFY_TYPE_TRAY, (char *)"MAIL_NOTIFY_TYPE_TRAY", (char *)"tray" }, + { 0, NULL, NULL } +}; + +GType +em_notify_flags_get_type (void) +{ + static GType type = 0; + if G_UNLIKELY(type == 0) + type = g_flags_register_static ("EmNotifyFlags", _em_notify_flags_values); + return type; +} + +/* self casting macros */ +#define SELF(x) EM_NOTIFY(x) +#define SELF_CONST(x) EM_NOTIFY_CONST(x) +#define IS_SELF(x) EM_IS_NOTIFY(x) +#define TYPE_SELF EM_TYPE_NOTIFY +#define SELF_CLASS(x) EM_NOTIFY_CLASS(x) + +#define SELF_GET_CLASS(x) EM_NOTIFY_GET_CLASS(x) + +/* self typedefs */ +typedef EmNotify Self; +typedef EmNotifyClass SelfClass; + +struct _EmNotifyPrivate { + EggTrayIcon * tray_icon; + GtkTooltips * tooltip; + GConfClient * client; + EmNotifyFlags notify_type; + gchar * notify_sound; + guint notify_id_type; + guint notify_id_sound; +}; +/* here are local prototypes */ +static void ___object_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); +static void em_notify_class_init (EmNotifyClass * c) G_GNUC_UNUSED; +static void em_notify_init (EmNotify * self) G_GNUC_UNUSED; +static void ___2_em_notify_dispose (GObject * object) G_GNUC_UNUSED; +static void em_notify_init_tray (EmNotify * self) G_GNUC_UNUSED; +static gboolean em_notify_tray_destroyed (GtkWidget * widget, GdkEvent * event, Self * self) G_GNUC_UNUSED; +static void em_notify_notify_changed_cb (GConfClient * client, guint cnxn_id, GConfEntry * entry, Self * self) G_GNUC_UNUSED; + +enum { + PROP_0, + PROP_TIP +}; + +/* pointer to the class of our parent */ +static GObjectClass *parent_class = NULL; + +/* Short form macros */ +#define self_peek em_notify_peek +#define self_set_tip em_notify_set_tip +#define self_notify em_notify_notify +#define self_init_tray em_notify_init_tray +#define self_tray_destroyed em_notify_tray_destroyed +#define self_notify_changed_cb em_notify_notify_changed_cb +GType +em_notify_get_type (void) +{ + static GType type = 0; + + if G_UNLIKELY(type == 0) { + static const GTypeInfo info = { + sizeof (EmNotifyClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) em_notify_class_init, + (GClassFinalizeFunc) NULL, + NULL /* class_data */, + sizeof (EmNotify), + 0 /* n_preallocs */, + (GInstanceInitFunc) em_notify_init, + NULL + }; + + type = g_type_register_static (G_TYPE_OBJECT, "EmNotify", &info, (GTypeFlags)0); + } + + return type; +} + +/* a macro for creating a new object of our type */ +#define GET_NEW ((EmNotify *)g_object_new(em_notify_get_type(), NULL)) + +/* a function for creating a new object of our type */ +#include <stdarg.h> +static EmNotify * GET_NEW_VARG (const char *first, ...) G_GNUC_UNUSED; +static EmNotify * +GET_NEW_VARG (const char *first, ...) +{ + EmNotify *ret; + va_list ap; + va_start (ap, first); + ret = (EmNotify *)g_object_new_valist (em_notify_get_type (), first, ap); + va_end (ap); + return ret; +} + + +static void +___dispose (GObject *obj_self) +{ + EmNotify *self G_GNUC_UNUSED = EM_NOTIFY (obj_self); + ___2_em_notify_dispose(obj_self); + if(self->_priv->tray_icon) { gtk_widget_destroy ((gpointer) self->_priv->tray_icon); self->_priv->tray_icon = NULL; } + if(self->_priv->tooltip) { gtk_object_destroy ((gpointer) self->_priv->tooltip); self->_priv->tooltip = NULL; } + if(self->_priv->client) { g_object_unref ((gpointer) self->_priv->client); self->_priv->client = NULL; } + if(self->_priv->notify_sound) { g_free ((gpointer) self->_priv->notify_sound); self->_priv->notify_sound = NULL; } +} + + +static void +___finalize(GObject *obj_self) +{ + EmNotify *self G_GNUC_UNUSED = EM_NOTIFY (obj_self); + gpointer priv G_GNUC_UNUSED = self->_priv; + if(G_OBJECT_CLASS(parent_class)->finalize) \ + (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self); +} + +static void +em_notify_class_init (EmNotifyClass * c G_GNUC_UNUSED) +{ + GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c; + + g_type_class_add_private(c,sizeof(EmNotifyPrivate)); + + parent_class = g_type_class_ref (G_TYPE_OBJECT); + + g_object_class->dispose = ___dispose; + g_object_class->finalize = ___finalize; + g_object_class->set_property = ___object_set_property; + { + GParamSpec *param_spec; + + param_spec = g_param_spec_string + ("tip" /* name */, + _("Tooltip") /* nick */, + _("Tooltip of the tray icon") /* blurb */, + NULL /* default_value */, + (GParamFlags)(G_PARAM_WRITABLE)); + g_object_class_install_property (g_object_class, + PROP_TIP, + param_spec); + } +} +static void +em_notify_init (EmNotify * self G_GNUC_UNUSED) +{ + self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self,TYPE_SELF,EmNotifyPrivate); + self->_priv->tray_icon = NULL; + self->_priv->tooltip = gtk_tooltips_new (); + self->_priv->client = g_object_ref(mail_config_get_gconf_client ()); + self->_priv->notify_sound = NULL; + self->_priv->notify_id_type = FALSE; + self->_priv->notify_id_sound = FALSE; + { + + self_init_tray(self); + // get GConf values + gconf_client_add_dir(selfp->client, "/apps/evolution/notify", + GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + selfp->notify_sound = gconf_client_get_string (selfp->client, "/apps/evolution/mail/notify/sound", NULL); + selfp->notify_type = gconf_client_get_int (selfp->client, "/apps/evolution/mail/notify/type", NULL); + + //register GConf listeners + selfp->notify_id_type = gconf_client_notify_add(selfp->client, + "/apps/evolution/mail/notify/type", + (GConfClientNotifyFunc) self_notify_changed_cb, self, NULL, NULL); + selfp->notify_id_sound = gconf_client_notify_add(selfp->client, + "/apps/evolution/mail/notify/sound", + (GConfClientNotifyFunc) self_notify_changed_cb, self, NULL, NULL); + + } +} + +static void +___object_set_property (GObject *object, + guint property_id, + const GValue *VAL G_GNUC_UNUSED, + GParamSpec *pspec G_GNUC_UNUSED) +{ + EmNotify *self G_GNUC_UNUSED; + + self = EM_NOTIFY (object); + + switch (property_id) { + case PROP_TIP: + { + + gtk_tooltips_set_tip(selfp->tooltip, + GTK_WIDGET (selfp->tray_icon), g_value_get_string(VAL), NULL); + + } + break; + default: +/* Apparently in g++ this is needed, glib is b0rk */ +#ifndef __PRETTY_FUNCTION__ +# undef G_STRLOC +# define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__) +#endif + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + + +static void +___2_em_notify_dispose (GObject * object G_GNUC_UNUSED) +#define PARENT_HANDLER(___object) \ + { if(G_OBJECT_CLASS(parent_class)->dispose) \ + (* G_OBJECT_CLASS(parent_class)->dispose)(___object); } +{ +{ + + Self *self = SELF(object); + puts(G_STRLOC); + gconf_client_notify_remove(selfp->client, selfp->notify_id_type); + gconf_client_notify_remove(selfp->client, selfp->notify_id_sound); + PARENT_HANDLER(object); + }} +#undef PARENT_HANDLER + +EmNotify * +em_notify_peek (void) +{ +{ + + static Self *self = NULL; + if (G_UNLIKELY(self == NULL)){ + self = GET_NEW; + g_object_add_weak_pointer(G_OBJECT(self), (gpointer) &self); + return self; + } + return (Self *) g_object_ref(self); + }} + +void +em_notify_set_tip (EmNotify * self, const gchar * text) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (EM_IS_NOTIFY (self)); +{ + + gboolean ret; //unused + gtk_tooltips_set_tip (selfp->tooltip, + GTK_WIDGET (selfp->tray_icon), text, NULL); + //show tooltip + g_signal_emit_by_name(selfp->tray_icon,"show-help", GTK_WIDGET_HELP_TOOLTIP, &ret); + }} + +void +em_notify_notify (EmNotify * self, gboolean new) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (EM_IS_NOTIFY (self)); +{ + + if(new){ + if (selfp->notify_type & MAIL_NOTIFY_TYPE_SOUND) + if (selfp->notify_sound != NULL) + gnome_sound_play (selfp->notify_sound); + if (selfp->notify_type & MAIL_NOTIFY_TYPE_BEEP) + gdk_beep (); + if (selfp->notify_type & MAIL_NOTIFY_TYPE_TRAY){ + gtk_widget_show_all(GTK_WIDGET(selfp->tray_icon)); + self_set_tip(self, _("You have mail!")); + } + } else + gtk_widget_hide(GTK_WIDGET(selfp->tray_icon)); + }} + +static void +em_notify_init_tray (EmNotify * self) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (EM_IS_NOTIFY (self)); +{ + + GtkWidget *image = e_icon_factory_get_image("stock_mail", + E_ICON_SIZE_MENU); + GtkWidget *evbox = gtk_event_box_new (); + selfp->tray_icon = egg_tray_icon_new("EmNotify"); + gtk_container_add (GTK_CONTAINER (evbox), image); + gtk_container_add (GTK_CONTAINER(selfp->tray_icon), evbox); + g_signal_connect (G_OBJECT (selfp->tray_icon), "destroy-event", + G_CALLBACK (self_tray_destroyed), self); + + //add drag and drop, event handling and popup menu + }} + +static gboolean +em_notify_tray_destroyed (GtkWidget * widget, GdkEvent * event, Self * self) +{ + g_return_val_if_fail (!(self) || IS_SELF (self), (gboolean )0); +{ + + g_object_unref(widget); + g_idle_add((GSourceFunc) self_init_tray, self); + return TRUE; + }} + +static void +em_notify_notify_changed_cb (GConfClient * client, guint cnxn_id, GConfEntry * entry, Self * self) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (IS_SELF (self)); +{ + + if(cnxn_id == selfp->notify_id_sound){ + if(selfp->notify_sound) + g_free(selfp->notify_sound); + selfp->notify_sound = gconf_client_get_string (client, "/apps/evolution/mail/notify/sound", NULL); + } else if(cnxn_id == selfp->notify_id_type){ + selfp->notify_type = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL); + + } else { + g_warning(G_STRLOC" - wrong cnx_id given by GConf."); + } + }} --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ mail/em-notify.h 2005-04-05 19:47:46.054866704 +0000 @@ -0,0 +1,104 @@ +/* Evolution new mail notification + * + * Copyright (C) 2005 Stéphane Konstantaropoulos + * + * Author: Stéphane Konstantaropoulos <stephane cs york ac uk> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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 <glib.h> +#include <glib-object.h> +#ifndef __EM_NOTIFY_H__ +#define __EM_NOTIFY_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <e-util/eggtrayicon.h> + +typedef enum { + MAIL_NOTIFY_TYPE_BEEP = 1<<0, + MAIL_NOTIFY_TYPE_SOUND = 1<<1, + MAIL_NOTIFY_TYPE_TRAY = 1<<2 +} EmNotifyFlags; +#define EM_TYPE_NOTIFY_FLAGS em_notify_flags_get_type() +GType em_notify_flags_get_type (void); + + +/* + * Type checking and casting macros + */ +#define EM_TYPE_NOTIFY (em_notify_get_type()) +#define EM_NOTIFY(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), em_notify_get_type(), EmNotify) +#define EM_NOTIFY_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), em_notify_get_type(), EmNotify const) +#define EM_NOTIFY_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), em_notify_get_type(), EmNotifyClass) +#define EM_IS_NOTIFY(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), em_notify_get_type ()) + +#define EM_NOTIFY_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), em_notify_get_type(), EmNotifyClass) + +/* Private structure type */ +typedef struct _EmNotifyPrivate EmNotifyPrivate; + +/* + * Main object structure + */ +#ifndef __TYPEDEF_EM_NOTIFY__ +#define __TYPEDEF_EM_NOTIFY__ +typedef struct _EmNotify EmNotify; +#endif +struct _EmNotify { + GObject __parent__; + /*< private >*/ + EmNotifyPrivate *_priv; +}; + +/* + * Class definition + */ +typedef struct _EmNotifyClass EmNotifyClass; +struct _EmNotifyClass { + GObjectClass __parent__; +}; + +/* + * Public methods + */ +GType em_notify_get_type (void); +/* use this and NOT g_object_new as this is singleton + * caller owns a reference to the EmNotify + * it has to be unreffed */ +EmNotify * em_notify_peek (void); +void em_notify_set_tip (EmNotify * self, + const gchar * text); +void em_notify_notify (EmNotify * self, + gboolean new); + +/* + * Argument wrapping macros + */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define EM_NOTIFY_PROP_TIP(arg) "tip", __extension__ ({gchar *z = (arg); z;}) +#else /* __GNUC__ && !__STRICT_ANSI__ */ +#define EM_NOTIFY_PROP_TIP(arg) "tip",(gchar *)(arg) +#endif /* __GNUC__ && !__STRICT_ANSI__ */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif
Attachment:
signature.asc
Description: This is a digitally signed message part