mail-notification

Fork of Jean-Yves Lefort's mail-notification, a tray icon to notify of new mail
git clone https://code.djc.id.au/git/mail-notification/

src/mn-popup.gob (6068B) - raw

      1 /*
      2  * Mail Notification
      3  * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License along
     16  * with this program; if not, write to the Free Software Foundation, Inc.,
     17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  */
     19 
     20 %headertop{
     21 #include <libnotify/notify.h>
     22 #include "mn-message.h"
     23 %}
     24 
     25 %{
     26 #include <glib/gi18n.h>
     27 #include "mn-conf.h"
     28 #include "mn-shell.h"
     29 #include "mn-util.h"
     30 %}
     31 
     32 class MN:Popup from Notify:Notification
     33 {
     34   private MNMessage *message unrefwith g_object_unref;
     35   property OBJECT message (flags = CONSTRUCT_ONLY, link, object_type = MN:Message, type = MNMessage *);
     36 
     37   public gboolean visible;
     38   public GTimeVal show_timestamp;
     39 
     40   constructor (self)
     41   {
     42     GString *body;
     43 
     44     body = g_string_new(NULL);
     45     self_append_row(body, _("Mailbox:"), selfp->message->mailbox->runtime_name);
     46     self_append_row(body, _("From:"), selfp->message->from);
     47     self_append_row(body, _("Subject:"), selfp->message->subject);
     48 
     49     g_object_set(self,
     50 		 "body", body->str,
     51 		 "icon-name", "stock_mail",
     52 		 NULL);
     53 
     54     if (mn_conf_get_enum_value(MN_TYPE_POPUP_POSITION, MN_CONF_POPUPS_POSITION) == MN_POPUP_POSITION_ATTACHED) {
     55       self_wait_for_icon_to_become_ready(self);
     56       g_object_set(self, "attach-widget", mn_shell->icon, NULL);
     57     }
     58 
     59     g_string_free(body, TRUE);
     60 
     61     self_add_actions(self);
     62 
     63     notify_notification_set_timeout(NOTIFY_NOTIFICATION(self), self_get_conf_timeout());
     64 
     65     g_signal_connect(self, "closed", G_CALLBACK(self_closed_h), NULL);
     66   }
     67 
     68   private void wait_for_icon_to_become_ready(self) {
     69     int x, y;
     70     int count = 0;
     71 
     72     /* When the tray icon is created, it can still take some time before
     73      * it has arrived at the correct position. This is especially the case
     74      * on KDE environments. To work around this, add a little delay of at
     75      * most 2 seconds before showing a popup which is attached to the notification */
     76     do {
     77         gdk_window_get_origin (gtk_widget_get_window (mn_shell->icon), &x, &y);
     78 
     79         if (x != 0 || y != 0) {
     80             break;
     81         }
     82 
     83         g_usleep(G_USEC_PER_SEC / 10);
     84         count++;
     85     } while (count < 20);
     86   }
     87 
     88   private void
     89     add_actions (self)
     90   {
     91     GSList *actions;
     92     GSList *l;
     93 
     94     /*
     95      * Note that notification-daemon currently assigns icons to
     96      * actions by prepending "stock_" to the action ID.
     97      */
     98 
     99     actions = mn_conf_get_string_list(MN_CONF_POPUPS_ACTIONS);
    100 
    101     MN_LIST_FOREACH(l, actions)
    102       {
    103 	char *name = l->data;
    104 	MNMessageAction *action;
    105 
    106 	action = mn_message_get_action(name);
    107 	if (action)
    108 	  {
    109 	    if (mn_message_can_perform_action(selfp->message, action))
    110 	      notify_notification_add_action(NOTIFY_NOTIFICATION(self),
    111 					     action->icon,
    112 					     _(action->label),
    113 					     self_action_cb,
    114 					     action,
    115 					     NULL);
    116 	  }
    117 	else
    118 	  g_warning(_("configuration key %s: there is no action named \"%s\""), MN_CONF_POPUPS_ACTIONS, name);
    119       }
    120 
    121     mn_g_slist_free_deep(actions);
    122   }
    123 
    124   private void
    125     action_cb (NotifyNotification *notification, char *id, gpointer user_data)
    126   {
    127     Self *self = SELF(notification);
    128     MNMessageAction *action = user_data;
    129 
    130     GDK_THREADS_ENTER();
    131 
    132     mn_message_perform_action(selfp->message, action, self_action_done_cb, self);
    133 
    134     GDK_THREADS_LEAVE();
    135   }
    136 
    137   private void
    138     action_done_cb (MNMessageAction *action, GError *err, gpointer data)
    139   {
    140     if (err && ! g_error_matches(err, MN_MESSAGE_ACTION_ERROR, MN_MESSAGE_ACTION_ERROR_CANCELLED))
    141       mn_show_error_dialog(NULL, _(action->error_message), "%s", err->message);
    142   }
    143 
    144   private void
    145     closed_h (NotifyNotification *notification, gpointer user_data)
    146   {
    147     Self *self = SELF(notification);
    148     self->visible = FALSE;
    149   }
    150 
    151   private void
    152     append_row (GString *body (check null),
    153 		const char *name (check null),
    154 		const char *value (check null))
    155     {
    156       char *escaped;
    157 
    158       if (*body->str)
    159 	g_string_append_c(body, '\n');
    160 
    161       g_string_append_printf(body, "<span weight=\"bold\">%s</span>", name);
    162 
    163       escaped = g_markup_escape_text(value, -1);
    164       g_string_append_printf(body, " %s", escaped);
    165       g_free(escaped);
    166     }
    167 
    168   private int
    169     get_conf_timeout (void)
    170   {
    171     switch (mn_conf_get_enum_value(MN_TYPE_EXPIRATION_ENABLED, MN_CONF_POPUPS_EXPIRATION_ENABLED))
    172       {
    173       case MN_EXPIRATION_ENABLED_DEFAULT:
    174 	return NOTIFY_EXPIRES_DEFAULT;
    175 
    176       case MN_EXPIRATION_ENABLED_FALSE:
    177 	return NOTIFY_EXPIRES_NEVER;
    178 
    179       case MN_EXPIRATION_ENABLED_TRUE:
    180 	return mn_conf_get_int(MN_CONF_POPUPS_EXPIRATION_DELAY) * 1000;
    181 
    182       default:
    183 	g_assert_not_reached();
    184 	return 0;
    185       }
    186   }
    187 
    188   public void
    189     show (self)
    190   {
    191     GError *err = NULL;
    192 
    193     if (self->visible)
    194       return;
    195 
    196     if (! notify_notification_show(NOTIFY_NOTIFICATION(self), &err))
    197       {
    198 	g_warning(_("unable to show popup: %s"), err->message);
    199 	g_error_free(err);
    200       }
    201 
    202     self->visible = TRUE;
    203     g_get_current_time(&self->show_timestamp);
    204   }
    205 
    206   public void
    207     close (self)
    208   {
    209     GError *err = NULL;
    210 
    211     if (! self->visible)
    212       return;
    213 
    214     if (! notify_notification_close(NOTIFY_NOTIFICATION(self), &err))
    215       {
    216 	g_warning(_("unable to close popup: %s"), err->message);
    217 	g_error_free(err);
    218       }
    219   }
    220 
    221   public MNPopup *
    222     new (MN:Message *message (check null type))
    223   {
    224     /* we set the summary here because libnotify requires it */
    225 
    226     /* translators: header capitalization */
    227     return GET_NEW_VARG("summary", _("New Message"),
    228 			MN_POPUP_PROP_MESSAGE(message),
    229 			NULL);
    230   }
    231 }