1 /* Copyright (c) 2006,2007 Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
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 "widgets/modest-main-window.h"
37 #include "widgets/modest-msg-edit-window.h"
38 #include "widgets/modest-msg-view-window.h"
39 /* include other impl specific header files */
41 /* 'private'/'protected' functions */
42 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
43 static void modest_window_mgr_init (ModestWindowMgr *obj);
44 static void modest_window_mgr_finalize (GObject *obj);
46 /* static void on_window_destroy (ModestWindow *window, */
47 /* ModestWindowMgr *self); */
48 static gboolean on_window_destroy (ModestWindow *window,
50 ModestWindowMgr *self);
59 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
60 struct _ModestWindowMgrPrivate {
62 ModestWindow *main_window;
63 gboolean fullscreen_mode;
64 gboolean show_toolbars;
65 gboolean show_toolbars_fullscreen;
67 GSList *windows_that_prevent_hibernation;
68 GSList *preregistered_uids;
69 GHashTable *destroy_handlers;
71 #define MODEST_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
72 MODEST_TYPE_WINDOW_MGR, \
73 ModestWindowMgrPrivate))
75 static GObjectClass *parent_class = NULL;
77 /* uncomment the following if you have defined any signals */
78 /* static guint signals[LAST_SIGNAL] = {0}; */
81 modest_window_mgr_get_type (void)
83 static GType my_type = 0;
85 static const GTypeInfo my_info = {
86 sizeof(ModestWindowMgrClass),
88 NULL, /* base finalize */
89 (GClassInitFunc) modest_window_mgr_class_init,
90 NULL, /* class finalize */
91 NULL, /* class data */
92 sizeof(ModestWindowMgr),
94 (GInstanceInitFunc) modest_window_mgr_init,
97 my_type = g_type_register_static (G_TYPE_OBJECT,
105 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
107 GObjectClass *gobject_class;
108 gobject_class = (GObjectClass*) klass;
110 parent_class = g_type_class_peek_parent (klass);
111 gobject_class->finalize = modest_window_mgr_finalize;
113 g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
117 modest_window_mgr_init (ModestWindowMgr *obj)
119 ModestWindowMgrPrivate *priv;
121 priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
122 priv->window_list = NULL;
123 priv->main_window = NULL;
124 priv->fullscreen_mode = FALSE;
126 priv->preregistered_uids = NULL;
128 /* Could not initialize it from gconf, singletons are not
130 priv->show_toolbars = FALSE;
131 priv->show_toolbars_fullscreen = FALSE;
132 priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
136 modest_window_mgr_finalize (GObject *obj)
138 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
140 if (priv->window_list) {
141 GList *iter = priv->window_list;
142 /* unregister pending windows */
144 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj),
145 MODEST_WINDOW (iter->data));
146 iter = g_list_next (iter);
148 g_list_free (priv->window_list);
149 priv->window_list = NULL;
152 g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
153 g_slist_free (priv->preregistered_uids);
156 /* Free the hash table with the handlers */
157 if (priv->destroy_handlers) {
158 g_hash_table_destroy (priv->destroy_handlers);
159 priv->destroy_handlers = NULL;
162 /* Do not unref priv->main_window because it does not hold a
165 G_OBJECT_CLASS(parent_class)->finalize (obj);
169 modest_window_mgr_new (void)
171 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
177 /* do we have uid? */
179 has_uid (GSList *list, const gchar *uid)
181 GSList *cursor = list;
187 if (cursor->data && strcmp (cursor->data, uid) == 0)
189 cursor = g_slist_next (cursor);
195 /* remove all from the list have have uid = uid */
197 remove_uid (GSList *list, const gchar *uid)
199 GSList *cursor = list, *start = list;
205 GSList *next = g_slist_next (cursor);
206 if (cursor->data && strcmp (cursor->data, uid) == 0) {
207 g_free (cursor->data);
208 start = g_slist_delete_link (start, cursor);
217 append_uid (GSList *list, const gchar *uid)
219 return g_slist_append (list, g_strdup(uid));
225 modest_window_mgr_register_header (ModestWindowMgr *self, TnyHeader *header)
227 ModestWindowMgrPrivate *priv;
230 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
231 g_return_if_fail (TNY_IS_HEADER(header));
233 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
234 uid = modest_tny_folder_get_header_unique_id (header);
236 if (!has_uid (priv->preregistered_uids, uid))
237 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
245 compare_msguids (ModestWindow *win,
248 const gchar *msg_uid;
250 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
253 /* Get message uid from msg window */
254 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
256 if (msg_uid && uid &&!strcmp (msg_uid, uid))
265 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
268 ModestWindowMgrPrivate *priv;
270 gboolean retval = FALSE;
273 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
274 g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
276 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
278 uid = modest_tny_folder_get_header_unique_id (header);
280 /* first, look for the window */
281 /* note, the UID cannot be in both the window list and the preregistered uid list */
282 if (priv->window_list) {
283 item = g_list_find_custom (priv->window_list,
284 uid, (GCompareFunc) compare_msguids);
288 *win = item ? MODEST_WINDOW(item->data) : NULL;
292 /* IF It's not in the window list. maybe it's in our uid list... */
293 retval = retval || has_uid (priv->preregistered_uids, uid);
303 modest_window_mgr_register_window (ModestWindowMgr *self,
304 ModestWindow *window)
306 static gboolean first_time = TRUE;
309 ModestWindowMgrPrivate *priv;
312 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
313 g_return_if_fail (MODEST_IS_WINDOW (window));
315 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
317 win = g_list_find (priv->window_list, window);
319 g_warning ("Trying to register an already registered window");
323 /* Check that it's not a second main window */
324 if (MODEST_IS_MAIN_WINDOW (window)) {
325 if (priv->main_window) {
326 g_warning ("Trying to register a second main window");
329 priv->main_window = window;
333 /* remove from the list of pre-registered uids */
334 if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
335 priv->preregistered_uids =
336 remove_uid (priv->preregistered_uids,
337 modest_msg_view_window_get_message_uid
338 (MODEST_MSG_VIEW_WINDOW (window)));
341 /* Add to list. Keep a reference to the window */
342 g_object_ref (window);
343 priv->window_list = g_list_prepend (priv->window_list, window);
345 /* Listen to object destruction */
346 handler_id = g_malloc0 (sizeof (gint));
347 *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
348 /* *handler_id = g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), self); */
349 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
351 /* Put into fullscreen if needed */
352 if (priv->fullscreen_mode)
353 gtk_window_fullscreen (GTK_WINDOW (window));
357 ModestConf *conf = modest_runtime_get_conf ();
358 priv->show_toolbars =
359 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
360 priv->show_toolbars_fullscreen =
361 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
365 /* Show/hide toolbar */
366 if (priv->fullscreen_mode)
367 show = priv->show_toolbars_fullscreen;
369 show = priv->show_toolbars;
370 modest_window_show_toolbar (window, show);
374 /* on_window_destroy (ModestWindow *window, ModestWindowMgr *self) */
376 on_window_destroy (ModestWindow *window,
378 ModestWindowMgr *self)
380 /* Specific stuff first */
381 if (MODEST_IS_MAIN_WINDOW (window)) {
382 ModestWindowMgrPrivate *priv;
383 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
385 /* If more than one window already opened */
386 if (g_list_length (priv->window_list) > 1) {
388 /* If the user wants to close all the windows */
389 if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
390 GList *iter = priv->window_list;
392 if (iter->data != window) {
393 GList *tmp = iter->next;
394 on_window_destroy (MODEST_WINDOW (iter->data),
399 iter = g_list_next (iter);
406 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
407 gboolean sent = FALSE;
408 gint response = GTK_RESPONSE_ACCEPT;
409 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
410 /* Save currently edited message to Drafts if it was not sent */
411 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
414 modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
415 _("mcen_nc_no_email_message_modified_save_changes"));
417 if (response != GTK_RESPONSE_CANCEL)
418 modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
424 /* Unregister window */
425 modest_window_mgr_unregister_window (self, window);
431 modest_window_mgr_unregister_window (ModestWindowMgr *self,
432 ModestWindow *window)
435 ModestWindowMgrPrivate *priv;
436 gint *tmp, handler_id;
438 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
439 g_return_if_fail (MODEST_IS_WINDOW (window));
441 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
443 win = g_list_find (priv->window_list, window);
445 g_warning ("Trying to unregister a window that has not being registered yet");
449 /* If it's the main window unset it */
450 if (priv->main_window == window)
451 priv->main_window = NULL;
454 modest_window_save_state (window);
456 /* Remove from list & hash table */
457 priv->window_list = g_list_remove_link (priv->window_list, win);
458 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
460 g_hash_table_remove (priv->destroy_handlers, window);
462 /* Remove the reference to the window. Disconnect also the
463 delete-event handler, we won't need it anymore */
464 g_signal_handler_disconnect (window, handler_id);
465 gtk_widget_destroy (win->data);
467 /* If there are no more windows registered then exit program */
468 if (priv->window_list == NULL) {
469 ModestConf *conf = modest_runtime_get_conf ();
471 /* Save show toolbar status */
472 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
473 priv->show_toolbars_fullscreen, NULL);
474 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
475 priv->show_toolbars, NULL);
483 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
486 ModestWindowMgrPrivate *priv;
489 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
491 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
493 /* If there is no change do nothing */
494 if (priv->fullscreen_mode == on)
497 priv->fullscreen_mode = on;
500 win = priv->window_list;
503 gtk_window_fullscreen (GTK_WINDOW (win->data));
504 modest_window_show_toolbar (MODEST_WINDOW (win->data),
505 priv->show_toolbars_fullscreen);
507 gtk_window_unfullscreen (GTK_WINDOW (win->data));
508 modest_window_show_toolbar (MODEST_WINDOW (win->data),
509 priv->show_toolbars);
511 win = g_list_next (win);
516 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
518 ModestWindowMgrPrivate *priv;
520 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
522 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
524 return priv->fullscreen_mode;
528 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
529 gboolean show_toolbars,
532 ModestWindowMgrPrivate *priv;
534 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
536 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
538 /* If nothing changes then return. Otherwise cache it, do not
539 save to GConf for the moment, it will be done when all
540 windows become unregistered in order to avoid unnecessary
543 if (priv->show_toolbars_fullscreen == show_toolbars)
546 priv->show_toolbars_fullscreen = show_toolbars;
548 if (priv->show_toolbars == show_toolbars)
551 priv->show_toolbars = show_toolbars;
554 /* Apply now if the view mode is the right one */
555 if ((fullscreen && priv->fullscreen_mode) ||
556 (!fullscreen && !priv->fullscreen_mode)) {
558 GList *win = priv->window_list;
561 modest_window_show_toolbar (MODEST_WINDOW (win->data),
563 win = g_list_next (win);
569 modest_window_mgr_get_main_window (ModestWindowMgr *self)
571 ModestWindowMgrPrivate *priv;
573 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
575 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
577 return priv->main_window;
581 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
583 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
584 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
586 /* Forget this window,
587 * so hibernation will be allowed again if no windows are remembered: */
588 priv->windows_that_prevent_hibernation =
589 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
593 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
595 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
596 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
598 GtkWindow *window = GTK_WINDOW (widget);
600 priv->windows_that_prevent_hibernation =
601 g_slist_append (priv->windows_that_prevent_hibernation, window);
603 /* Allow hibernation again when the window has been hidden: */
604 g_signal_connect (window, "hide",
605 G_CALLBACK (on_nonhibernating_window_hide), self);
608 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
611 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
613 if (GTK_WIDGET_VISIBLE(window)) {
614 on_nonhibernating_window_show (GTK_WIDGET (window), self);
616 /* Wait for it to be shown: */
617 g_signal_connect (window, "show",
618 G_CALLBACK (on_nonhibernating_window_show), self);
622 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
624 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
626 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
628 /* Prevent hibernation if any open windows are currently
629 * preventing hibernation: */
630 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
634 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
636 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
638 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
640 /* Iterate over all windows */
641 GList *win = priv->window_list;
643 ModestWindow *window = MODEST_WINDOW (win->data);
645 /* This calls the vfunc,
646 * so each window can do its own thing: */
647 modest_window_save_state (window);
650 win = g_list_next (win);