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_confirmation_dialog (GTK_WINDOW (window),
431 _("mcen_nc_no_email_message_modified_save_changes"));
433 if (response != GTK_RESPONSE_CANCEL)
434 modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
440 /* Unregister window */
441 modest_window_mgr_unregister_window (self, window);
447 modest_window_mgr_unregister_window (ModestWindowMgr *self,
448 ModestWindow *window)
451 ModestWindowMgrPrivate *priv;
452 gint *tmp, handler_id;
454 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
455 g_return_if_fail (MODEST_IS_WINDOW (window));
457 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
459 win = g_list_find (priv->window_list, window);
461 g_warning ("Trying to unregister a window that has not being registered yet");
465 /* If it's the main window unset it */
466 if (priv->main_window == window)
467 priv->main_window = NULL;
470 modest_window_save_state (window);
472 /* Remove from list & hash table */
473 priv->window_list = g_list_remove_link (priv->window_list, win);
474 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
476 g_hash_table_remove (priv->destroy_handlers, window);
478 /* Remove the reference to the window. Disconnect also the
479 delete-event handler, we won't need it anymore */
480 g_signal_handler_disconnect (window, handler_id);
481 gtk_widget_destroy (win->data);
483 /* If there are no more windows registered then exit program */
484 if (priv->window_list == NULL) {
485 ModestConf *conf = modest_runtime_get_conf ();
487 /* Save show toolbar status */
488 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
489 priv->show_toolbars_fullscreen, NULL);
490 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
491 priv->show_toolbars, NULL);
499 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
502 ModestWindowMgrPrivate *priv;
505 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
507 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
509 /* If there is no change do nothing */
510 if (priv->fullscreen_mode == on)
513 priv->fullscreen_mode = on;
516 win = priv->window_list;
519 gtk_window_fullscreen (GTK_WINDOW (win->data));
520 modest_window_show_toolbar (MODEST_WINDOW (win->data),
521 priv->show_toolbars_fullscreen);
523 gtk_window_unfullscreen (GTK_WINDOW (win->data));
524 modest_window_show_toolbar (MODEST_WINDOW (win->data),
525 priv->show_toolbars);
527 win = g_list_next (win);
532 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
534 ModestWindowMgrPrivate *priv;
536 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
538 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
540 return priv->fullscreen_mode;
544 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
545 gboolean show_toolbars,
548 ModestWindowMgrPrivate *priv;
550 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
552 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
554 /* If nothing changes then return. Otherwise cache it, do not
555 save to GConf for the moment, it will be done when all
556 windows become unregistered in order to avoid unnecessary
559 if (priv->show_toolbars_fullscreen == show_toolbars)
562 priv->show_toolbars_fullscreen = show_toolbars;
564 if (priv->show_toolbars == show_toolbars)
567 priv->show_toolbars = show_toolbars;
570 /* Apply now if the view mode is the right one */
571 if ((fullscreen && priv->fullscreen_mode) ||
572 (!fullscreen && !priv->fullscreen_mode)) {
574 GList *win = priv->window_list;
577 modest_window_show_toolbar (MODEST_WINDOW (win->data),
579 win = g_list_next (win);
585 modest_window_mgr_get_main_window (ModestWindowMgr *self)
587 ModestWindowMgrPrivate *priv;
589 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
591 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
593 return priv->main_window;
597 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
599 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
600 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
602 /* Forget this window,
603 * so hibernation will be allowed again if no windows are remembered: */
604 priv->windows_that_prevent_hibernation =
605 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
609 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
611 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
612 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
614 GtkWindow *window = GTK_WINDOW (widget);
616 priv->windows_that_prevent_hibernation =
617 g_slist_append (priv->windows_that_prevent_hibernation, window);
619 /* Allow hibernation again when the window has been hidden: */
620 g_signal_connect (window, "hide",
621 G_CALLBACK (on_nonhibernating_window_hide), self);
624 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
627 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
629 if (GTK_WIDGET_VISIBLE(window)) {
630 on_nonhibernating_window_show (GTK_WIDGET (window), self);
632 /* Wait for it to be shown: */
633 g_signal_connect (window, "show",
634 G_CALLBACK (on_nonhibernating_window_show), self);
638 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
640 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
642 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
644 /* Prevent hibernation if any open windows are currently
645 * preventing hibernation: */
646 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
650 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
652 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
654 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
656 /* Iterate over all windows */
657 GList *win = priv->window_list;
659 ModestWindow *window = MODEST_WINDOW (win->data);
661 /* This calls the vfunc,
662 * so each window can do its own thing: */
663 modest_window_save_state (window);
666 win = g_list_next (win);