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 }