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-evolution-folder-tree-client.gob (9054B) - 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 <gtk/gtk.h>
     22 %}
     23 
     24 %privateheader{
     25 #include "mn-evolution-client.h"
     26 %}
     27 
     28 %{
     29 #include <glib/gi18n.h>
     30 #include "mn-evolution-client-dbus.h"
     31 #include "mn-dbus-properties-client-dbus.h"
     32 #include "mn-evolution.h"
     33 #include "mn-shell.h"
     34 #include "mn-util.h"
     35 %}
     36 
     37 class MN:Evolution:Folder:Tree:Client from Gtk:HBox
     38 {
     39   private DBusGProxy *proxy;
     40   private DBusGProxy *properties_proxy;
     41 
     42   property BOOLEAN connected (export)
     43     get
     44     {
     45       g_value_set_boolean(VAL, selfp->proxy != NULL);
     46     };
     47 
     48   public char *selected_uri destroywith g_free;
     49   property STRING selected_uri (export)
     50     set
     51     {
     52       g_free(self->selected_uri);
     53       self->selected_uri = g_value_dup_string(VAL);
     54 
     55       if (selfp->proxy)
     56 	self_sync_selected_uri(self);
     57     }
     58     get
     59     {
     60       g_value_set_string(VAL, self->selected_uri);
     61     };
     62 
     63   private MNEvolutionClient *client;
     64 
     65   private unsigned int contact_error_idle_id;
     66 
     67   signal private NONE (NONE)
     68     void folder_activated (self);
     69 
     70   init (self)
     71   {
     72     selfp->client = mn_evolution_client_get();
     73     g_signal_connect_swapped(selfp->client, "notify::proxy", G_CALLBACK(self_update), self);
     74 
     75     self_update(self);
     76   }
     77 
     78   dispose (self)
     79   {
     80     self_clear_proxy(self);
     81 
     82     mn_source_clear(&selfp->contact_error_idle_id);
     83 
     84     if (selfp->client)
     85       {
     86 	g_signal_handlers_disconnect_by_func(selfp->client, self_update, self);
     87 	selfp->client = NULL;
     88       }
     89   }
     90 
     91   private void
     92     clear_proxy (self)
     93   {
     94     if (selfp->proxy)
     95       {
     96 	/*
     97 	 * We cannot unreference the proxy because of a memory
     98 	 * management bug in DBusGProxy
     99 	 * (https://bugs.freedesktop.org/show_bug.cgi?id=14030), so
    100 	 * simply disconnect the signals and nullify the proxy.
    101 	 */
    102 
    103 	dbus_g_proxy_disconnect_signal(selfp->proxy,
    104 				       MN_EVOLUTION_FOLDER_TREE_SERVER_SIGNAL_FOLDER_SELECTED,
    105 				       G_CALLBACK(self_folder_selected_h),
    106 				       self);
    107 	dbus_g_proxy_disconnect_signal(selfp->proxy,
    108 				       MN_EVOLUTION_FOLDER_TREE_SERVER_SIGNAL_FOLDER_ACTIVATED,
    109 				       G_CALLBACK(self_folder_activated_h),
    110 				       self);
    111 
    112 	mn_remove_weak_pointer(&selfp->proxy); /* also sets it to NULL */
    113       }
    114   }
    115 
    116   private void
    117     update (self)
    118   {
    119     MNEvolutionClient *client;
    120 
    121     /*
    122      * We do not unconditionally create the GtkSocket to avoid the
    123      * widget change flicker that would occur if Evolution cannot be
    124      * contacted.
    125      */
    126 
    127     client = mn_evolution_client_get();
    128     if (client->proxy)
    129       {
    130 	GtkWidget *sock;
    131 
    132 	sock = gtk_socket_new();
    133 
    134 	g_signal_connect(sock, "plug-removed", G_CALLBACK(self_plug_removed_h), NULL);
    135 
    136 	/*
    137 	 * In order to be able to call gtk_socket_get_id(), the socket
    138 	 * must be added to a toplevel window.
    139 	 */
    140 	g_signal_connect(sock, "realize", G_CALLBACK(self_realize_h), self);
    141 
    142 	self_set_widget(self, sock);
    143       }
    144     else
    145       self_handle_contact_error(self);
    146   }
    147 
    148   private gboolean
    149     plug_removed_h (GtkSocket *sock, gpointer user_data)
    150   {
    151     /*
    152      * Do not destroy the socket, it will be destroyed when removed
    153      * from the vbox in set_widget().
    154      */
    155     return TRUE;
    156   }
    157 
    158   private void
    159     realize_h (GtkWidget *widget, gpointer user_data)
    160   {
    161     Self *self = user_data;
    162     MNEvolutionClient *client;
    163 
    164     client = mn_evolution_client_get();
    165     if (client->proxy)
    166       {
    167 	guint32 id;
    168 	GError *err = NULL;
    169 
    170 	id = (guint32) gtk_socket_get_id(GTK_SOCKET(widget));
    171 
    172 	if (org_gnome_MailNotification_Evolution_folder_tree_new(client->proxy, id, &err))
    173 	  {
    174 	    char *service;
    175 	    char *path;
    176 
    177 	    self_clear_proxy(self);
    178 
    179 	    service = g_strdup_printf(MN_EVOLUTION_FOLDER_TREE_SERVER_SERVICE, id);
    180 	    path = g_strdup_printf(MN_EVOLUTION_FOLDER_TREE_SERVER_PATH, id);
    181 
    182 	    selfp->proxy = dbus_g_proxy_new_for_name_owner(mn_shell->session_bus,
    183 							   service,
    184 							   path,
    185 							   MN_EVOLUTION_FOLDER_TREE_SERVER_INTERFACE,
    186 							   NULL);
    187 
    188 	    g_free(service);
    189 	    g_free(path);
    190 
    191 	    if (selfp->proxy)
    192 	      {
    193 		/*
    194 		 * We must add a weak pointer, so that if the proxy is
    195 		 * destroyed after Evolution exits we won't try to
    196 		 * clear an invalid proxy in clear_proxy().
    197 		 */
    198 		mn_add_weak_pointer(&selfp->proxy);
    199 
    200 		selfp->properties_proxy = dbus_g_proxy_new_from_proxy(selfp->proxy, DBUS_INTERFACE_PROPERTIES, NULL);
    201 
    202 		dbus_g_proxy_add_signal(selfp->proxy,
    203 					MN_EVOLUTION_FOLDER_TREE_SERVER_SIGNAL_FOLDER_SELECTED,
    204 					G_TYPE_STRING,	/* uri */
    205 					G_TYPE_INVALID);
    206 		dbus_g_proxy_add_signal(selfp->proxy,
    207 					MN_EVOLUTION_FOLDER_TREE_SERVER_SIGNAL_FOLDER_ACTIVATED,
    208 					G_TYPE_INVALID);
    209 
    210 		dbus_g_proxy_connect_signal(selfp->proxy,
    211 					    MN_EVOLUTION_FOLDER_TREE_SERVER_SIGNAL_FOLDER_SELECTED,
    212 					    G_CALLBACK(self_folder_selected_h),
    213 					    self,
    214 					    NULL);
    215 		dbus_g_proxy_connect_signal(selfp->proxy,
    216 					    MN_EVOLUTION_FOLDER_TREE_SERVER_SIGNAL_FOLDER_ACTIVATED,
    217 					    G_CALLBACK(self_folder_activated_h),
    218 					    self,
    219 					    NULL);
    220 
    221 		/* give the folder tree a decent height */
    222 		gtk_widget_set_size_request(widget, -1, 150);
    223 
    224 		self_sync_selected_uri(self);
    225 		g_object_notify(G_OBJECT(self), "connected");
    226 
    227 		return;		/* success */
    228 	      }
    229 	  }
    230 	else
    231 	  {
    232 	    /* unlikely to ever happen, not worth a translation */
    233 	    g_warning("cannot create folder tree: %s", err->message);
    234 	    g_error_free(err);
    235 	  }
    236       }
    237 
    238     /*
    239      * Failure. We cannot call handle_contact_error() from here since
    240      * it would destroy the GtkSocket that is currently being
    241      * realized. Use an idle callback.
    242      */
    243     if (! selfp->contact_error_idle_id)
    244       selfp->contact_error_idle_id = gdk_threads_add_idle(self_contact_error_cb, self);
    245   }
    246 
    247   private gboolean
    248     contact_error_cb (gpointer data)
    249   {
    250     Self *self = data;
    251 
    252     self_handle_contact_error(self);
    253 
    254     selfp->contact_error_idle_id = 0;
    255     return FALSE;		/* remove source */
    256   }
    257 
    258   private void
    259     handle_contact_error (self)
    260   {
    261     GtkWidget *label;
    262 
    263     if (selfp->proxy)
    264       {
    265 	self_clear_proxy(self);
    266 	g_object_notify(G_OBJECT(self), "connected");
    267       }
    268 
    269     label = gtk_label_new(_("Mail Notification can not contact Evolution. Make sure that Evolution is running and that the Evolution Jean-Yves Lefort's Mail Notification plugin is loaded."));
    270 
    271     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    272     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
    273     gtk_label_set_selectable(GTK_LABEL(label), TRUE);
    274 
    275     self_set_widget(self, label);
    276   }
    277 
    278   private void
    279     sync_selected_uri (self)
    280   {
    281     GValue value = { 0, };
    282     GError *err = NULL;
    283 
    284     g_return_if_fail(selfp->proxy != NULL);
    285 
    286     if (! self->selected_uri)
    287       return;
    288 
    289     g_value_init(&value, G_TYPE_STRING);
    290     g_value_set_string(&value, self->selected_uri);
    291 
    292     if (! org_freedesktop_DBus_Properties_set(selfp->properties_proxy,
    293 					      MN_EVOLUTION_FOLDER_TREE_SERVER_INTERFACE,
    294 					      MN_EVOLUTION_FOLDER_TREE_SERVER_PROPERTY_URI,
    295 					      &value,
    296 					      &err))
    297       {
    298 	g_warning("cannot set D-Bus property %s of interface %s: %s",
    299 		  MN_EVOLUTION_FOLDER_TREE_SERVER_PROPERTY_URI,
    300 		  MN_EVOLUTION_FOLDER_TREE_SERVER_INTERFACE,
    301 		  err->message);
    302 	g_error_free(err);
    303       }
    304 
    305     g_value_unset(&value);
    306   }
    307 
    308   private void
    309     set_widget (self, Gtk:Widget *widget (check null type))
    310   {
    311     GList *children;
    312 
    313     children = gtk_container_get_children(GTK_CONTAINER(self));
    314     if (children)
    315       {
    316 	g_assert(g_list_length(children) == 1);
    317 	gtk_container_remove(GTK_CONTAINER(self), children->data);
    318 	g_list_free(children);
    319       }
    320 
    321     gtk_box_pack_start(GTK_BOX(self), widget, TRUE, TRUE, 0);
    322     gtk_widget_show(widget);
    323   }
    324 
    325   private void
    326     folder_selected_h (DBusGProxy *proxy,
    327 		       const char *uri,
    328 		       gpointer user_data)
    329   {
    330     Self *self = user_data;
    331 
    332     /* this is a main loop callback */
    333     GDK_THREADS_ENTER();
    334 
    335     g_free(self->selected_uri);
    336     self->selected_uri = g_strdup(uri);
    337 
    338     g_object_notify(G_OBJECT(self), "selected-uri");
    339 
    340     GDK_THREADS_LEAVE();
    341   }
    342 
    343   private void
    344     folder_activated_h (DBusGProxy *proxy, gpointer user_data)
    345   {
    346     Self *self = user_data;
    347 
    348     /* this is a main loop callback */
    349     GDK_THREADS_ENTER();
    350 
    351     self_folder_activated(self);
    352 
    353     GDK_THREADS_LEAVE();
    354   }
    355 
    356   public GtkWidget *
    357     new (void)
    358   {
    359     return GTK_WIDGET(GET_NEW);
    360   }
    361 }