source: trunk/third/evolution/shell/evolution-activity-client.c @ 18142

Revision 18142, 12.0 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18141, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* evolution-activity-client.c
3 *
4 * Copyright (C) 2001  Ximian, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
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 GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Ettore Perazzoli <ettore@ximian.com>
21 */
22
23/* Another evil GTK+ object wrapper for a CORBA API.  In this case, the wrapper
24   is needed to avoid sending too frequent CORBA requests across the wire, thus
25   slowing the client down.  The wrapper makes sure that there is a minimum
26   amount of time between each CORBA method invocation.  */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32#include "evolution-activity-client.h"
33
34#include "e-shell-corba-icon-utils.h"
35
36#include <gtk/gtksignal.h>
37#include <gtk/gtkmain.h>
38
39#include <bonobo/bonobo-listener.h>
40
41#include <gal/util/e-util.h>
42
43
44#define PARENT_TYPE gtk_object_get_type ()
45static GtkObjectClass *parent_class = NULL;
46
47/* The minimum time between updates, in msecs.  */
48#define UPDATE_DELAY 1000
49
50enum {
51        SHOW_DETAILS,
52        CANCEL,
53        LAST_SIGNAL
54};
55
56static guint signals[LAST_SIGNAL] = { 0 };
57
58struct _EvolutionActivityClientPrivate {
59        /* The ::Activity interface that we QI from the shell.  */
60        GNOME_Evolution_Activity activity_interface;
61
62        /* BonoboListener used to get notification about actions that the user
63           requested on the activity.  */
64        BonoboListener *listener;
65
66        /* Id of this activity.  */
67        GNOME_Evolution_Activity_ActivityId activity_id;
68
69        /* Id for the GTK+ timeout used to do updates.  */
70        int next_update_timeout_id;
71
72        /* Wether we have to actually push an update at this timeout.  */
73        int have_pending_update;
74
75        /* Data for the next update.  */
76        char *new_information;
77        double new_progress;
78};
79
80
81/* Utility functions.  */
82
83static gboolean
84corba_update_progress (EvolutionActivityClient *activity_client,
85                       const char *information,
86                       double progress)
87{
88        EvolutionActivityClientPrivate *priv;
89        CORBA_Environment ev;
90        gboolean retval;
91
92        priv = activity_client->priv;
93
94        CORBA_exception_init (&ev);
95
96        GNOME_Evolution_Activity_operationProgressing (priv->activity_interface,
97                                                       priv->activity_id,
98                                                       information,
99                                                       progress,
100                                                       &ev);
101
102        if (ev._major == CORBA_NO_EXCEPTION) {
103                retval = TRUE;
104        } else {
105                g_warning ("EvolutionActivityClient: Error updating progress -- %s",
106                           ev._repo_id);
107                retval = FALSE;
108        }
109
110        CORBA_exception_free (&ev);
111
112        return retval;
113}
114
115static gboolean
116update_timeout_callback (void *data)
117{
118        EvolutionActivityClient *activity_client;
119        EvolutionActivityClientPrivate *priv;
120
121        activity_client = EVOLUTION_ACTIVITY_CLIENT (data);
122        priv = activity_client->priv;
123
124        if (priv->have_pending_update) {
125                priv->have_pending_update = FALSE;
126                corba_update_progress (activity_client, priv->new_information, priv->new_progress);
127                return TRUE;
128        } else {
129                priv->next_update_timeout_id = 0;
130                return FALSE;
131        }
132}
133
134
135/* BonoboListener callback.  */
136
137static void
138listener_callback (BonoboListener *listener,
139                   char *event_name,
140                   CORBA_any *any,
141                   CORBA_Environment *ev,
142                   void *data)
143{
144        EvolutionActivityClient *activity_client;
145
146        activity_client = EVOLUTION_ACTIVITY_CLIENT (data);
147
148        if (strcmp (event_name, "ShowDetails") == 0)
149                gtk_signal_emit (GTK_OBJECT (activity_client), signals[SHOW_DETAILS]);
150        else if (strcmp (event_name, "Cancel") == 0)
151                gtk_signal_emit (GTK_OBJECT (activity_client), signals[CANCEL]);
152        else
153                g_warning ("EvolutionActivityClient: Unknown event from listener -- %s", event_name);
154}
155
156
157/* GtkObject methods.  */
158
159static void
160impl_destroy (GtkObject *object)
161{
162        EvolutionActivityClient *activity_client;
163        EvolutionActivityClientPrivate *priv;
164        CORBA_Environment ev;
165
166        activity_client = EVOLUTION_ACTIVITY_CLIENT (object);
167        priv = activity_client->priv;
168
169        if (priv->next_update_timeout_id != 0)
170                g_source_remove (priv->next_update_timeout_id);
171
172        CORBA_exception_init (&ev);
173
174        if (! CORBA_Object_is_nil (priv->activity_interface, &ev)) {
175                GNOME_Evolution_Activity_operationFinished (priv->activity_interface,
176                                                            priv->activity_id,
177                                                            &ev);
178                if (ev._major != CORBA_NO_EXCEPTION)
179                        g_warning ("EvolutionActivityClient: Error reporting completion of operation -- %s",
180                                   ev._repo_id);
181
182                CORBA_Object_release (priv->activity_interface, &ev);
183        }
184
185        CORBA_exception_free (&ev);
186
187        if (priv->listener != NULL)
188                bonobo_object_unref (BONOBO_OBJECT (priv->listener));
189
190        g_free (priv->new_information);
191
192        g_free (priv);
193
194        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
195}
196
197
198static void
199class_init (EvolutionActivityClientClass *klass)
200{
201        GtkObjectClass *object_class;
202
203        parent_class = gtk_type_class (PARENT_TYPE);
204
205        object_class = GTK_OBJECT_CLASS (klass);
206        object_class->destroy = impl_destroy;
207
208        signals[SHOW_DETAILS]
209                = gtk_signal_new ("show_details",
210                                  GTK_RUN_FIRST,
211                                  object_class->type,
212                                  GTK_SIGNAL_OFFSET (EvolutionActivityClientClass, show_details),
213                                  gtk_marshal_NONE__NONE,
214                                  GTK_TYPE_NONE, 0);
215
216        signals[CANCEL]
217                = gtk_signal_new ("cancel",
218                                  GTK_RUN_FIRST,
219                                  object_class->type,
220                                  GTK_SIGNAL_OFFSET (EvolutionActivityClientClass, cancel),
221                                  gtk_marshal_NONE__NONE,
222                                  GTK_TYPE_NONE, 0);
223
224        gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
225}
226
227
228static void
229init (EvolutionActivityClient *activity_client)
230{
231        EvolutionActivityClientPrivate *priv;
232
233        priv = g_new (EvolutionActivityClientPrivate, 1);
234        priv->activity_interface     = CORBA_OBJECT_NIL;
235        priv->listener               = bonobo_listener_new (listener_callback, activity_client);
236        priv->activity_id            = (GNOME_Evolution_Activity_ActivityId) 0;
237        priv->next_update_timeout_id = 0;
238        priv->have_pending_update    = FALSE;
239        priv->new_information        = NULL;
240        priv->new_progress           = 0.0;
241
242        activity_client->priv = priv;
243}
244
245
246gboolean
247evolution_activity_client_construct (EvolutionActivityClient *activity_client,
248                                     EvolutionShellClient *shell_client,
249                                     const char *component_id,
250                                     GdkPixbuf **animated_icon,
251                                     const char *information,
252                                     gboolean cancellable,
253                                     gboolean *suggest_display_return)
254{
255        EvolutionActivityClientPrivate *priv;
256        GNOME_Evolution_Activity activity_interface;
257        CORBA_Environment ev;
258        CORBA_boolean suggest_display;
259        GNOME_Evolution_AnimatedIcon *corba_animated_icon;
260
261        g_return_val_if_fail (activity_client != NULL, FALSE);
262        g_return_val_if_fail (EVOLUTION_IS_ACTIVITY_CLIENT (activity_client), FALSE);
263        g_return_val_if_fail (shell_client != NULL, FALSE);
264        g_return_val_if_fail (EVOLUTION_IS_SHELL_CLIENT (shell_client), FALSE);
265        g_return_val_if_fail (animated_icon != NULL, FALSE);
266        g_return_val_if_fail (*animated_icon != NULL, FALSE);
267        g_return_val_if_fail (information != NULL, FALSE);
268        g_return_val_if_fail (suggest_display_return != NULL, FALSE);
269
270        priv = activity_client->priv;
271        g_return_val_if_fail (priv->activity_interface == CORBA_OBJECT_NIL, FALSE);
272
273        GTK_OBJECT_UNSET_FLAGS (activity_client, GTK_FLOATING);
274
275        CORBA_exception_init (&ev);
276
277        activity_interface = evolution_shell_client_get_activity_interface (shell_client);
278        priv->activity_interface = CORBA_Object_duplicate (activity_interface, &ev);
279        if (ev._major != CORBA_NO_EXCEPTION) {
280                priv->activity_interface = CORBA_OBJECT_NIL;
281                CORBA_exception_free (&ev);
282                return FALSE;
283        }
284
285        corba_animated_icon = e_new_corba_animated_icon_from_pixbuf_array (animated_icon);
286
287        GNOME_Evolution_Activity_operationStarted (activity_interface,
288                                                   component_id,
289                                                   corba_animated_icon,
290                                                   information,
291                                                   cancellable,
292                                                   bonobo_object_corba_objref (BONOBO_OBJECT (priv->listener)),
293                                                   &priv->activity_id,
294                                                   &suggest_display,
295                                                   &ev);
296
297        CORBA_free (corba_animated_icon);
298
299        if (ev._major != CORBA_NO_EXCEPTION) {
300                CORBA_exception_free (&ev);
301                return FALSE;
302        }
303
304        *suggest_display_return = (gboolean) suggest_display;
305
306        CORBA_exception_free (&ev);
307        return TRUE;
308}
309
310EvolutionActivityClient *
311evolution_activity_client_new (EvolutionShellClient *shell_client,
312                               const char *component_id,
313                               GdkPixbuf **animated_icon,
314                               const char *information,
315                               gboolean cancellable,
316                               gboolean *suggest_display_return)
317{
318        EvolutionActivityClient *activity_client;
319
320        g_return_val_if_fail (shell_client != NULL, NULL);
321        g_return_val_if_fail (EVOLUTION_IS_SHELL_CLIENT (shell_client), NULL);
322        g_return_val_if_fail (animated_icon != NULL, NULL);
323        g_return_val_if_fail (*animated_icon != NULL, NULL);
324        g_return_val_if_fail (information != NULL, NULL);
325        g_return_val_if_fail (suggest_display_return != NULL, NULL);
326
327        activity_client = gtk_type_new (evolution_activity_client_get_type ());
328
329        if (! evolution_activity_client_construct (activity_client,
330                                                   shell_client,
331                                                   component_id,
332                                                   animated_icon,
333                                                   information,
334                                                   cancellable,
335                                                   suggest_display_return)) {
336                gtk_object_unref (GTK_OBJECT (activity_client));
337                return NULL;
338        }
339
340        return activity_client;
341}
342
343
344gboolean
345evolution_activity_client_update (EvolutionActivityClient *activity_client,
346                                  const char *information,
347                                  double progress)
348{
349        EvolutionActivityClientPrivate *priv;
350        gboolean retval;
351
352        g_return_val_if_fail (activity_client != NULL, FALSE);
353        g_return_val_if_fail (EVOLUTION_IS_ACTIVITY_CLIENT (activity_client), FALSE);
354        g_return_val_if_fail (information != NULL, FALSE);
355        g_return_val_if_fail (progress == -1.0 || (progress >= 0.0 && progress <= 1.0), FALSE);
356
357        priv = activity_client->priv;
358
359        if (priv->next_update_timeout_id == 0) {
360                /* There is no pending timeout, so the last CORBA update
361                   happened more than UPDATE_DELAY msecs ago. So we set up a
362                   timeout so we can check against it at the next update
363                   request.
364
365                   Notice that GLib timeouts or other operations on this object
366                   can be invoked within a remote CORBA invocation, so we need
367                   to set `next_update_timeout_id' and `have_pending_update'
368                   before doing the CORBA call, or nasty race conditions might
369                   happen.  */
370
371                priv->have_pending_update = FALSE;
372
373                priv->next_update_timeout_id = g_timeout_add (UPDATE_DELAY,
374                                                              update_timeout_callback,
375                                                              activity_client);
376
377                retval = corba_update_progress (activity_client, information, progress);
378        } else {
379                /* There is a pending timeout, so the last CORBA update
380                   happened less than UPDATE_DELAY msecs ago.  So just queue an
381                   update instead.  */
382
383                g_free (priv->new_information);
384                priv->new_information = g_strdup (information);
385                priv->new_progress = progress;
386
387                priv->have_pending_update = TRUE;
388
389                retval = TRUE;
390        }
391
392        return retval;
393}
394
395GNOME_Evolution_Activity_DialogAction
396evolution_activity_client_request_dialog (EvolutionActivityClient *activity_client,
397                                          GNOME_Evolution_Activity_DialogType dialog_type)
398{
399        EvolutionActivityClientPrivate *priv;
400        GNOME_Evolution_Activity_DialogAction retval;
401        CORBA_Environment ev;
402
403        g_return_val_if_fail (activity_client != NULL, GNOME_Evolution_Activity_DIALOG_ACTION_ERROR);
404        g_return_val_if_fail (EVOLUTION_IS_ACTIVITY_CLIENT (activity_client), GNOME_Evolution_Activity_DIALOG_ACTION_ERROR);
405
406        priv = activity_client->priv;
407
408        CORBA_exception_init (&ev);
409
410        retval = GNOME_Evolution_Activity_requestDialog (priv->activity_interface,
411                                                         priv->activity_id,
412                                                         dialog_type,
413                                                         &ev);
414        if (ev._major != CORBA_NO_EXCEPTION) {
415                g_warning ("EvolutionActivityClient: Error requesting a dialog -- %s", ev._repo_id);
416                retval = GNOME_Evolution_Activity_DIALOG_ACTION_ERROR;
417        }
418
419        CORBA_exception_free (&ev);
420
421        return retval;
422}
423
424
425E_MAKE_TYPE (evolution_activity_client, "EvolutionActivityClient", EvolutionActivityClient,
426             class_init, init, PARENT_TYPE)
Note: See TracBrowser for help on using the repository browser.