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)) {
256 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
257 /* Save currently edited message to Drafts if it was not sent */
258 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
260 modest_platform_run_confirmation_dialog (GTK_WINDOW (self),
261 _("mcen_nc_no_email_message_modified_save_changes"));
262 if (response != GTK_RESPONSE_CANCEL) {
263 modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
269 /* Unregister window */
270 modest_window_mgr_unregister_window (self, window);
274 modest_window_mgr_unregister_window (ModestWindowMgr *self,
275 ModestWindow *window)
278 ModestWindowMgrPrivate *priv;
279 gint *tmp, handler_id;
281 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
282 g_return_if_fail (MODEST_IS_WINDOW (window));
284 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
286 win = g_list_find (priv->window_list, window);
288 g_warning ("Trying to unregister a window that has not being registered yet");
292 /* If it's the main window unset it */
293 if (priv->main_window == window)
294 priv->main_window = NULL;
297 modest_window_save_state (window);
299 /* Remove from list & hash table */
300 priv->window_list = g_list_remove_link (priv->window_list, win);
301 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
303 g_hash_table_remove (priv->destroy_handlers, window);
305 /* Remove the reference to the window. We need to block the
306 destroy event handler to avoid recursive calls */
307 g_signal_handler_block (window, handler_id);
308 gtk_widget_destroy (win->data);
309 if (G_IS_OBJECT (window))
310 g_signal_handler_unblock (window, handler_id);
312 /* If there are no more windows registered then exit program */
313 if (priv->window_list == NULL) {
314 ModestConf *conf = modest_runtime_get_conf ();
316 /* Save show toolbar status */
317 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
318 priv->show_toolbars_fullscreen, NULL);
319 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
320 priv->show_toolbars, NULL);
328 compare_msguids (ModestWindow *win,
331 const gchar *msg_uid;
333 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
336 /* Get message uid from msg window */
337 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
339 if (msg_uid && uid &&!strcmp (msg_uid, uid))
346 modest_window_mgr_find_window_by_header (ModestWindowMgr *self,
349 ModestWindowMgrPrivate *priv;
353 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
354 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
356 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
357 msg_uid = modest_tny_folder_get_header_unique_id (header);
359 /* Look for the window */
360 if (priv->window_list)
361 win = g_list_find_custom (priv->window_list,
363 (GCompareFunc) compare_msguids);
367 /* Return the window */
375 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
378 ModestWindowMgrPrivate *priv;
381 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
383 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
385 /* If there is no change do nothing */
386 if (priv->fullscreen_mode == on)
389 priv->fullscreen_mode = on;
392 win = priv->window_list;
395 gtk_window_fullscreen (GTK_WINDOW (win->data));
396 modest_window_show_toolbar (MODEST_WINDOW (win->data),
397 priv->show_toolbars_fullscreen);
399 gtk_window_unfullscreen (GTK_WINDOW (win->data));
400 modest_window_show_toolbar (MODEST_WINDOW (win->data),
401 priv->show_toolbars);
403 win = g_list_next (win);
408 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
410 ModestWindowMgrPrivate *priv;
412 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
414 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
416 return priv->fullscreen_mode;
420 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
421 gboolean show_toolbars,
424 ModestWindowMgrPrivate *priv;
426 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
428 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
430 /* If nothing changes then return. Otherwise cache it, do not
431 save to GConf for the moment, it will be done when all
432 windows become unregistered in order to avoid unnecessary
435 if (priv->show_toolbars_fullscreen == show_toolbars)
438 priv->show_toolbars_fullscreen = show_toolbars;
440 if (priv->show_toolbars == show_toolbars)
443 priv->show_toolbars = show_toolbars;
446 /* Apply now if the view mode is the right one */
447 if ((fullscreen && priv->fullscreen_mode) ||
448 (!fullscreen && !priv->fullscreen_mode)) {
450 GList *win = priv->window_list;
453 modest_window_show_toolbar (MODEST_WINDOW (win->data),
455 win = g_list_next (win);
461 modest_window_mgr_get_main_window (ModestWindowMgr *self)
463 ModestWindowMgrPrivate *priv;
465 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
467 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
469 return priv->main_window;
473 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
475 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
476 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
478 /* Forget this window,
479 * so hibernation will be allowed again if no windows are remembered: */
480 priv->windows_that_prevent_hibernation =
481 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
485 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
487 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
488 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
490 GtkWindow *window = GTK_WINDOW (widget);
492 priv->windows_that_prevent_hibernation =
493 g_slist_append (priv->windows_that_prevent_hibernation, window);
495 /* Allow hibernation again when the window has been hidden: */
496 g_signal_connect (window, "hide",
497 G_CALLBACK (on_nonhibernating_window_hide), self);
500 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
503 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
505 if (GTK_WIDGET_VISIBLE(window)) {
506 on_nonhibernating_window_show (GTK_WIDGET (window), self);
508 /* Wait for it to be shown: */
509 g_signal_connect (window, "show",
510 G_CALLBACK (on_nonhibernating_window_show), self);
514 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
516 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
518 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
520 /* Prevent hibernation if any open windows are currently
521 * preventing hibernation: */
522 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
526 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
528 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
530 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
532 /* Iterate over all windows */
533 GList *win = priv->window_list;
535 ModestWindow *window = MODEST_WINDOW (win->data);
537 /* This calls the vfunc,
538 * so each window can do its own thing: */
539 modest_window_save_state (window);
542 win = g_list_next (win);