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. Disconnect also the
320 delete-event handler, we won't need it anymore */
321 g_signal_handler_disconnect (window, handler_id);
322 gtk_widget_destroy (win->data);
324 /* If there are no more windows registered then exit program */
325 if (priv->window_list == NULL) {
326 ModestConf *conf = modest_runtime_get_conf ();
328 /* Save show toolbar status */
329 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN,
330 priv->show_toolbars_fullscreen, NULL);
331 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR,
332 priv->show_toolbars, NULL);
340 compare_msguids (ModestWindow *win,
343 const gchar *msg_uid;
345 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
348 /* Get message uid from msg window */
349 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
351 if (msg_uid && uid &&!strcmp (msg_uid, uid))
358 modest_window_mgr_find_window_by_header (ModestWindowMgr *self,
361 ModestWindowMgrPrivate *priv;
365 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
366 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
368 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
369 msg_uid = modest_tny_folder_get_header_unique_id (header);
371 /* Look for the window */
372 if (priv->window_list)
373 win = g_list_find_custom (priv->window_list,
375 (GCompareFunc) compare_msguids);
379 /* Return the window */
387 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
390 ModestWindowMgrPrivate *priv;
393 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
395 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
397 /* If there is no change do nothing */
398 if (priv->fullscreen_mode == on)
401 priv->fullscreen_mode = on;
404 win = priv->window_list;
407 gtk_window_fullscreen (GTK_WINDOW (win->data));
408 modest_window_show_toolbar (MODEST_WINDOW (win->data),
409 priv->show_toolbars_fullscreen);
411 gtk_window_unfullscreen (GTK_WINDOW (win->data));
412 modest_window_show_toolbar (MODEST_WINDOW (win->data),
413 priv->show_toolbars);
415 win = g_list_next (win);
420 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
422 ModestWindowMgrPrivate *priv;
424 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
426 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
428 return priv->fullscreen_mode;
432 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
433 gboolean show_toolbars,
436 ModestWindowMgrPrivate *priv;
438 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
440 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
442 /* If nothing changes then return. Otherwise cache it, do not
443 save to GConf for the moment, it will be done when all
444 windows become unregistered in order to avoid unnecessary
447 if (priv->show_toolbars_fullscreen == show_toolbars)
450 priv->show_toolbars_fullscreen = show_toolbars;
452 if (priv->show_toolbars == show_toolbars)
455 priv->show_toolbars = show_toolbars;
458 /* Apply now if the view mode is the right one */
459 if ((fullscreen && priv->fullscreen_mode) ||
460 (!fullscreen && !priv->fullscreen_mode)) {
462 GList *win = priv->window_list;
465 modest_window_show_toolbar (MODEST_WINDOW (win->data),
467 win = g_list_next (win);
473 modest_window_mgr_get_main_window (ModestWindowMgr *self)
475 ModestWindowMgrPrivate *priv;
477 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
479 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
481 return priv->main_window;
485 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
487 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
488 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
490 /* Forget this window,
491 * so hibernation will be allowed again if no windows are remembered: */
492 priv->windows_that_prevent_hibernation =
493 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
497 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
499 ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
500 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
502 GtkWindow *window = GTK_WINDOW (widget);
504 priv->windows_that_prevent_hibernation =
505 g_slist_append (priv->windows_that_prevent_hibernation, window);
507 /* Allow hibernation again when the window has been hidden: */
508 g_signal_connect (window, "hide",
509 G_CALLBACK (on_nonhibernating_window_hide), self);
512 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
515 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
517 if (GTK_WIDGET_VISIBLE(window)) {
518 on_nonhibernating_window_show (GTK_WIDGET (window), self);
520 /* Wait for it to be shown: */
521 g_signal_connect (window, "show",
522 G_CALLBACK (on_nonhibernating_window_show), self);
526 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
528 g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
530 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
532 /* Prevent hibernation if any open windows are currently
533 * preventing hibernation: */
534 return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
538 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
540 g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
542 ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
544 /* Iterate over all windows */
545 GList *win = priv->window_list;
547 ModestWindow *window = MODEST_WINDOW (win->data);
549 /* This calls the vfunc,
550 * so each window can do its own thing: */
551 modest_window_save_state (window);
554 win = g_list_next (win);