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 }