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