evolution-3.6.4/shell/e-shell.c

No issues found

   1 /*
   2  * e-shell.c
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) version 3.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  19  *
  20  */
  21 
  22 /**
  23  * SECTION: e-shell
  24  * @short_description: the backbone of Evolution
  25  * @include: shell/e-shell.h
  26  **/
  27 
  28 #ifdef HAVE_CONFIG_H
  29 #include <config.h>
  30 #endif
  31 
  32 #include "e-shell.h"
  33 
  34 #include <glib/gi18n.h>
  35 #include <libebackend/libebackend.h>
  36 #include <libedataserverui/libedataserverui.h>
  37 
  38 #include "e-util/e-util.h"
  39 #include "e-util/e-util-private.h"
  40 #include "smclient/eggsmclient.h"
  41 #include "widgets/misc/e-preferences-window.h"
  42 
  43 #include "e-shell-backend.h"
  44 #include "e-shell-enumtypes.h"
  45 #include "e-shell-window.h"
  46 #include "e-shell-utils.h"
  47 
  48 #define E_SHELL_GET_PRIVATE(obj) \
  49 	(G_TYPE_INSTANCE_GET_PRIVATE \
  50 	((obj), E_TYPE_SHELL, EShellPrivate))
  51 
  52 struct _EShellPrivate {
  53 	GQueue alerts;
  54 	EShellSettings *settings;
  55 	ESourceRegistry *registry;
  56 	GActionGroup *action_group;
  57 	GtkWidget *preferences_window;
  58 
  59 	/* Shell Backends */
  60 	GList *loaded_backends;              /* not referenced */
  61 	GHashTable *backends_by_name;
  62 	GHashTable *backends_by_scheme;
  63 
  64 	gpointer preparing_for_line_change;  /* weak pointer */
  65 	gpointer preparing_for_quit;         /* weak pointer */
  66 
  67 	gchar *geometry;
  68 	gchar *module_directory;
  69 
  70 	gchar *startup_view;
  71 
  72 	guint auto_reconnect		: 1;
  73 	guint express_mode		: 1;
  74 	guint meego_mode		: 1;
  75 	guint modules_loaded		: 1;
  76 	guint network_available		: 1;
  77 	guint network_available_locked	: 1;
  78 	guint online			: 1;
  79 	guint quit_cancelled		: 1;
  80 	guint safe_mode			: 1;
  81 	guint small_screen_mode		: 1;
  82 };
  83 
  84 enum {
  85 	PROP_0,
  86 	PROP_EXPRESS_MODE,
  87 	PROP_MEEGO_MODE,
  88 	PROP_SMALL_SCREEN_MODE,
  89 	PROP_GEOMETRY,
  90 	PROP_MODULE_DIRECTORY,
  91 	PROP_NETWORK_AVAILABLE,
  92 	PROP_ONLINE,
  93 	PROP_REGISTRY,
  94 	PROP_SHELL_SETTINGS
  95 };
  96 
  97 enum {
  98 	EVENT,
  99 	HANDLE_URI,
 100 	PREPARE_FOR_OFFLINE,
 101 	PREPARE_FOR_ONLINE,
 102 	PREPARE_FOR_QUIT,
 103 	QUIT_REQUESTED,
 104 	LAST_SIGNAL
 105 };
 106 
 107 enum {
 108 	DEBUG_KEY_SETTINGS = 1 << 0
 109 };
 110 
 111 static GDebugKey debug_keys[] = {
 112 	{ "settings",	DEBUG_KEY_SETTINGS }
 113 };
 114 
 115 static gpointer default_shell;
 116 static guint signals[LAST_SIGNAL];
 117 
 118 /* Forward Declarations */
 119 static void e_shell_initable_init (GInitableIface *interface);
 120 
 121 G_DEFINE_TYPE_WITH_CODE (
 122 	EShell,
 123 	e_shell,
 124 	GTK_TYPE_APPLICATION,
 125 	G_IMPLEMENT_INTERFACE (
 126 		G_TYPE_INITABLE, e_shell_initable_init)
 127 	G_IMPLEMENT_INTERFACE (
 128 		E_TYPE_EXTENSIBLE, NULL))
 129 
 130 static void
 131 shell_parse_debug_string (EShell *shell)
 132 {
 133 	guint flags;
 134 
 135 	flags = g_parse_debug_string (
 136 		g_getenv ("EVOLUTION_DEBUG"),
 137 		debug_keys, G_N_ELEMENTS (debug_keys));
 138 
 139 	if (flags & DEBUG_KEY_SETTINGS)
 140 		e_shell_settings_enable_debug (shell->priv->settings);
 141 }
 142 
 143 static void
 144 shell_alert_response_cb (EShell *shell,
 145                          gint response_id,
 146                          EAlert *alert)
 147 {
 148 	g_signal_handlers_disconnect_by_func (
 149 		alert, shell_alert_response_cb, shell);
 150 
 151 	g_queue_remove (&shell->priv->alerts, alert);
 152 
 153 	g_object_unref (alert);
 154 }
 155 
 156 static void
 157 shell_notify_online_cb (EShell *shell)
 158 {
 159 	gboolean online;
 160 
 161 	online = e_shell_get_online (shell);
 162 	e_passwords_set_online (online);
 163 }
 164 
 165 static gboolean
 166 shell_window_delete_event_cb (GtkWindow *window,
 167                               GdkEvent *event,
 168                               GtkApplication *application)
 169 {
 170 	/* If other windows are open we can safely close this one. */
 171 	if (g_list_length (gtk_application_get_windows (application)) > 1)
 172 		return FALSE;
 173 
 174 	/* Otherwise we initiate application quit. */
 175 	e_shell_quit (E_SHELL (application), E_SHELL_QUIT_LAST_WINDOW);
 176 
 177 	return TRUE;
 178 }
 179 
 180 static void
 181 shell_action_new_window_cb (GSimpleAction *action,
 182                             GVariant *parameter,
 183                             EShell *shell)
 184 {
 185 	GtkApplication *application;
 186 	GList *list;
 187 	const gchar *view_name;
 188 
 189 	application = GTK_APPLICATION (shell);
 190 	list = gtk_application_get_windows (application);
 191 
 192 	view_name = g_variant_get_string (parameter, NULL);
 193 
 194 	/* Present the first EShellWindow showing 'view_name'. */
 195 	while (list != NULL) {
 196 		GtkWindow *window = GTK_WINDOW (list->data);
 197 
 198 		if (E_IS_SHELL_WINDOW (window)) {
 199 			const gchar *active_view;
 200 
 201 			active_view = e_shell_window_get_active_view (
 202 				E_SHELL_WINDOW (window));
 203 			if (g_strcmp0 (active_view, view_name) == 0) {
 204 				gtk_window_present (window);
 205 				return;
 206 			}
 207 		}
 208 
 209 		list = g_list_next (list);
 210 	}
 211 
 212 	/* No suitable EShellWindow found, so create one. */
 213 	e_shell_create_shell_window (shell, view_name);
 214 }
 215 
 216 static void
 217 shell_action_handle_uris_cb (GSimpleAction *action,
 218                              GVariant *parameter,
 219                              EShell *shell)
 220 {
 221 	const gchar **uris;
 222 
 223 	/* Do not use g_strfreev() here. */
 224 	uris = g_variant_get_strv (parameter, NULL);
 225 	e_shell_handle_uris (shell, uris, FALSE);
 226 	g_free (uris);
 227 }
 228 
 229 static void
 230 shell_action_quit_cb (GSimpleAction *action,
 231                       GVariant *parameter,
 232                       EShell *shell)
 233 {
 234 	e_shell_quit (shell, E_SHELL_QUIT_REMOTE_REQUEST);
 235 }
 236 
 237 static void
 238 shell_add_actions (GApplication *application)
 239 {
 240 	EShell *shell;
 241 	GSimpleActionGroup *action_group;
 242 	GSimpleAction *action;
 243 
 244 	/* Add actions that remote instances can invoke. */
 245 
 246 	action_group = g_simple_action_group_new ();
 247 
 248 	action = g_simple_action_new ("new-window", G_VARIANT_TYPE_STRING);
 249 	g_signal_connect (
 250 		action, "activate",
 251 		G_CALLBACK (shell_action_new_window_cb), application);
 252 	g_simple_action_group_insert (action_group, G_ACTION (action));
 253 	g_object_unref (action);
 254 
 255 	action = g_simple_action_new (
 256 		"handle-uris", G_VARIANT_TYPE_STRING_ARRAY);
 257 	g_signal_connect (
 258 		action, "activate",
 259 		G_CALLBACK (shell_action_handle_uris_cb), application);
 260 	g_simple_action_group_insert (action_group, G_ACTION (action));
 261 	g_object_unref (action);
 262 
 263 	action = g_simple_action_new ("quit", NULL);
 264 	g_signal_connect (
 265 		action, "activate",
 266 		G_CALLBACK (shell_action_quit_cb), application);
 267 	g_simple_action_group_insert (action_group, G_ACTION (action));
 268 	g_object_unref (action);
 269 
 270 	shell = E_SHELL (application);
 271 	shell->priv->action_group = G_ACTION_GROUP (action_group);
 272 
 273 	g_application_set_action_group (
 274 		application, shell->priv->action_group);
 275 }
 276 
 277 static void
 278 shell_ready_for_offline (EShell *shell,
 279                          EActivity *activity,
 280                          gboolean is_last_ref)
 281 {
 282 	if (!is_last_ref)
 283 		return;
 284 
 285 	/* Increment the reference count so we can safely emit
 286 	 * a signal without triggering the toggle reference. */
 287 	g_object_ref (activity);
 288 
 289 	e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 290 
 291 	g_object_remove_toggle_ref (
 292 		G_OBJECT (activity), (GToggleNotify)
 293 		shell_ready_for_offline, shell);
 294 
 295 	/* Finalize the activity. */
 296 	g_object_unref (activity);
 297 
 298 	shell->priv->online = FALSE;
 299 	g_object_notify (G_OBJECT (shell), "online");
 300 }
 301 
 302 static void
 303 shell_prepare_for_offline (EShell *shell)
 304 {
 305 	/* Are preparations already in progress? */
 306 	if (shell->priv->preparing_for_line_change != NULL)
 307 		return;
 308 
 309 	shell->priv->preparing_for_line_change = e_activity_new ();
 310 
 311 	e_activity_set_text (
 312 		shell->priv->preparing_for_line_change,
 313 		_("Preparing to go offline..."));
 314 
 315 	g_object_add_toggle_ref (
 316 		G_OBJECT (shell->priv->preparing_for_line_change),
 317 		(GToggleNotify) shell_ready_for_offline, shell);
 318 
 319 	g_object_add_weak_pointer (
 320 		G_OBJECT (shell->priv->preparing_for_line_change),
 321 		&shell->priv->preparing_for_line_change);
 322 
 323 	g_signal_emit (
 324 		shell, signals[PREPARE_FOR_OFFLINE], 0,
 325 		shell->priv->preparing_for_line_change);
 326 
 327 	g_object_unref (shell->priv->preparing_for_line_change);
 328 }
 329 
 330 static void
 331 shell_ready_for_online (EShell *shell,
 332                         EActivity *activity,
 333                         gboolean is_last_ref)
 334 {
 335 	if (!is_last_ref)
 336 		return;
 337 
 338 	/* Increment the reference count so we can safely emit
 339 	 * a signal without triggering the toggle reference. */
 340 	g_object_ref (activity);
 341 
 342 	e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 343 
 344 	g_object_remove_toggle_ref (
 345 		G_OBJECT (activity), (GToggleNotify)
 346 		shell_ready_for_online, shell);
 347 
 348 	/* Finalize the activity. */
 349 	g_object_unref (activity);
 350 
 351 	shell->priv->online = TRUE;
 352 	g_object_notify (G_OBJECT (shell), "online");
 353 }
 354 
 355 static void
 356 shell_prepare_for_online (EShell *shell)
 357 {
 358 	/* Are preparations already in progress? */
 359 	if (shell->priv->preparing_for_line_change != NULL)
 360 		return;
 361 
 362 	shell->priv->preparing_for_line_change = e_activity_new ();
 363 
 364 	e_activity_set_text (
 365 		shell->priv->preparing_for_line_change,
 366 		_("Preparing to go online..."));
 367 
 368 	g_object_add_toggle_ref (
 369 		G_OBJECT (shell->priv->preparing_for_line_change),
 370 		(GToggleNotify) shell_ready_for_online, shell);
 371 
 372 	g_object_add_weak_pointer (
 373 		G_OBJECT (shell->priv->preparing_for_line_change),
 374 		&shell->priv->preparing_for_line_change);
 375 
 376 	g_signal_emit (
 377 		shell, signals[PREPARE_FOR_ONLINE], 0,
 378 		shell->priv->preparing_for_line_change);
 379 
 380 	g_object_unref (shell->priv->preparing_for_line_change);
 381 }
 382 
 383 static void
 384 shell_ready_for_quit (EShell *shell,
 385                       EActivity *activity,
 386                       gboolean is_last_ref)
 387 {
 388 	GtkApplication *application;
 389 	GList *list;
 390 
 391 	if (!is_last_ref)
 392 		return;
 393 
 394 	application = GTK_APPLICATION (shell);
 395 
 396 	/* Increment the reference count so we can safely emit
 397 	 * a signal without triggering the toggle reference. */
 398 	g_object_ref (activity);
 399 
 400 	e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 401 
 402 	g_object_remove_toggle_ref (
 403 		G_OBJECT (activity), (GToggleNotify)
 404 		shell_ready_for_quit, shell);
 405 
 406 	/* Finalize the activity. */
 407 	g_object_unref (activity);
 408 
 409 	/* Destroy all watched windows.  Note, we iterate over a -copy-
 410 	 * of the watched windows list because the act of destroying a
 411 	 * watched window will modify the watched windows list, which
 412 	 * would derail the iteration. */
 413 	list = g_list_copy (gtk_application_get_windows (application));
 414 	g_list_foreach (list, (GFunc) gtk_widget_destroy, NULL);
 415 	g_list_free (list);
 416 
 417 	if (gtk_main_level () > 0)
 418 		gtk_main_quit ();
 419 }
 420 
 421 static void
 422 shell_prepare_for_quit (EShell *shell)
 423 {
 424 	GtkApplication *application;
 425 	GList *list, *iter;
 426 
 427 	/* Are preparations already in progress? */
 428 	if (shell->priv->preparing_for_quit != NULL)
 429 		return;
 430 
 431 	application = GTK_APPLICATION (shell);
 432 
 433 	shell->priv->preparing_for_quit = e_activity_new ();
 434 
 435 	e_activity_set_text (
 436 		shell->priv->preparing_for_quit,
 437 		_("Preparing to quit..."));
 438 
 439 	g_object_add_toggle_ref (
 440 		G_OBJECT (shell->priv->preparing_for_quit),
 441 		(GToggleNotify) shell_ready_for_quit, shell);
 442 
 443 	g_object_add_weak_pointer (
 444 		G_OBJECT (shell->priv->preparing_for_quit),
 445 		&shell->priv->preparing_for_quit);
 446 
 447 	g_signal_emit (
 448 		shell, signals[PREPARE_FOR_QUIT], 0,
 449 		shell->priv->preparing_for_quit);
 450 
 451 	g_object_unref (shell->priv->preparing_for_quit);
 452 
 453 	/* Desensitize all watched windows to prevent user action. */
 454 	list = gtk_application_get_windows (application);
 455 	for (iter = list; iter != NULL; iter = iter->next)
 456 		gtk_widget_set_sensitive (GTK_WIDGET (iter->data), FALSE);
 457 }
 458 
 459 static gboolean
 460 shell_request_quit (EShell *shell,
 461                     EShellQuitReason reason)
 462 {
 463 	/* Are preparations already in progress? */
 464 	if (shell->priv->preparing_for_quit != NULL)
 465 		return TRUE;
 466 
 467 	/* Give the application a chance to cancel quit. */
 468 	shell->priv->quit_cancelled = FALSE;
 469 	g_signal_emit (shell, signals[QUIT_REQUESTED], 0, reason);
 470 
 471 	return !shell->priv->quit_cancelled;
 472 }
 473 
 474 /* Helper for shell_add_backend() */
 475 static void
 476 shell_split_and_insert_items (GHashTable *hash_table,
 477                               const gchar *items,
 478                               EShellBackend *shell_backend)
 479 {
 480 	gpointer key;
 481 	gchar **strv;
 482 	gint ii;
 483 
 484 	strv = g_strsplit_set (items, ":", -1);
 485 
 486 	for (ii = 0; strv[ii] != NULL; ii++) {
 487 		key = (gpointer) g_intern_string (strv[ii]);
 488 		g_hash_table_insert (hash_table, key, shell_backend);
 489 	}
 490 
 491 	g_strfreev (strv);
 492 }
 493 
 494 static void
 495 shell_process_backend (EShellBackend *shell_backend,
 496                        EShell *shell)
 497 {
 498 	EShellBackendClass *class;
 499 	GHashTable *backends_by_name;
 500 	GHashTable *backends_by_scheme;
 501 	const gchar *string;
 502 
 503 	class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 504 	backends_by_name = shell->priv->backends_by_name;
 505 	backends_by_scheme = shell->priv->backends_by_scheme;
 506 
 507 	if ((string = class->name) != NULL)
 508 		g_hash_table_insert (
 509 			backends_by_name, (gpointer)
 510 			g_intern_string (string), shell_backend);
 511 
 512 	if ((string = class->aliases) != NULL)
 513 		shell_split_and_insert_items (
 514 			backends_by_name, string, shell_backend);
 515 
 516 	if ((string = class->schemes) != NULL)
 517 		shell_split_and_insert_items (
 518 			backends_by_scheme, string, shell_backend);
 519 }
 520 
 521 static void
 522 shell_sm_quit_requested_cb (EShell *shell,
 523                             EggSMClient *sm_client)
 524 {
 525 	EShellQuitReason reason = E_SHELL_QUIT_SESSION_REQUEST;
 526 	gboolean will_quit;
 527 
 528 	/* If preparations are already in progress then we have already
 529 	 * committed ourselves to quitting, and can answer 'yes'. */
 530 	if (shell->priv->preparing_for_quit == NULL)
 531 		will_quit = shell_request_quit (shell, reason);
 532 	else
 533 		will_quit = TRUE;
 534 
 535 	egg_sm_client_will_quit (sm_client, will_quit);
 536 }
 537 
 538 static void
 539 shell_sm_quit_cancelled_cb (EShell *shell,
 540                             EggSMClient *sm_client)
 541 {
 542 	/* Nothing to do.  This is just to aid debugging. */
 543 }
 544 
 545 static void
 546 shell_sm_quit_cb (EShell *shell,
 547                   EggSMClient *sm_client)
 548 {
 549 	shell_prepare_for_quit (shell);
 550 }
 551 
 552 static void
 553 shell_set_express_mode (EShell *shell,
 554                         gboolean express_mode)
 555 {
 556 	shell->priv->express_mode = express_mode;
 557 }
 558 
 559 static void
 560 shell_set_meego_mode (EShell *shell,
 561                       gboolean is_meego)
 562 {
 563 	shell->priv->meego_mode = is_meego;
 564 }
 565 
 566 static void
 567 shell_set_small_screen_mode (EShell *shell,
 568                              gboolean small_screen)
 569 {
 570 	shell->priv->small_screen_mode = small_screen;
 571 }
 572 
 573 static void
 574 shell_set_geometry (EShell *shell,
 575                     const gchar *geometry)
 576 {
 577 	g_return_if_fail (shell->priv->geometry == NULL);
 578 
 579 	shell->priv->geometry = g_strdup (geometry);
 580 }
 581 
 582 static void
 583 shell_set_module_directory (EShell *shell,
 584                             const gchar *module_directory)
 585 {
 586 	g_return_if_fail (shell->priv->module_directory == NULL);
 587 
 588 	shell->priv->module_directory = g_strdup (module_directory);
 589 }
 590 
 591 static void
 592 shell_set_property (GObject *object,
 593                     guint property_id,
 594                     const GValue *value,
 595                     GParamSpec *pspec)
 596 {
 597 	switch (property_id) {
 598 		case PROP_EXPRESS_MODE:
 599 			shell_set_express_mode (
 600 				E_SHELL (object),
 601 				g_value_get_boolean (value));
 602 			return;
 603 
 604 		case PROP_MEEGO_MODE:
 605 			shell_set_meego_mode (
 606 				E_SHELL (object),
 607 				g_value_get_boolean (value));
 608 			return;
 609 
 610 		case PROP_SMALL_SCREEN_MODE:
 611 			shell_set_small_screen_mode (
 612 				E_SHELL (object),
 613 				g_value_get_boolean (value));
 614 			return;
 615 
 616 		case PROP_GEOMETRY:
 617 			shell_set_geometry (
 618 				E_SHELL (object),
 619 				g_value_get_string (value));
 620 			return;
 621 
 622 		case PROP_MODULE_DIRECTORY:
 623 			shell_set_module_directory (
 624 				E_SHELL (object),
 625 				g_value_get_string (value));
 626 			return;
 627 
 628 		case PROP_NETWORK_AVAILABLE:
 629 			e_shell_set_network_available (
 630 				E_SHELL (object),
 631 				g_value_get_boolean (value));
 632 			return;
 633 
 634 		case PROP_ONLINE:
 635 			e_shell_set_online (
 636 				E_SHELL (object),
 637 				g_value_get_boolean (value));
 638 			return;
 639 	}
 640 
 641 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 642 }
 643 
 644 static void
 645 shell_get_property (GObject *object,
 646                     guint property_id,
 647                     GValue *value,
 648                     GParamSpec *pspec)
 649 {
 650 	switch (property_id) {
 651 		case PROP_EXPRESS_MODE:
 652 			g_value_set_boolean (
 653 				value, e_shell_get_express_mode (
 654 				E_SHELL (object)));
 655 			return;
 656 
 657 		case PROP_MEEGO_MODE:
 658 			g_value_set_boolean (
 659 				value, e_shell_get_meego_mode (
 660 				E_SHELL (object)));
 661 			return;
 662 
 663 		case PROP_SMALL_SCREEN_MODE:
 664 			g_value_set_boolean (
 665 				value, e_shell_get_small_screen_mode (
 666 				E_SHELL (object)));
 667 			return;
 668 
 669 		case PROP_MODULE_DIRECTORY:
 670 			g_value_set_string (
 671 				value, e_shell_get_module_directory (
 672 				E_SHELL (object)));
 673 			return;
 674 
 675 		case PROP_NETWORK_AVAILABLE:
 676 			g_value_set_boolean (
 677 				value, e_shell_get_network_available (
 678 				E_SHELL (object)));
 679 			return;
 680 
 681 		case PROP_ONLINE:
 682 			g_value_set_boolean (
 683 				value, e_shell_get_online (
 684 				E_SHELL (object)));
 685 			return;
 686 
 687 		case PROP_REGISTRY:
 688 			g_value_set_object (
 689 				value, e_shell_get_registry (
 690 				E_SHELL (object)));
 691 			return;
 692 
 693 		case PROP_SHELL_SETTINGS:
 694 			g_value_set_object (
 695 				value, e_shell_get_shell_settings (
 696 				E_SHELL (object)));
 697 			return;
 698 	}
 699 
 700 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 701 }
 702 
 703 static void
 704 shell_dispose (GObject *object)
 705 {
 706 	EShellPrivate *priv;
 707 	EAlert *alert;
 708 
 709 	priv = E_SHELL_GET_PRIVATE (object);
 710 
 711 	while ((alert = g_queue_pop_head (&priv->alerts)) != NULL) {
 712 		g_signal_handlers_disconnect_by_func (
 713 			alert, shell_alert_response_cb, object);
 714 		g_object_unref (alert);
 715 	}
 716 
 717 	while ((alert = g_queue_pop_head (&priv->alerts)) != NULL) {
 718 		g_signal_handlers_disconnect_by_func (
 719 			alert, shell_alert_response_cb, object);
 720 		g_object_unref (alert);
 721 	}
 722 
 723 	if (priv->startup_view != NULL) {
 724 		g_free (priv->startup_view);
 725 		priv->startup_view = NULL;
 726 	}
 727 
 728 	if (priv->settings != NULL) {
 729 		g_object_unref (priv->settings);
 730 		priv->settings = NULL;
 731 	}
 732 
 733 	if (priv->registry != NULL) {
 734 		g_object_unref (priv->registry);
 735 		priv->registry = NULL;
 736 	}
 737 
 738 	if (priv->action_group != NULL) {
 739 		g_object_unref (priv->action_group);
 740 		priv->action_group = NULL;
 741 	}
 742 
 743 	if (priv->preferences_window != NULL) {
 744 		g_object_unref (priv->preferences_window);
 745 		priv->preferences_window = NULL;
 746 	}
 747 
 748 	if (priv->preparing_for_line_change != NULL) {
 749 		g_object_remove_weak_pointer (
 750 			G_OBJECT (priv->preparing_for_line_change),
 751 			&priv->preparing_for_line_change);
 752 	}
 753 
 754 	/* Chain up to parent's dispose() method. */
 755 	G_OBJECT_CLASS (e_shell_parent_class)->dispose (object);
 756 }
 757 
 758 static void
 759 shell_finalize (GObject *object)
 760 {
 761 	EShellPrivate *priv;
 762 
 763 	priv = E_SHELL_GET_PRIVATE (object);
 764 
 765 	g_hash_table_destroy (priv->backends_by_name);
 766 	g_hash_table_destroy (priv->backends_by_scheme);
 767 
 768 	g_list_foreach (priv->loaded_backends, (GFunc) g_object_unref, NULL);
 769 	g_list_free (priv->loaded_backends);
 770 
 771 	g_free (priv->geometry);
 772 	g_free (priv->module_directory);
 773 
 774 	/* Chain up to parent's finalize() method. */
 775 	G_OBJECT_CLASS (e_shell_parent_class)->finalize (object);
 776 }
 777 
 778 static void
 779 shell_constructed (GObject *object)
 780 {
 781 	GNetworkMonitor *monitor;
 782 
 783 	/* The first EShell instance is the default. */
 784 	if (default_shell == NULL) {
 785 		default_shell = object;
 786 		g_object_add_weak_pointer (object, &default_shell);
 787 	}
 788 
 789 	/* Synchronize network monitoring. */
 790 
 791 	monitor = g_network_monitor_get_default ();
 792 
 793 	g_object_bind_property (
 794 		monitor, "network-available",
 795 		object, "network-available",
 796 		G_BINDING_SYNC_CREATE);
 797 
 798 	/* Chain up to parent's constructed() method. */
 799 	G_OBJECT_CLASS (e_shell_parent_class)->constructed (object);
 800 }
 801 
 802 static void
 803 shell_startup (GApplication *application)
 804 {
 805 	e_file_lock_create ();
 806 
 807 	/* Destroy the lock file when the EShell is finalized
 808 	 * to indicate a clean shut down to the next session. */
 809 	g_object_weak_ref (
 810 		G_OBJECT (application),
 811 		(GWeakNotify) e_file_lock_destroy, NULL);
 812 
 813 	/* Chain up to parent's startup() method. */
 814 	G_APPLICATION_CLASS (e_shell_parent_class)->startup (application);
 815 }
 816 
 817 static void
 818 shell_activate (GApplication *application)
 819 {
 820 	GList *list;
 821 
 822 	/* Do not chain up.  Default method just emits a warning. */
 823 
 824 	list = gtk_application_get_windows (GTK_APPLICATION (application));
 825 
 826 	/* Present the first EShellWindow, if found. */
 827 	while (list != NULL) {
 828 		GtkWindow *window = GTK_WINDOW (list->data);
 829 
 830 		if (E_IS_SHELL_WINDOW (window)) {
 831 			gtk_window_present (window);
 832 			return;
 833 		}
 834 
 835 		list = g_list_next (list);
 836 	}
 837 
 838 	/* No EShellWindow found, so create one. */
 839 	e_shell_create_shell_window (E_SHELL (application), NULL);
 840 }
 841 
 842 static void
 843 shell_window_added (GtkApplication *application,
 844                     GtkWindow *window)
 845 {
 846 	gchar *role;
 847 
 848 	/* Chain up to parent's window_added() method. */
 849 	GTK_APPLICATION_CLASS (e_shell_parent_class)->
 850 		window_added (application, window);
 851 
 852 	g_signal_connect (
 853 		window, "delete-event",
 854 		G_CALLBACK (shell_window_delete_event_cb), application);
 855 
 856 	/* We use the window's own type name and memory
 857 	 * address to form a unique window role for X11. */
 858 	role = g_strdup_printf (
 859 		"%s-%" G_GINTPTR_FORMAT,
 860 		G_OBJECT_TYPE_NAME (window),
 861 		(gintptr) window);
 862 	gtk_window_set_role (window, role);
 863 	g_free (role);
 864 }
 865 
 866 static gboolean
 867 shell_initable_init (GInitable *initable,
 868                      GCancellable *cancellable,
 869                      GError **error)
 870 {
 871 	GApplication *application = G_APPLICATION (initable);
 872 	EShellPrivate *priv;
 873 
 874 	priv = E_SHELL_GET_PRIVATE (initable);
 875 
 876 	shell_add_actions (application);
 877 
 878 	priv->registry = e_source_registry_new_sync (cancellable, error);
 879 	if (priv->registry == NULL)
 880 		return FALSE;
 881 
 882 	if (!g_application_register (application, cancellable, error))
 883 		return FALSE;
 884 
 885 	return TRUE;
 886 }
 887 
 888 static void
 889 e_shell_class_init (EShellClass *class)
 890 {
 891 	GObjectClass *object_class;
 892 	GApplicationClass *application_class;
 893 	GtkApplicationClass *gtk_application_class;
 894 
 895 	g_type_class_add_private (class, sizeof (EShellPrivate));
 896 
 897 	object_class = G_OBJECT_CLASS (class);
 898 	object_class->set_property = shell_set_property;
 899 	object_class->get_property = shell_get_property;
 900 	object_class->dispose = shell_dispose;
 901 	object_class->finalize = shell_finalize;
 902 	object_class->constructed = shell_constructed;
 903 
 904 	application_class = G_APPLICATION_CLASS (class);
 905 	application_class->startup = shell_startup;
 906 	application_class->activate = shell_activate;
 907 
 908 	gtk_application_class = GTK_APPLICATION_CLASS (class);
 909 	gtk_application_class->window_added = shell_window_added;
 910 
 911 	/**
 912 	 * EShell:express-mode
 913 	 *
 914 	 * Express mode alters Evolution's user interface to be more
 915 	 * usable on devices with small screens.
 916 	 **/
 917 	g_object_class_install_property (
 918 		object_class,
 919 		PROP_EXPRESS_MODE,
 920 		g_param_spec_boolean (
 921 			"express-mode",
 922 			"Express Mode",
 923 			"Whether express mode is enabled",
 924 			FALSE,
 925 			G_PARAM_READWRITE |
 926 			G_PARAM_CONSTRUCT_ONLY));
 927 
 928 	/**
 929 	 * EShell:meego
 930 	 *
 931 	 * Are we running under meego - if so, adapt ourselves
 932 	 * to fit in well with their theming.
 933 	 **/
 934 	g_object_class_install_property (
 935 		object_class,
 936 		PROP_MEEGO_MODE,
 937 		g_param_spec_boolean (
 938 			"meego-mode",
 939 			"Meego Mode",
 940 			"Whether meego mode is enabled",
 941 			FALSE,
 942 			G_PARAM_READWRITE |
 943 			G_PARAM_CONSTRUCT_ONLY));
 944 
 945 	/**
 946 	 * EShell:small-screen
 947 	 *
 948 	 * Are we running with a small (1024x600) screen - if so, start
 949 	 * throwing the babies overboard to fit onto that screen size.
 950 	 **/
 951 	g_object_class_install_property (
 952 		object_class,
 953 		PROP_SMALL_SCREEN_MODE,
 954 		g_param_spec_boolean (
 955 			"small-screen-mode",
 956 			"Small Screen Mode",
 957 			"Whether we run on a rather small screen",
 958 			FALSE,
 959 			G_PARAM_READWRITE |
 960 			G_PARAM_CONSTRUCT_ONLY));
 961 
 962 	/**
 963 	 * EShell:geometry
 964 	 *
 965 	 * User-specified initial window geometry string to apply
 966 	 * to the first #EShellWindow created.
 967 	 **/
 968 	g_object_class_install_property (
 969 		object_class,
 970 		PROP_GEOMETRY,
 971 		g_param_spec_string (
 972 			"geometry",
 973 			"Geometry",
 974 			"Initial window geometry string",
 975 			NULL,
 976 			G_PARAM_WRITABLE |
 977 			G_PARAM_CONSTRUCT_ONLY));
 978 
 979 	/**
 980 	 * EShell:module-directory
 981 	 *
 982 	 * The directory from which to load #EModule<!-- -->s.
 983 	 **/
 984 	g_object_class_install_property (
 985 		object_class,
 986 		PROP_MODULE_DIRECTORY,
 987 		g_param_spec_string (
 988 			"module-directory",
 989 			"Module Directory",
 990 			"The directory from which to load EModules",
 991 			NULL,
 992 			G_PARAM_READWRITE |
 993 			G_PARAM_CONSTRUCT_ONLY));
 994 
 995 	/**
 996 	 * EShell:network-available
 997 	 *
 998 	 * Whether the network is available.
 999 	 **/
1000 	g_object_class_install_property (
1001 		object_class,
1002 		PROP_NETWORK_AVAILABLE,
1003 		g_param_spec_boolean (
1004 			"network-available",
1005 			"Network Available",
1006 			"Whether the network is available",
1007 			TRUE,
1008 			G_PARAM_READWRITE));
1009 
1010 	/**
1011 	 * EShell:online
1012 	 *
1013 	 * Whether the shell is online.
1014 	 **/
1015 	g_object_class_install_property (
1016 		object_class,
1017 		PROP_ONLINE,
1018 		g_param_spec_boolean (
1019 			"online",
1020 			"Online",
1021 			"Whether the shell is online",
1022 			FALSE,
1023 			G_PARAM_READWRITE |
1024 			G_PARAM_CONSTRUCT));
1025 
1026 	/**
1027 	 * EShell:registry
1028 	 *
1029 	 * The #ESourceRegistry manages #ESource instances.
1030 	 **/
1031 	g_object_class_install_property (
1032 		object_class,
1033 		PROP_REGISTRY,
1034 		g_param_spec_object (
1035 			"registry",
1036 			"Registry",
1037 			"Data source registry",
1038 			E_TYPE_SOURCE_REGISTRY,
1039 			G_PARAM_READABLE));
1040 
1041 	/**
1042 	 * EShell:settings
1043 	 *
1044 	 * The #EShellSettings object stores application settings.
1045 	 **/
1046 	g_object_class_install_property (
1047 		object_class,
1048 		PROP_SHELL_SETTINGS,
1049 		g_param_spec_object (
1050 			"shell-settings",
1051 			"Shell Settings",
1052 			"Application-wide settings",
1053 			E_TYPE_SHELL_SETTINGS,
1054 			G_PARAM_READABLE));
1055 
1056 	/**
1057 	 * EShell::event
1058 	 * @shell: the #EShell which emitted the signal
1059 	 * @event_data: data associated with the event
1060 	 *
1061 	 * This signal is used to broadcast custom events to the entire
1062 	 * application.  The nature of @event_data depends on the event
1063 	 * being broadcast.  The signal's detail denotes the event.
1064 	 **/
1065 	signals[EVENT] = g_signal_new (
1066 		"event",
1067 		G_OBJECT_CLASS_TYPE (object_class),
1068 		G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED | G_SIGNAL_ACTION,
1069 		0, NULL, NULL,
1070 		g_cclosure_marshal_VOID__POINTER,
1071 		G_TYPE_NONE, 1,
1072 		G_TYPE_POINTER);
1073 
1074 	/**
1075 	 * EShell::handle-uri
1076 	 * @shell: the #EShell which emitted the signal
1077 	 * @uri: the URI to be handled
1078 	 *
1079 	 * Emitted when @shell receives a URI to be handled, usually by
1080 	 * way of a command-line argument.  An #EShellBackend should listen
1081 	 * for this signal and try to handle the URI, usually by opening an
1082 	 * editor window for the identified resource.
1083 	 *
1084 	 * Returns: %TRUE if the URI could be handled, %FALSE otherwise
1085 	 **/
1086 	signals[HANDLE_URI] = g_signal_new (
1087 		"handle-uri",
1088 		G_OBJECT_CLASS_TYPE (object_class),
1089 		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1090 		G_STRUCT_OFFSET (EShellClass, handle_uri),
1091 		g_signal_accumulator_true_handled, NULL,
1092 		e_marshal_BOOLEAN__STRING,
1093 		G_TYPE_BOOLEAN, 1,
1094 		G_TYPE_STRING);
1095 
1096 	/**
1097 	 * EShell::prepare-for-offline
1098 	 * @shell: the #EShell which emitted the signal
1099 	 * @activity: the #EActivity for offline preparations
1100 	 *
1101 	 * Emitted when the user elects to work offline.  An #EShellBackend
1102 	 * should listen for this signal and make preparations for working
1103 	 * in offline mode.
1104 	 *
1105 	 * If preparations for working offline cannot immediately be
1106 	 * completed (such as when synchronizing with a remote server),
1107 	 * the #EShellBackend should reference the @activity until
1108 	 * preparations are complete, and then unreference the @activity.
1109 	 * This will delay Evolution from actually going to offline mode
1110 	 * until all backends have unreferenced @activity.
1111 	 **/
1112 	signals[PREPARE_FOR_OFFLINE] = g_signal_new (
1113 		"prepare-for-offline",
1114 		G_OBJECT_CLASS_TYPE (object_class),
1115 		G_SIGNAL_RUN_FIRST,
1116 		G_STRUCT_OFFSET (EShellClass, prepare_for_offline),
1117 		NULL, NULL,
1118 		g_cclosure_marshal_VOID__OBJECT,
1119 		G_TYPE_NONE, 1,
1120 		E_TYPE_ACTIVITY);
1121 
1122 	/**
1123 	 * EShell::prepare-for-online
1124 	 * @shell: the #EShell which emitted the signal
1125 	 * @activity: the #EActivity for offline preparations
1126 	 *
1127 	 * Emitted when the user elects to work online.  An #EShellBackend
1128 	 * should listen for this signal and make preparations for working
1129 	 * in online mode.
1130 	 *
1131 	 * If preparations for working online cannot immediately be
1132 	 * completed (such as when re-connecting to a remote server), the
1133 	 * #EShellBackend should reference the @activity until preparations
1134 	 * are complete, and then unreference the @activity.  This will
1135 	 * delay Evolution from actually going to online mode until all
1136 	 * backends have unreferenced @activity.
1137 	 **/
1138 	signals[PREPARE_FOR_ONLINE] = g_signal_new (
1139 		"prepare-for-online",
1140 		G_OBJECT_CLASS_TYPE (object_class),
1141 		G_SIGNAL_RUN_FIRST,
1142 		G_STRUCT_OFFSET (EShellClass, prepare_for_online),
1143 		NULL, NULL,
1144 		g_cclosure_marshal_VOID__OBJECT,
1145 		G_TYPE_NONE, 1,
1146 		E_TYPE_ACTIVITY);
1147 
1148 	/**
1149 	 * EShell::prepare-for-quit
1150 	 * @shell: the #EShell which emitted the signal
1151 	 * @activity: the #EActivity for quit preparations
1152 	 *
1153 	 * Emitted when the user elects to quit the application, after
1154 	 * #EShell::quit-requested.  An #EShellBackend should listen for
1155 	 * this signal and make preparations for shutting down.
1156 	 *
1157 	 * If preparations for shutting down cannot immediately be completed
1158 	 * (such as when there are uncompleted network operations), the
1159 	 * #EShellBackend should reference the @activity until preparations
1160 	 * are complete, and then unreference the @activity.  This will
1161 	 * delay Evolution from actually shutting down until all backends
1162 	 * have unreferenced @activity.
1163 	 **/
1164 	signals[PREPARE_FOR_QUIT] = g_signal_new (
1165 		"prepare-for-quit",
1166 		G_OBJECT_CLASS_TYPE (object_class),
1167 		G_SIGNAL_RUN_FIRST,
1168 		G_STRUCT_OFFSET (EShellClass, prepare_for_quit),
1169 		NULL, NULL,
1170 		g_cclosure_marshal_VOID__OBJECT,
1171 		G_TYPE_NONE, 1,
1172 		E_TYPE_ACTIVITY);
1173 
1174 	/**
1175 	 * EShell::quit-requested
1176 	 * @shell: the #EShell which emitted the signal
1177 	 * @reason: the reason for quitting
1178 	 *
1179 	 * Emitted when the user elects to quit the application, before
1180 	 * #EShell::prepare-for-quit.
1181 	 *
1182 	 * #EShellBackend<!-- -->s and editor windows can listen for
1183 	 * this signal to prompt the user to save changes or finish
1184 	 * scheduled operations immediately (such as sending mail in
1185 	 * Outbox).  If the user elects to cancel, the signal handler
1186 	 * should call e_shell_cancel_quit() to abort the quit.
1187 	 **/
1188 	signals[QUIT_REQUESTED] = g_signal_new (
1189 		"quit-requested",
1190 		G_OBJECT_CLASS_TYPE (object_class),
1191 		G_SIGNAL_RUN_FIRST,
1192 		G_STRUCT_OFFSET (EShellClass, quit_requested),
1193 		NULL, NULL,
1194 		g_cclosure_marshal_VOID__ENUM,
1195 		G_TYPE_NONE, 1,
1196 		E_TYPE_SHELL_QUIT_REASON);
1197 }
1198 
1199 static void
1200 e_shell_initable_init (GInitableIface *interface)
1201 {
1202 	interface->init = shell_initable_init;
1203 }
1204 
1205 static void
1206 e_shell_init (EShell *shell)
1207 {
1208 	GHashTable *backends_by_name;
1209 	GHashTable *backends_by_scheme;
1210 	GtkIconTheme *icon_theme;
1211 	EggSMClient *sm_client;
1212 
1213 	shell->priv = E_SHELL_GET_PRIVATE (shell);
1214 
1215 	backends_by_name = g_hash_table_new (g_str_hash, g_str_equal);
1216 	backends_by_scheme = g_hash_table_new (g_str_hash, g_str_equal);
1217 
1218 	g_queue_init (&shell->priv->alerts);
1219 
1220 	shell->priv->settings = g_object_new (E_TYPE_SHELL_SETTINGS, NULL);
1221 	shell->priv->preferences_window = e_preferences_window_new (shell);
1222 	shell->priv->backends_by_name = backends_by_name;
1223 	shell->priv->backends_by_scheme = backends_by_scheme;
1224 	shell->priv->safe_mode = e_file_lock_exists ();
1225 
1226 	shell->priv->startup_view = NULL;
1227 
1228 	g_object_ref_sink (shell->priv->preferences_window);
1229 
1230 	/* Add our icon directory to the theme's search path
1231 	 * here instead of in main() so Anjal picks it up. */
1232 	icon_theme = gtk_icon_theme_get_default ();
1233 	gtk_icon_theme_append_search_path (icon_theme, EVOLUTION_ICONDIR);
1234 
1235 	shell_parse_debug_string (shell);
1236 
1237 	g_signal_connect (
1238 		shell, "notify::online",
1239 		G_CALLBACK (shell_notify_online_cb), NULL);
1240 
1241 	/* XXX Do this after creating the EShellSettings instance,
1242 	 *     otherwise the GSettings bindings will not get set up. */
1243 
1244 	e_shell_settings_install_property_for_key (
1245 		"start-offline",
1246 		"org.gnome.evolution.shell",
1247 		"start-offline");
1248 
1249 	/*** Session Management ***/
1250 
1251 	sm_client = egg_sm_client_get ();
1252 
1253 	/* Not participating in session saving yet. */
1254 	egg_sm_client_set_mode (EGG_SM_CLIENT_MODE_NO_RESTART);
1255 
1256 	g_signal_connect_swapped (
1257 		sm_client, "quit-requested",
1258 		G_CALLBACK (shell_sm_quit_requested_cb), shell);
1259 
1260 	g_signal_connect_swapped (
1261 		sm_client, "quit-cancelled",
1262 		G_CALLBACK (shell_sm_quit_cancelled_cb), shell);
1263 
1264 	g_signal_connect_swapped (
1265 		sm_client, "quit",
1266 		G_CALLBACK (shell_sm_quit_cb), shell);
1267 }
1268 
1269 /**
1270  * e_shell_get_default:
1271  *
1272  * Returns the #EShell created by <function>main()</function>.
1273  *
1274  * Try to obtain the #EShell from elsewhere if you can.  This function
1275  * is intended as a temporary workaround for when that proves difficult.
1276  *
1277  * Returns: the #EShell singleton
1278  **/
1279 EShell *
1280 e_shell_get_default (void)
1281 {
1282 	return default_shell;
1283 }
1284 
1285 /**
1286  * e_shell_load_modules:
1287  * @shell: an #EShell
1288  *
1289  * Loads all installed modules and performs some internal bookkeeping.
1290  * This function should be called after creating the #EShell instance
1291  * but before initiating migration or starting the main loop.
1292  **/
1293 void
1294 e_shell_load_modules (EShell *shell)
1295 {
1296 	const gchar *module_directory;
1297 	GList *list;
1298 
1299 	g_return_if_fail (E_IS_SHELL (shell));
1300 
1301 	if (shell->priv->modules_loaded)
1302 		return;
1303 
1304 	/* Load all shared library modules. */
1305 
1306 	module_directory = e_shell_get_module_directory (shell);
1307 	g_return_if_fail (module_directory != NULL);
1308 
1309 	list = e_module_load_all_in_directory (module_directory);
1310 	g_list_foreach (list, (GFunc) g_type_module_unuse, NULL);
1311 	g_list_free (list);
1312 
1313 	/* Process shell backends. */
1314 
1315 	list = g_list_sort (
1316 		e_extensible_list_extensions (
1317 		E_EXTENSIBLE (shell), E_TYPE_SHELL_BACKEND),
1318 		(GCompareFunc) e_shell_backend_compare);
1319 	g_list_foreach (list, (GFunc) shell_process_backend, shell);
1320 	shell->priv->loaded_backends = list;
1321 
1322 	shell->priv->modules_loaded = TRUE;
1323 }
1324 
1325 /**
1326  * e_shell_get_shell_backends:
1327  * @shell: an #EShell
1328  *
1329  * Returns a list of loaded #EShellBackend instances.  The list is
1330  * owned by @shell and should not be modified or freed.
1331  *
1332  * Returns: a list of loaded #EShellBackend instances
1333  **/
1334 GList *
1335 e_shell_get_shell_backends (EShell *shell)
1336 {
1337 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1338 
1339 	return shell->priv->loaded_backends;
1340 }
1341 
1342 /**
1343  * e_shell_get_canonical_name:
1344  * @shell: an #EShell
1345  * @name: the name or alias of an #EShellBackend
1346  *
1347  * Returns the canonical name for the #EShellBackend whose name or alias
1348  * is @name.
1349  *
1350  * Returns: the canonical #EShellBackend name
1351  **/
1352 const gchar *
1353 e_shell_get_canonical_name (EShell *shell,
1354                             const gchar *name)
1355 {
1356 	EShellBackend *shell_backend;
1357 
1358 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1359 
1360 	/* Handle NULL or empty name arguments silently. */
1361 	if (name == NULL || *name == '\0')
1362 		return NULL;
1363 
1364 	shell_backend = e_shell_get_backend_by_name (shell, name);
1365 
1366 	if (shell_backend == NULL)
1367 		return NULL;
1368 
1369 	return E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
1370 }
1371 
1372 /**
1373  * e_shell_get_backend_by_name:
1374  * @shell: an #EShell
1375  * @name: the name or alias of an #EShellBackend
1376  *
1377  * Returns the corresponding #EShellBackend for the given name or alias,
1378  * or %NULL if @name is not recognized.
1379  *
1380  * Returns: the #EShellBackend named @name, or %NULL
1381  **/
1382 EShellBackend *
1383 e_shell_get_backend_by_name (EShell *shell,
1384                              const gchar *name)
1385 {
1386 	GHashTable *hash_table;
1387 
1388 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1389 	g_return_val_if_fail (name != NULL, NULL);
1390 
1391 	hash_table = shell->priv->backends_by_name;
1392 
1393 	return g_hash_table_lookup (hash_table, name);
1394 }
1395 
1396 /**
1397  * e_shell_get_backend_by_scheme:
1398  * @shell: an #EShell
1399  * @scheme: a URI scheme
1400  *
1401  * Returns the #EShellBackend that implements the given URI scheme,
1402  * or %NULL if @scheme is not recognized.
1403  *
1404  * Returns: the #EShellBackend that implements @scheme, or %NULL
1405  **/
1406 EShellBackend *
1407 e_shell_get_backend_by_scheme (EShell *shell,
1408                                const gchar *scheme)
1409 {
1410 	GHashTable *hash_table;
1411 
1412 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1413 	g_return_val_if_fail (scheme != NULL, NULL);
1414 
1415 	hash_table = shell->priv->backends_by_scheme;
1416 
1417 	return g_hash_table_lookup (hash_table, scheme);
1418 }
1419 
1420 /**
1421  * e_shell_get_shell_settings:
1422  * @shell: an #EShell
1423  *
1424  * Returns the #EShellSettings instance for @shell.
1425  *
1426  * Returns: the #EShellSettings instance for @shell
1427  **/
1428 EShellSettings *
1429 e_shell_get_shell_settings (EShell *shell)
1430 {
1431 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1432 
1433 	return shell->priv->settings;
1434 }
1435 
1436 /**
1437  * e_shell_get_registry:
1438  * @shell: an #EShell
1439  *
1440  * Returns the shell's #ESourceRegistry which holds all #ESource instances.
1441  *
1442  * Returns: the #ESourceRegistry
1443  **/
1444 ESourceRegistry *
1445 e_shell_get_registry (EShell *shell)
1446 {
1447 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1448 
1449 	return shell->priv->registry;
1450 }
1451 
1452 /**
1453  * e_shell_create_shell_window:
1454  * @shell: an #EShell
1455  * @view_name: name of the initial shell view, or %NULL
1456  *
1457  * Creates a new #EShellWindow.  Use this function instead of
1458  * e_shell_window_new() so that @shell can properly configure
1459  * the window.
1460  *
1461  * Returns: a new #EShellWindow
1462  **/
1463 GtkWidget *
1464 e_shell_create_shell_window (EShell *shell,
1465                              const gchar *view_name)
1466 {
1467 	GtkWidget *shell_window;
1468 	GList *link;
1469 
1470 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1471 
1472 	if (g_application_get_is_remote (G_APPLICATION (shell)))
1473 		goto remote;
1474 
1475 	view_name = e_shell_get_canonical_name (shell, view_name);
1476 
1477 	/* EShellWindow initializes its active view from a GSetting key,
1478 	 * so set the key ahead of time to control the intial view. */
1479 	if (view_name != NULL) {
1480 		GSettings *settings;
1481 
1482 		settings = g_settings_new ("org.gnome.evolution.shell");
1483 		g_settings_set_string (
1484 			settings, "default-component-id", view_name);
1485 		g_object_unref (settings);
1486 	}
1487 
1488 	shell_window = e_shell_window_new (
1489 		shell,
1490 		shell->priv->safe_mode,
1491 		shell->priv->geometry);
1492 
1493 	/* Submit any outstanding alerts. */
1494 	link = g_queue_peek_head_link (&shell->priv->alerts);
1495 	while (link != NULL) {
1496 		e_alert_sink_submit_alert (
1497 			E_ALERT_SINK (shell_window),
1498 			E_ALERT (link->data));
1499 		link = g_list_next (link);
1500 	}
1501 
1502 	/* Clear the first-time-only options. */
1503 	shell->priv->safe_mode = FALSE;
1504 	g_free (shell->priv->geometry);
1505 	shell->priv->geometry = NULL;
1506 
1507 	gtk_widget_show (shell_window);
1508 
1509 	return shell_window;
1510 
1511 remote:  /* Send a message to the other Evolution process. */
1512 
1513 	if (view_name != NULL) {
1514 		g_action_group_activate_action (
1515 			G_ACTION_GROUP (shell), "new-window",
1516 			g_variant_new_string (view_name));
1517 	} else
1518 		g_application_activate (G_APPLICATION (shell));
1519 
1520 	return NULL;
1521 }
1522 
1523 /**
1524  * e_shell_handle_uris:
1525  * @shell: an #EShell
1526  * @uris: %NULL-terminated list of URIs
1527  * @do_import: request an import of the URIs
1528  *
1529  * Emits the #EShell::handle-uri signal for each URI.
1530  *
1531  * Returns: the number of URIs successfully handled
1532  **/
1533 guint
1534 e_shell_handle_uris (EShell *shell,
1535                      const gchar * const *uris,
1536                      gboolean do_import)
1537 {
1538 	guint n_handled = 0;
1539 	guint ii;
1540 
1541 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1542 	g_return_val_if_fail (uris != NULL, FALSE);
1543 
1544 	if (g_application_get_is_remote (G_APPLICATION (shell)))
1545 		goto remote;
1546 
1547 	if (do_import) {
1548 		n_handled = e_shell_utils_import_uris (shell, uris);
1549 	} else {
1550 		for (ii = 0; uris[ii] != NULL; ii++) {
1551 			gboolean handled;
1552 
1553 			g_signal_emit (
1554 				shell, signals[HANDLE_URI],
1555 				0, uris[ii], &handled);
1556 			n_handled += handled ? 1 : 0;
1557 		}
1558 
1559 		if (n_handled == 0)
1560 			n_handled = e_shell_utils_import_uris (shell, uris);
1561 	}
1562 
1563 	return n_handled;
1564 
1565 remote:  /* Send a message to the other Evolution process. */
1566 
1567 	g_action_group_activate_action (
1568 		G_ACTION_GROUP (shell), "handle-uris",
1569 		g_variant_new_strv (uris, -1));
1570 
1571 	/* As far as we're concerned, all URIs have been handled. */
1572 
1573 	return g_strv_length ((gchar **) uris);
1574 }
1575 
1576 /**
1577  * e_shell_submit_alert:
1578  * @shell: an #EShell
1579  * @alert: an #EAlert
1580  *
1581  * Broadcasts @alert to all #EShellWindow<!-- -->s.  This should only
1582  * be used for application-wide alerts such as a network outage.  Submit
1583  * view-specific alerts to the appropriate #EShellContent instance.
1584  **/
1585 void
1586 e_shell_submit_alert (EShell *shell,
1587                       EAlert *alert)
1588 {
1589 	GtkApplication *application;
1590 	GList *list, *iter;
1591 
1592 	g_return_if_fail (E_IS_SHELL (shell));
1593 	g_return_if_fail (E_IS_ALERT (alert));
1594 
1595 	application = GTK_APPLICATION (shell);
1596 
1597 	g_queue_push_tail (&shell->priv->alerts, g_object_ref (alert));
1598 
1599 	g_signal_connect_swapped (
1600 		alert, "response",
1601 		G_CALLBACK (shell_alert_response_cb), shell);
1602 
1603 	list = gtk_application_get_windows (application);
1604 
1605 	/* Submit the alert to all available EShellWindows. */
1606 	for (iter = list; iter != NULL; iter = g_list_next (iter))
1607 		if (E_IS_SHELL_WINDOW (iter->data))
1608 			e_alert_sink_submit_alert (
1609 				E_ALERT_SINK (iter->data), alert);
1610 }
1611 
1612 /**
1613  * e_shell_get_active_window:
1614  * @shell: an #EShell or %NULL to use the default shell
1615  *
1616  * Returns the most recently focused watched window, according to
1617  * gtk_application_get_windows().  Convenient for finding a parent
1618  * for a transient window.
1619  *
1620  * Note the returned window is not necessarily an #EShellWindow.
1621  *
1622  * Returns: the most recently focused watched window
1623  **/
1624 GtkWindow *
1625 e_shell_get_active_window (EShell *shell)
1626 {
1627 	GtkApplication *application;
1628 	GList *list;
1629 
1630 	if (shell == NULL)
1631 		shell = e_shell_get_default ();
1632 
1633 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1634 
1635 	application = GTK_APPLICATION (shell);
1636 	list = gtk_application_get_windows (application);
1637 
1638 	if (list == NULL)
1639 		return NULL;
1640 
1641 	/* Sanity check */
1642 	g_return_val_if_fail (GTK_IS_WINDOW (list->data), NULL);
1643 
1644 	return GTK_WINDOW (list->data);
1645 }
1646 
1647 /**
1648  * e_shell_get_express_mode:
1649  * @shell: an #EShell
1650  *
1651  * Returns %TRUE if Evolution is in express mode.
1652  *
1653  * Returns: %TRUE if Evolution is in express mode
1654  **/
1655 gboolean
1656 e_shell_get_express_mode (EShell *shell)
1657 {
1658 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1659 
1660 	return shell->priv->express_mode;
1661 }
1662 
1663 /**
1664  * e_shell_get_meego_mode:
1665  * @shell: an #EShell
1666  *
1667  * Returns %TRUE if Evolution is in MeeGo mode.
1668  *
1669  * Returns: %TRUE if Evolution is in MeeGo mode
1670  **/
1671 gboolean
1672 e_shell_get_meego_mode (EShell *shell)
1673 {
1674 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1675 
1676 	return shell->priv->meego_mode;
1677 }
1678 
1679 /**
1680  * e_shell_get_small_screen_mode:
1681  * @shell: an #EShell
1682  *
1683  * Returns %TRUE if Evolution is in small (netbook) screen mode.
1684  *
1685  * Returns: %TRUE if Evolution is in small screen mode
1686  **/
1687 gboolean
1688 e_shell_get_small_screen_mode (EShell *shell)
1689 {
1690 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1691 
1692 	return shell->priv->small_screen_mode;
1693 }
1694 
1695 /**
1696  * e_shell_get_module_directory:
1697  * @shell: an #EShell
1698  *
1699  * Returns the directory from which #EModule<!-- -->s were loaded.
1700  *
1701  * Returns: the #EModule directory
1702  **/
1703 const gchar *
1704 e_shell_get_module_directory (EShell *shell)
1705 {
1706 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1707 
1708 	return shell->priv->module_directory;
1709 }
1710 
1711 /**
1712  * e_shell_get_network_available:
1713  * @shell: an #EShell
1714  *
1715  * Returns %TRUE if a network is available.
1716  *
1717  * Returns: %TRUE if a network is available
1718  **/
1719 gboolean
1720 e_shell_get_network_available (EShell *shell)
1721 {
1722 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1723 
1724 	return shell->priv->network_available;
1725 }
1726 
1727 /**
1728  * e_shell_set_network_available:
1729  * @shell: an #EShell
1730  * @network_available: whether a network is available
1731  *
1732  * Sets whether a network is available.  This is usually called in
1733  * response to a status change signal from NetworkManager.  If the
1734  * network becomes unavailable while #EShell:online is %TRUE, the
1735  * @shell will force #EShell:online to %FALSE until the network
1736  * becomes available again.
1737  **/
1738 void
1739 e_shell_set_network_available (EShell *shell,
1740                                gboolean network_available)
1741 {
1742 	g_return_if_fail (E_IS_SHELL (shell));
1743 
1744 	if (shell->priv->network_available_locked)
1745 		return;
1746 
1747 	if (shell->priv->network_available == network_available)
1748 		return;
1749 
1750 	shell->priv->network_available = network_available;
1751 	g_object_notify (G_OBJECT (shell), "network-available");
1752 
1753 	/* If we're being forced offline, perhaps due to a network outage,
1754 	 * reconnect automatically when the network becomes available. */
1755 	if (!network_available && shell->priv->online) {
1756 		g_message ("Network disconnected.  Forced offline.");
1757 		e_shell_set_online (shell, FALSE);
1758 		shell->priv->auto_reconnect = TRUE;
1759 	} else if (network_available && shell->priv->auto_reconnect) {
1760 		g_message ("Connection established.  Going online.");
1761 		e_shell_set_online (shell, TRUE);
1762 		shell->priv->auto_reconnect = FALSE;
1763 	}
1764 }
1765 
1766 /**
1767  * e_shell_lock_network_available:
1768  * @shell: an #EShell
1769  *
1770  * Locks the value of #EShell:network-available to %TRUE.  Further
1771  * attempts to set the property will be ignored.
1772  *
1773  * This is used for the --force-online command-line option, which is
1774  * intended to override the network availability status as reported
1775  * by NetworkManager or other network monitoring software.
1776  **/
1777 void
1778 e_shell_lock_network_available (EShell *shell)
1779 {
1780 	g_return_if_fail (E_IS_SHELL (shell));
1781 
1782 	e_shell_set_network_available (shell, TRUE);
1783 	shell->priv->network_available_locked = TRUE;
1784 }
1785 
1786 /**
1787  * e_shell_get_online:
1788  * @shell: an #EShell
1789  *
1790  * Returns %TRUE if Evolution is online, %FALSE if Evolution is offline.
1791  * Evolution may be offline because the user elected to work offline, or
1792  * because the network has become unavailable.
1793  *
1794  * Returns: %TRUE if Evolution is online
1795  **/
1796 gboolean
1797 e_shell_get_online (EShell *shell)
1798 {
1799 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1800 
1801 	return shell->priv->online;
1802 }
1803 
1804 /**
1805  * e_shell_set_online:
1806  * @shell: an #EShell
1807  * @online: %TRUE to go online, %FALSE to go offline
1808  *
1809  * Asynchronously places Evolution in online or offline mode.
1810  **/
1811 void
1812 e_shell_set_online (EShell *shell,
1813                     gboolean online)
1814 {
1815 	g_return_if_fail (E_IS_SHELL (shell));
1816 
1817 	if (online == shell->priv->online)
1818 		return;
1819 
1820 	if (online)
1821 		shell_prepare_for_online (shell);
1822 	else
1823 		shell_prepare_for_offline (shell);
1824 }
1825 
1826 /**
1827  * e_shell_get_preferences_window:
1828  * @shell: an #EShell
1829  *
1830  * Returns the Evolution Preferences window.
1831  *
1832  * Returns: the preferences window
1833  **/
1834 GtkWidget *
1835 e_shell_get_preferences_window (EShell *shell)
1836 {
1837 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1838 
1839 	return shell->priv->preferences_window;
1840 }
1841 
1842 /**
1843  * e_shell_event:
1844  * @shell: an #EShell
1845  * @event_name: the name of the event
1846  * @event_data: data associated with the event
1847  *
1848  * The #EShell::event signal acts as a cheap mechanism for broadcasting
1849  * events to the rest of the application, such as new mail arriving.  The
1850  * @event_name is used as the signal detail, and @event_data may point to
1851  * an object or data structure associated with the event.
1852  **/
1853 void
1854 e_shell_event (EShell *shell,
1855                const gchar *event_name,
1856                gpointer event_data)
1857 {
1858 	GQuark detail;
1859 
1860 	g_return_if_fail (E_IS_SHELL (shell));
1861 	g_return_if_fail (event_name != NULL);
1862 
1863 	detail = g_quark_from_string (event_name);
1864 	g_signal_emit (shell, signals[EVENT], detail, event_data);
1865 }
1866 
1867 /**
1868  * e_shell_quit:
1869  * @shell: an #EShell
1870  * @reason: the reason for quitting
1871  *
1872  * Requests an application shutdown.  This happens in two phases: the
1873  * first is synchronous, the second is asynchronous.
1874  *
1875  * In the first phase, the @shell emits a #EShell::quit-requested signal
1876  * to potentially give the user a chance to cancel shutdown.  If the user
1877  * cancels shutdown, the function returns %FALSE.  Otherwise it proceeds
1878  * into the second phase.
1879  *
1880  * In the second phase, the @shell emits a #EShell::prepare-for-quit
1881  * signal and immediately returns %TRUE.  Signal handlers may delay the
1882  * actual application shutdown while they clean up resources, but there
1883  * is no way to cancel shutdown at this point.
1884  *
1885  * Consult the documentation for these two signals for details on how
1886  * to handle them.
1887  *
1888  * Returns: %TRUE if shutdown is underway, %FALSE if it was cancelled
1889  **/
1890 gboolean
1891 e_shell_quit (EShell *shell,
1892               EShellQuitReason reason)
1893 {
1894 	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
1895 
1896 	if (g_application_get_is_remote (G_APPLICATION (shell)))
1897 		goto remote;
1898 
1899 	if (!shell_request_quit (shell, reason))
1900 		return FALSE;
1901 
1902 	shell_prepare_for_quit (shell);
1903 
1904 	return TRUE;
1905 
1906 remote:  /* Send a message to the other Evolution process. */
1907 
1908 	g_action_group_activate_action (
1909 		G_ACTION_GROUP (shell), "quit", NULL);
1910 
1911 	return TRUE;
1912 }
1913 
1914 /**
1915  * e_shell_cancel_quit:
1916  * @shell: an #EShell
1917  *
1918  * This function may only be called from #EShell::quit-requested signal
1919  * handlers to prevent Evolution from quitting.  Calling this will stop
1920  * further emission of the #EShell::quit-requested signal.
1921  *
1922  * Note: This function has no effect during a #EShell::prepare-for-quit
1923  * signal emission.
1924  **/
1925 void
1926 e_shell_cancel_quit (EShell *shell)
1927 {
1928 	g_return_if_fail (E_IS_SHELL (shell));
1929 
1930 	shell->priv->quit_cancelled = TRUE;
1931 
1932 	g_signal_stop_emission (shell, signals[QUIT_REQUESTED], 0);
1933 }
1934 
1935 /**
1936  * e_shell_adapt_window_size:
1937  * @shell: an #EShell
1938  * @window: a #GtkWindow to adapt to full-screen
1939  *
1940  * This is used to adapt to window's size to be optimal for
1941  * the platform. The shell settings are used to determine if
1942  * a window should be set to full screen etc.
1943  *
1944  * This method is best called when the widget is realized on
1945  * a given screen.
1946  **/
1947 void
1948 e_shell_adapt_window_size (EShell *shell,
1949                            GtkWindow *window)
1950 {
1951 	GdkScreen *screen;
1952 	GdkRectangle rect;
1953 	GdkWindow *gdk_window;
1954 	gint monitor;
1955 
1956 	if (!e_shell_get_meego_mode (shell) ||
1957 	    !e_shell_get_small_screen_mode (shell))
1958 		return;
1959 
1960 	screen = gdk_screen_get_default ();
1961 	gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
1962 	monitor = gdk_screen_get_monitor_at_window (screen, gdk_window);
1963 	gdk_screen_get_monitor_geometry (screen, monitor, &rect);
1964 
1965 	gtk_window_set_default_size (window, rect.width, rect.height);
1966 	gtk_window_set_decorated (window, FALSE);
1967 	gtk_window_maximize (window);
1968 }
1969 
1970 void
1971 e_shell_set_startup_view (EShell *shell,
1972                           const gchar *view)
1973 {
1974 	g_return_if_fail (E_IS_SHELL (shell));
1975 
1976 	shell->priv->startup_view = g_strdup (view);
1977 }
1978 
1979 const gchar *
1980 e_shell_get_startup_view (EShell *shell)
1981 {
1982 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1983 
1984 	return shell->priv->startup_view;
1985 }