* Fixed a compilation warning
[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 "widgets/modest-main-window.h"
34 #include "widgets/modest-msg-edit-window.h"
35 #include "widgets/modest-msg-view-window.h"
36 /* include other impl specific header files */
37
38 /* 'private'/'protected' functions */
39 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
40 static void modest_window_mgr_init       (ModestWindowMgr *obj);
41 static void modest_window_mgr_finalize   (GObject *obj);
42
43 static void on_window_destroy            (ModestWindow *window, 
44                                           ModestWindowMgr *self);
45
46 /* list my signals  */
47 enum {
48         /* MY_SIGNAL_1, */
49         /* MY_SIGNAL_2, */
50         LAST_SIGNAL
51 };
52
53 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
54 struct _ModestWindowMgrPrivate {
55         GList *window_list;
56         ModestWindow *main_window;
57         gboolean fullscreen_mode;
58         gboolean show_toolbars;
59         gboolean show_toolbars_fullscreen;
60         
61         GSList* windows_that_prevent_hibernation;
62 };
63 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
64                                                MODEST_TYPE_WINDOW_MGR, \
65                                                ModestWindowMgrPrivate))
66 /* globals */
67 static GObjectClass *parent_class = NULL;
68
69 /* uncomment the following if you have defined any signals */
70 /* static guint signals[LAST_SIGNAL] = {0}; */
71
72 GType
73 modest_window_mgr_get_type (void)
74 {
75         static GType my_type = 0;
76         if (!my_type) {
77                 static const GTypeInfo my_info = {
78                         sizeof(ModestWindowMgrClass),
79                         NULL,           /* base init */
80                         NULL,           /* base finalize */
81                         (GClassInitFunc) modest_window_mgr_class_init,
82                         NULL,           /* class finalize */
83                         NULL,           /* class data */
84                         sizeof(ModestWindowMgr),
85                         1,              /* n_preallocs */
86                         (GInstanceInitFunc) modest_window_mgr_init,
87                         NULL
88                 };
89                 my_type = g_type_register_static (G_TYPE_OBJECT,
90                                                   "ModestWindowMgr",
91                                                   &my_info, 0);
92         }
93         return my_type;
94 }
95
96 static void
97 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
98 {
99         GObjectClass *gobject_class;
100         gobject_class = (GObjectClass*) klass;
101
102         parent_class            = g_type_class_peek_parent (klass);
103         gobject_class->finalize = modest_window_mgr_finalize;
104
105         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
106 }
107
108 static void
109 modest_window_mgr_init (ModestWindowMgr *obj)
110 {
111         ModestWindowMgrPrivate *priv;
112
113         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
114         priv->window_list = NULL;
115         priv->main_window = NULL;
116         priv->fullscreen_mode = FALSE;
117
118         /* Could not initialize it from gconf, singletons are not
119            ready yet */
120         priv->show_toolbars = FALSE;
121         priv->show_toolbars_fullscreen = FALSE;
122 }
123
124 static void
125 modest_window_mgr_finalize (GObject *obj)
126 {
127         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
128
129         if (priv->window_list) {
130                 GList *iter = priv->window_list;
131                 /* unregister pending windows */
132                 while (iter) {
133                         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), 
134                                                              MODEST_WINDOW (iter->data));
135                         iter = g_list_next (iter);
136                 }
137                 g_list_free (priv->window_list);
138                 priv->window_list = NULL;
139         }
140
141         /* Do not unref priv->main_window because it does not hold a
142            new reference */
143
144         G_OBJECT_CLASS(parent_class)->finalize (obj);
145 }
146
147 ModestWindowMgr*
148 modest_window_mgr_new (void)
149 {
150         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
151 }
152
153 void 
154 modest_window_mgr_register_window (ModestWindowMgr *self, 
155                                    ModestWindow *window)
156 {
157         static gboolean first_time = TRUE;
158         GList *win;
159         gboolean show;
160         ModestWindowMgrPrivate *priv;
161
162         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
163         g_return_if_fail (MODEST_IS_WINDOW (window));
164
165         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
166
167         win = g_list_find (priv->window_list, window);
168         if (win) {
169                 g_warning ("Trying to register an already registered window");
170                 return;
171         }
172
173         /* Check that it's not a second main window */
174         if (MODEST_IS_MAIN_WINDOW (window)) {
175                 if (priv->main_window) {
176                         g_warning ("Trying to register a second main window");
177                         return;
178                 } else {
179                         priv->main_window = window;
180                 }
181         }
182
183         /* Add to list. Keep a reference to the window */
184         g_object_ref (window);
185         priv->window_list = g_list_prepend (priv->window_list, window);
186
187         /* Listen to object destruction */
188         g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), self);
189
190         /* Put into fullscreen if needed */
191         if (priv->fullscreen_mode)
192                 gtk_window_fullscreen (GTK_WINDOW (window));
193
194         /* Fill caches */
195         if (first_time) {
196                 ModestConf *conf = modest_runtime_get_conf ();
197                 priv->show_toolbars = 
198                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
199                 priv->show_toolbars_fullscreen = 
200                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
201                 first_time = FALSE;
202         }
203
204         /* Show/hide toolbar */
205         if (priv->fullscreen_mode)
206                 show = priv->show_toolbars_fullscreen;
207         else
208                 show = priv->show_toolbars;
209         modest_window_show_toolbar (window, show);
210 }
211
212 static void
213 on_window_destroy (ModestWindow *window, ModestWindowMgr *self)
214 {
215         /* Specific stuff first */
216         if (MODEST_IS_MAIN_WINDOW (window)) {
217                 ModestWindowMgrPrivate *priv;
218                 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
219
220                 /* If more than one window already opened */
221                 if (g_list_length (priv->window_list) > 1) {
222
223                         /* If the user wants to close all the windows */
224                         if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
225                                 GList *iter = priv->window_list;
226                                 do {
227                                         if (iter->data != window) {
228                                                 GList *tmp = iter->next;
229                                                 on_window_destroy (MODEST_WINDOW (iter->data),
230                                                                    self);
231                                                 iter = tmp;
232                                         } else {
233                                                 iter = g_list_next (iter);
234                                         }
235                                 } while (iter);
236                         }
237                 }
238         } else {
239                 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
240                         /* TODO: Save currently edited message to Drafts
241                            folder */
242                 }
243         }
244
245         /* Unregister window */
246         modest_window_mgr_unregister_window (self, window);
247 }
248
249 void 
250 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
251                                      ModestWindow *window)
252 {
253         GList *win;
254         ModestWindowMgrPrivate *priv;
255
256         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
257         g_return_if_fail (MODEST_IS_WINDOW (window));
258
259         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
260
261         win = g_list_find (priv->window_list, window);
262         if (!win) {
263                 g_warning ("Trying to unregister a window that has not being registered yet");
264                 return;
265         }
266
267         /* Remove from list. Remove the reference to the window */
268         g_object_unref (win->data);
269         priv->window_list = g_list_remove_link (priv->window_list, win);
270
271         /* If there are no more windows registered then exit program */
272         if (priv->window_list == NULL) {
273                 ModestConf *conf = modest_runtime_get_conf ();
274
275                 /* Save show toolbar status */
276                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, 
277                                       priv->show_toolbars_fullscreen, NULL);
278                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR, 
279                                       priv->show_toolbars, NULL);
280
281                 /* Quit main loop */
282                 gtk_main_quit ();
283         }
284 }
285
286 static gint
287 compare_msguids (ModestWindow *win,
288                  const gchar *uid)
289 {
290         const gchar *msg_uid;
291
292         if (!MODEST_IS_MSG_VIEW_WINDOW (win))
293                 return 1;
294
295         /* Get message uid from msg window */
296         msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
297         if (msg_uid && !strcmp (msg_uid, uid))
298                 return 0;
299         else
300                 return 1;
301 }
302
303 ModestWindow*  
304 modest_window_mgr_find_window_by_msguid (ModestWindowMgr *self, 
305                                          const gchar *msguid)
306 {
307         ModestWindowMgrPrivate *priv;
308         GList *win = NULL;
309
310         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
311         g_return_val_if_fail (msguid != NULL, NULL);
312
313         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
314
315         /* Look for the window */
316         if (priv->window_list)
317                 win = g_list_find_custom (priv->window_list, 
318                                           msguid, 
319                                           (GCompareFunc) compare_msguids);
320
321         if (win)
322                 return win->data;
323         else 
324                 return NULL;
325 }
326
327 void
328 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
329                                        gboolean on)
330 {
331         ModestWindowMgrPrivate *priv;
332         GList *win = NULL;
333
334         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
335
336         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
337
338         /* If there is no change do nothing */
339         if (priv->fullscreen_mode == on)
340                 return;
341
342         priv->fullscreen_mode = on;
343
344         /* Update windows */
345         win = priv->window_list;
346         while (win) {
347                 if (on) {
348                         gtk_window_fullscreen (GTK_WINDOW (win->data));
349                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
350                                                     priv->show_toolbars_fullscreen);
351                 } else {
352                         gtk_window_unfullscreen (GTK_WINDOW (win->data));
353                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
354                                                     priv->show_toolbars);
355                 }
356                 win = g_list_next (win);
357         }
358 }
359
360 gboolean
361 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
362 {
363         ModestWindowMgrPrivate *priv;
364
365         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
366
367         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
368
369         return priv->fullscreen_mode;
370 }
371
372 void 
373 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
374                                  gboolean show_toolbars,
375                                  gboolean fullscreen)
376 {
377         ModestWindowMgrPrivate *priv;
378
379         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
380
381         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
382
383         /* If nothing changes then return. Otherwise cache it, do not
384            save to GConf for the moment, it will be done when all
385            windows become unregistered in order to avoid unnecessary
386            ModestConf calls */
387         if (fullscreen) {
388                 if (priv->show_toolbars_fullscreen == show_toolbars)
389                         return;
390                 else
391                         priv->show_toolbars_fullscreen = show_toolbars;
392         } else {
393                 if (priv->show_toolbars == show_toolbars)
394                         return;
395                 else
396                         priv->show_toolbars = show_toolbars;
397         }
398
399         /* Apply now if the view mode is the right one */
400         if ((fullscreen && priv->fullscreen_mode) ||
401             (!fullscreen && !priv->fullscreen_mode)) {
402
403                 GList *win = priv->window_list;
404
405                 while (win) {
406                         modest_window_show_toolbar (MODEST_WINDOW (win->data),
407                                                     show_toolbars);
408                         win = g_list_next (win);
409                 }
410         }
411 }
412
413 ModestWindow*  
414 modest_window_mgr_get_main_window (ModestWindowMgr *self)
415 {
416         ModestWindowMgrPrivate *priv;
417
418         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
419
420         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
421
422         return priv->main_window;
423 }
424
425 static void
426 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
427 {
428         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
429         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
430         
431         /* Forget this window,
432          * so hibernation will be allowed again if no windows are remembered: */
433         priv->windows_that_prevent_hibernation =
434                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
435 }
436
437 static void
438 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
439 {
440         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
441         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
442         
443         GtkWindow *window = GTK_WINDOW (widget);
444         
445         priv->windows_that_prevent_hibernation = 
446                         g_slist_append (priv->windows_that_prevent_hibernation, window);
447         
448         /* Allow hibernation again when the window has been hidden: */
449         g_signal_connect (window, "hide", 
450                 G_CALLBACK (on_nonhibernating_window_hide), self);
451 }
452
453 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self, GtkWindow *window)
454 {
455         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
456         
457         if (GTK_WIDGET_VISIBLE(window)) {
458                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
459         }
460         else
461         {
462                 /* Wait for it to be shown: */
463                 g_signal_connect (window, "show", 
464                         G_CALLBACK (on_nonhibernating_window_show), self);      
465         }
466 }
467
468 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
469 {
470         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
471         
472         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
473         
474         /* Prevent hibernation if any open windows are currently 
475          * preventing hibernation: */
476         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
477 }
478
479
480 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
481 {
482         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
483         
484         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
485
486         /* Iterate over all windows */
487         GList *win = priv->window_list;
488         while (win) {
489                 ModestWindow *window = MODEST_WINDOW (win->data);
490                 if (window) {
491                         /* This calls the vfunc, 
492                          * so each window can do its own thing: */
493                         modest_window_save_state (window);
494                 }       
495                 
496                 win = g_list_next (win);
497         }
498 }
499
500