Fixes NB#138110, sometimes manual send&receive does not work
[modest] / src / widgets / modest-window-mgr.c
1 /* Copyright (c) 2006,2007 Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <string.h>
31 #include "modest-window-mgr.h"
32 #include "modest-runtime.h"
33 #include "modest-tny-folder.h"
34 #include "modest-ui-actions.h"
35 #include "modest-platform.h"
36 #include "modest-defs.h"
37 #include "widgets/modest-main-window.h"
38 #include "widgets/modest-msg-edit-window.h"
39 #include "widgets/modest-msg-view-window.h"
40 #include "modest-debug.h"
41 #include <tny-simple-list.h>
42
43
44 /* 'private'/'protected' functions */
45 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
46 static void modest_window_mgr_init       (ModestWindowMgr *obj);
47 static void modest_window_mgr_finalize   (GObject *obj);
48
49 static gboolean modest_window_mgr_register_window_default (ModestWindowMgr *self, 
50                                                            ModestWindow *window,
51                                                            ModestWindow *parent);
52 static void modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
53                                                          ModestWindow *window);
54 static void modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
55                                                            gboolean on);
56 static gboolean modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self);
57 static void modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
58                                                      GType window_type,
59                                                      gboolean show_toolbars,
60                                                      gboolean fullscreen);
61 static ModestWindow* modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show);
62 static GtkWindow *modest_window_mgr_get_modal_default (ModestWindowMgr *self);
63 static void modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
64                                                  GtkWindow *window,
65                                                  GtkWindow *parent);
66 static gboolean modest_window_mgr_close_all_windows_default (ModestWindowMgr *self);
67 static gboolean modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, 
68                                                                   TnyHeader *header,
69                                                                   ModestWindow **win);
70 static gboolean modest_window_mgr_find_registered_message_uid_default (ModestWindowMgr *self, 
71                                                                        const gchar *msg_uid,
72                                                                        ModestWindow **win);
73 static GList *modest_window_mgr_get_window_list_default (ModestWindowMgr *self);
74 static ModestWindow *modest_window_mgr_show_initial_window_default (ModestWindowMgr *self);
75 static ModestWindow *modest_window_mgr_get_current_top_default (ModestWindowMgr *self);
76 static gboolean modest_window_mgr_screen_is_on_default (ModestWindowMgr *self);
77 static void modest_window_mgr_create_caches_default (ModestWindowMgr *self);
78 static void modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
79                                                 ModestMailOperation *mail_op,
80                                                 ModestMailOperationQueueNotification type,
81                                                 ModestWindowMgr *self);
82 static void on_mail_operation_started (ModestMailOperation *mail_op,
83                                        gpointer user_data);
84 static void on_mail_operation_finished (ModestMailOperation *mail_op,
85                                         gpointer user_data);
86
87 /* list my signals  */
88 enum {
89         WINDOW_LIST_EMPTY_SIGNAL,
90         PROGRESS_LIST_CHANGED_SIGNAL,
91         NUM_SIGNALS
92 };
93
94 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
95 struct _ModestWindowMgrPrivate {
96         guint         banner_counter;
97
98         ModestWindow *main_window;
99
100         GSList       *windows_that_prevent_hibernation;
101         GSList       *preregistered_uids;
102         
103         guint        closing_time;
104
105         GtkWidget    *cached_view;
106         GtkWidget    *cached_editor;
107         guint        idle_load_view_id;
108         guint        idle_load_editor_id;
109
110         guint        queue_change_handler;
111         TnyList      *progress_operations;
112         GSList       *sighandlers;
113 };
114
115 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
116                                                MODEST_TYPE_WINDOW_MGR, \
117                                                ModestWindowMgrPrivate))
118 /* globals */
119 static GObjectClass *parent_class = NULL;
120
121 /* uncomment the following if you have defined any signals */
122 static guint signals[NUM_SIGNALS] = {0};
123
124 GType
125 modest_window_mgr_get_type (void)
126 {
127         static GType my_type = 0;
128         if (!my_type) {
129                 static const GTypeInfo my_info = {
130                         sizeof(ModestWindowMgrClass),
131                         NULL,           /* base init */
132                         NULL,           /* base finalize */
133                         (GClassInitFunc) modest_window_mgr_class_init,
134                         NULL,           /* class finalize */
135                         NULL,           /* class data */
136                         sizeof(ModestWindowMgr),
137                         1,              /* n_preallocs */
138                         (GInstanceInitFunc) modest_window_mgr_init,
139                         NULL
140                 };
141                 my_type = g_type_register_static (G_TYPE_OBJECT,
142                                                   "ModestWindowMgr",
143                                                   &my_info, 0);
144         }
145         return my_type;
146 }
147
148 static void
149 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
150 {
151         GObjectClass *gobject_class;
152         ModestWindowMgrClass *mgr_class;
153
154         gobject_class = (GObjectClass*) klass;
155         mgr_class = (ModestWindowMgrClass *) klass;
156
157         parent_class            = g_type_class_peek_parent (klass);
158         gobject_class->finalize = modest_window_mgr_finalize;
159         mgr_class->register_window = modest_window_mgr_register_window_default;
160         mgr_class->unregister_window = modest_window_mgr_unregister_window_default;
161         mgr_class->set_fullscreen_mode = modest_window_mgr_set_fullscreen_mode_default;
162         mgr_class->get_fullscreen_mode = modest_window_mgr_get_fullscreen_mode_default;
163         mgr_class->show_toolbars = modest_window_mgr_show_toolbars_default;
164         mgr_class->get_main_window = modest_window_mgr_get_main_window_default;
165         mgr_class->get_modal = modest_window_mgr_get_modal_default;
166         mgr_class->set_modal = modest_window_mgr_set_modal_default;
167         mgr_class->close_all_windows = modest_window_mgr_close_all_windows_default;
168         mgr_class->find_registered_header = modest_window_mgr_find_registered_header_default;
169         mgr_class->find_registered_message_uid = modest_window_mgr_find_registered_message_uid_default;
170         mgr_class->get_window_list = modest_window_mgr_get_window_list_default;
171         mgr_class->show_initial_window = modest_window_mgr_show_initial_window_default;
172         mgr_class->get_current_top = modest_window_mgr_get_current_top_default;
173         mgr_class->screen_is_on = modest_window_mgr_screen_is_on_default;
174         mgr_class->create_caches = modest_window_mgr_create_caches_default;
175
176         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
177
178
179         /**
180          * ModestWindowMgr::window-list-empty
181          * @self: the #ModestWindowMgr that emits the signal
182          * @user_data: user data set when the signal handler was connected
183          *
184          * Issued whenever the window list becomes empty
185          */
186         signals[WINDOW_LIST_EMPTY_SIGNAL] =
187                 g_signal_new ("window-list-empty",
188                               G_TYPE_FROM_CLASS (gobject_class),
189                               G_SIGNAL_RUN_FIRST,
190                               G_STRUCT_OFFSET (ModestWindowMgrClass, window_list_empty),
191                               NULL, NULL,
192                               g_cclosure_marshal_VOID__VOID,
193                               G_TYPE_NONE, 0);
194
195         /**
196          * ModestWindowMgr::progress-list-changed
197          * @self: the #ModestWindowMgr that emits the signal
198          * @user_data: user data set when the signal handler was connected
199          *
200          * Issued whenever the progress mail operations list becomes changed
201          */
202         signals[PROGRESS_LIST_CHANGED_SIGNAL] =
203                 g_signal_new ("progress-list-changed",
204                               G_TYPE_FROM_CLASS (gobject_class),
205                               G_SIGNAL_RUN_FIRST,
206                               G_STRUCT_OFFSET (ModestWindowMgrClass, progress_list_changed),
207                               NULL, NULL,
208                               g_cclosure_marshal_VOID__VOID,
209                               G_TYPE_NONE, 0);
210 }
211
212 static gboolean
213 idle_load_view (ModestWindowMgr *mgr)
214 {
215         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
216         
217         priv->cached_view = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
218         priv->idle_load_view_id = 0;
219         return FALSE;
220 }
221
222 static gboolean
223 idle_load_editor (ModestWindowMgr *mgr)
224 {
225         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
226         
227         priv->cached_editor = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
228         priv->idle_load_editor_id = 0;
229         return FALSE;
230 }
231
232 static void
233 load_new_view (ModestWindowMgr *self)
234 {
235         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
236         if ((priv->cached_view == NULL) && (priv->idle_load_view_id == 0))
237                 priv->idle_load_view_id = g_timeout_add (2500, (GSourceFunc) idle_load_view, self);
238 }
239
240 static void
241 load_new_editor (ModestWindowMgr *self)
242 {
243         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
244         if ((priv->cached_editor == NULL) && (priv->idle_load_editor_id == 0))
245                 priv->idle_load_editor_id = g_timeout_add (5000, (GSourceFunc) idle_load_editor, self);
246 }
247
248 static void
249 modest_window_mgr_init (ModestWindowMgr *obj)
250 {
251         ModestWindowMgrPrivate *priv;
252
253         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
254         priv->banner_counter = 0;
255         priv->main_window = NULL;
256
257         priv->preregistered_uids = NULL;
258
259         priv->closing_time = 0;
260
261         priv->cached_view = NULL;
262         priv->cached_editor = NULL;
263
264         priv->windows_that_prevent_hibernation = NULL;
265
266         priv->queue_change_handler = 0;
267         priv->progress_operations = TNY_LIST (tny_simple_list_new ());
268 }
269
270 static void
271 modest_window_mgr_finalize (GObject *obj)
272 {
273         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
274
275         if (priv->idle_load_view_id > 0) {
276                 g_source_remove (priv->idle_load_view_id);
277                 priv->idle_load_view_id = 0;
278         }
279         
280         if (priv->idle_load_editor_id > 0) {
281                 g_source_remove (priv->idle_load_editor_id);
282                 priv->idle_load_editor_id = 0;
283         }
284         
285         if (priv->cached_view) {
286                 gtk_widget_destroy (priv->cached_view);
287                 priv->cached_view = NULL;
288         }
289         if (priv->cached_editor) {
290                 gtk_widget_destroy (priv->cached_editor);
291                 priv->cached_editor = NULL;
292         }
293
294         if (priv->windows_that_prevent_hibernation) {
295                 g_slist_free (priv->windows_that_prevent_hibernation);
296                 priv->cached_editor = NULL;
297         }
298
299         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
300         priv->sighandlers = NULL;
301
302         if (priv->queue_change_handler > 0) {
303                 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
304                                              priv->queue_change_handler);
305                 priv->queue_change_handler = 0;
306         }
307
308         if (priv->progress_operations) {
309                 g_object_unref (priv->progress_operations);
310                 priv->progress_operations = NULL;
311         }
312
313         g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
314         g_slist_free (priv->preregistered_uids);
315
316         G_OBJECT_CLASS(parent_class)->finalize (obj);
317 }
318
319 ModestWindowMgr*
320 modest_window_mgr_new (void)
321 {
322         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
323 }
324
325
326
327
328 /* do we have uid? */
329 static gboolean
330 has_uid (GSList *list, const gchar *uid)
331 {
332         GSList *cursor = list;
333
334         if (!uid)
335                 return FALSE;
336         
337         while (cursor) {
338                 if (cursor->data && strcmp (cursor->data, uid) == 0)
339                         return TRUE;
340                 cursor = g_slist_next (cursor);
341         }
342         return FALSE;
343 }
344
345
346 /* remove all from the list have have uid = uid */
347 static GSList*
348 remove_uid (GSList *list, const gchar *uid)
349 {
350         GSList *cursor = list, *start = list;
351         
352         if (!uid)
353                 return list;
354         
355         while (cursor) {
356                 GSList *next = g_slist_next (cursor);
357                 if (cursor->data && strcmp (cursor->data, uid) == 0) {
358                         g_free (cursor->data);
359                         start = g_slist_delete_link (start, cursor);
360                 }
361                 cursor = next;
362         }
363         return start;
364 }
365
366
367 static GSList *
368 append_uid (GSList *list, const gchar *uid)
369 {
370         return g_slist_append (list, g_strdup(uid));
371 }
372
373
374
375 void 
376 modest_window_mgr_register_header (ModestWindowMgr *self,  TnyHeader *header, const gchar *alt_uid)
377 {
378         ModestWindowMgrPrivate *priv;
379         gchar* uid;
380         
381         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
382         g_return_if_fail (TNY_IS_HEADER(header));
383                 
384         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
385         if (alt_uid != NULL) {
386                 uid = g_strdup (alt_uid);
387         } else {
388                 uid = modest_tny_folder_get_header_unique_id (header);
389         }
390
391         if (!has_uid (priv->preregistered_uids, uid)) {
392                 MODEST_DEBUG_BLOCK(g_debug ("registering new uid %s", uid););
393                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
394         } else
395                 MODEST_DEBUG_BLOCK(g_debug ("already had uid %s", uid););
396         
397         g_free (uid);
398 }
399
400 void 
401 modest_window_mgr_unregister_header (ModestWindowMgr *self,  TnyHeader *header)
402 {
403         ModestWindowMgrPrivate *priv;
404         gchar* uid;
405         
406         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
407         g_return_if_fail (TNY_IS_HEADER(header));
408                 
409         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
410         uid = modest_tny_folder_get_header_unique_id (header);
411
412         if (!has_uid (priv->preregistered_uids, uid)) {
413                 MODEST_DEBUG_BLOCK(g_debug ("trying to unregister non-existing uid %s", uid););
414                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
415         } else
416                 MODEST_DEBUG_BLOCK(g_debug ("unregistering uid %s", uid););
417         
418         if (has_uid (priv->preregistered_uids, uid)) {
419                 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
420                 if (has_uid (priv->preregistered_uids, uid))
421                         g_debug ("BUG: uid %s NOT removed", uid);
422                 else
423                         MODEST_DEBUG_BLOCK(g_debug ("uid %s removed", uid););
424         }
425                 
426         g_free (uid);
427 }
428
429
430 #define MODEST_WINDOW_HELP_ID_PARAM "help-id"
431
432 void
433 modest_window_mgr_register_help_id (ModestWindowMgr *self, GtkWindow *win, const gchar* help_id)
434 {
435         /* we don't need 'self', but for API consistency... */
436         g_return_if_fail (self && MODEST_IS_WINDOW_MGR(self));
437
438         g_return_if_fail (win && GTK_IS_WINDOW(win));
439         g_return_if_fail (help_id);
440         
441         g_object_set_data_full (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM,
442                                 g_strdup(help_id), g_free);
443 }
444
445
446 const gchar*
447 modest_window_mgr_get_help_id (ModestWindowMgr *self, GtkWindow *win)
448 {
449         /* we don't need 'self', but for API consistency... */
450         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR (self), NULL);
451         g_return_val_if_fail (win, NULL);
452
453         return g_object_get_data (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM);
454 }
455
456 gboolean
457 modest_window_mgr_close_all_windows (ModestWindowMgr *self)
458 {
459         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_windows (self);
460 }
461
462 static gboolean
463 modest_window_mgr_close_all_windows_default (ModestWindowMgr *self)
464 {
465         return TRUE;
466 }
467
468
469 gboolean
470 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
471                                                   ModestWindow **win)
472 {
473         return MODEST_WINDOW_MGR_GET_CLASS (self)->find_registered_header (self, header, win);
474 }
475
476 static gboolean
477 modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, TnyHeader *header,
478                                                   ModestWindow **win)
479 {
480         gchar* uid = NULL;
481
482         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
483         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
484
485         uid = modest_tny_folder_get_header_unique_id (header);
486
487         if (uid)
488                 return modest_window_mgr_find_registered_message_uid (self, uid, win);
489         else
490                 return FALSE;
491 }
492
493 gboolean
494 modest_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
495                                                ModestWindow **win)
496 {
497         return MODEST_WINDOW_MGR_GET_CLASS (self)->find_registered_message_uid (self, msg_uid, win);
498 }
499
500 static gboolean
501 modest_window_mgr_find_registered_message_uid_default (ModestWindowMgr *self, const gchar *msg_uid,
502                                                        ModestWindow **win)
503 {
504         ModestWindowMgrPrivate *priv = NULL;
505         gchar* uid = NULL;
506         gboolean has_header = FALSE;
507
508         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
509         g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
510
511         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
512
513         if (win)
514                 *win = NULL;
515
516         has_header = has_uid (priv->preregistered_uids, msg_uid);
517         g_free (uid);
518
519         return has_header;
520 }
521
522 GList *
523 modest_window_mgr_get_window_list (ModestWindowMgr *self)
524 {
525         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_window_list (self);
526 }
527
528 static GList *
529 modest_window_mgr_get_window_list_default (ModestWindowMgr *self)
530 {
531         return NULL;
532 }
533
534 gboolean
535 modest_window_mgr_register_window (ModestWindowMgr *self, 
536                                    ModestWindow *window,
537                                    ModestWindow *parent)
538 {
539         /* If this is the first registered window then reset the
540            status of the TnyDevice as it might be forced to be offline
541            when modest is running in the background (see
542            modest_tny_account_store_new()) */
543         if (modest_window_mgr_get_num_windows (self) == 0) {
544                 if (tny_device_is_forced (modest_runtime_get_device ()))
545                         tny_device_reset (modest_runtime_get_device ());
546         }
547
548         return MODEST_WINDOW_MGR_GET_CLASS (self)->register_window (self, window, parent);
549 }
550
551 static gboolean
552 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
553                                            ModestWindow *window,
554                                            ModestWindow *parent)
555 {
556         ModestWindowMgrPrivate *priv;
557
558         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
559         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
560
561         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
562
563         /* We set up the queue change handler */
564         if (priv->queue_change_handler == 0) {
565                 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
566                                                                "queue-changed",
567                                                                G_CALLBACK (modest_window_mgr_on_queue_changed),
568                                                                self);
569         }
570
571         /* Check that it's not a second main window */
572         if (MODEST_IS_MAIN_WINDOW (window)) {
573                 if (priv->main_window) {
574                         g_warning ("%s: trying to register a second main window",
575                                    __FUNCTION__);
576                         return FALSE;
577                 } else {
578                         priv->main_window = window;
579                 }
580         }
581
582         /* remove from the list of pre-registered uids */
583         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
584                 const gchar *uid = modest_msg_view_window_get_message_uid
585                         (MODEST_MSG_VIEW_WINDOW (window));
586
587                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
588                 
589                 if (has_uid (priv->preregistered_uids, uid)) {
590                         priv->preregistered_uids = 
591                                 remove_uid (priv->preregistered_uids,
592                                             modest_msg_view_window_get_message_uid
593                                             (MODEST_MSG_VIEW_WINDOW (window)));
594                 }
595         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
596                 const gchar *uid = modest_msg_edit_window_get_message_uid
597                         (MODEST_MSG_EDIT_WINDOW (window));
598                 
599                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
600
601                 priv->preregistered_uids = 
602                         remove_uid (priv->preregistered_uids,
603                                     modest_msg_edit_window_get_message_uid
604                                     (MODEST_MSG_EDIT_WINDOW (window)));
605         }
606
607         return TRUE;
608 }
609
610 void 
611 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
612                                      ModestWindow *window)
613 {
614         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
615 }
616
617 static void 
618 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
619                                              ModestWindow *window)
620 {
621         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
622         g_return_if_fail (MODEST_IS_WINDOW (window));
623
624         /* Save state */
625         modest_window_save_state (window);
626
627         /* Disconnect all the window signals */
628         modest_window_disconnect_signals (window);
629         
630         /* Destroy the window */
631         gtk_widget_destroy (GTK_WIDGET (window));
632 }
633
634
635
636 void
637 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
638                                        gboolean on)
639 {
640         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
641 }
642
643 static void
644 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
645                                                gboolean on)
646 {
647         return;
648 }
649
650 gboolean
651 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
652 {
653         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
654 }
655
656 static gboolean
657 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
658 {
659         return FALSE;
660 }
661
662 void 
663 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
664                                  GType window_type,
665                                  gboolean show_toolbars,
666                                  gboolean fullscreen)
667 {
668         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
669 }
670
671 static void 
672 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
673                                          GType window_type,
674                                          gboolean show_toolbars,
675                                          gboolean fullscreen)
676 {
677         return;
678 }
679
680 void
681 modest_window_mgr_set_main_window (ModestWindowMgr *self, ModestWindow *win)
682 {
683         ModestWindowMgrPrivate *priv;
684         
685         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
686
687         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
688         priv->main_window = win;
689 }
690
691 ModestWindow*  
692 modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
693 {
694         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_main_window (self, show);
695 }
696
697 static ModestWindow*  
698 modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show)
699 {
700         ModestWindowMgrPrivate *priv;
701         
702         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
703
704         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
705         if (priv->main_window)
706                 return priv->main_window;
707
708         if (show) 
709                 return modest_main_window_new ();
710         else return NULL;
711 }
712
713
714 gboolean
715 modest_window_mgr_main_window_exists  (ModestWindowMgr *self)
716 {
717         ModestWindowMgrPrivate *priv;
718         
719         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
720         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
721
722         return priv->main_window != NULL;
723 }
724
725
726 GtkWindow *
727 modest_window_mgr_get_modal (ModestWindowMgr *self)
728 {
729         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
730 }
731
732 static GtkWindow *
733 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
734 {
735         return NULL;
736 }
737
738
739 void
740 modest_window_mgr_set_modal (ModestWindowMgr *self, 
741                              GtkWindow *window,
742                              GtkWindow *parent)
743 {
744         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
745 }
746
747 static void
748 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
749                                      GtkWindow *window,
750                                      GtkWindow *parent)
751 {
752         return;
753 }
754
755
756 static void
757 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
758 {
759         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
760         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
761         
762         /* Forget this window,
763          * so hibernation will be allowed again if no windows are remembered: */
764         priv->windows_that_prevent_hibernation =
765                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
766 }
767
768 static void
769 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
770 {
771         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
772         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
773         
774         GtkWindow *window = GTK_WINDOW (widget);
775         
776         priv->windows_that_prevent_hibernation = 
777                         g_slist_append (priv->windows_that_prevent_hibernation, window);
778         
779         /* Allow hibernation again when the window has been hidden: */
780         g_signal_connect (window, "hide", 
781                 G_CALLBACK (on_nonhibernating_window_hide), self);
782 }
783
784 void
785 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
786                                                                   GtkWindow *window)
787 {
788         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
789         
790         if (GTK_WIDGET_VISIBLE(window)) {
791                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
792         } else {
793                 /* Wait for it to be shown: */
794                 g_signal_connect (window, "show", 
795                         G_CALLBACK (on_nonhibernating_window_show), self);      
796         }
797 }
798
799 gboolean
800 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
801 {
802         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
803         
804         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
805         
806         /* Prevent hibernation if any open windows are currently 
807          * preventing hibernation: */
808         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
809 }
810
811
812 void
813 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
814 {
815         GList *window_list;
816         GList *node;
817         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
818         
819         /* Iterate over all windows */
820         window_list = modest_window_mgr_get_window_list (self);
821         node = window_list;
822         while (node) {
823                 ModestWindow *window = MODEST_WINDOW (node->data);
824                 if (window) {
825                         /* This calls the vfunc, 
826                          * so each window can do its own thing: */
827                         modest_window_save_state (window);
828                 }
829
830                 node = g_list_next (node);
831         }
832         g_list_free (window_list);
833 }
834
835 guint
836 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
837 {
838         ModestWindowMgrPrivate *priv;
839         gint num_windows = 0;
840         GList *window_list;
841
842         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
843
844         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
845
846         window_list = modest_window_mgr_get_window_list (self);
847
848         if (window_list) {
849                 num_windows = g_list_length (window_list);
850                 g_list_free (window_list);
851         }
852
853         /* Do not take into account the main window if it was hidden */
854         if (num_windows && priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window))
855                 num_windows--;
856
857         return num_windows + priv->banner_counter;
858 }
859
860 GtkWidget *   
861 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
862 {
863         GtkWidget *result;
864         ModestWindowMgrPrivate *priv;
865
866         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
867
868         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
869                 
870         if (priv->cached_editor) {
871                 result = priv->cached_editor;
872                 priv->cached_editor = NULL;
873                 load_new_editor (self);
874         } else {
875                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
876         }
877
878         return result;
879 }
880
881 GtkWidget *   
882 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
883 {
884         GtkWidget *result;
885         ModestWindowMgrPrivate *priv;
886
887         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
888         
889         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
890
891         if (priv->cached_view) {
892                 result = priv->cached_view;
893                 priv->cached_view = NULL;
894                 load_new_view (self);
895         } else {
896                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
897         }
898
899         return result;
900 }
901
902 void
903 modest_window_mgr_register_banner (ModestWindowMgr *self)
904 {
905         ModestWindowMgrPrivate *priv;
906
907         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
908         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
909
910         priv->banner_counter++;
911 }
912
913 void
914 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
915 {
916         ModestWindowMgrPrivate *priv;
917
918         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
919         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
920
921         priv->banner_counter--;
922         if (modest_window_mgr_get_num_windows (self) == 0)
923                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
924 }
925
926 ModestWindow *
927 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
928 {
929         ModestWindow *window = NULL;
930
931         /* Call the children */
932         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
933
934         if (window) {
935                 ModestAccountMgr *mgr;
936
937                 /* Show the initial window */
938                 gtk_widget_show (GTK_WIDGET (window));
939
940                 /* If there are no accounts then show the account wizard */
941                 mgr = modest_runtime_get_account_mgr();
942                 if (!modest_account_mgr_has_accounts (mgr, TRUE)) {
943                         if (!modest_ui_actions_run_account_setup_wizard (window)) {
944                                 g_debug ("%s: couldn't show account setup wizard", __FUNCTION__);
945                         }
946                 }
947         }
948
949         return window;
950 }
951
952 static ModestWindow *
953 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
954 {
955         /* By default it returns the main window creating it if
956            needed */
957         return modest_window_mgr_get_main_window (self, TRUE);
958 }
959
960
961 ModestWindow *
962 modest_window_mgr_get_current_top (ModestWindowMgr *self) 
963 {
964         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_current_top (self);
965 }
966
967
968 static ModestWindow *
969 modest_window_mgr_get_current_top_default (ModestWindowMgr *self)
970 {
971         g_return_val_if_reached (NULL);
972 }
973
974 gboolean
975 modest_window_mgr_screen_is_on (ModestWindowMgr *self)
976 {
977         return MODEST_WINDOW_MGR_GET_CLASS (self)->screen_is_on (self);
978 }
979
980 static gboolean
981 modest_window_mgr_screen_is_on_default (ModestWindowMgr *self)
982 {
983         /* Default implementation is assuming screen is always on */
984
985         return TRUE;
986 }
987
988 void
989 modest_window_mgr_create_caches (ModestWindowMgr *mgr)
990 {
991         MODEST_WINDOW_MGR_GET_CLASS (mgr)->create_caches (mgr);
992 }
993
994 static void
995 modest_window_mgr_create_caches_default (ModestWindowMgr *self)
996 {
997         load_new_editor (self);
998         load_new_view (self);
999 }
1000
1001 static gboolean
1002 tny_list_find (TnyList *list, GObject *item)
1003 {
1004         TnyIterator *iterator;
1005         gboolean found = FALSE;
1006
1007         for (iterator = tny_list_create_iterator (list);
1008              !tny_iterator_is_done (iterator) && !found;
1009              tny_iterator_next (iterator)) {
1010                 GObject *current = tny_iterator_get_current (iterator);
1011                 if (current == item)
1012                         found = TRUE;
1013                 g_object_unref (current);
1014         }
1015         g_object_unref (iterator);
1016         
1017         return found;
1018 }
1019
1020 static void
1021 modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
1022                                     ModestMailOperation *mail_op,
1023                                     ModestMailOperationQueueNotification type,
1024                                     ModestWindowMgr *self)
1025 {       
1026         ModestWindowMgrPrivate *priv;
1027
1028         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1029
1030         /* We register to track progress */
1031         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
1032                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1033                                                                G_OBJECT (mail_op),
1034                                                                "operation-started",
1035                                                                G_CALLBACK (on_mail_operation_started),
1036                                                                self);
1037                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1038                                                                G_OBJECT (mail_op),
1039                                                                "operation-finished",
1040                                                                G_CALLBACK (on_mail_operation_finished),
1041                                                                self);
1042         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
1043                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1044                                                                   G_OBJECT (mail_op),
1045                                                                   "operation-started");
1046                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1047                                                                   G_OBJECT (mail_op),
1048                                                                   "operation-finished");
1049                 if (tny_list_find  (priv->progress_operations, G_OBJECT (mail_op))) {
1050                         tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1051                         g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1052                 }
1053         }
1054 }
1055
1056 static void 
1057 on_mail_operation_started (ModestMailOperation *mail_op,
1058                            gpointer user_data)
1059 {
1060         ModestWindowMgr *self;
1061         ModestWindowMgrPrivate *priv;
1062         ModestMailOperationTypeOperation op_type;
1063
1064         self = MODEST_WINDOW_MGR (user_data);
1065         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1066
1067         /* First we check if the operation is a send receive operation,
1068          * If now, we don't handle this */
1069         op_type = modest_mail_operation_get_type_operation (mail_op);
1070         if (op_type != MODEST_MAIL_OPERATION_TYPE_SEND &&
1071             op_type != MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
1072                 return;
1073         }
1074
1075         if (!tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1076                 tny_list_prepend (priv->progress_operations, G_OBJECT (mail_op));
1077                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1078         }
1079 }
1080
1081 static void 
1082 on_mail_operation_finished (ModestMailOperation *mail_op,
1083                             gpointer user_data)
1084 {
1085         ModestWindowMgr *self;
1086         ModestWindowMgrPrivate *priv;
1087
1088         self = MODEST_WINDOW_MGR (user_data);
1089         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1090
1091         if (tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1092                 tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1093                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1094         }
1095 }
1096
1097 TnyList *
1098 modest_window_mgr_get_progress_operations (ModestWindowMgr *self)
1099 {
1100         ModestWindowMgrPrivate *priv;
1101
1102         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1103
1104         return tny_list_copy (priv->progress_operations);
1105 }
1106
1107 gboolean 
1108 modest_window_mgr_has_progress_operation (ModestWindowMgr *self)
1109 {
1110         ModestWindowMgrPrivate *priv;
1111
1112         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1113
1114         return tny_list_get_length (priv->progress_operations) > 0;
1115 }
1116
1117 gboolean 
1118 modest_window_mgr_has_progress_operation_on_account (ModestWindowMgr *self,
1119                                                      const gchar *account_name)
1120 {
1121         ModestWindowMgrPrivate *priv;
1122         gint account_ops = 0;
1123         TnyIterator *iterator;
1124
1125         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1126
1127         if (account_name == NULL)
1128                 return 0;
1129
1130         for (iterator = tny_list_create_iterator (priv->progress_operations);
1131              !tny_iterator_is_done (iterator);
1132              tny_iterator_next (iterator)) {
1133                 ModestMailOperation *mail_op; 
1134                 TnyAccount *account;
1135
1136                 mail_op= MODEST_MAIL_OPERATION (tny_iterator_get_current (iterator));
1137                 account = modest_mail_operation_get_account (mail_op);
1138
1139                 if (account != NULL) {
1140                         const gchar *current_name;
1141
1142                         current_name = tny_account_get_id (account);
1143                         if (current_name && strcmp (current_name, account_name) == 0)
1144                                 account_ops ++;
1145                         g_object_unref (account);
1146                 }
1147
1148                 g_object_unref (mail_op);
1149         }
1150         g_object_unref (iterator);
1151
1152         return account_ops;
1153 }
1154