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);
243 modest_window_mgr_unregister_header (ModestWindowMgr *self, TnyHeader *header)
245 ModestWindowMgrPrivate *priv;
248 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
249 g_return_if_fail (TNY_IS_HEADER(header));
251 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
252 uid = modest_tny_folder_get_header_unique_id (header);
254 if (has_uid (priv->preregistered_uids, uid))
255 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
261 compare_msguids (ModestWindow *win,
264 const gchar *msg_uid;
266 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
269 /* Get message uid from msg window */
270 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
272 if (msg_uid && uid &&!strcmp (msg_uid, uid))
281 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
284 ModestWindowMgrPrivate *priv;
286 gboolean retval = FALSE;
289 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
290 g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
292 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
294 uid = modest_tny_folder_get_header_unique_id (header);
296 /* first, look for the window */
297 /* note, the UID cannot be in both the window list and the preregistered uid list */
298 if (priv->window_list) {
299 item = g_list_find_custom (priv->window_list,
300 uid, (GCompareFunc) compare_msguids);
304 *win = item ? MODEST_WINDOW(item->data) : NULL;
308 /* IF It's not in the window list. maybe it's in our uid list... */
309 retval = retval || has_uid (priv->preregistered_uids, uid);
319 modest_window_mgr_register_window (ModestWindowMgr *self,
320 ModestWindow *window)
322 static gboolean first_time = TRUE;
325 ModestWindowMgrPrivate *priv;
328 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
329 g_return_if_fail (MODEST_IS_WINDOW (window));
331 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
333 win = g_list_find (priv->window_list, window);
335 g_warning ("Trying to register an already registered window");
339 /* Check that it's not a second main window */
340 if (MODEST_IS_MAIN_WINDOW (window)) {
341 if (priv->main_window) {
342 g_warning ("Trying to register a second main window");
345 priv->main_window = window;
349 /* remove from the list of pre-registered uids */
350 if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
351 priv->preregistered_uids =
352 remove_uid (priv->preregistered_uids,
353 modest_msg_view_window_get_message_uid
354 (MODEST_MSG_VIEW_WINDOW (window)));
357 /* Add to list. Keep a reference to the window */
358 g_object_ref (window);
359 priv->window_list = g_list_prepend (priv->window_list, window);
361 /* Listen to object destruction */
362 handler_id = g_malloc0 (sizeof (gint));
363 *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
364 /* *handler_id = g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), self); */
365 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
367 /* Put into fullscreen if needed */
368 if (priv->fullscreen_mode)
369 gtk_window_fullscreen (GTK_WINDOW (window));
373 ModestConf *conf = modest_runtime_get_conf ();
374 priv->show_toolbars =
375 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
376 priv->show_toolbars_fullscreen =
377 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
381 /* Show/hide toolbar */
382 if (priv->fullscreen_mode)
383 show = priv->show_toolbars_fullscreen;
385 show = priv->show_toolbars;
386 modest_window_show_toolbar (window, show);
390 /* on_window_destroy (ModestWindow *window, ModestWindowMgr *self) */
392 on_window_destroy (ModestWindow *window,
394 ModestWindowMgr *self)
396 /* Specific stuff first */
397 if (MODEST_IS_MAIN_WINDOW (window)) {
398 ModestWindowMgrPrivate *priv;
399 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
401 /* If more than one window already opened */
402 if (g_list_length (priv->window_list) > 1) {
404 /* If the user wants to close all the windows */
405 if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
406 GList *iter = priv->window_list;
408 if (iter->data != window) {
409 GList *tmp = iter->next;
410 on_window_destroy (MODEST_WINDOW (iter->data),
415 iter = g_list_next (iter);
422 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
423 gboolean sent = FALSE;
424 gint response = GTK_RESPONSE_ACCEPT;
425 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
426 /* Save currently edited message to Drafts if it was not sent */
427 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
430 modest_platform_run_yes_no_dialog (GTK_WINDOW (window),
431 _("mcen_nc_no_email_message_modified_save_changes"));
433 if (response != GTK_RESPONSE_NO)
434 modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
440 /* Save configuration state (TODO: why edit window does not require this function ?) */
441 if (!MODEST_IS_MSG_EDIT_WINDOW (window))
442 modest_window_save_state (MODEST_WINDOW(window));
445 /* Unregister window */
446 modest_window_mgr_unregister_window (self, window);
452 modest_window_mgr_unregister_window (ModestWindowMgr *self,
453 ModestWindow *window)
456 ModestWindowMgrPrivate *priv;
457 gint *tmp, handler_id;
459 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
460 g_return_if_fail (MODEST_IS_WINDOW (window));
462 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
464 win = g_list_find (priv->window_list, window);
466 g_warning ("Trying to unregister a window that has not being registered yet");
470 /* If it's the main window unset it */
471 if (priv->main_window == window)
472 priv->main_window = NULL;
475 modest_window_save_state (window);
477 /* Remove from list & hash table */
478 priv->window_list = g_list_remove_link (priv->window_list, win);
479 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
481 g_hash_table_remove (priv->destroy_handlers, window);
483 /* Remove the reference to the window. Disconnect also the
484 delete-event handler, we won't need it anymore */
485 g_signal_handler_disconnect (window, handler_id);
486 gtk_widget_destroy (win->data);
488 /* If there are no more windows registered then exit program */
489 if (priv->window_list == NULL) {
490 ModestConf *conf = modest_runtime_get_conf ();
492 /* Save show toolbar status */
493 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
494 priv->show_toolbars_fullscreen, NULL);
495 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
496 priv->show_toolbars, NULL);
499 /* FIXME: do we ever need to do this here? */
500 if (gtk_main_level() > 0)
506 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
509 ModestWindowMgrPrivate *priv;
512 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
514 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
516 /* If there is no change do nothing */
517 if (priv->fullscreen_mode == on)
520 priv->fullscreen_mode = on;
523 win = priv->window_list;
526 gtk_window_fullscreen (GTK_WINDOW (win->data));
527 modest_window_show_toolbar (MODEST_WINDOW (win->data),
528 priv->show_toolbars_fullscreen);
530 gtk_window_unfullscreen (GTK_WINDOW (win->data));
531 modest_window_show_toolbar (MODEST_WINDOW (win->data),
532 priv->show_toolbars);
534 win = g_list_next (win);
539 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
541 ModestWindowMgrPrivate *priv;
543 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
545 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
547 return priv->fullscreen_mode;
551 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
552 gboolean show_toolbars,
555 ModestWindowMgrPrivate *priv;
557 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
559 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
561 /* If nothing changes then return. Otherwise cache it, do not
562 save to GConf for the moment, it will be done when all
563 windows become unregistered in order to avoid unnecessary
566 if (priv->show_toolbars_fullscreen == show_toolbars)
569 priv->show_toolbars_fullscreen = show_toolbars;
571 if (priv->show_toolbars == show_toolbars)
574 priv->show_toolbars = show_toolbars;
577 /* Apply now if the view mode is the right one */
578 if ((fullscreen && priv->fullscreen_mode) ||
579 (!fullscreen && !priv->fullscreen_mode)) {
581 GList *win = priv->window_list;
584 modest_window_show_toolbar (MODEST_WINDOW (win->data),
586 win = g_list_next (win);
592 modest_window_mgr_get_main_window (ModestWindowMgr *self)
594 ModestWindowMgrPrivate *priv;
596 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
598 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
600 return priv->main_window;
604 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
606 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
607 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
609 /* Forget this window,
610 * so hibernation will be allowed again if no windows are remembered: */
611 priv->windows_that_prevent_hibernation =
612 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
616 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
618 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
619 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
621 GtkWindow *window = GTK_WINDOW (widget);
623 priv->windows_that_prevent_hibernation =
624 g_slist_append (priv->windows_that_prevent_hibernation, window);
626 /* Allow hibernation again when the window has been hidden: */
627 g_signal_connect (window, "hide",
628 G_CALLBACK (on_nonhibernating_window_hide), self);
631 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
634 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
636 if (GTK_WIDGET_VISIBLE(window)) {
637 on_nonhibernating_window_show (GTK_WIDGET (window), self);
639 /* Wait for it to be shown: */
640 g_signal_connect (window, "show",
641 G_CALLBACK (on_nonhibernating_window_show), self);
645 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
647 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
649 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
651 /* Prevent hibernation if any open windows are currently
652 * preventing hibernation: */
653 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
657 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
659 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
661 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
663 /* Iterate over all windows */
664 GList *win = priv->window_list;
666 ModestWindow *window = MODEST_WINDOW (win->data);
668 /* This calls the vfunc,
669 * so each window can do its own thing: */
670 modest_window_save_state (window);
673 win = g_list_next (win);