1 /*
2  * e-shell-window.c
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  *
17  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
18  *
19  */
20 
21 /**
22  * SECTION: e-shell-window
23  * @short_description: the main window
24  * @include: shell/e-shell-window.h
25  **/
26 
27 #include "evolution-config.h"
28 
29 #include "e-shell-window-private.h"
30 
31 enum {
32 	PROP_0,
33 	PROP_ACTIVE_VIEW,
34 	PROP_ALERT_BAR,
35 	PROP_FOCUS_TRACKER,
36 	PROP_GEOMETRY,
37 	PROP_SAFE_MODE,
38 	PROP_SHELL,
39 	PROP_MENUBAR_VISIBLE,
40 	PROP_SIDEBAR_VISIBLE,
41 	PROP_SWITCHER_VISIBLE,
42 	PROP_TASKBAR_VISIBLE,
43 	PROP_TOOLBAR_VISIBLE,
44 	PROP_UI_MANAGER
45 };
46 
47 enum {
48 	CLOSE_ALERT,
49 	SHELL_VIEW_CREATED,
50 	LAST_SIGNAL
51 };
52 
53 static gulong signals[LAST_SIGNAL];
54 
55 /* Forward Declarations */
56 static void	e_shell_window_alert_sink_init
57 					(EAlertSinkInterface *iface);
58 
59 G_DEFINE_TYPE_WITH_CODE (
60 	EShellWindow,
61 	e_shell_window,
62 	GTK_TYPE_WINDOW,
63 	G_IMPLEMENT_INTERFACE (
64 		E_TYPE_ALERT_SINK, e_shell_window_alert_sink_init)
65 	G_IMPLEMENT_INTERFACE (
66 		E_TYPE_EXTENSIBLE, NULL))
67 
68 static const char *css =
69 ".table-header {\
70 	border-bottom: 1px solid @borders;\
71 }\
72 .button {\
73 	padding: 3px 5px;\
74 }\
75 .table-header .button {\
76 	border-right: 1px solid @borders;\
77 }\
78 .table-header .button.last {\
79 	border-right: none;\
80 }\
81 toolbar {\
82 	border-bottom: 1px solid @borders;\
83 }\
84 .taskbar border {\
85 	border-width: 1px 0 0 0;\
86 }\
87 .header-box {\
88 	border-bottom: 1px solid @borders;\
89 	padding: 3px;\
90 }\
91 #e-attachment-bar {\
92 	border-top: 1px solid @borders;\
93 }\
94 ";
95 
96 static void
shell_window_menubar_update_new_menu(EShellWindow * shell_window)97 shell_window_menubar_update_new_menu (EShellWindow *shell_window)
98 {
99 	GtkWidget *menu;
100 	GtkWidget *widget;
101 	const gchar *path;
102 
103 	/* Update the "File -> New" submenu. */
104 	path = "/main-menu/file-menu/new-menu";
105 	menu = e_shell_window_create_new_menu (shell_window);
106 	widget = e_shell_window_get_managed_widget (shell_window, path);
107 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), menu);
108 	gtk_widget_show (widget);
109 }
110 
111 static void
shell_window_toolbar_update_new_menu(GtkMenuToolButton * menu_tool_button,GParamSpec * pspec,EShellWindow * shell_window)112 shell_window_toolbar_update_new_menu (GtkMenuToolButton *menu_tool_button,
113                                       GParamSpec *pspec,
114                                       EShellWindow *shell_window)
115 {
116 	GtkWidget *menu;
117 
118 	/* Update the "New" menu tool button submenu. */
119 	menu = e_shell_window_create_new_menu (shell_window);
120 	gtk_menu_tool_button_set_menu (menu_tool_button, menu);
121 }
122 
123 static gboolean
shell_window_active_view_to_prefer_item(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)124 shell_window_active_view_to_prefer_item (GBinding *binding,
125                                          const GValue *source_value,
126                                          GValue *target_value,
127                                          gpointer user_data)
128 {
129 	GObject *source_object;
130 	EShell *shell;
131 	EShellBackend *shell_backend;
132 	const gchar *active_view;
133 	const gchar *prefer_item;
134 
135 	active_view = g_value_get_string (source_value);
136 
137 	source_object = g_binding_get_source (binding);
138 	shell = e_shell_window_get_shell (E_SHELL_WINDOW (source_object));
139 	shell_backend = e_shell_get_backend_by_name (shell, active_view);
140 	prefer_item = e_shell_backend_get_prefer_new_item (shell_backend);
141 
142 	g_value_set_string (target_value, prefer_item);
143 
144 	return TRUE;
145 }
146 
147 static void
shell_window_set_notebook_page(EShellWindow * shell_window,GParamSpec * pspec,GtkNotebook * notebook)148 shell_window_set_notebook_page (EShellWindow *shell_window,
149                                 GParamSpec *pspec,
150                                 GtkNotebook *notebook)
151 {
152 	EShellView *shell_view;
153 	const gchar *view_name;
154 	gint page_num;
155 
156 	view_name = e_shell_window_get_active_view (shell_window);
157 	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
158 
159 	page_num = e_shell_view_get_page_num (shell_view);
160 	g_return_if_fail (page_num >= 0);
161 
162 	gtk_notebook_set_current_page (notebook, page_num);
163 }
164 
165 static void
shell_window_online_button_clicked_cb(EOnlineButton * button,EShellWindow * shell_window)166 shell_window_online_button_clicked_cb (EOnlineButton *button,
167                                        EShellWindow *shell_window)
168 {
169 	if (e_online_button_get_online (button))
170 		gtk_action_activate (ACTION (WORK_OFFLINE));
171 	else
172 		gtk_action_activate (ACTION (WORK_ONLINE));
173 }
174 
175 static void
shell_window_update_close_action_cb(EShellWindow * shell_window)176 shell_window_update_close_action_cb (EShellWindow *shell_window)
177 {
178 	EShell *shell;
179 	GtkApplication *application;
180 	GList *list;
181 	gint n_shell_windows = 0;
182 
183 	shell = e_shell_window_get_shell (shell_window);
184 
185 	application = GTK_APPLICATION (shell);
186 	list = gtk_application_get_windows (application);
187 
188 	/* Count the shell windows. */
189 	while (list != NULL) {
190 		if (E_IS_SHELL_WINDOW (list->data))
191 			n_shell_windows++;
192 		list = g_list_next (list);
193 	}
194 
195 	/* Disable Close Window if there's only one shell window.
196 	 * Helps prevent users from accidentally quitting. */
197 	gtk_action_set_sensitive (ACTION (CLOSE), n_shell_windows > 1);
198 }
199 
200 static void
shell_window_set_geometry(EShellWindow * shell_window,const gchar * geometry)201 shell_window_set_geometry (EShellWindow *shell_window,
202                            const gchar *geometry)
203 {
204 	g_return_if_fail (shell_window->priv->geometry == NULL);
205 
206 	shell_window->priv->geometry = g_strdup (geometry);
207 }
208 
209 static void
shell_window_set_shell(EShellWindow * shell_window,EShell * shell)210 shell_window_set_shell (EShellWindow *shell_window,
211                         EShell *shell)
212 {
213 	GArray *array;
214 	gulong handler_id;
215 
216 	g_return_if_fail (shell_window->priv->shell == NULL);
217 
218 	shell_window->priv->shell = shell;
219 
220 	g_object_add_weak_pointer (
221 		G_OBJECT (shell), &shell_window->priv->shell);
222 
223 	/* Need to disconnect these when the window is closing. */
224 
225 	array = shell_window->priv->signal_handler_ids;
226 
227 	handler_id = g_signal_connect_swapped (
228 		shell, "window-added",
229 		G_CALLBACK (shell_window_update_close_action_cb),
230 		shell_window);
231 
232 	g_array_append_val (array, handler_id);
233 
234 	handler_id = g_signal_connect_swapped (
235 		shell, "window-removed",
236 		G_CALLBACK (shell_window_update_close_action_cb),
237 		shell_window);
238 
239 	g_array_append_val (array, handler_id);
240 
241 	g_object_notify (G_OBJECT (shell), "online");
242 }
243 
244 static void
shell_window_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)245 shell_window_set_property (GObject *object,
246                            guint property_id,
247                            const GValue *value,
248                            GParamSpec *pspec)
249 {
250 	switch (property_id) {
251 		case PROP_ACTIVE_VIEW:
252 			e_shell_window_set_active_view (
253 				E_SHELL_WINDOW (object),
254 				g_value_get_string (value));
255 			return;
256 
257 		case PROP_GEOMETRY:
258 			shell_window_set_geometry (
259 				E_SHELL_WINDOW (object),
260 				g_value_get_string (value));
261 			return;
262 
263 		case PROP_SAFE_MODE:
264 			e_shell_window_set_safe_mode (
265 				E_SHELL_WINDOW (object),
266 				g_value_get_boolean (value));
267 			return;
268 
269 		case PROP_SHELL:
270 			shell_window_set_shell (
271 				E_SHELL_WINDOW (object),
272 				g_value_get_object (value));
273 			return;
274 
275 		case PROP_MENUBAR_VISIBLE:
276 			e_shell_window_set_menubar_visible (
277 				E_SHELL_WINDOW (object),
278 				g_value_get_boolean (value));
279 			return;
280 
281 		case PROP_SIDEBAR_VISIBLE:
282 			e_shell_window_set_sidebar_visible (
283 				E_SHELL_WINDOW (object),
284 				g_value_get_boolean (value));
285 			return;
286 
287 		case PROP_SWITCHER_VISIBLE:
288 			e_shell_window_set_switcher_visible (
289 				E_SHELL_WINDOW (object),
290 				g_value_get_boolean (value));
291 			return;
292 
293 		case PROP_TASKBAR_VISIBLE:
294 			e_shell_window_set_taskbar_visible (
295 				E_SHELL_WINDOW (object),
296 				g_value_get_boolean (value));
297 			return;
298 
299 		case PROP_TOOLBAR_VISIBLE:
300 			e_shell_window_set_toolbar_visible (
301 				E_SHELL_WINDOW (object),
302 				g_value_get_boolean (value));
303 			return;
304 	}
305 
306 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
307 }
308 
309 static void
shell_window_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)310 shell_window_get_property (GObject *object,
311                            guint property_id,
312                            GValue *value,
313                            GParamSpec *pspec)
314 {
315 	switch (property_id) {
316 		case PROP_ACTIVE_VIEW:
317 			g_value_set_string (
318 				value, e_shell_window_get_active_view (
319 				E_SHELL_WINDOW (object)));
320 			return;
321 
322 		case PROP_ALERT_BAR:
323 			g_value_set_object (
324 				value, e_shell_window_get_alert_bar (
325 				E_SHELL_WINDOW (object)));
326 			return;
327 
328 		case PROP_FOCUS_TRACKER:
329 			g_value_set_object (
330 				value, e_shell_window_get_focus_tracker (
331 				E_SHELL_WINDOW (object)));
332 			return;
333 
334 		case PROP_SAFE_MODE:
335 			g_value_set_boolean (
336 				value, e_shell_window_get_safe_mode (
337 				E_SHELL_WINDOW (object)));
338 			return;
339 
340 		case PROP_SHELL:
341 			g_value_set_object (
342 				value, e_shell_window_get_shell (
343 				E_SHELL_WINDOW (object)));
344 			return;
345 
346 		case PROP_MENUBAR_VISIBLE:
347 			g_value_set_boolean (
348 				value, e_shell_window_get_menubar_visible (
349 				E_SHELL_WINDOW (object)));
350 			return;
351 
352 		case PROP_SIDEBAR_VISIBLE:
353 			g_value_set_boolean (
354 				value, e_shell_window_get_sidebar_visible (
355 				E_SHELL_WINDOW (object)));
356 			return;
357 
358 		case PROP_SWITCHER_VISIBLE:
359 			g_value_set_boolean (
360 				value, e_shell_window_get_switcher_visible (
361 				E_SHELL_WINDOW (object)));
362 			return;
363 
364 		case PROP_TASKBAR_VISIBLE:
365 			g_value_set_boolean (
366 				value, e_shell_window_get_taskbar_visible (
367 				E_SHELL_WINDOW (object)));
368 			return;
369 
370 		case PROP_TOOLBAR_VISIBLE:
371 			g_value_set_boolean (
372 				value, e_shell_window_get_toolbar_visible (
373 				E_SHELL_WINDOW (object)));
374 			return;
375 
376 		case PROP_UI_MANAGER:
377 			g_value_set_object (
378 				value, e_shell_window_get_ui_manager (
379 				E_SHELL_WINDOW (object)));
380 			return;
381 	}
382 
383 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
384 }
385 
386 static void
shell_window_dispose(GObject * object)387 shell_window_dispose (GObject *object)
388 {
389 	e_shell_window_private_dispose (E_SHELL_WINDOW (object));
390 
391 	/* Chain up to parent's dispose() method. */
392 	G_OBJECT_CLASS (e_shell_window_parent_class)->dispose (object);
393 }
394 
395 static void
shell_window_finalize(GObject * object)396 shell_window_finalize (GObject *object)
397 {
398 	e_shell_window_private_finalize (E_SHELL_WINDOW (object));
399 
400 	/* Chain up to parent's finalize() method. */
401 	G_OBJECT_CLASS (e_shell_window_parent_class)->finalize (object);
402 }
403 
404 static void
shell_window_constructed(GObject * object)405 shell_window_constructed (GObject *object)
406 {
407 	EShellWindow *shell_window = E_SHELL_WINDOW (object);
408 
409 	e_shell_window_private_constructed (shell_window);
410 
411 	e_extensible_load_extensions (E_EXTENSIBLE (object));
412 
413 	/* Chain up to parent's constructed() method. */
414 	G_OBJECT_CLASS (e_shell_window_parent_class)->constructed (object);
415 }
416 
417 static void
shell_window_close_alert(EShellWindow * shell_window)418 shell_window_close_alert (EShellWindow *shell_window)
419 {
420 	EShellView *shell_view;
421 	EShellContent *shell_content;
422 	GtkWidget *alert_bar;
423 	const gchar *view_name;
424 
425 	/* Close view-specific alerts first, followed by global alerts. */
426 
427 	view_name = e_shell_window_get_active_view (shell_window);
428 	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
429 	shell_content = e_shell_view_get_shell_content (shell_view);
430 	alert_bar = e_shell_content_get_alert_bar (shell_content);
431 
432 	if (!e_alert_bar_close_alert (E_ALERT_BAR (alert_bar))) {
433 		alert_bar = e_shell_window_get_alert_bar (shell_window);
434 		e_alert_bar_close_alert (E_ALERT_BAR (alert_bar));
435 	}
436 }
437 
438 static void
shell_window_menubar_deactivate_cb(GtkWidget * main_menu,gpointer user_data)439 shell_window_menubar_deactivate_cb (GtkWidget *main_menu,
440 				    gpointer user_data)
441 {
442 	EShellWindow *shell_window = user_data;
443 
444 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
445 
446 	if (!e_shell_window_get_menubar_visible (shell_window))
447 		gtk_widget_hide (main_menu);
448 }
449 
450 static GtkWidget *
shell_window_construct_menubar(EShellWindow * shell_window)451 shell_window_construct_menubar (EShellWindow *shell_window)
452 {
453 	GtkWidget *main_menu;
454 
455 	main_menu = e_shell_window_get_managed_widget (
456 		shell_window, "/main-menu");
457 
458 	g_signal_connect (main_menu, "deactivate",
459 		G_CALLBACK (shell_window_menubar_deactivate_cb), shell_window);
460 
461 	e_binding_bind_property (
462 		shell_window, "menubar-visible",
463 		main_menu, "visible",
464 		G_BINDING_SYNC_CREATE);
465 
466 	e_signal_connect_notify (
467 		shell_window, "notify::active-view",
468 		G_CALLBACK (shell_window_menubar_update_new_menu), NULL);
469 
470 	return main_menu;
471 }
472 
473 static GtkWidget *
shell_window_construct_toolbar(EShellWindow * shell_window)474 shell_window_construct_toolbar (EShellWindow *shell_window)
475 {
476 	GtkUIManager *ui_manager;
477 	GtkWidget *toolbar;
478 	GtkWidget *box;
479 	GtkToolItem *item;
480 
481 	ui_manager = e_shell_window_get_ui_manager (shell_window);
482 
483 	box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
484 	gtk_widget_show (box);
485 
486 	e_binding_bind_property (
487 		shell_window, "toolbar-visible",
488 		box, "visible",
489 		G_BINDING_SYNC_CREATE);
490 
491 	toolbar = e_shell_window_get_managed_widget (
492 		shell_window, "/main-toolbar");
493 
494 	gtk_style_context_add_class (
495 		gtk_widget_get_style_context (toolbar),
496 		GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
497 
498 	/* XXX Having this separator in the UI definition doesn't work
499 	 *     because GtkUIManager is unaware of the "New" button, so
500 	 *     it makes the separator invisible.  One possibility is to
501 	 *     define a GtkAction subclass for which create_tool_item()
502 	 *     return an EMenuToolButton.  Then both this separator
503 	 *     and the "New" button could be added to the UI definition.
504 	 *     Tempting, but the "New" button and its dynamically
505 	 *     generated menu is already a complex beast, and I'm not
506 	 *     convinced having it proxy some new type of GtkAction
507 	 *     is worth the extra effort. */
508 	item = gtk_separator_tool_item_new ();
509 	gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
510 	gtk_widget_show (GTK_WIDGET (item));
511 
512 	/* Translators: a 'New' toolbar button caption which is context sensitive and
513 	   runs one of the actions under File->New menu */
514 	item = e_menu_tool_button_new (C_("toolbar-button", "New"));
515 	gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
516 	gtk_widget_add_accelerator (
517 		GTK_WIDGET (item), "clicked",
518 		gtk_ui_manager_get_accel_group (ui_manager),
519 		GDK_KEY_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
520 	gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
521 	gtk_widget_show (GTK_WIDGET (item));
522 
523 	/* XXX The ECalShellBackend has a hack where it forces the
524 	 *     EMenuToolButton to update its button image by forcing
525 	 *     a "notify::active-view" signal emission on the window.
526 	 *     This will trigger the property binding, which will set
527 	 *     EMenuToolButton's "prefer-item" property, which will
528 	 *     invoke shell_window_toolbar_update_new_menu(), which
529 	 *     will cause EMenuToolButton to update its button image.
530 	 *
531 	 *     It's a bit of a Rube Goldberg machine and should be
532 	 *     reworked, but it's just serving one (now documented)
533 	 *     corner case and works for now. */
534 	e_binding_bind_property_full (
535 		shell_window, "active-view",
536 		item, "prefer-item",
537 		G_BINDING_SYNC_CREATE,
538 		shell_window_active_view_to_prefer_item,
539 		(GBindingTransformFunc) NULL,
540 		NULL, (GDestroyNotify) NULL);
541 
542 	g_signal_connect (
543 		item, "notify::prefer-item",
544 		G_CALLBACK (shell_window_toolbar_update_new_menu),
545 		shell_window);
546 
547 	gtk_box_pack_start (GTK_BOX (box), toolbar, TRUE, TRUE, 0);
548 
549 	toolbar = e_shell_window_get_managed_widget (
550 		shell_window, "/search-toolbar");
551 	gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
552 
553 	toolbar = e_shell_window_get_managed_widget (
554 		shell_window, "/close-toolbar");
555 	gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
556 
557 	return box;
558 }
559 
560 static GtkWidget *
shell_window_construct_sidebar(EShellWindow * shell_window)561 shell_window_construct_sidebar (EShellWindow *shell_window)
562 {
563 	GtkWidget *notebook;
564 	GtkWidget *switcher;
565 
566 	switcher = e_shell_switcher_new ();
567 	shell_window->priv->switcher = g_object_ref_sink (switcher);
568 
569 	e_binding_bind_property (
570 		shell_window, "sidebar-visible",
571 		switcher, "visible",
572 		G_BINDING_SYNC_CREATE);
573 
574 	e_binding_bind_property (
575 		shell_window, "switcher-visible",
576 		switcher, "toolbar-visible",
577 		G_BINDING_SYNC_CREATE);
578 
579 	notebook = gtk_notebook_new ();
580 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
581 	gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
582 	gtk_container_add (GTK_CONTAINER (switcher), notebook);
583 	shell_window->priv->sidebar_notebook = g_object_ref (notebook);
584 	gtk_widget_show (notebook);
585 
586 	e_signal_connect_notify (
587 		shell_window, "notify::active-view",
588 		G_CALLBACK (shell_window_set_notebook_page), notebook);
589 
590 	return switcher;
591 }
592 
593 static GtkWidget *
shell_window_construct_content(EShellWindow * shell_window)594 shell_window_construct_content (EShellWindow *shell_window)
595 {
596 	GtkWidget *box;
597 	GtkWidget *widget;
598 
599 	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
600 	gtk_widget_show (box);
601 
602 	widget = e_alert_bar_new ();
603 	gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
604 	shell_window->priv->alert_bar = g_object_ref (widget);
605 	/* EAlertBar controls its own visibility. */
606 
607 	widget = gtk_notebook_new ();
608 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
609 	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
610 	gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0);
611 	shell_window->priv->content_notebook = g_object_ref (widget);
612 	gtk_widget_show (widget);
613 
614 	e_signal_connect_notify (
615 		shell_window, "notify::active-view",
616 		G_CALLBACK (shell_window_set_notebook_page), widget);
617 
618 	return box;
619 }
620 
621 static GtkWidget *
shell_window_construct_taskbar(EShellWindow * shell_window)622 shell_window_construct_taskbar (EShellWindow *shell_window)
623 {
624 	EShell *shell;
625 	GtkWidget *box;
626 	GtkWidget *notebook;
627 	GtkWidget *status_area;
628 	GtkWidget *online_button;
629 	GtkWidget *tooltip_label;
630 	GtkStyleContext *style_context;
631 	gint height;
632 
633 	shell = e_shell_window_get_shell (shell_window);
634 
635 	box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
636 	gtk_container_set_border_width (GTK_CONTAINER (box), 3);
637 	gtk_widget_show (box);
638 
639 	status_area = gtk_frame_new (NULL);
640 	style_context = gtk_widget_get_style_context (status_area);
641 	gtk_style_context_add_class (style_context, "taskbar");
642 	gtk_container_add (GTK_CONTAINER (status_area), box);
643 
644 	e_binding_bind_property (
645 		shell_window, "taskbar-visible",
646 		status_area, "visible",
647 		G_BINDING_SYNC_CREATE);
648 
649 	/* Make the status area as large as the task bar. */
650 	gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height);
651 	gtk_widget_set_size_request (status_area, -1, (height * 2) + 6);
652 
653 	online_button = e_online_button_new ();
654 	gtk_box_pack_start (
655 		GTK_BOX (box), online_button, FALSE, TRUE, 0);
656 	gtk_widget_show (online_button);
657 
658 	e_binding_bind_property (
659 		shell, "online",
660 		online_button, "online",
661 		G_BINDING_SYNC_CREATE);
662 
663 	e_binding_bind_property (
664 		shell, "network-available",
665 		online_button, "sensitive",
666 		G_BINDING_SYNC_CREATE);
667 
668 	g_signal_connect (
669 		online_button, "clicked",
670 		G_CALLBACK (shell_window_online_button_clicked_cb),
671 		shell_window);
672 
673 	tooltip_label = gtk_label_new ("");
674 	gtk_misc_set_alignment (GTK_MISC (tooltip_label), 0.0, 0.5);
675 	gtk_box_pack_start (
676 		GTK_BOX (box), tooltip_label, TRUE, TRUE, 0);
677 	shell_window->priv->tooltip_label = g_object_ref (tooltip_label);
678 	gtk_widget_hide (tooltip_label);
679 
680 	notebook = gtk_notebook_new ();
681 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
682 	gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
683 	gtk_box_pack_start (GTK_BOX (box), notebook, TRUE, TRUE, 0);
684 	shell_window->priv->status_notebook = g_object_ref (notebook);
685 	gtk_widget_show (notebook);
686 
687 	e_signal_connect_notify (
688 		shell_window, "notify::active-view",
689 		G_CALLBACK (shell_window_set_notebook_page), notebook);
690 
691 	return status_area;
692 }
693 
694 static EShellView *
shell_window_create_shell_view(EShellWindow * shell_window,const gchar * view_name)695 shell_window_create_shell_view (EShellWindow *shell_window,
696                                 const gchar *view_name)
697 {
698 	EShell *shell;
699 	EShellView *shell_view;
700 	EShellBackend *shell_backend;
701 	GHashTable *loaded_views;
702 	GtkUIManager *ui_manager;
703 	GtkNotebook *notebook;
704 	GtkAction *action;
705 	GtkWidget *widget;
706 	const gchar *name;
707 	const gchar *id;
708 	gint page_num;
709 	GType type;
710 
711 	shell = e_shell_window_get_shell (shell_window);
712 	shell_backend = e_shell_get_backend_by_name (shell, view_name);
713 
714 	if (shell_backend == NULL) {
715 		g_critical ("Unknown shell view name: %s", view_name);
716 		return NULL;
717 	}
718 
719 	name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
720 	type = E_SHELL_BACKEND_GET_CLASS (shell_backend)->shell_view_type;
721 
722 	/* First off, start the shell backend. */
723 	e_shell_backend_start (shell_backend);
724 
725 	/* Determine the page number for the new shell view. */
726 	notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook);
727 	page_num = gtk_notebook_get_n_pages (notebook);
728 
729 	/* Get the switcher action for this view. */
730 	action = e_shell_window_get_shell_view_action (shell_window, name);
731 
732 	/* Create the shell view. */
733 	shell_view = g_object_new (
734 		type, "action", action, "page-num", page_num,
735 		"shell-window", shell_window, NULL);
736 
737 	/* Register the shell view. */
738 	loaded_views = shell_window->priv->loaded_views;
739 	g_hash_table_insert (loaded_views, g_strdup (name), shell_view);
740 
741 	/* Register the GtkUIManager ID for the shell view. */
742 	id = E_SHELL_VIEW_GET_CLASS (shell_view)->ui_manager_id;
743 	ui_manager = e_shell_window_get_ui_manager (shell_window);
744 	e_plugin_ui_register_manager (ui_manager, id, shell_view);
745 
746 	/* Add pages to the various shell window notebooks. */
747 
748 	/* We can't determine the shell view's page number until after the
749 	 * shell view is fully initialized because the shell view may load
750 	 * other shell views during initialization, and those other shell
751 	 * views will append their widgets to the notebooks before us. */
752 	page_num = gtk_notebook_get_n_pages (notebook);
753 	e_shell_view_set_page_num (shell_view, page_num);
754 
755 	notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook);
756 	widget = GTK_WIDGET (e_shell_view_get_shell_content (shell_view));
757 	gtk_notebook_append_page (notebook, widget, NULL);
758 
759 	notebook = GTK_NOTEBOOK (shell_window->priv->sidebar_notebook);
760 	widget = GTK_WIDGET (e_shell_view_get_shell_sidebar (shell_view));
761 	gtk_notebook_append_page (notebook, widget, NULL);
762 
763 	notebook = GTK_NOTEBOOK (shell_window->priv->status_notebook);
764 	widget = GTK_WIDGET (e_shell_view_get_shell_taskbar (shell_view));
765 	gtk_notebook_append_page (notebook, widget, NULL);
766 
767 	e_binding_bind_property (
768 		widget, "height-request",
769 		shell_window->priv->tooltip_label, "height-request",
770 		G_BINDING_SYNC_CREATE);
771 
772 	/* Listen for changes that affect the shell window. */
773 
774 	e_signal_connect_notify_swapped (
775 		action, "notify::icon-name",
776 		G_CALLBACK (e_shell_window_update_icon), shell_window);
777 
778 	e_signal_connect_notify_swapped (
779 		shell_view, "notify::title",
780 		G_CALLBACK (e_shell_window_update_title), shell_window);
781 
782 	e_signal_connect_notify_swapped (
783 		shell_view, "notify::view-id",
784 		G_CALLBACK (e_shell_window_update_view_menu), shell_window);
785 
786 	return shell_view;
787 }
788 
789 static void
shell_window_submit_alert(EAlertSink * alert_sink,EAlert * alert)790 shell_window_submit_alert (EAlertSink *alert_sink,
791                            EAlert *alert)
792 {
793 	EShellWindow *shell_window;
794 	GtkWidget *alert_bar;
795 
796 	shell_window = E_SHELL_WINDOW (alert_sink);
797 
798 	if (!gtk_widget_get_mapped (GTK_WIDGET (shell_window)) ||
799 	    shell_window->priv->postponed_alerts) {
800 		shell_window->priv->postponed_alerts = g_slist_prepend (
801 			shell_window->priv->postponed_alerts, g_object_ref (alert));
802 		return;
803 	}
804 
805 	alert_bar = e_shell_window_get_alert_bar (shell_window);
806 
807 	e_alert_bar_submit_alert (E_ALERT_BAR (alert_bar), alert);
808 }
809 
810 static gboolean
shell_window_submit_postponed_alerts_idle_cb(gpointer user_data)811 shell_window_submit_postponed_alerts_idle_cb (gpointer user_data)
812 {
813 	EShellWindow *shell_window = user_data;
814 	EAlertSink *alert_sink;
815 	GSList *postponed_alerts, *link;
816 
817 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
818 
819 	postponed_alerts = g_slist_reverse (shell_window->priv->postponed_alerts);
820 	shell_window->priv->postponed_alerts = NULL;
821 
822 	alert_sink = E_ALERT_SINK (shell_window);
823 
824 	for (link = postponed_alerts; link; link = g_slist_next (link)) {
825 		EAlert *alert = link->data;
826 
827 		shell_window_submit_alert (alert_sink, alert);
828 	}
829 
830 	g_slist_free_full (postponed_alerts, g_object_unref);
831 
832 	return FALSE;
833 }
834 
835 static void
shell_window_map(GtkWidget * widget)836 shell_window_map (GtkWidget *widget)
837 {
838 	EShellWindow *shell_window;
839 	EShellView *shell_view;
840 
841 	g_return_if_fail (E_IS_SHELL_WINDOW (widget));
842 
843 	shell_window = E_SHELL_WINDOW (widget);
844 
845 	/* Do this before the parent's map() is called, to distinguish from search and from window open */
846 	shell_view = e_shell_window_peek_shell_view (shell_window, e_shell_window_get_active_view (shell_window));
847 	if (shell_view) {
848 		EShellContent *shell_content;
849 
850 		shell_content = e_shell_view_get_shell_content (shell_view);
851 		if (shell_content)
852 			e_shell_content_focus_search_results (shell_content);
853 	}
854 
855 	/* Chain up to parent's method */
856 	GTK_WIDGET_CLASS (e_shell_window_parent_class)->map (widget);
857 
858 	g_idle_add_full (
859 		G_PRIORITY_LOW,
860 		shell_window_submit_postponed_alerts_idle_cb,
861 		g_object_ref (shell_window), g_object_unref);
862 }
863 
864 static gboolean
shell_window_delete_event_cb(GtkWidget * widget,GdkEventAny * event)865 shell_window_delete_event_cb (GtkWidget *widget,
866 			      GdkEventAny *event)
867 {
868 	g_return_val_if_fail (E_IS_SHELL_WINDOW (widget), FALSE);
869 
870 	e_alert_bar_clear (E_ALERT_BAR (E_SHELL_WINDOW (widget)->priv->alert_bar));
871 
872 	return FALSE;
873 }
874 
875 static void
e_shell_window_class_init(EShellWindowClass * class)876 e_shell_window_class_init (EShellWindowClass *class)
877 {
878 	GObjectClass *object_class;
879 	GtkWidgetClass *widget_class;
880 	GtkBindingSet *binding_set;
881 
882 	g_type_class_add_private (class, sizeof (EShellWindowPrivate));
883 
884 	object_class = G_OBJECT_CLASS (class);
885 	object_class->set_property = shell_window_set_property;
886 	object_class->get_property = shell_window_get_property;
887 	object_class->dispose = shell_window_dispose;
888 	object_class->finalize = shell_window_finalize;
889 	object_class->constructed = shell_window_constructed;
890 
891 	widget_class = GTK_WIDGET_CLASS (class);
892 	widget_class->map = shell_window_map;
893 
894 	class->close_alert = shell_window_close_alert;
895 	class->construct_menubar = shell_window_construct_menubar;
896 	class->construct_toolbar = shell_window_construct_toolbar;
897 	class->construct_sidebar = shell_window_construct_sidebar;
898 	class->construct_content = shell_window_construct_content;
899 	class->construct_taskbar = shell_window_construct_taskbar;
900 	class->create_shell_view = shell_window_create_shell_view;
901 
902 	/**
903 	 * EShellWindow:active-view
904 	 *
905 	 * Name of the active #EShellView.
906 	 **/
907 	g_object_class_install_property (
908 		object_class,
909 		PROP_ACTIVE_VIEW,
910 		g_param_spec_string (
911 			"active-view",
912 			"Active Shell View",
913 			"Name of the active shell view",
914 			NULL,
915 			G_PARAM_READWRITE |
916 			G_PARAM_STATIC_STRINGS));
917 
918 	/**
919 	 * EShellWindow:alert-bar
920 	 *
921 	 * Displays informational and error messages.
922 	 **/
923 	g_object_class_install_property (
924 		object_class,
925 		PROP_ALERT_BAR,
926 		g_param_spec_object (
927 			"alert-bar",
928 			"Alert Bar",
929 			"Displays informational and error messages",
930 			E_TYPE_ALERT_BAR,
931 			G_PARAM_READABLE |
932 			G_PARAM_STATIC_STRINGS));
933 
934 	/**
935 	 * EShellWindow:focus-tracker
936 	 *
937 	 * The shell window's #EFocusTracker.
938 	 **/
939 	g_object_class_install_property (
940 		object_class,
941 		PROP_FOCUS_TRACKER,
942 		g_param_spec_object (
943 			"focus-tracker",
944 			"Focus Tracker",
945 			"The shell window's EFocusTracker",
946 			E_TYPE_FOCUS_TRACKER,
947 			G_PARAM_READABLE |
948 			G_PARAM_STATIC_STRINGS));
949 
950 	/**
951 	 * EShellWindow:geometry
952 	 *
953 	 * User-specified initial window geometry string.
954 	 **/
955 	g_object_class_install_property (
956 		object_class,
957 		PROP_GEOMETRY,
958 		g_param_spec_string (
959 			"geometry",
960 			"Geometry",
961 			"Initial window geometry string",
962 			NULL,
963 			G_PARAM_WRITABLE |
964 			G_PARAM_CONSTRUCT_ONLY |
965 			G_PARAM_STATIC_STRINGS));
966 
967 	/**
968 	 * EShellWindow:safe-mode
969 	 *
970 	 * Whether the shell window is in safe mode.
971 	 **/
972 	g_object_class_install_property (
973 		object_class,
974 		PROP_SAFE_MODE,
975 		g_param_spec_boolean (
976 			"safe-mode",
977 			"Safe Mode",
978 			"Whether the shell window is in safe mode",
979 			FALSE,
980 			G_PARAM_READWRITE |
981 			G_PARAM_CONSTRUCT |
982 			G_PARAM_STATIC_STRINGS));
983 
984 	/**
985 	 * EShellWindow:shell
986 	 *
987 	 * The #EShell singleton.
988 	 **/
989 	g_object_class_install_property (
990 		object_class,
991 		PROP_SHELL,
992 		g_param_spec_object (
993 			"shell",
994 			"Shell",
995 			"The EShell singleton",
996 			E_TYPE_SHELL,
997 			G_PARAM_READWRITE |
998 			G_PARAM_CONSTRUCT_ONLY |
999 			G_PARAM_STATIC_STRINGS));
1000 
1001 	/**
1002 	 * EShellWindow:menubar-visible
1003 	 *
1004 	 * Whether the shell window's menu bar is visible.
1005 	 *
1006 	 * Since: 3.24
1007 	 **/
1008 	g_object_class_install_property (
1009 		object_class,
1010 		PROP_MENUBAR_VISIBLE,
1011 		g_param_spec_boolean (
1012 			"menubar-visible",
1013 			"Menubar Visible",
1014 			"Whether the shell window's menu bar is visible",
1015 			TRUE,
1016 			G_PARAM_READWRITE |
1017 			G_PARAM_STATIC_STRINGS));
1018 
1019 	/**
1020 	 * EShellWindow:sidebar-visible
1021 	 *
1022 	 * Whether the shell window's side bar is visible.
1023 	 **/
1024 	g_object_class_install_property (
1025 		object_class,
1026 		PROP_SIDEBAR_VISIBLE,
1027 		g_param_spec_boolean (
1028 			"sidebar-visible",
1029 			"Sidebar Visible",
1030 			"Whether the shell window's side bar is visible",
1031 			TRUE,
1032 			G_PARAM_READWRITE |
1033 			G_PARAM_STATIC_STRINGS));
1034 
1035 	/**
1036 	 * EShellWindow:switcher-visible
1037 	 *
1038 	 * Whether the shell window's switcher buttons are visible.
1039 	 **/
1040 	g_object_class_install_property (
1041 		object_class,
1042 		PROP_SWITCHER_VISIBLE,
1043 		g_param_spec_boolean (
1044 			"switcher-visible",
1045 			"Switcher Visible",
1046 			"Whether the shell window's "
1047 			"switcher buttons are visible",
1048 			TRUE,
1049 			G_PARAM_READWRITE |
1050 			G_PARAM_STATIC_STRINGS));
1051 
1052 	/**
1053 	 * EShellWindow:taskbar-visible
1054 	 *
1055 	 * Whether the shell window's task bar is visible.
1056 	 **/
1057 	g_object_class_install_property (
1058 		object_class,
1059 		PROP_TASKBAR_VISIBLE,
1060 		g_param_spec_boolean (
1061 			"taskbar-visible",
1062 			"Taskbar Visible",
1063 			"Whether the shell window's task bar is visible",
1064 			TRUE,
1065 			G_PARAM_READWRITE |
1066 			G_PARAM_STATIC_STRINGS));
1067 
1068 	/**
1069 	 * EShellWindow:toolbar-visible
1070 	 *
1071 	 * Whether the shell window's tool bar is visible.
1072 	 **/
1073 	g_object_class_install_property (
1074 		object_class,
1075 		PROP_TOOLBAR_VISIBLE,
1076 		g_param_spec_boolean (
1077 			"toolbar-visible",
1078 			"Toolbar Visible",
1079 			"Whether the shell window's tool bar is visible",
1080 			TRUE,
1081 			G_PARAM_READWRITE |
1082 			G_PARAM_STATIC_STRINGS));
1083 
1084 	/**
1085 	 * EShellWindow:ui-manager
1086 	 *
1087 	 * The shell window's #GtkUIManager.
1088 	 **/
1089 	g_object_class_install_property (
1090 		object_class,
1091 		PROP_UI_MANAGER,
1092 		g_param_spec_object (
1093 			"ui-manager",
1094 			"UI Manager",
1095 			"The shell window's GtkUIManager",
1096 			GTK_TYPE_UI_MANAGER,
1097 			G_PARAM_READABLE |
1098 			G_PARAM_STATIC_STRINGS));
1099 
1100 	/**
1101 	 * EShellWindow::close-alert
1102 	 * @shell_window: the #EShellWindow which emitted the signal
1103 	 *
1104 	 * Closes either one #EShellView-specific #EAlert or else one
1105 	 * global #EAlert.  This signal is bound to the Escape key.
1106 	 **/
1107 	signals[CLOSE_ALERT] = g_signal_new (
1108 		"close-alert",
1109 		G_OBJECT_CLASS_TYPE (object_class),
1110 		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1111 		G_STRUCT_OFFSET (EShellWindowClass, close_alert),
1112 		NULL, NULL,
1113 		g_cclosure_marshal_VOID__VOID,
1114 		G_TYPE_NONE, 0);
1115 
1116 	/**
1117 	 * EShellWindow::shell-view-created
1118 	 * @shell_window: the #EShellWindow which emitted the signal
1119 	 * @shell_view: the new #EShellView
1120 	 *
1121 	 * Emitted when a new #EShellView is instantiated by way of
1122 	 * e_shell_window_get_shell_view().  The signal detail denotes
1123 	 * the new view name, which can be used to obtain notification
1124 	 * of when a particular #EShellView is created.
1125 	 **/
1126 	signals[SHELL_VIEW_CREATED] = g_signal_new (
1127 		"shell-view-created",
1128 		G_OBJECT_CLASS_TYPE (object_class),
1129 		G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
1130 		G_STRUCT_OFFSET (EShellWindowClass, shell_view_created),
1131 		NULL, NULL,
1132 		g_cclosure_marshal_VOID__OBJECT,
1133 		G_TYPE_NONE, 1,
1134 		E_TYPE_SHELL_VIEW);
1135 
1136 	binding_set = gtk_binding_set_by_class (class);
1137 	gtk_binding_entry_add_signal (
1138 		binding_set, GDK_KEY_Escape, 0, "close-alert", 0);
1139 }
1140 
1141 static void
e_shell_window_alert_sink_init(EAlertSinkInterface * iface)1142 e_shell_window_alert_sink_init (EAlertSinkInterface *iface)
1143 {
1144 	iface->submit_alert = shell_window_submit_alert;
1145 }
1146 
1147 static void
e_shell_window_init(EShellWindow * shell_window)1148 e_shell_window_init (EShellWindow *shell_window)
1149 {
1150 	GtkCssProvider *css_provider;
1151 
1152 	shell_window->priv = E_SHELL_WINDOW_GET_PRIVATE (shell_window);
1153 
1154 	e_shell_window_private_init (shell_window);
1155 
1156 	css_provider = gtk_css_provider_new ();
1157 	gtk_css_provider_load_from_data (css_provider, css, -1, NULL);
1158 	gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
1159 		GTK_STYLE_PROVIDER (css_provider),
1160 		GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1161 
1162 	g_signal_connect (shell_window, "delete-event",
1163 		G_CALLBACK (shell_window_delete_event_cb), NULL);
1164 }
1165 
1166 /**
1167  * e_shell_window_new:
1168  * @shell: an #EShell
1169  * @safe_mode: whether to initialize the window to "safe mode"
1170  * @geometry: initial window geometry string, or %NULL
1171  *
1172  * Returns a new #EShellWindow.
1173  *
1174  * It's up to the various #EShellView<!-- -->'s to define exactly
1175  * what "safe mode" means, but the #EShell usually puts the initial
1176  * #EShellWindow into "safe mode" if detects the previous Evolution
1177  * session crashed.
1178  *
1179  * The initial view for the window is determined by GSettings key
1180  * <filename>/org/gnome/evolution/shell/default-component-id</filename>.
1181  * Or, if the GSettings key is not set or can't be read, the first view
1182  * in the switcher is used.
1183  *
1184  * Returns: a new #EShellWindow
1185  **/
1186 GtkWidget *
e_shell_window_new(EShell * shell,gboolean safe_mode,const gchar * geometry)1187 e_shell_window_new (EShell *shell,
1188                     gboolean safe_mode,
1189                     const gchar *geometry)
1190 {
1191 	return g_object_new (
1192 		E_TYPE_SHELL_WINDOW,
1193 		"shell", shell, "geometry", geometry,
1194 		"safe-mode", safe_mode, NULL);
1195 }
1196 
1197 /**
1198  * e_shell_window_get_shell:
1199  * @shell_window: an #EShellWindow
1200  *
1201  * Returns the #EShell that was passed to e_shell_window_new().
1202  *
1203  * Returns: the #EShell
1204  **/
1205 EShell *
e_shell_window_get_shell(EShellWindow * shell_window)1206 e_shell_window_get_shell (EShellWindow *shell_window)
1207 {
1208 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1209 
1210 	return E_SHELL (shell_window->priv->shell);
1211 }
1212 
1213 /**
1214  * e_shell_window_is_main_instance:
1215  * @shell_window: an #EShellWindow
1216  *
1217  * Returns, whether the @shell_window is the main instance, which is
1218  * the window which was created as the first @shell_window.
1219  *
1220  * Returns: whether the @shell_window is the main instance
1221  **/
1222 gboolean
e_shell_window_is_main_instance(EShellWindow * shell_window)1223 e_shell_window_is_main_instance (EShellWindow *shell_window)
1224 {
1225 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1226 
1227 	return shell_window->priv->is_main_instance;
1228 }
1229 
1230 /**
1231  * e_shell_window_get_shell_view:
1232  * @shell_window: an #EShellWindow
1233  * @view_name: name of a shell view
1234  *
1235  * Returns the #EShellView named @view_name (see the
1236  * <structfield>name</structfield> field in #EShellBackendInfo).  This
1237  * will also instantiate the #EShellView the first time it's requested.
1238  * To reduce resource consumption, Evolution tries to delay instantiating
1239  * shell views until the user switches to them.  So in general, only the
1240  * active view name, as returned by e_shell_window_get_active_view(),
1241  * should be requested.
1242  *
1243  * The function emits an #EShellWindow::shell-view-created signal with
1244  * @view_name as the signal detail when it instantiates an #EShellView.
1245  *
1246  * Returns: the requested #EShellView, or %NULL if no such view is
1247  *          registered
1248  **/
1249 EShellView *
e_shell_window_get_shell_view(EShellWindow * shell_window,const gchar * view_name)1250 e_shell_window_get_shell_view (EShellWindow *shell_window,
1251                                const gchar *view_name)
1252 {
1253 	EShellView *shell_view;
1254 	EShellWindowClass *class;
1255 
1256 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1257 	g_return_val_if_fail (view_name != NULL, NULL);
1258 
1259 	shell_view = e_shell_window_peek_shell_view (shell_window, view_name);
1260 	if (shell_view != NULL)
1261 		return shell_view;
1262 
1263 	class = E_SHELL_WINDOW_GET_CLASS (shell_window);
1264 	g_return_val_if_fail (class != NULL, NULL);
1265 	g_return_val_if_fail (class->create_shell_view != NULL, NULL);
1266 
1267 	shell_view = class->create_shell_view (shell_window, view_name);
1268 
1269 	g_signal_emit (
1270 		shell_window, signals[SHELL_VIEW_CREATED],
1271 		g_quark_from_string (view_name), shell_view);
1272 
1273 	return shell_view;
1274 }
1275 
1276 /**
1277  * e_shell_window_peek_shell_view:
1278  * @shell_window: an #EShellWindow
1279  * @view_name: name of a shell view
1280  *
1281  * Returns the #EShellView named @view_name (see the
1282  * <structfield>name</structfield> field in #EShellBackendInfo), or
1283  * %NULL if the requested view has not yet been instantiated.  Unlike
1284  * e_shell_window_get_shell_view(), this function will not instantiate
1285  * the view itself.
1286  *
1287  * Returns: the requested #EShellView, or %NULL if no such view is
1288  *          instantiated
1289  **/
1290 EShellView *
e_shell_window_peek_shell_view(EShellWindow * shell_window,const gchar * view_name)1291 e_shell_window_peek_shell_view (EShellWindow *shell_window,
1292                                 const gchar *view_name)
1293 {
1294 	GHashTable *loaded_views;
1295 
1296 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1297 	g_return_val_if_fail (view_name != NULL, NULL);
1298 
1299 	loaded_views = shell_window->priv->loaded_views;
1300 
1301 	return g_hash_table_lookup (loaded_views, view_name);
1302 }
1303 
1304 /**
1305  * e_shell_window_get_shell_view_action:
1306  * @shell_window: an #EShellWindow
1307  * @view_name: name of a shell view
1308  *
1309  * Returns the switcher action for @view_name.
1310  *
1311  * An #EShellWindow creates a #GtkRadioAction for each registered subclass
1312  * of #EShellView.  This action gets passed to the #EShellSwitcher, which
1313  * displays a button that proxies the action.  When the #EShellView named
1314  * @view_name is active, the action's icon becomes the @shell_window icon.
1315  *
1316  * Returns: the switcher action for the #EShellView named @view_name,
1317  *          or %NULL if no such shell view exists
1318  **/
1319 GtkAction *
e_shell_window_get_shell_view_action(EShellWindow * shell_window,const gchar * view_name)1320 e_shell_window_get_shell_view_action (EShellWindow *shell_window,
1321                                       const gchar *view_name)
1322 {
1323 	GtkAction *action;
1324 	gchar *action_name;
1325 
1326 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1327 	g_return_val_if_fail (view_name != NULL, NULL);
1328 
1329 	action_name = g_strdup_printf (E_SHELL_SWITCHER_FORMAT, view_name);
1330 	action = e_shell_window_get_action (shell_window, action_name);
1331 	g_free (action_name);
1332 
1333 	return action;
1334 }
1335 
1336 /**
1337  * e_shell_window_get_alert_bar:
1338  * @shell_window: an #EShellWindow
1339  *
1340  * Returns the #EAlertBar used to display informational and error messages.
1341  *
1342  * Returns: the #EAlertBar for @shell_window
1343  **/
1344 GtkWidget *
e_shell_window_get_alert_bar(EShellWindow * shell_window)1345 e_shell_window_get_alert_bar (EShellWindow *shell_window)
1346 {
1347 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1348 
1349 	return shell_window->priv->alert_bar;
1350 }
1351 
1352 /**
1353  * e_shell_window_get_focus_tracker:
1354  * @shell_window: an #EShellWindow
1355  *
1356  * Returns @shell_window<!-- -->'s focus tracker, which directs
1357  * Cut, Copy, Paste and Select All main menu activations to the
1358  * appropriate editable or selectable widget.
1359  *
1360  * Returns: the #EFocusTracker for @shell_window
1361  **/
1362 EFocusTracker *
e_shell_window_get_focus_tracker(EShellWindow * shell_window)1363 e_shell_window_get_focus_tracker (EShellWindow *shell_window)
1364 {
1365 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1366 
1367 	return shell_window->priv->focus_tracker;
1368 }
1369 
1370 /**
1371  * e_shell_window_get_ui_manager:
1372  * @shell_window: an #EShellWindow
1373  *
1374  * Returns @shell_window<!-- -->'s user interface manager, which
1375  * manages the window's menus and toolbars via #GtkAction<!-- -->s.
1376  * This is the mechanism by which shell views and plugins can extend
1377  * Evolution's menus and toolbars.
1378  *
1379  * Returns: the #GtkUIManager for @shell_window
1380  **/
1381 GtkUIManager *
e_shell_window_get_ui_manager(EShellWindow * shell_window)1382 e_shell_window_get_ui_manager (EShellWindow *shell_window)
1383 {
1384 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1385 
1386 	return shell_window->priv->ui_manager;
1387 }
1388 
1389 /**
1390  * e_shell_window_get_action:
1391  * @shell_window: an #EShellWindow
1392  * @action_name: the name of an action
1393  *
1394  * Returns the #GtkAction named @action_name in @shell_window<!-- -->'s
1395  * user interface manager, or %NULL if no such action exists.
1396  *
1397  * Returns: the #GtkAction named @action_name
1398  **/
1399 GtkAction *
e_shell_window_get_action(EShellWindow * shell_window,const gchar * action_name)1400 e_shell_window_get_action (EShellWindow *shell_window,
1401                            const gchar *action_name)
1402 {
1403 	GtkUIManager *ui_manager;
1404 
1405 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1406 	g_return_val_if_fail (action_name != NULL, NULL);
1407 
1408 	ui_manager = e_shell_window_get_ui_manager (shell_window);
1409 
1410 	return e_lookup_action (ui_manager, action_name);
1411 }
1412 
1413 /**
1414  * e_shell_window_get_action_group:
1415  * @shell_window: an #EShellWindow
1416  * @group_name: the name of an action group
1417  *
1418  * Returns the #GtkActionGroup named @group_name in
1419  * @shell_window<!-- -->'s user interface manager, or %NULL if no
1420  * such action group exists.
1421  *
1422  * Returns: the #GtkActionGroup named @group_name
1423  **/
1424 GtkActionGroup *
e_shell_window_get_action_group(EShellWindow * shell_window,const gchar * group_name)1425 e_shell_window_get_action_group (EShellWindow *shell_window,
1426                                  const gchar *group_name)
1427 {
1428 	GtkUIManager *ui_manager;
1429 
1430 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1431 	g_return_val_if_fail (group_name != NULL, NULL);
1432 
1433 	ui_manager = e_shell_window_get_ui_manager (shell_window);
1434 
1435 	return e_lookup_action_group (ui_manager, group_name);
1436 }
1437 
1438 /**
1439  * e_shell_window_get_managed_widget:
1440  * @shell_window: an #EShellWindow
1441  * @widget_path: path in the UI definition
1442  *
1443  * Looks up a widget in @shell_window<!-- -->'s user interface manager by
1444  * following a path.  See gtk_ui_manager_get_widget() for more information
1445  * about paths.
1446  *
1447  * Returns: the widget found by following the path, or %NULL if no widget
1448  *          was found
1449  **/
1450 GtkWidget *
e_shell_window_get_managed_widget(EShellWindow * shell_window,const gchar * widget_path)1451 e_shell_window_get_managed_widget (EShellWindow *shell_window,
1452                                    const gchar *widget_path)
1453 {
1454 	GtkUIManager *ui_manager;
1455 	GtkWidget *widget;
1456 
1457 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1458 	g_return_val_if_fail (widget_path != NULL, NULL);
1459 
1460 	ui_manager = e_shell_window_get_ui_manager (shell_window);
1461 	widget = gtk_ui_manager_get_widget (ui_manager, widget_path);
1462 
1463 	g_return_val_if_fail (widget != NULL, NULL);
1464 
1465 	return widget;
1466 }
1467 
1468 /**
1469  * e_shell_window_get_active_view:
1470  * @shell_window: an #EShellWindow
1471  *
1472  * Returns the name of the active #EShellView.
1473  *
1474  * Returns: the name of the active view
1475  **/
1476 const gchar *
e_shell_window_get_active_view(EShellWindow * shell_window)1477 e_shell_window_get_active_view (EShellWindow *shell_window)
1478 {
1479 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
1480 
1481 	return shell_window->priv->active_view;
1482 }
1483 
1484 /**
1485  * e_shell_window_set_active_view:
1486  * @shell_window: an #EShellWindow
1487  * @view_name: the name of the shell view to switch to
1488  *
1489  * Switches @shell_window to the #EShellView named @view_name, causing
1490  * the entire content of @shell_window to change.  This is typically
1491  * called as a result of the user clicking one of the switcher buttons.
1492  *
1493  * The name of the newly activated shell view is also written to GSettings key
1494  * <filename>/org/gnome/evolution/shell/default-component-id</filename>.
1495  * This makes the active shell view persistent across Evolution sessions.
1496  * It also causes new shell windows created within the current Evolution
1497  * session to open to the most recently selected shell view.
1498  **/
1499 void
e_shell_window_set_active_view(EShellWindow * shell_window,const gchar * view_name)1500 e_shell_window_set_active_view (EShellWindow *shell_window,
1501                                 const gchar *view_name)
1502 {
1503 	GtkAction *action;
1504 	EShellView *shell_view;
1505 
1506 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1507 	g_return_if_fail (view_name != NULL);
1508 
1509 	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
1510 	g_return_if_fail (shell_view != NULL);
1511 
1512 	action = e_shell_view_get_action (shell_view);
1513 	gtk_action_activate (action);
1514 
1515 	/* Renegotiate the shell window size in case a newly-created
1516 	 * shell view needs tweaked to accommodate a smaller screen. */
1517 	gtk_widget_queue_resize (GTK_WIDGET (shell_window));
1518 }
1519 
1520 /**
1521  * e_shell_window_get_safe_mode:
1522  * @shell_window: an #EShellWindow
1523  *
1524  * Returns %TRUE if @shell_window is in "safe mode".
1525  *
1526  * It's up to the various #EShellView<!-- -->'s to define exactly
1527  * what "safe mode" means.  The @shell_window simply manages the
1528  * "safe mode" state.
1529  *
1530  * Returns: %TRUE if @shell_window is in "safe mode"
1531  **/
1532 gboolean
e_shell_window_get_safe_mode(EShellWindow * shell_window)1533 e_shell_window_get_safe_mode (EShellWindow *shell_window)
1534 {
1535 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1536 
1537 	return shell_window->priv->safe_mode;
1538 }
1539 
1540 /**
1541  * e_shell_window_set_safe_mode:
1542  * @shell_window: an #EShellWindow
1543  * @safe_mode: whether to put @shell_window into "safe mode"
1544  *
1545  * If %TRUE, puts @shell_window into "safe mode".
1546  *
1547  * It's up to the various #EShellView<!-- -->'s to define exactly
1548  * what "safe mode" means.  The @shell_window simply manages the
1549  * "safe mode" state.
1550  **/
1551 void
e_shell_window_set_safe_mode(EShellWindow * shell_window,gboolean safe_mode)1552 e_shell_window_set_safe_mode (EShellWindow *shell_window,
1553                               gboolean safe_mode)
1554 {
1555 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1556 
1557 	if (shell_window->priv->safe_mode == safe_mode)
1558 		return;
1559 
1560 	shell_window->priv->safe_mode = safe_mode;
1561 
1562 	g_object_notify (G_OBJECT (shell_window), "safe-mode");
1563 }
1564 
1565 /**
1566  * e_shell_window_add_action_group:
1567  * @shell_window: an #EShellWindow
1568  * @group_name: the name of the new action group
1569  *
1570  * Creates a new #GtkActionGroup and adds it to @shell_window<!-- -->'s
1571  * user interface manager.  This also takes care of details like setting
1572  * the translation domain.
1573  **/
1574 void
e_shell_window_add_action_group(EShellWindow * shell_window,const gchar * group_name)1575 e_shell_window_add_action_group (EShellWindow *shell_window,
1576                                  const gchar *group_name)
1577 {
1578 	e_shell_window_add_action_group_full (shell_window, group_name, NULL);
1579 }
1580 
1581 void
e_shell_window_add_action_group_full(EShellWindow * shell_window,const gchar * group_name,const gchar * for_view_name)1582 e_shell_window_add_action_group_full (EShellWindow *shell_window,
1583 				      const gchar *group_name,
1584 				      const gchar *for_view_name)
1585 {
1586 	GtkActionGroup *action_group;
1587 	GtkUIManager *ui_manager;
1588 	const gchar *domain;
1589 
1590 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1591 	g_return_if_fail (group_name != NULL);
1592 
1593 	ui_manager = e_shell_window_get_ui_manager (shell_window);
1594 	domain = GETTEXT_PACKAGE;
1595 
1596 	action_group = gtk_action_group_new (group_name);
1597 	gtk_action_group_set_translation_domain (action_group, domain);
1598 	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1599 
1600 	if (for_view_name) {
1601 		GPtrArray *view_groups;
1602 
1603 		view_groups = g_hash_table_lookup (shell_window->priv->action_groups_by_view, for_view_name);
1604 
1605 		if (!view_groups) {
1606 			view_groups = g_ptr_array_new_with_free_func (g_object_unref);
1607 			g_hash_table_insert (shell_window->priv->action_groups_by_view, g_strdup (for_view_name), view_groups);
1608 		}
1609 
1610 		/* Takes ownership of the action_group. */
1611 		g_ptr_array_add (view_groups, action_group);
1612 	} else {
1613 		g_object_unref (action_group);
1614 	}
1615 }
1616 
1617 static void
shell_window_menubar_info_response_cb(EAlert * alert,gint response_id,gpointer user_data)1618 shell_window_menubar_info_response_cb (EAlert *alert,
1619 				       gint response_id,
1620 				       gpointer user_data)
1621 {
1622 	GWeakRef *weakref = user_data;
1623 
1624 	g_return_if_fail (weakref != NULL);
1625 
1626 	if (response_id == GTK_RESPONSE_APPLY) {
1627 		EShellWindow *shell_window;
1628 
1629 		shell_window = g_weak_ref_get (weakref);
1630 		if (shell_window) {
1631 			e_shell_window_set_menubar_visible (shell_window, TRUE);
1632 			g_object_unref (shell_window);
1633 		}
1634 	}
1635 }
1636 
1637 /**
1638  * e_shell_window_get_menubar_visible:
1639  * @shell_window: an #EShellWindow
1640  *
1641  * Returns %TRUE if @shell_window<!-- -->'s menu bar is visible.
1642  *
1643  * Returns: %TRUE is the menu bar is visible
1644  *
1645  * Since: 3.24
1646  **/
1647 gboolean
e_shell_window_get_menubar_visible(EShellWindow * shell_window)1648 e_shell_window_get_menubar_visible (EShellWindow *shell_window)
1649 {
1650 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1651 
1652 	return shell_window->priv->menubar_visible;
1653 }
1654 
1655 /**
1656  * e_shell_window_set_menubar_visible:
1657  * @shell_window: an #EShellWindow
1658  * @menubar_visible: whether the menu bar should be visible
1659  *
1660  * Makes @shell_window<!-- -->'s menu bar visible or invisible.
1661  *
1662  * Since: 3.24
1663  **/
1664 void
e_shell_window_set_menubar_visible(EShellWindow * shell_window,gboolean menubar_visible)1665 e_shell_window_set_menubar_visible (EShellWindow *shell_window,
1666 				    gboolean menubar_visible)
1667 {
1668 	GSettings *settings;
1669 
1670 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1671 
1672 	if (shell_window->priv->menubar_visible == menubar_visible)
1673 		return;
1674 
1675 	shell_window->priv->menubar_visible = menubar_visible;
1676 
1677 	settings = e_util_ref_settings ("org.gnome.evolution.shell");
1678 	if (!menubar_visible &&
1679 	    g_settings_get_boolean (settings, e_shell_window_is_main_instance (shell_window) ? "menubar-visible" : "menubar-visible-sub")) {
1680 		/* The menu bar had been just hidden. Show a hint how to enable it. */
1681 		EAlert *alert;
1682 
1683 		alert = e_alert_new ("shell:menubar-hidden", NULL);
1684 
1685 		g_signal_connect_data (alert, "response", G_CALLBACK (shell_window_menubar_info_response_cb),
1686 			e_weak_ref_new (shell_window), (GClosureNotify) e_weak_ref_free, 0);
1687 
1688 		e_alert_sink_submit_alert (E_ALERT_SINK (shell_window), alert);
1689 		e_alert_start_timer (alert, 30);
1690 		g_object_unref (alert);
1691 	}
1692 	g_object_unref (settings);
1693 
1694 	g_object_notify (G_OBJECT (shell_window), "menubar-visible");
1695 }
1696 
1697 /**
1698  * e_shell_window_get_sidebar_visible:
1699  * @shell_window: an #EShellWindow
1700  *
1701  * Returns %TRUE if @shell_window<!-- -->'s side bar is visible.
1702  *
1703  * Returns: %TRUE is the side bar is visible
1704  **/
1705 gboolean
e_shell_window_get_sidebar_visible(EShellWindow * shell_window)1706 e_shell_window_get_sidebar_visible (EShellWindow *shell_window)
1707 {
1708 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1709 
1710 	return shell_window->priv->sidebar_visible;
1711 }
1712 
1713 /**
1714  * e_shell_window_set_sidebar_visible:
1715  * @shell_window: an #EShellWindow
1716  * @sidebar_visible: whether the side bar should be visible
1717  *
1718  * Makes @shell_window<!-- -->'s side bar visible or invisible.
1719  **/
1720 void
e_shell_window_set_sidebar_visible(EShellWindow * shell_window,gboolean sidebar_visible)1721 e_shell_window_set_sidebar_visible (EShellWindow *shell_window,
1722                                     gboolean sidebar_visible)
1723 {
1724 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1725 
1726 	if (shell_window->priv->sidebar_visible == sidebar_visible)
1727 		return;
1728 
1729 	shell_window->priv->sidebar_visible = sidebar_visible;
1730 
1731 	g_object_notify (G_OBJECT (shell_window), "sidebar-visible");
1732 }
1733 
1734 /**
1735  * e_shell_window_get_switcher_visible:
1736  * @shell_window: an #EShellWindow
1737  *
1738  * Returns %TRUE if @shell_window<!-- -->'s switcher buttons are visible.
1739  *
1740  * Returns: %TRUE is the switcher buttons are visible
1741  **/
1742 gboolean
e_shell_window_get_switcher_visible(EShellWindow * shell_window)1743 e_shell_window_get_switcher_visible (EShellWindow *shell_window)
1744 {
1745 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1746 
1747 	return shell_window->priv->switcher_visible;
1748 }
1749 
1750 /**
1751  * e_shell_window_set_switcher_visible:
1752  * @shell_window: an #EShellWindow
1753  * @switcher_visible: whether the switcher buttons should be visible
1754  *
1755  * Makes @shell_window<!-- -->'s switcher buttons visible or invisible.
1756  **/
1757 void
e_shell_window_set_switcher_visible(EShellWindow * shell_window,gboolean switcher_visible)1758 e_shell_window_set_switcher_visible (EShellWindow *shell_window,
1759                                      gboolean switcher_visible)
1760 {
1761 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1762 
1763 	if (shell_window->priv->switcher_visible == switcher_visible)
1764 		return;
1765 
1766 	shell_window->priv->switcher_visible = switcher_visible;
1767 
1768 	g_object_notify (G_OBJECT (shell_window), "switcher-visible");
1769 }
1770 
1771 /**
1772  * e_shell_window_get_taskbar_visible:
1773  * @shell_window: an #EShellWindow
1774  *
1775  * Returns %TRUE if @shell_window<!-- -->'s task bar is visible.
1776  *
1777  * Returns: %TRUE is the task bar is visible
1778  **/
1779 gboolean
e_shell_window_get_taskbar_visible(EShellWindow * shell_window)1780 e_shell_window_get_taskbar_visible (EShellWindow *shell_window)
1781 {
1782 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1783 
1784 	return shell_window->priv->taskbar_visible;
1785 }
1786 
1787 /**
1788  * e_shell_window_set_taskbar_visible:
1789  * @shell_window: an #EShellWindow
1790  * @taskbar_visible: whether the task bar should be visible
1791  *
1792  * Makes @shell_window<!-- -->'s task bar visible or invisible.
1793  **/
1794 void
e_shell_window_set_taskbar_visible(EShellWindow * shell_window,gboolean taskbar_visible)1795 e_shell_window_set_taskbar_visible (EShellWindow *shell_window,
1796                                     gboolean taskbar_visible)
1797 {
1798 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1799 
1800 	if (shell_window->priv->taskbar_visible == taskbar_visible)
1801 		return;
1802 
1803 	shell_window->priv->taskbar_visible = taskbar_visible;
1804 
1805 	g_object_notify (G_OBJECT (shell_window), "taskbar-visible");
1806 }
1807 
1808 /**
1809  * e_shell_window_get_toolbar_visible:
1810  * @shell_window: an #EShellWindow
1811  *
1812  * Returns %TRUE if @shell_window<!-- -->'s tool bar is visible.
1813  *
1814  * Returns: %TRUE if the tool bar is visible
1815  **/
1816 gboolean
e_shell_window_get_toolbar_visible(EShellWindow * shell_window)1817 e_shell_window_get_toolbar_visible (EShellWindow *shell_window)
1818 {
1819 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
1820 
1821 	return shell_window->priv->toolbar_visible;
1822 }
1823 
1824 /**
1825  * e_shell_window_set_toolbar_visible:
1826  * @shell_window: an #EShellWindow
1827  * @toolbar_visible: whether the tool bar should be visible
1828  *
1829  * Makes @shell_window<!-- -->'s tool bar visible or invisible.
1830  **/
1831 void
e_shell_window_set_toolbar_visible(EShellWindow * shell_window,gboolean toolbar_visible)1832 e_shell_window_set_toolbar_visible (EShellWindow *shell_window,
1833                                     gboolean toolbar_visible)
1834 {
1835 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1836 
1837 	if (shell_window->priv->toolbar_visible == toolbar_visible)
1838 		return;
1839 
1840 	shell_window->priv->toolbar_visible = toolbar_visible;
1841 
1842 	g_object_notify (G_OBJECT (shell_window), "toolbar-visible");
1843 }
1844 
1845 typedef struct {
1846 	EShellWindow *shell_window;
1847 	ESource *source;
1848 	gchar *extension_name;
1849 	EShellWindowConnetClientFunc connected_cb;
1850 	gpointer user_data;
1851 	GDestroyNotify destroy_user_data;
1852 
1853 	EClient *client;
1854 } ConnectClientData;
1855 
1856 static void
connect_client_data_free(gpointer ptr)1857 connect_client_data_free (gpointer ptr)
1858 {
1859 	ConnectClientData *cc_data = ptr;
1860 
1861 	if (cc_data) {
1862 		if (cc_data->client && cc_data->connected_cb)
1863 			cc_data->connected_cb (cc_data->shell_window, cc_data->client, cc_data->user_data);
1864 
1865 		g_clear_object (&cc_data->shell_window);
1866 		g_clear_object (&cc_data->source);
1867 		g_clear_object (&cc_data->client);
1868 		g_free (cc_data->extension_name);
1869 
1870 		if (cc_data->destroy_user_data)
1871 			cc_data->destroy_user_data (cc_data->user_data);
1872 
1873 		g_slice_free (ConnectClientData, cc_data);
1874 	}
1875 }
1876 
1877 static void
shell_window_connect_client_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)1878 shell_window_connect_client_thread (EAlertSinkThreadJobData *job_data,
1879 				    gpointer user_data,
1880 				    GCancellable *cancellable,
1881 				    GError **error)
1882 {
1883 	ConnectClientData *cc_data = user_data;
1884 	EShell *shell;
1885 	EClientCache *client_cache;
1886 	GError *local_error = NULL;
1887 
1888 	g_return_if_fail (cc_data != NULL);
1889 
1890 	shell = e_shell_window_get_shell (cc_data->shell_window);
1891 	client_cache = e_shell_get_client_cache (shell);
1892 
1893 	cc_data->client = e_client_cache_get_client_sync (client_cache,
1894 		cc_data->source, cc_data->extension_name, 30, cancellable, &local_error);
1895 
1896 	e_util_propagate_open_source_job_error (job_data, cc_data->extension_name, local_error, error);
1897 }
1898 
1899 /**
1900  * e_shell_window_connect_client:
1901  * @shell_window: an #EShellWindow
1902  * @source: an #ESource to connect to
1903  * @extension_name: an extension name
1904  * @connected_cb: a callback to be called when the client is opened
1905  * @user_data: a user data passed to @connected_cb
1906  * @destroy_user_data: (allow none): callback to free @user_data when no longer needed
1907  *
1908  * Get's an #EClient from shell's #EClientCache in a dedicated thread, thus
1909  * the operation doesn't block UI. The @connected_cb is called in the main thread,
1910  * but only when the operation succeeded. Any failure is propageted to UI.
1911  *
1912  * Since: 3.16
1913  **/
1914 void
e_shell_window_connect_client(EShellWindow * shell_window,ESource * source,const gchar * extension_name,EShellWindowConnetClientFunc connected_cb,gpointer user_data,GDestroyNotify destroy_user_data)1915 e_shell_window_connect_client (EShellWindow *shell_window,
1916 			       ESource *source,
1917 			       const gchar *extension_name,
1918 			       EShellWindowConnetClientFunc connected_cb,
1919 			       gpointer user_data,
1920 			       GDestroyNotify destroy_user_data)
1921 {
1922 	ConnectClientData *cc_data;
1923 	EShellView *shell_view;
1924 	EActivity *activity;
1925 	gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL, *display_name;
1926 
1927 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1928 	g_return_if_fail (E_IS_SOURCE (source));
1929 	g_return_if_fail (extension_name != NULL);
1930 	g_return_if_fail (connected_cb != NULL);
1931 
1932 	shell_view = e_shell_window_get_shell_view (shell_window,
1933 		e_shell_window_get_active_view (shell_window));
1934 
1935 	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
1936 
1937 	display_name = e_util_get_source_full_name (e_shell_get_registry (e_shell_backend_get_shell (e_shell_view_get_shell_backend (shell_view))), source);
1938 
1939 	if (!e_util_get_open_source_job_info (extension_name, display_name,
1940 		&description, &alert_ident, &alert_arg_0)) {
1941 		g_free (display_name);
1942 		g_warn_if_reached ();
1943 		return;
1944 	}
1945 
1946 	g_free (display_name);
1947 
1948 	cc_data = g_slice_new0 (ConnectClientData);
1949 	cc_data->shell_window = g_object_ref (shell_window);
1950 	cc_data->source = g_object_ref (source);
1951 	cc_data->extension_name = g_strdup (extension_name);
1952 	cc_data->connected_cb = connected_cb;
1953 	cc_data->user_data = user_data;
1954 	cc_data->destroy_user_data = destroy_user_data;
1955 	cc_data->client = NULL;
1956 
1957 	activity = e_shell_view_submit_thread_job (shell_view, description, alert_ident, alert_arg_0,
1958 		shell_window_connect_client_thread, cc_data, connect_client_data_free);
1959 
1960 	g_clear_object (&activity);
1961 	g_free (description);
1962 	g_free (alert_ident);
1963 	g_free (alert_arg_0);
1964 }
1965 
1966 /**
1967  * e_shell_window_register_new_item_actions:
1968  * @shell_window: an #EShellWindow
1969  * @backend_name: name of an #EShellBackend
1970  * @entries: an array of #GtkActionEntry<!-- -->s
1971  * @n_entries: number of elements in the array
1972  *
1973  * Registers a list of #GtkAction<!-- -->s to appear in
1974  * @shell_window<!-- -->'s "New" menu and toolbar button.  This
1975  * function should be called from an #EShell<!-- -->'s
1976  * #GtkApplication::window-added signal handler.  The #EShellBackend
1977  * calling this function should pass its own name for the @backend_name
1978  * argument (i.e. the <structfield>name</structfield> field from its own
1979  * #EShellBackendInfo).
1980  *
1981  * The registered #GtkAction<!-- -->s should be for creating individual
1982  * items such as an email message or a calendar appointment.  The action
1983  * labels should be marked for translation with the "New" context using
1984  * the NC_() macro.
1985  **/
1986 void
e_shell_window_register_new_item_actions(EShellWindow * shell_window,const gchar * backend_name,GtkActionEntry * entries,guint n_entries)1987 e_shell_window_register_new_item_actions (EShellWindow *shell_window,
1988                                           const gchar *backend_name,
1989                                           GtkActionEntry *entries,
1990                                           guint n_entries)
1991 {
1992 	GtkActionGroup *action_group;
1993 	GtkAccelGroup *accel_group;
1994 	GtkUIManager *ui_manager;
1995 	guint ii;
1996 
1997 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
1998 	g_return_if_fail (backend_name != NULL);
1999 	g_return_if_fail (entries != NULL);
2000 
2001 	action_group = ACTION_GROUP (NEW_ITEM);
2002 	ui_manager = e_shell_window_get_ui_manager (shell_window);
2003 	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
2004 	backend_name = g_intern_string (backend_name);
2005 
2006 	/* XXX The action label translations are retrieved from the
2007 	 *     message context "New", but gtk_action_group_add_actions()
2008 	 *     does not support message contexts.  So we have to fetch
2009 	 *     the label translations ourselves before adding them to
2010 	 *     the action group.
2011 	 *
2012 	 *     gtk_action_group_set_translate_func() does not help here
2013 	 *     because the action tooltips do not use a message context
2014 	 *     (though I suppose they could). */
2015 	for (ii = 0; ii < n_entries; ii++)
2016 		entries[ii].label = g_dpgettext2 (
2017 			GETTEXT_PACKAGE, "New", entries[ii].label);
2018 
2019 	gtk_action_group_add_actions (
2020 		action_group, entries, n_entries, shell_window);
2021 
2022 	/* Tag each action with the name of the shell backend that
2023 	 * registered it.  This is used to help sort actions in the
2024 	 * "New" menu. */
2025 
2026 	for (ii = 0; ii < n_entries; ii++) {
2027 		const gchar *action_name;
2028 		GtkAction *action;
2029 
2030 		action_name = entries[ii].name;
2031 
2032 		action = gtk_action_group_get_action (
2033 			action_group, action_name);
2034 
2035 		gtk_action_set_accel_group (action, accel_group);
2036 
2037 		g_object_set_data (
2038 			G_OBJECT (action),
2039 			"backend-name", (gpointer) backend_name);
2040 
2041 		/* The first action becomes the first item in the "New"
2042 		 * menu, and consequently its icon is shown in the "New"
2043 		 * button when the shell backend's view is active.  This
2044 		 * is all sorted out in shell_window_extract_actions().
2045 		 * Note, the data value just needs to be non-zero. */
2046 		if (ii == 0)
2047 			g_object_set_data (
2048 				G_OBJECT (action),
2049 				"primary", GINT_TO_POINTER (TRUE));
2050 	}
2051 }
2052 
2053 /**
2054  * e_shell_window_register_new_source_actions:
2055  * @shell_window: an #EShellWindow
2056  * @backend_name: name of an #EShellBackend
2057  * @entries: an array of #GtkActionEntry<!-- -->s
2058  * @n_entries: number of elements in the array
2059  *
2060  * Registers a list of #GtkAction<!-- -->s to appear in
2061  * @shell_window<!-- -->'s "New" menu and toolbar button.  This
2062  * function should be called from an #EShell<!-- -->'s
2063  * #GtkApplication::window-added signal handler.  The #EShellBackend
2064  * calling this function should pass its own name for the @backend_name
2065  * argument (i.e. the <structfield>name</structfield> field from its own
2066  * #EShellBackendInfo).
2067  *
2068  * The registered #GtkAction<!-- -->s should be for creating item
2069  * containers such as an email folder or a calendar.  The action labels
2070  * should be marked for translation with the "New" context using the
2071  * NC_() macro.
2072  **/
2073 void
e_shell_window_register_new_source_actions(EShellWindow * shell_window,const gchar * backend_name,GtkActionEntry * entries,guint n_entries)2074 e_shell_window_register_new_source_actions (EShellWindow *shell_window,
2075                                             const gchar *backend_name,
2076                                             GtkActionEntry *entries,
2077                                             guint n_entries)
2078 {
2079 	GtkActionGroup *action_group;
2080 	GtkAccelGroup *accel_group;
2081 	GtkUIManager *ui_manager;
2082 	guint ii;
2083 
2084 	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
2085 	g_return_if_fail (backend_name != NULL);
2086 	g_return_if_fail (entries != NULL);
2087 
2088 	action_group = ACTION_GROUP (NEW_SOURCE);
2089 	ui_manager = e_shell_window_get_ui_manager (shell_window);
2090 	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
2091 	backend_name = g_intern_string (backend_name);
2092 
2093 	/* XXX The action label translations are retrieved from the
2094 	 *     message context "New", but gtk_action_group_add_actions()
2095 	 *     does not support message contexts.  So we have to fetch
2096 	 *     the label translations ourselves before adding them to
2097 	 *     the action group.
2098 	 *
2099 	 *     gtk_action_group_set_translate_func() does not help here
2100 	 *     because the action tooltips do not use a message context
2101 	 *     (though I suppose they could). */
2102 	for (ii = 0; ii < n_entries; ii++)
2103 		entries[ii].label = g_dpgettext2 (
2104 			GETTEXT_PACKAGE, "New", entries[ii].label);
2105 
2106 	gtk_action_group_add_actions (
2107 		action_group, entries, n_entries, shell_window);
2108 
2109 	/* Tag each action with the name of the shell backend that
2110 	 * registered it.  This is used to help sort actions in the
2111 	 * "New" menu. */
2112 
2113 	for (ii = 0; ii < n_entries; ii++) {
2114 		const gchar *action_name;
2115 		GtkAction *action;
2116 
2117 		action_name = entries[ii].name;
2118 
2119 		action = gtk_action_group_get_action (
2120 			action_group, action_name);
2121 
2122 		gtk_action_set_accel_group (action, accel_group);
2123 
2124 		g_object_set_data (
2125 			G_OBJECT (action),
2126 			"backend-name", (gpointer) backend_name);
2127 	}
2128 }
2129 
2130 /**
2131  * e_shell_window_get_need_input:
2132  * @shell_window: an #EShellWindow
2133  * @event: a #GdkEventKey
2134  *
2135  * Returns: Whether the key @event should be processed by currently
2136  *    focused widget in the @window, instead of being processed
2137  *    bu usual means including accelerators.
2138  *
2139  * Since: 3.32
2140  **/
2141 gboolean
e_shell_window_get_need_input(EShellWindow * shell_window,GdkEventKey * event)2142 e_shell_window_get_need_input (EShellWindow *shell_window,
2143 			       GdkEventKey *event)
2144 {
2145 	GtkWidget *focused;
2146 
2147 	g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
2148 	g_return_val_if_fail (event != NULL, FALSE);
2149 
2150 	if ((event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0)
2151 		return FALSE;
2152 
2153 	if (event->keyval == GDK_KEY_F1 ||
2154 	    event->keyval == GDK_KEY_F2 ||
2155 	    event->keyval == GDK_KEY_F3 ||
2156 	    event->keyval == GDK_KEY_F4 ||
2157 	    event->keyval == GDK_KEY_F5 ||
2158 	    event->keyval == GDK_KEY_F6 ||
2159 	    event->keyval == GDK_KEY_F7 ||
2160 	    event->keyval == GDK_KEY_F8 ||
2161 	    event->keyval == GDK_KEY_F9 ||
2162 	    event->keyval == GDK_KEY_F10 ||
2163 	    event->keyval == GDK_KEY_F11 ||
2164 	    event->keyval == GDK_KEY_F12 ||
2165 	    event->keyval == GDK_KEY_Tab ||
2166 	    event->keyval == GDK_KEY_KP_Tab)
2167 		return FALSE;
2168 
2169 	focused = gtk_window_get_focus (GTK_WINDOW (shell_window));
2170 
2171 	/* The F2 is used as a shortcut to rename folder in the Mail view */
2172 	return focused && (GTK_IS_ENTRY (focused) ||
2173 		GTK_IS_EDITABLE (focused) ||
2174 		(GTK_IS_TREE_VIEW (focused) && event->keyval != GDK_KEY_F2 && gtk_tree_view_get_search_column (GTK_TREE_VIEW (focused)) >= 0));
2175 }
2176