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