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 GHashTable *destroy_handlers;
70 #define MODEST_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
71 MODEST_TYPE_WINDOW_MGR, \
72 ModestWindowMgrPrivate))
74 static GObjectClass *parent_class = NULL;
76 /* uncomment the following if you have defined any signals */
77 /* static guint signals[LAST_SIGNAL] = {0}; */
80 modest_window_mgr_get_type (void)
82 static GType my_type = 0;
84 static const GTypeInfo my_info = {
85 sizeof(ModestWindowMgrClass),
87 NULL, /* base finalize */
88 (GClassInitFunc) modest_window_mgr_class_init,
89 NULL, /* class finalize */
90 NULL, /* class data */
91 sizeof(ModestWindowMgr),
93 (GInstanceInitFunc) modest_window_mgr_init,
96 my_type = g_type_register_static (G_TYPE_OBJECT,
104 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
106 GObjectClass *gobject_class;
107 gobject_class = (GObjectClass*) klass;
109 parent_class = g_type_class_peek_parent (klass);
110 gobject_class->finalize = modest_window_mgr_finalize;
112 g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
116 modest_window_mgr_init (ModestWindowMgr *obj)
118 ModestWindowMgrPrivate *priv;
120 priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
121 priv->window_list = NULL;
122 priv->main_window = NULL;
123 priv->fullscreen_mode = FALSE;
125 /* Could not initialize it from gconf, singletons are not
127 priv->show_toolbars = FALSE;
128 priv->show_toolbars_fullscreen = FALSE;
129 priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
133 modest_window_mgr_finalize (GObject *obj)
135 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
137 if (priv->window_list) {
138 GList *iter = priv->window_list;
139 /* unregister pending windows */
141 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj),
142 MODEST_WINDOW (iter->data));
143 iter = g_list_next (iter);
145 g_list_free (priv->window_list);
146 priv->window_list = NULL;
149 /* Free the hash table with the handlers */
150 if (priv->destroy_handlers) {
151 g_hash_table_destroy (priv->destroy_handlers);
152 priv->destroy_handlers = NULL;
155 /* Do not unref priv->main_window because it does not hold a
158 G_OBJECT_CLASS(parent_class)->finalize (obj);
162 modest_window_mgr_new (void)
164 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
168 modest_window_mgr_register_window (ModestWindowMgr *self,
169 ModestWindow *window)
171 static gboolean first_time = TRUE;
174 ModestWindowMgrPrivate *priv;
177 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
178 g_return_if_fail (MODEST_IS_WINDOW (window));
180 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
182 win = g_list_find (priv->window_list, window);
184 g_warning ("Trying to register an already registered window");
188 /* Check that it's not a second main window */
189 if (MODEST_IS_MAIN_WINDOW (window)) {
190 if (priv->main_window) {
191 g_warning ("Trying to register a second main window");
194 priv->main_window = window;
198 /* Add to list. Keep a reference to the window */
199 g_object_ref (window);
200 priv->window_list = g_list_prepend (priv->window_list, window);
202 /* Listen to object destruction */
203 handler_id = g_malloc0 (sizeof (gint));
204 *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
205 /* *handler_id = g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), self); */
206 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
208 /* Put into fullscreen if needed */
209 if (priv->fullscreen_mode)
210 gtk_window_fullscreen (GTK_WINDOW (window));
214 ModestConf *conf = modest_runtime_get_conf ();
215 priv->show_toolbars =
216 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
217 priv->show_toolbars_fullscreen =
218 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
222 /* Show/hide toolbar */
223 if (priv->fullscreen_mode)
224 show = priv->show_toolbars_fullscreen;
226 show = priv->show_toolbars;
227 modest_window_show_toolbar (window, show);
231 /* on_window_destroy (ModestWindow *window, ModestWindowMgr *self) */
233 on_window_destroy (ModestWindow *window,
235 ModestWindowMgr *self)
237 /* Specific stuff first */
238 if (MODEST_IS_MAIN_WINDOW (window)) {
239 ModestWindowMgrPrivate *priv;
240 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
242 /* If more than one window already opened */
243 if (g_list_length (priv->window_list) > 1) {
245 /* If the user wants to close all the windows */
246 if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
247 GList *iter = priv->window_list;
249 if (iter->data != window) {
250 GList *tmp = iter->next;
251 on_window_destroy (MODEST_WINDOW (iter->data),
256 iter = g_list_next (iter);
263 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
264 gboolean sent = FALSE;
265 gint response = GTK_RESPONSE_ACCEPT;
266 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
267 /* Save currently edited message to Drafts if it was not sent */
268 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
271 modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
272 _("mcen_nc_no_email_message_modified_save_changes"));
274 if (response != GTK_RESPONSE_CANCEL)
275 modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
281 /* Unregister window */
282 modest_window_mgr_unregister_window (self, window);
288 modest_window_mgr_unregister_window (ModestWindowMgr *self,
289 ModestWindow *window)
292 ModestWindowMgrPrivate *priv;
293 gint *tmp, handler_id;
295 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
296 g_return_if_fail (MODEST_IS_WINDOW (window));
298 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
300 win = g_list_find (priv->window_list, window);
302 g_warning ("Trying to unregister a window that has not being registered yet");
306 /* If it's the main window unset it */
307 if (priv->main_window == window)
308 priv->main_window = NULL;
311 modest_window_save_state (window);
313 /* Remove from list & hash table */
314 priv->window_list = g_list_remove_link (priv->window_list, win);
315 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
317 g_hash_table_remove (priv->destroy_handlers, window);
319 /* Remove the reference to the window. We need to block the
320 destroy event handler to avoid recursive calls */
321 g_signal_handler_block (window, handler_id);
322 gtk_widget_destroy (win->data);
323 if (G_IS_OBJECT (window))
324 g_signal_handler_unblock (window, handler_id);
326 /* If there are no more windows registered then exit program */
327 if (priv->window_list == NULL) {
328 ModestConf *conf = modest_runtime_get_conf ();
330 /* Save show toolbar status */
331 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
332 priv->show_toolbars_fullscreen, NULL);
333 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
334 priv->show_toolbars, NULL);
342 compare_msguids (ModestWindow *win,
345 const gchar *msg_uid;
347 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
350 /* Get message uid from msg window */
351 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
353 if (msg_uid && uid &&!strcmp (msg_uid, uid))
360 modest_window_mgr_find_window_by_header (ModestWindowMgr *self,
363 ModestWindowMgrPrivate *priv;
367 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
368 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
370 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
371 msg_uid = modest_tny_folder_get_header_unique_id (header);
373 /* Look for the window */
374 if (priv->window_list)
375 win = g_list_find_custom (priv->window_list,
377 (GCompareFunc) compare_msguids);
381 /* Return the window */
389 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
392 ModestWindowMgrPrivate *priv;
395 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
397 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
399 /* If there is no change do nothing */
400 if (priv->fullscreen_mode == on)
403 priv->fullscreen_mode = on;
406 win = priv->window_list;
409 gtk_window_fullscreen (GTK_WINDOW (win->data));
410 modest_window_show_toolbar (MODEST_WINDOW (win->data),
411 priv->show_toolbars_fullscreen);
413 gtk_window_unfullscreen (GTK_WINDOW (win->data));
414 modest_window_show_toolbar (MODEST_WINDOW (win->data),
415 priv->show_toolbars);
417 win = g_list_next (win);
422 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
424 ModestWindowMgrPrivate *priv;
426 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
428 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
430 return priv->fullscreen_mode;
434 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
435 gboolean show_toolbars,
438 ModestWindowMgrPrivate *priv;
440 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
442 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
444 /* If nothing changes then return. Otherwise cache it, do not
445 save to GConf for the moment, it will be done when all
446 windows become unregistered in order to avoid unnecessary
449 if (priv->show_toolbars_fullscreen == show_toolbars)
452 priv->show_toolbars_fullscreen = show_toolbars;
454 if (priv->show_toolbars == show_toolbars)
457 priv->show_toolbars = show_toolbars;
460 /* Apply now if the view mode is the right one */
461 if ((fullscreen && priv->fullscreen_mode) ||
462 (!fullscreen && !priv->fullscreen_mode)) {
464 GList *win = priv->window_list;
467 modest_window_show_toolbar (MODEST_WINDOW (win->data),
469 win = g_list_next (win);
475 modest_window_mgr_get_main_window (ModestWindowMgr *self)
477 ModestWindowMgrPrivate *priv;
479 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
481 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
483 return priv->main_window;
487 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
489 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
490 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
492 /* Forget this window,
493 * so hibernation will be allowed again if no windows are remembered: */
494 priv->windows_that_prevent_hibernation =
495 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
499 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
501 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
502 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
504 GtkWindow *window = GTK_WINDOW (widget);
506 priv->windows_that_prevent_hibernation =
507 g_slist_append (priv->windows_that_prevent_hibernation, window);
509 /* Allow hibernation again when the window has been hidden: */
510 g_signal_connect (window, "hide",
511 G_CALLBACK (on_nonhibernating_window_hide), self);
514 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
517 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
519 if (GTK_WIDGET_VISIBLE(window)) {
520 on_nonhibernating_window_show (GTK_WIDGET (window), self);
522 /* Wait for it to be shown: */
523 g_signal_connect (window, "show",
524 G_CALLBACK (on_nonhibernating_window_show), self);
528 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
530 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
532 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
534 /* Prevent hibernation if any open windows are currently
535 * preventing hibernation: */
536 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
540 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
542 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
544 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
546 /* Iterate over all windows */
547 GList *win = priv->window_list;
549 ModestWindow *window = MODEST_WINDOW (win->data);
551 /* This calls the vfunc,
552 * so each window can do its own thing: */
553 modest_window_save_state (window);
556 win = g_list_next (win);