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);
56 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
57 struct _ModestWindowMgrPrivate {
59 ModestWindow *main_window;
60 gboolean fullscreen_mode;
61 gboolean show_toolbars;
62 gboolean show_toolbars_fullscreen;
64 GSList *windows_that_prevent_hibernation;
65 GHashTable *destroy_handlers;
67 #define MODEST_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
68 MODEST_TYPE_WINDOW_MGR, \
69 ModestWindowMgrPrivate))
71 static GObjectClass *parent_class = NULL;
73 /* uncomment the following if you have defined any signals */
74 /* static guint signals[LAST_SIGNAL] = {0}; */
77 modest_window_mgr_get_type (void)
79 static GType my_type = 0;
81 static const GTypeInfo my_info = {
82 sizeof(ModestWindowMgrClass),
84 NULL, /* base finalize */
85 (GClassInitFunc) modest_window_mgr_class_init,
86 NULL, /* class finalize */
87 NULL, /* class data */
88 sizeof(ModestWindowMgr),
90 (GInstanceInitFunc) modest_window_mgr_init,
93 my_type = g_type_register_static (G_TYPE_OBJECT,
101 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
103 GObjectClass *gobject_class;
104 gobject_class = (GObjectClass*) klass;
106 parent_class = g_type_class_peek_parent (klass);
107 gobject_class->finalize = modest_window_mgr_finalize;
109 g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
113 modest_window_mgr_init (ModestWindowMgr *obj)
115 ModestWindowMgrPrivate *priv;
117 priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
118 priv->window_list = NULL;
119 priv->main_window = NULL;
120 priv->fullscreen_mode = FALSE;
122 /* Could not initialize it from gconf, singletons are not
124 priv->show_toolbars = FALSE;
125 priv->show_toolbars_fullscreen = FALSE;
126 priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
130 modest_window_mgr_finalize (GObject *obj)
132 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
134 if (priv->window_list) {
135 GList *iter = priv->window_list;
136 /* unregister pending windows */
138 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj),
139 MODEST_WINDOW (iter->data));
140 iter = g_list_next (iter);
142 g_list_free (priv->window_list);
143 priv->window_list = NULL;
146 /* Free the hash table with the handlers */
147 if (priv->destroy_handlers) {
148 g_hash_table_destroy (priv->destroy_handlers);
149 priv->destroy_handlers = NULL;
152 /* Do not unref priv->main_window because it does not hold a
155 G_OBJECT_CLASS(parent_class)->finalize (obj);
159 modest_window_mgr_new (void)
161 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
165 modest_window_mgr_register_window (ModestWindowMgr *self,
166 ModestWindow *window)
168 static gboolean first_time = TRUE;
171 ModestWindowMgrPrivate *priv;
174 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
175 g_return_if_fail (MODEST_IS_WINDOW (window));
177 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
179 win = g_list_find (priv->window_list, window);
181 g_warning ("Trying to register an already registered window");
185 /* Check that it's not a second main window */
186 if (MODEST_IS_MAIN_WINDOW (window)) {
187 if (priv->main_window) {
188 g_warning ("Trying to register a second main window");
191 priv->main_window = window;
195 /* Add to list. Keep a reference to the window */
196 g_object_ref (window);
197 priv->window_list = g_list_prepend (priv->window_list, window);
199 /* Listen to object destruction */
200 handler_id = g_malloc0 (sizeof (gint));
201 *handler_id = g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), self);
202 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
204 /* Put into fullscreen if needed */
205 if (priv->fullscreen_mode)
206 gtk_window_fullscreen (GTK_WINDOW (window));
210 ModestConf *conf = modest_runtime_get_conf ();
211 priv->show_toolbars =
212 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
213 priv->show_toolbars_fullscreen =
214 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
218 /* Show/hide toolbar */
219 if (priv->fullscreen_mode)
220 show = priv->show_toolbars_fullscreen;
222 show = priv->show_toolbars;
223 modest_window_show_toolbar (window, show);
227 on_window_destroy (ModestWindow *window, ModestWindowMgr *self)
229 /* Specific stuff first */
230 if (MODEST_IS_MAIN_WINDOW (window)) {
231 ModestWindowMgrPrivate *priv;
232 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
234 /* If more than one window already opened */
235 if (g_list_length (priv->window_list) > 1) {
237 /* If the user wants to close all the windows */
238 if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
239 GList *iter = priv->window_list;
241 if (iter->data != window) {
242 GList *tmp = iter->next;
243 on_window_destroy (MODEST_WINDOW (iter->data),
247 iter = g_list_next (iter);
253 if (MODEST_IS_MSG_EDIT_WINDOW (window))
254 /* Save currently edited message to Drafts */
255 if (modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
257 modest_platform_run_confirmation_dialog (GTK_WINDOW (self),
258 _("mcen_nc_no_email_message_modified_save_changes"));
259 if (response != GTK_RESPONSE_CANCEL) {
260 modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
265 /* Unregister window */
266 modest_window_mgr_unregister_window (self, window);
270 modest_window_mgr_unregister_window (ModestWindowMgr *self,
271 ModestWindow *window)
274 ModestWindowMgrPrivate *priv;
277 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
278 g_return_if_fail (MODEST_IS_WINDOW (window));
280 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
282 win = g_list_find (priv->window_list, window);
284 g_warning ("Trying to unregister a window that has not being registered yet");
288 /* If it's the main window unset it */
289 if (priv->main_window == window)
290 priv->main_window = NULL;
293 modest_window_save_state (window);
295 /* Remove from list */
296 priv->window_list = g_list_remove_link (priv->window_list, win);
298 /* Remove the reference to the window. We need to block the
299 destroy event handler to avoid recursive calls */
300 handler_id = g_hash_table_lookup (priv->destroy_handlers, window);
301 g_signal_handler_block (window, *handler_id);
302 gtk_widget_destroy (win->data);
303 if (G_IS_OBJECT (window)) {
304 g_warning ("This should not happen the window was not completely destroyed");
305 g_signal_handler_unblock (window, *handler_id);
307 g_hash_table_remove (priv->destroy_handlers, window);
309 /* If there are no more windows registered then exit program */
310 if (priv->window_list == NULL) {
311 ModestConf *conf = modest_runtime_get_conf ();
313 /* Save show toolbar status */
314 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
315 priv->show_toolbars_fullscreen, NULL);
316 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
317 priv->show_toolbars, NULL);
325 compare_msguids (ModestWindow *win,
328 const gchar *msg_uid;
330 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
333 /* Get message uid from msg window */
334 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
336 if (msg_uid && uid &&!strcmp (msg_uid, uid))
343 modest_window_mgr_find_window_by_header (ModestWindowMgr *self,
346 ModestWindowMgrPrivate *priv;
350 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
351 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
353 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
354 msg_uid = modest_tny_folder_get_header_unique_id (header);
356 /* Look for the window */
357 if (priv->window_list)
358 win = g_list_find_custom (priv->window_list,
360 (GCompareFunc) compare_msguids);
364 /* Return the window */
372 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
375 ModestWindowMgrPrivate *priv;
378 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
380 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
382 /* If there is no change do nothing */
383 if (priv->fullscreen_mode == on)
386 priv->fullscreen_mode = on;
389 win = priv->window_list;
392 gtk_window_fullscreen (GTK_WINDOW (win->data));
393 modest_window_show_toolbar (MODEST_WINDOW (win->data),
394 priv->show_toolbars_fullscreen);
396 gtk_window_unfullscreen (GTK_WINDOW (win->data));
397 modest_window_show_toolbar (MODEST_WINDOW (win->data),
398 priv->show_toolbars);
400 win = g_list_next (win);
405 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
407 ModestWindowMgrPrivate *priv;
409 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
411 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
413 return priv->fullscreen_mode;
417 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
418 gboolean show_toolbars,
421 ModestWindowMgrPrivate *priv;
423 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
425 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
427 /* If nothing changes then return. Otherwise cache it, do not
428 save to GConf for the moment, it will be done when all
429 windows become unregistered in order to avoid unnecessary
432 if (priv->show_toolbars_fullscreen == show_toolbars)
435 priv->show_toolbars_fullscreen = show_toolbars;
437 if (priv->show_toolbars == show_toolbars)
440 priv->show_toolbars = show_toolbars;
443 /* Apply now if the view mode is the right one */
444 if ((fullscreen && priv->fullscreen_mode) ||
445 (!fullscreen && !priv->fullscreen_mode)) {
447 GList *win = priv->window_list;
450 modest_window_show_toolbar (MODEST_WINDOW (win->data),
452 win = g_list_next (win);
458 modest_window_mgr_get_main_window (ModestWindowMgr *self)
460 ModestWindowMgrPrivate *priv;
462 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
464 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
466 return priv->main_window;
470 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
472 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
473 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
475 /* Forget this window,
476 * so hibernation will be allowed again if no windows are remembered: */
477 priv->windows_that_prevent_hibernation =
478 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
482 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
484 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
485 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
487 GtkWindow *window = GTK_WINDOW (widget);
489 priv->windows_that_prevent_hibernation =
490 g_slist_append (priv->windows_that_prevent_hibernation, window);
492 /* Allow hibernation again when the window has been hidden: */
493 g_signal_connect (window, "hide",
494 G_CALLBACK (on_nonhibernating_window_hide), self);
497 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
500 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
502 if (GTK_WIDGET_VISIBLE(window)) {
503 on_nonhibernating_window_show (GTK_WIDGET (window), self);
505 /* Wait for it to be shown: */
506 g_signal_connect (window, "show",
507 G_CALLBACK (on_nonhibernating_window_show), self);
511 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
513 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
515 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
517 /* Prevent hibernation if any open windows are currently
518 * preventing hibernation: */
519 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
523 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
525 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
527 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
529 /* Iterate over all windows */
530 GList *win = priv->window_list;
532 ModestWindow *window = MODEST_WINDOW (win->data);
534 /* This calls the vfunc,
535 * so each window can do its own thing: */
536 modest_window_save_state (window);
539 win = g_list_next (win);