Wiped ModestMainWindow out
[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         return retval;
556 }
557
558 static gboolean
559 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
560                                            ModestWindow *window,
561                                            ModestWindow *parent)
562 {
563         ModestWindowMgrPrivate *priv;
564
565         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
566         g_return_val_if_fail (MODEST_IS_WINDOW (window), FALSE);
567
568         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
569
570         /* We set up the queue change handler */
571         if (priv->queue_change_handler == 0) {
572                 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
573                                                                "queue-changed",
574                                                                G_CALLBACK (modest_window_mgr_on_queue_changed),
575                                                                self);
576         }
577
578
579         /* remove from the list of pre-registered uids */
580         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
581                 const gchar *uid = modest_msg_view_window_get_message_uid
582                         (MODEST_MSG_VIEW_WINDOW (window));
583
584                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
585
586                 if (has_uid (priv->preregistered_uids, uid)) {
587                         priv->preregistered_uids = 
588                                 remove_uid (priv->preregistered_uids,
589                                             modest_msg_view_window_get_message_uid
590                                             (MODEST_MSG_VIEW_WINDOW (window)));
591                 }
592         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
593                 const gchar *uid = modest_msg_edit_window_get_message_uid
594                         (MODEST_MSG_EDIT_WINDOW (window));
595
596                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
597
598                 priv->preregistered_uids = 
599                         remove_uid (priv->preregistered_uids,
600                                     modest_msg_edit_window_get_message_uid
601                                     (MODEST_MSG_EDIT_WINDOW (window)));
602         }
603
604         return TRUE;
605 }
606
607 void 
608 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
609                                      ModestWindow *window)
610 {
611         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
612 }
613
614 static void 
615 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
616                                              ModestWindow *window)
617 {
618         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
619         g_return_if_fail (MODEST_IS_WINDOW (window));
620
621         /* Save state */
622         modest_window_save_state (window);
623
624         /* Disconnect all the window signals */
625         modest_window_disconnect_signals (window);
626         
627         /* Destroy the window */
628         gtk_widget_destroy (GTK_WIDGET (window));
629 }
630
631
632
633 void
634 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
635                                        gboolean on)
636 {
637         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
638 }
639
640 static void
641 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
642                                                gboolean on)
643 {
644         return;
645 }
646
647 gboolean
648 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
649 {
650         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
651 }
652
653 static gboolean
654 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
655 {
656         return FALSE;
657 }
658
659 void
660 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
661                                  GType window_type,
662                                  gboolean show_toolbars,
663                                  gboolean fullscreen)
664 {
665         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
666 }
667
668 static void
669 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
670                                          GType window_type,
671                                          gboolean show_toolbars,
672                                          gboolean fullscreen)
673 {
674         return;
675 }
676
677 GtkWindow *
678 modest_window_mgr_get_modal (ModestWindowMgr *self)
679 {
680         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
681 }
682
683 static GtkWindow *
684 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
685 {
686         return NULL;
687 }
688
689
690 void
691 modest_window_mgr_set_modal (ModestWindowMgr *self, 
692                              GtkWindow *window,
693                              GtkWindow *parent)
694 {
695         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
696 }
697
698 static void
699 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
700                                      GtkWindow *window,
701                                      GtkWindow *parent)
702 {
703         return;
704 }
705
706
707 static void
708 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
709 {
710         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
711         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
712         
713         /* Forget this window,
714          * so hibernation will be allowed again if no windows are remembered: */
715         priv->windows_that_prevent_hibernation =
716                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
717 }
718
719 static void
720 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
721 {
722         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
723         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
724         
725         GtkWindow *window = GTK_WINDOW (widget);
726         
727         priv->windows_that_prevent_hibernation = 
728                         g_slist_append (priv->windows_that_prevent_hibernation, window);
729         
730         /* Allow hibernation again when the window has been hidden: */
731         g_signal_connect (window, "hide", 
732                 G_CALLBACK (on_nonhibernating_window_hide), self);
733 }
734
735 void
736 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
737                                                                   GtkWindow *window)
738 {
739         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
740         
741         if (GTK_WIDGET_VISIBLE(window)) {
742                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
743         } else {
744                 /* Wait for it to be shown: */
745                 g_signal_connect (window, "show", 
746                         G_CALLBACK (on_nonhibernating_window_show), self);      
747         }
748 }
749
750 gboolean
751 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
752 {
753         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
754         
755         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
756         
757         /* Prevent hibernation if any open windows are currently 
758          * preventing hibernation: */
759         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
760 }
761
762
763 void
764 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
765 {
766         GList *window_list;
767         GList *node;
768         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
769         
770         /* Iterate over all windows */
771         window_list = modest_window_mgr_get_window_list (self);
772         node = window_list;
773         while (node) {
774                 ModestWindow *window = MODEST_WINDOW (node->data);
775                 if (window) {
776                         /* This calls the vfunc, 
777                          * so each window can do its own thing: */
778                         modest_window_save_state (window);
779                 }
780
781                 node = g_list_next (node);
782         }
783         g_list_free (window_list);
784 }
785
786 guint
787 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
788 {
789         ModestWindowMgrPrivate *priv;
790         gint num_windows = 0;
791         GList *window_list;
792
793         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
794
795         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
796
797         window_list = modest_window_mgr_get_window_list (self);
798
799         if (window_list) {
800                 num_windows = g_list_length (window_list);
801                 g_list_free (window_list);
802         }
803
804         return num_windows + priv->banner_counter;
805 }
806
807 GtkWidget *   
808 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
809 {
810         GtkWidget *result;
811         ModestWindowMgrPrivate *priv;
812
813         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
814
815         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
816                 
817         if (priv->cached_editor) {
818                 result = priv->cached_editor;
819                 priv->cached_editor = NULL;
820                 load_new_editor (self);
821         } else {
822                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
823         }
824
825         return result;
826 }
827
828 GtkWidget *   
829 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
830 {
831         GtkWidget *result;
832         ModestWindowMgrPrivate *priv;
833
834         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
835         
836         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
837
838         if (priv->cached_view) {
839                 result = priv->cached_view;
840                 priv->cached_view = NULL;
841                 load_new_view (self);
842         } else {
843                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
844         }
845
846         return result;
847 }
848
849 void
850 modest_window_mgr_register_banner (ModestWindowMgr *self)
851 {
852         ModestWindowMgrPrivate *priv;
853
854         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
855         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
856
857         priv->banner_counter++;
858 }
859
860 void
861 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
862 {
863         ModestWindowMgrPrivate *priv;
864
865         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
866         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
867
868         priv->banner_counter--;
869         if (modest_window_mgr_get_num_windows (self) == 0)
870                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
871 }
872
873 ModestWindow *
874 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
875 {
876         ModestWindow *window = NULL;
877
878         /* Call the children */
879         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
880
881         if (window) {
882                 ModestAccountMgr *mgr;
883
884                 /* Show the initial window */
885                 gtk_widget_show (GTK_WIDGET (window));
886
887                 /* If there are no accounts then show the account wizard */
888                 mgr = modest_runtime_get_account_mgr();
889                 if (!modest_account_mgr_has_accounts (mgr, TRUE)) {
890                         if (!modest_ui_actions_run_account_setup_wizard (window)) {
891                                 g_debug ("%s: couldn't show account setup wizard", __FUNCTION__);
892                         }
893                 }
894         }
895
896         return window;
897 }
898
899 static ModestWindow *
900 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
901 {
902         g_warning ("You must implement %s", __FUNCTION__);
903
904         return NULL;
905 }
906
907
908 ModestWindow *
909 modest_window_mgr_get_current_top (ModestWindowMgr *self) 
910 {
911         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_current_top (self);
912 }
913
914
915 static ModestWindow *
916 modest_window_mgr_get_current_top_default (ModestWindowMgr *self)
917 {
918         g_return_val_if_reached (NULL);
919 }
920
921 gboolean
922 modest_window_mgr_screen_is_on (ModestWindowMgr *self)
923 {
924         return MODEST_WINDOW_MGR_GET_CLASS (self)->screen_is_on (self);
925 }
926
927 static gboolean
928 modest_window_mgr_screen_is_on_default (ModestWindowMgr *self)
929 {
930         /* Default implementation is assuming screen is always on */
931
932         return TRUE;
933 }
934
935 void
936 modest_window_mgr_create_caches (ModestWindowMgr *mgr)
937 {
938         MODEST_WINDOW_MGR_GET_CLASS (mgr)->create_caches (mgr);
939 }
940
941 static void
942 modest_window_mgr_create_caches_default (ModestWindowMgr *self)
943 {
944         load_new_editor (self);
945         load_new_view (self);
946 }
947
948 static gboolean
949 tny_list_find (TnyList *list, GObject *item)
950 {
951         TnyIterator *iterator;
952         gboolean found = FALSE;
953
954         for (iterator = tny_list_create_iterator (list);
955              !tny_iterator_is_done (iterator) && !found;
956              tny_iterator_next (iterator)) {
957                 GObject *current = tny_iterator_get_current (iterator);
958                 if (current == item)
959                         found = TRUE;
960                 g_object_unref (current);
961         }
962         g_object_unref (iterator);
963         
964         return found;
965 }
966
967 static void
968 modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
969                                     ModestMailOperation *mail_op,
970                                     ModestMailOperationQueueNotification type,
971                                     ModestWindowMgr *self)
972 {       
973         ModestWindowMgrPrivate *priv;
974
975         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
976
977         /* We register to track progress */
978         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
979                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
980                                                                G_OBJECT (mail_op),
981                                                                "operation-started",
982                                                                G_CALLBACK (on_mail_operation_started),
983                                                                self);
984                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
985                                                                G_OBJECT (mail_op),
986                                                                "operation-finished",
987                                                                G_CALLBACK (on_mail_operation_finished),
988                                                                self);
989         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
990                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
991                                                                   G_OBJECT (mail_op),
992                                                                   "operation-started");
993                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
994                                                                   G_OBJECT (mail_op),
995                                                                   "operation-finished");
996                 if (tny_list_find  (priv->progress_operations, G_OBJECT (mail_op))) {
997                         tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
998                         g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
999                 }
1000         }
1001 }
1002
1003 static void 
1004 on_mail_operation_started (ModestMailOperation *mail_op,
1005                            gpointer user_data)
1006 {
1007         ModestWindowMgr *self;
1008         ModestWindowMgrPrivate *priv;
1009         ModestMailOperationTypeOperation op_type;
1010
1011         self = MODEST_WINDOW_MGR (user_data);
1012         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1013
1014         /* First we check if the operation is a send receive operation,
1015          * If now, we don't handle this */
1016         op_type = modest_mail_operation_get_type_operation (mail_op);
1017         if (op_type != MODEST_MAIL_OPERATION_TYPE_SEND &&
1018             op_type != MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
1019                 return;
1020         }
1021
1022         if (!tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1023                 tny_list_prepend (priv->progress_operations, G_OBJECT (mail_op));
1024                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1025         }
1026 }
1027
1028 static void 
1029 on_mail_operation_finished (ModestMailOperation *mail_op,
1030                             gpointer user_data)
1031 {
1032         ModestWindowMgr *self;
1033         ModestWindowMgrPrivate *priv;
1034
1035         self = MODEST_WINDOW_MGR (user_data);
1036         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1037
1038         if (tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1039                 tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1040                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1041         }
1042 }
1043
1044 TnyList *
1045 modest_window_mgr_get_progress_operations (ModestWindowMgr *self)
1046 {
1047         ModestWindowMgrPrivate *priv;
1048
1049         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1050
1051         return tny_list_copy (priv->progress_operations);
1052 }
1053
1054 gboolean 
1055 modest_window_mgr_has_progress_operation (ModestWindowMgr *self)
1056 {
1057         ModestWindowMgrPrivate *priv;
1058
1059         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1060
1061         return tny_list_get_length (priv->progress_operations) > 0;
1062 }
1063
1064 gboolean 
1065 modest_window_mgr_has_progress_operation_on_account (ModestWindowMgr *self,
1066                                                      const gchar *account_name)
1067 {
1068         ModestWindowMgrPrivate *priv;
1069         gint account_ops = 0;
1070         TnyIterator *iterator;
1071
1072         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1073
1074         if (account_name == NULL)
1075                 return 0;
1076
1077         for (iterator = tny_list_create_iterator (priv->progress_operations);
1078              !tny_iterator_is_done (iterator);
1079              tny_iterator_next (iterator)) {
1080                 ModestMailOperation *mail_op; 
1081                 TnyAccount *account;
1082
1083                 mail_op= MODEST_MAIL_OPERATION (tny_iterator_get_current (iterator));
1084                 account = modest_mail_operation_get_account (mail_op);
1085
1086                 if (account != NULL) {
1087                         const gchar *current_name;
1088
1089                         current_name = tny_account_get_id (account);
1090                         if (current_name && strcmp (current_name, account_name) == 0)
1091                                 account_ops ++;
1092                         g_object_unref (account);
1093                 }
1094
1095                 g_object_unref (mail_op);
1096         }
1097         g_object_unref (iterator);
1098
1099         return account_ops;
1100 }
1101
1102 /* 'Protected method' must be only called by children */
1103 gboolean
1104 _modest_window_mgr_close_active_modals (ModestWindowMgr *self)
1105 {
1106         GtkWidget *modal;
1107
1108         /* Exit if there are no windows */
1109         if (!modest_window_mgr_get_num_windows (self)) {
1110                 g_warning ("%s: there are no windows to close", __FUNCTION__);
1111                 return FALSE;
1112         }
1113
1114         /* Check that there is no active modal dialog */
1115         modal = (GtkWidget *) modest_window_mgr_get_modal (self);
1116         while (modal && GTK_IS_DIALOG (modal)) {
1117                 GtkWidget *parent;
1118
1119 #if defined(MODEST_TOOLKIT_HILDON2) || defined(MODEST_TOOLKIT_HILDON)
1120 #include <hildon/hildon.h>
1121                 /* If it's a hildon note then don't try to close it as
1122                    this is the default behaviour of WM, delete event
1123                    is not issued for this kind of notes as we want the
1124                    user to always click on a button */
1125                 if (HILDON_IS_NOTE (modal)) {
1126                         gtk_window_present (GTK_WINDOW (modal));
1127                         return FALSE;
1128                 }
1129 #endif
1130
1131                 /* Get the parent */
1132                 parent = (GtkWidget *) gtk_window_get_transient_for (GTK_WINDOW (modal));
1133
1134                 /* Try to close it */
1135                 gtk_dialog_response (GTK_DIALOG (modal), GTK_RESPONSE_DELETE_EVENT);
1136
1137                 /* Maybe the dialog was not closed, because a close
1138                    confirmation dialog for example. Then ignore the
1139                    register process */
1140                 if (GTK_IS_WINDOW (modal)) {
1141                         gtk_window_present (GTK_WINDOW (modal));
1142                         return FALSE;
1143                 }
1144
1145                 /* Get next modal */
1146                 modal = parent;
1147         }
1148         return TRUE;
1149 }
1150
1151 gboolean
1152 modest_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1153 {
1154         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_but_initial (self);
1155 }
1156
1157 static gboolean
1158 modest_window_mgr_close_all_but_initial_default (ModestWindowMgr *self)
1159 {
1160         /* Empty default implementation */
1161         return FALSE;
1162 }
1163
1164 ModestWindow *
1165 modest_window_mgr_get_folder_window (ModestWindowMgr *self)
1166 {
1167         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_folder_window (self);
1168 }
1169
1170 static ModestWindow *
1171 modest_window_mgr_get_folder_window_default (ModestWindowMgr *self)
1172 {
1173         /* Default implementation returns NULL always */
1174
1175         return NULL;
1176 }
1177