1 /*
2 * pluma-window.c
3 * This file is part of pluma
4 *
5 * Copyright (C) 2005 - Paolo Maggi
6 * Copyright (C) 2012-2021 MATE Developers
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 /*
25 * Modified by the pluma Team, 2005. See the AUTHORS file for a
26 * list of people on the pluma Team.
27 * See the ChangeLog files for a list of changes.
28 *
29 * $Id$
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include <time.h>
37 #include <sys/types.h>
38 #include <string.h>
39
40 #include <gdk/gdk.h>
41 #include <glib/gi18n.h>
42 #include <gio/gio.h>
43 #include <gtk/gtk.h>
44 #include <gtksourceview/gtksource.h>
45 #include <libpeas/peas-extension-set.h>
46
47 #include "pluma-ui.h"
48 #include "pluma-window.h"
49 #include "pluma-window-private.h"
50 #include "pluma-app.h"
51 #include "pluma-notebook.h"
52 #include "pluma-statusbar.h"
53 #include "pluma-utils.h"
54 #include "pluma-commands.h"
55 #include "pluma-debug.h"
56 #include "pluma-language-manager.h"
57 #include "pluma-panel.h"
58 #include "pluma-documents-panel.h"
59 #include "pluma-plugins-engine.h"
60 #include "pluma-window-activatable.h"
61 #include "pluma-enum-types.h"
62 #include "pluma-dirs.h"
63 #include "pluma-status-combo-box.h"
64 #include "pluma-settings.h"
65
66 #define LANGUAGE_NONE (const gchar *)"LangNone"
67 #define TAB_WIDTH_DATA "PlumaWindowTabWidthData"
68 #define LANGUAGE_DATA "PlumaWindowLanguageData"
69 #define FULLSCREEN_ANIMATION_SPEED 4
70
71 #define PLUMA_WINDOW_DEFAULT_WIDTH 650
72 #define PLUMA_WINDOW_DEFAULT_HEIGHT 500
73
74 /* Local variables */
75 static gboolean cansave = TRUE;
76
77 /* Signals */
78 enum
79 {
80 TAB_ADDED,
81 TAB_REMOVED,
82 TABS_REORDERED,
83 ACTIVE_TAB_CHANGED,
84 ACTIVE_TAB_STATE_CHANGED,
85 LAST_SIGNAL
86 };
87
88 static guint signals[LAST_SIGNAL] = { 0 };
89
90 enum
91 {
92 PROP_0,
93 PROP_STATE
94 };
95
96 enum
97 {
98 TARGET_URI_LIST = 100
99 };
100
101 G_DEFINE_TYPE_WITH_PRIVATE (PlumaWindow, pluma_window, GTK_TYPE_WINDOW)
102
103 static void recent_manager_changed (GtkRecentManager *manager,
104 PlumaWindow *window);
105
106 static void
pluma_window_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)107 pluma_window_get_property (GObject *object,
108 guint prop_id,
109 GValue *value,
110 GParamSpec *pspec)
111 {
112 PlumaWindow *window = PLUMA_WINDOW (object);
113
114 switch (prop_id)
115 {
116 case PROP_STATE:
117 g_value_set_enum (value,
118 pluma_window_get_state (window));
119 break;
120 default:
121 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122 break;
123 }
124 }
125
126 static void
save_panes_state(PlumaWindow * window)127 save_panes_state (PlumaWindow *window)
128 {
129 gint pane_page;
130
131 pluma_debug (DEBUG_WINDOW);
132
133 g_settings_set (window->priv->editor_settings, PLUMA_SETTINGS_WINDOW_SIZE,
134 "(ii)", window->priv->width, window->priv->height);
135
136 g_settings_set_int (window->priv->editor_settings, PLUMA_SETTINGS_WINDOW_STATE,
137 window->priv->window_state);
138
139 if (window->priv->side_panel_size > 0)
140 g_settings_set_int (window->priv->editor_settings,
141 PLUMA_SETTINGS_SIDE_PANEL_SIZE,
142 window->priv->side_panel_size);
143
144 pane_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (window->priv->side_panel));
145 if (pane_page != 0)
146 g_settings_set_int (window->priv->editor_settings,
147 PLUMA_SETTINGS_SIDE_PANEL_ACTIVE_PAGE,
148 pane_page);
149
150 if (window->priv->bottom_panel_size > 0)
151 g_settings_set_int (window->priv->editor_settings,
152 PLUMA_SETTINGS_BOTTOM_PANEL_SIZE,
153 window->priv->bottom_panel_size);
154
155 pane_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (window->priv->bottom_panel));
156 if (pane_page != 0)
157 g_settings_set_int (window->priv->editor_settings,
158 PLUMA_SETTINGS_BOTTOM_PANEL_ACTIVE_PAGE, pane_page);
159 }
160
161 static void
pluma_window_dispose(GObject * object)162 pluma_window_dispose (GObject *object)
163 {
164 PlumaWindow *window;
165
166 pluma_debug (DEBUG_WINDOW);
167
168 window = PLUMA_WINDOW (object);
169
170 /* Stop tracking removal of panes otherwise we always
171 * end up with thinking we had no pane active, since they
172 * should all be removed below */
173 if (window->priv->bottom_panel_item_removed_handler_id != 0)
174 {
175 g_signal_handler_disconnect (window->priv->bottom_panel,
176 window->priv->bottom_panel_item_removed_handler_id);
177 window->priv->bottom_panel_item_removed_handler_id = 0;
178 }
179
180 /* First of all, force collection so that plugins
181 * really drop some of the references.
182 */
183 peas_engine_garbage_collect (PEAS_ENGINE (pluma_plugins_engine_get_default ()));
184
185 /* save the panes position and make sure to deactivate plugins
186 * for this window, but only once */
187 if (!window->priv->dispose_has_run)
188 {
189 save_panes_state (window);
190
191 /* Note that unreffing the extensions will automatically remove
192 all extensions which in turn will deactivate the extension */
193 g_object_unref (window->priv->extensions);
194
195 peas_engine_garbage_collect (PEAS_ENGINE (pluma_plugins_engine_get_default ()));
196
197 window->priv->dispose_has_run = TRUE;
198 }
199
200 if (window->priv->fullscreen_animation_timeout_id != 0)
201 {
202 g_source_remove (window->priv->fullscreen_animation_timeout_id);
203 window->priv->fullscreen_animation_timeout_id = 0;
204 }
205
206 if (window->priv->fullscreen_controls != NULL)
207 {
208 gtk_widget_destroy (window->priv->fullscreen_controls);
209
210 window->priv->fullscreen_controls = NULL;
211 }
212
213 if (window->priv->recents_handler_id != 0)
214 {
215 GtkRecentManager *recent_manager;
216
217 recent_manager = gtk_recent_manager_get_default ();
218 g_signal_handler_disconnect (recent_manager,
219 window->priv->recents_handler_id);
220 window->priv->recents_handler_id = 0;
221 }
222
223 if (window->priv->manager != NULL)
224 {
225 g_object_unref (window->priv->manager);
226 window->priv->manager = NULL;
227 }
228
229 if (window->priv->message_bus != NULL)
230 {
231 g_object_unref (window->priv->message_bus);
232 window->priv->message_bus = NULL;
233 }
234
235 if (window->priv->window_group != NULL)
236 {
237 g_object_unref (window->priv->window_group);
238 window->priv->window_group = NULL;
239 }
240
241 /* We must free the settings after saving the panels */
242 g_clear_object (&window->priv->editor_settings);
243
244 /* Now that there have broken some reference loops,
245 * force collection again.
246 */
247 peas_engine_garbage_collect (PEAS_ENGINE (pluma_plugins_engine_get_default ()));
248
249 G_OBJECT_CLASS (pluma_window_parent_class)->dispose (object);
250 }
251
252 static void
pluma_window_finalize(GObject * object)253 pluma_window_finalize (GObject *object)
254 {
255 PlumaWindow *window;
256
257 pluma_debug (DEBUG_WINDOW);
258
259 window = PLUMA_WINDOW (object);
260
261 if (window->priv->default_location != NULL)
262 g_object_unref (window->priv->default_location);
263
264 G_OBJECT_CLASS (pluma_window_parent_class)->finalize (object);
265 }
266
267 static gboolean
pluma_window_window_state_event(GtkWidget * widget,GdkEventWindowState * event)268 pluma_window_window_state_event (GtkWidget *widget,
269 GdkEventWindowState *event)
270 {
271 PlumaWindow *window = PLUMA_WINDOW (widget);
272
273 window->priv->window_state = event->new_window_state;
274
275 return GTK_WIDGET_CLASS (pluma_window_parent_class)->window_state_event (widget, event);
276 }
277
278 static gboolean
pluma_window_configure_event(GtkWidget * widget,GdkEventConfigure * event)279 pluma_window_configure_event (GtkWidget *widget,
280 GdkEventConfigure *event)
281 {
282 PlumaWindow *window = PLUMA_WINDOW (widget);
283
284 window->priv->width = event->width;
285 window->priv->height = event->height;
286
287 return GTK_WIDGET_CLASS (pluma_window_parent_class)->configure_event (widget, event);
288 }
289
290 /*
291 * GtkWindow catches keybindings for the menu items _before_ passing them to
292 * the focused widget. This is unfortunate and means that pressing ctrl+V
293 * in an entry on a panel ends up pasting text in the TextView.
294 * Here we override GtkWindow's handler to do the same things that it
295 * does, but in the opposite order and then we chain up to the grand
296 * parent handler, skipping gtk_window_key_press_event.
297 */
298 static gboolean
pluma_window_key_press_event(GtkWidget * widget,GdkEventKey * event)299 pluma_window_key_press_event (GtkWidget *widget,
300 GdkEventKey *event)
301 {
302 static gpointer grand_parent_class = NULL;
303 GtkWindow *window = GTK_WINDOW (widget);
304 gboolean handled = FALSE;
305 /* FIXME: avoid making a new gsettings variable here */
306 GSettings *settings = g_settings_new (PLUMA_SCHEMA_ID);
307
308 if (event->state & GDK_CONTROL_MASK)
309 {
310 gchar *font;
311 gchar *tempsize;
312 gint nsize;
313
314 font = g_settings_get_string (settings, PLUMA_SETTINGS_EDITOR_FONT);
315 tempsize = g_strdup (font);
316
317 g_strreverse (tempsize);
318 g_strcanon (tempsize, "1234567890", '\0');
319 g_strreverse (tempsize);
320
321 gchar tempfont [strlen (font)];
322 strcpy (tempfont, font);
323 tempfont [strlen (font) - strlen (tempsize)] = 0;
324
325 sscanf (tempsize, "%d", &nsize);
326
327 if ((event->keyval == GDK_KEY_plus) || (event->keyval == GDK_KEY_KP_Add))
328 {
329 nsize = nsize + 1;
330 sprintf (tempsize, "%d", nsize);
331
332 if (!g_settings_get_boolean (settings, PLUMA_SETTINGS_USE_DEFAULT_FONT) && (nsize < 73))
333 {
334 gchar *tmp = g_strconcat (tempfont, tempsize, NULL);
335 g_settings_set_string (settings, PLUMA_SETTINGS_EDITOR_FONT, tmp);
336 g_free (tmp);
337 }
338 }
339 else if ((event->keyval == GDK_KEY_minus) || (event->keyval == GDK_KEY_KP_Subtract))
340 {
341 nsize = nsize - 1;
342 sprintf (tempsize, "%d", nsize);
343
344 if (!g_settings_get_boolean (settings, PLUMA_SETTINGS_USE_DEFAULT_FONT) && (nsize > 5))
345 {
346 gchar *tmp = g_strconcat (tempfont, tempsize, NULL);
347 g_settings_set_string (settings, PLUMA_SETTINGS_EDITOR_FONT, tmp);
348 g_free (tmp);
349 }
350 }
351 else if (event->keyval == GDK_KEY_y)
352 {
353 g_settings_set_boolean (settings, PLUMA_SETTINGS_DISPLAY_LINE_NUMBERS,
354 !g_settings_get_boolean (settings, PLUMA_SETTINGS_DISPLAY_LINE_NUMBERS));
355 }
356
357 if (g_settings_get_boolean (settings, PLUMA_SETTINGS_CTRL_TABS_SWITCH_TABS))
358 {
359 GtkNotebook *notebook = GTK_NOTEBOOK (_pluma_window_get_notebook (PLUMA_WINDOW (window)));
360
361 int pages = gtk_notebook_get_n_pages (notebook);
362 int page_num = gtk_notebook_get_current_page (notebook);
363
364 if (event->keyval == GDK_KEY_ISO_Left_Tab)
365 {
366 if (page_num != 0)
367 gtk_notebook_prev_page (notebook);
368 else
369 gtk_notebook_set_current_page (notebook, (pages - 1));
370 handled = TRUE;
371 }
372
373 if (event->keyval == GDK_KEY_Tab)
374 {
375 if (page_num != (pages -1))
376 gtk_notebook_next_page (notebook);
377 else
378 gtk_notebook_set_current_page (notebook, 0);
379 handled = TRUE;
380 }
381 }
382 g_free (font);
383 g_free (tempsize);
384 }
385
386 g_object_unref (settings);
387
388 if (grand_parent_class == NULL)
389 grand_parent_class = g_type_class_peek_parent (pluma_window_parent_class);
390
391 /* handle focus widget key events */
392 if (!handled)
393 handled = gtk_window_propagate_key_event (window, event);
394
395 /* handle mnemonics and accelerators */
396 if (!handled)
397 handled = gtk_window_activate_key (window, event);
398
399 /* Chain up, invokes binding set */
400 if (!handled)
401 handled = GTK_WIDGET_CLASS (grand_parent_class)->key_press_event (widget, event);
402
403 return handled;
404 }
405
406 static void
pluma_window_tab_removed(PlumaWindow * window,PlumaTab * tab)407 pluma_window_tab_removed (PlumaWindow *window,
408 PlumaTab *tab)
409 {
410 peas_engine_garbage_collect (PEAS_ENGINE (pluma_plugins_engine_get_default ()));
411 }
412
413 static void
pluma_window_class_init(PlumaWindowClass * klass)414 pluma_window_class_init (PlumaWindowClass *klass)
415 {
416 GObjectClass *object_class = G_OBJECT_CLASS (klass);
417 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
418
419 klass->tab_removed = pluma_window_tab_removed;
420
421 object_class->dispose = pluma_window_dispose;
422 object_class->finalize = pluma_window_finalize;
423 object_class->get_property = pluma_window_get_property;
424
425 widget_class->window_state_event = pluma_window_window_state_event;
426 widget_class->configure_event = pluma_window_configure_event;
427 widget_class->key_press_event = pluma_window_key_press_event;
428
429 signals[TAB_ADDED] =
430 g_signal_new ("tab_added",
431 G_OBJECT_CLASS_TYPE (object_class),
432 G_SIGNAL_RUN_FIRST,
433 G_STRUCT_OFFSET (PlumaWindowClass, tab_added),
434 NULL, NULL, NULL,
435 G_TYPE_NONE,
436 1,
437 PLUMA_TYPE_TAB);
438 signals[TAB_REMOVED] =
439 g_signal_new ("tab_removed",
440 G_OBJECT_CLASS_TYPE (object_class),
441 G_SIGNAL_RUN_FIRST,
442 G_STRUCT_OFFSET (PlumaWindowClass, tab_removed),
443 NULL, NULL, NULL,
444 G_TYPE_NONE,
445 1,
446 PLUMA_TYPE_TAB);
447 signals[TABS_REORDERED] =
448 g_signal_new ("tabs_reordered",
449 G_OBJECT_CLASS_TYPE (object_class),
450 G_SIGNAL_RUN_FIRST,
451 G_STRUCT_OFFSET (PlumaWindowClass, tabs_reordered),
452 NULL, NULL, NULL,
453 G_TYPE_NONE,
454 0);
455 signals[ACTIVE_TAB_CHANGED] =
456 g_signal_new ("active_tab_changed",
457 G_OBJECT_CLASS_TYPE (object_class),
458 G_SIGNAL_RUN_FIRST,
459 G_STRUCT_OFFSET (PlumaWindowClass, active_tab_changed),
460 NULL, NULL, NULL,
461 G_TYPE_NONE,
462 1,
463 PLUMA_TYPE_TAB);
464 signals[ACTIVE_TAB_STATE_CHANGED] =
465 g_signal_new ("active_tab_state_changed",
466 G_OBJECT_CLASS_TYPE (object_class),
467 G_SIGNAL_RUN_FIRST,
468 G_STRUCT_OFFSET (PlumaWindowClass, active_tab_state_changed),
469 NULL, NULL, NULL,
470 G_TYPE_NONE,
471 0);
472
473 g_object_class_install_property (object_class,
474 PROP_STATE,
475 g_param_spec_flags ("state",
476 "State",
477 "The window's state",
478 PLUMA_TYPE_WINDOW_STATE,
479 PLUMA_WINDOW_STATE_NORMAL,
480 G_PARAM_READABLE |
481 G_PARAM_STATIC_STRINGS));
482 }
483
484 static void
menu_item_select_cb(GtkMenuItem * proxy,PlumaWindow * window)485 menu_item_select_cb (GtkMenuItem *proxy,
486 PlumaWindow *window)
487 {
488 GtkAction *action;
489 char *message;
490
491 action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy));
492 g_return_if_fail (action != NULL);
493
494 g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
495 if (message)
496 {
497 gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
498 window->priv->tip_message_cid, message);
499 g_free (message);
500 }
501 }
502
503 static void
menu_item_deselect_cb(GtkMenuItem * proxy,PlumaWindow * window)504 menu_item_deselect_cb (GtkMenuItem *proxy,
505 PlumaWindow *window)
506 {
507 gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
508 window->priv->tip_message_cid);
509 }
510
511 static void
connect_proxy_cb(GtkUIManager * manager,GtkAction * action,GtkWidget * proxy,PlumaWindow * window)512 connect_proxy_cb (GtkUIManager *manager,
513 GtkAction *action,
514 GtkWidget *proxy,
515 PlumaWindow *window)
516 {
517 if (GTK_IS_MENU_ITEM (proxy))
518 {
519 g_signal_connect (proxy, "select",
520 G_CALLBACK (menu_item_select_cb), window);
521 g_signal_connect (proxy, "deselect",
522 G_CALLBACK (menu_item_deselect_cb), window);
523 }
524 }
525
526 static void
disconnect_proxy_cb(GtkUIManager * manager,GtkAction * action,GtkWidget * proxy,PlumaWindow * window)527 disconnect_proxy_cb (GtkUIManager *manager,
528 GtkAction *action,
529 GtkWidget *proxy,
530 PlumaWindow *window)
531 {
532 if (GTK_IS_MENU_ITEM (proxy))
533 {
534 g_signal_handlers_disconnect_by_func
535 (proxy, G_CALLBACK (menu_item_select_cb), window);
536 g_signal_handlers_disconnect_by_func
537 (proxy, G_CALLBACK (menu_item_deselect_cb), window);
538 }
539 }
540
541 static void
apply_toolbar_style(PlumaWindow * window,GtkWidget * toolbar)542 apply_toolbar_style (PlumaWindow *window,
543 GtkWidget *toolbar)
544 {
545 switch (window->priv->toolbar_style)
546 {
547 case PLUMA_TOOLBAR_SYSTEM:
548 pluma_debug_message (DEBUG_WINDOW, "PLUMA: SYSTEM");
549 gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar));
550 break;
551
552 case PLUMA_TOOLBAR_ICONS:
553 pluma_debug_message (DEBUG_WINDOW, "PLUMA: ICONS");
554 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
555 GTK_TOOLBAR_ICONS);
556 break;
557
558 case PLUMA_TOOLBAR_ICONS_AND_TEXT:
559 pluma_debug_message (DEBUG_WINDOW, "PLUMA: ICONS_AND_TEXT");
560 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
561 GTK_TOOLBAR_BOTH);
562 break;
563
564 case PLUMA_TOOLBAR_ICONS_BOTH_HORIZ:
565 pluma_debug_message (DEBUG_WINDOW, "PLUMA: ICONS_BOTH_HORIZ");
566 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
567 GTK_TOOLBAR_BOTH_HORIZ);
568 break;
569 }
570 }
571
572 /* Returns TRUE if toolbar is visible */
573 static gboolean
set_toolbar_style(PlumaWindow * window,PlumaWindow * origin)574 set_toolbar_style (PlumaWindow *window,
575 PlumaWindow *origin)
576 {
577 gboolean visible;
578 PlumaToolbarSetting style;
579 GtkAction *action;
580
581 if (origin == NULL)
582 visible = g_settings_get_boolean (window->priv->editor_settings,
583 PLUMA_SETTINGS_TOOLBAR_VISIBLE);
584 else
585 visible = gtk_widget_get_visible (origin->priv->toolbar);
586
587 /* Set visibility */
588 if (visible)
589 gtk_widget_show (window->priv->toolbar);
590 else
591 gtk_widget_hide (window->priv->toolbar);
592
593 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
594 "ViewToolbar");
595
596 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
597 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
598
599 /* Set style */
600 if (origin == NULL)
601 {
602 PlumaSettings *settings;
603
604 settings = _pluma_settings_get_singleton ();
605 style = pluma_settings_get_toolbar_style (settings);
606 }
607 else
608 {
609 style = origin->priv->toolbar_style;
610 }
611
612 window->priv->toolbar_style = style;
613
614 apply_toolbar_style (window, window->priv->toolbar);
615
616 return visible;
617 }
618
619 static void
update_next_prev_doc_sensitivity(PlumaWindow * window,PlumaTab * tab)620 update_next_prev_doc_sensitivity (PlumaWindow *window,
621 PlumaTab *tab)
622 {
623 gint tab_number;
624 GtkNotebook *notebook;
625 GtkAction *action;
626
627 pluma_debug (DEBUG_WINDOW);
628
629 notebook = GTK_NOTEBOOK (_pluma_window_get_notebook (window));
630
631 tab_number = gtk_notebook_page_num (notebook, GTK_WIDGET (tab));
632 g_return_if_fail (tab_number >= 0);
633
634 action = gtk_action_group_get_action (window->priv->action_group,
635 "DocumentsPreviousDocument");
636 gtk_action_set_sensitive (action, tab_number != 0);
637
638 action = gtk_action_group_get_action (window->priv->action_group,
639 "DocumentsNextDocument");
640 gtk_action_set_sensitive (action,
641 tab_number < gtk_notebook_get_n_pages (notebook) - 1);
642 }
643
644 static void
update_next_prev_doc_sensitivity_per_window(PlumaWindow * window)645 update_next_prev_doc_sensitivity_per_window (PlumaWindow *window)
646 {
647 PlumaTab *tab;
648 GtkAction *action;
649
650 pluma_debug (DEBUG_WINDOW);
651
652 tab = pluma_window_get_active_tab (window);
653 if (tab != NULL)
654 {
655 update_next_prev_doc_sensitivity (window, tab);
656
657 return;
658 }
659
660 action = gtk_action_group_get_action (window->priv->action_group,
661 "DocumentsPreviousDocument");
662 gtk_action_set_sensitive (action, FALSE);
663
664 action = gtk_action_group_get_action (window->priv->action_group,
665 "DocumentsNextDocument");
666 gtk_action_set_sensitive (action, FALSE);
667
668 }
669
670 static void
received_clipboard_contents(GtkClipboard * clipboard,GtkSelectionData * selection_data,PlumaWindow * window)671 received_clipboard_contents (GtkClipboard *clipboard,
672 GtkSelectionData *selection_data,
673 PlumaWindow *window)
674 {
675 gboolean sens;
676 GtkAction *action;
677
678 /* getting clipboard contents is async, so we need to
679 * get the current tab and its state */
680
681 if (window->priv->active_tab != NULL)
682 {
683 PlumaTabState state;
684 gboolean state_normal;
685
686 state = pluma_tab_get_state (window->priv->active_tab);
687 state_normal = (state == PLUMA_TAB_STATE_NORMAL);
688
689 sens = state_normal &&
690 gtk_selection_data_targets_include_text (selection_data);
691 }
692 else
693 {
694 sens = FALSE;
695 }
696
697 action = gtk_action_group_get_action (window->priv->action_group, "EditPaste");
698
699 gtk_action_set_sensitive (action, sens);
700
701 g_object_unref (window);
702 }
703
704 static void
set_paste_sensitivity_according_to_clipboard(PlumaWindow * window,GtkClipboard * clipboard)705 set_paste_sensitivity_according_to_clipboard (PlumaWindow *window,
706 GtkClipboard *clipboard)
707 {
708 GdkDisplay *display;
709
710 display = gtk_clipboard_get_display (clipboard);
711
712 if (gdk_display_supports_selection_notification (display))
713 {
714 gtk_clipboard_request_contents (clipboard,
715 gdk_atom_intern_static_string ("TARGETS"),
716 (GtkClipboardReceivedFunc) received_clipboard_contents,
717 g_object_ref (window));
718 }
719 else
720 {
721 GtkAction *action;
722
723 action = gtk_action_group_get_action (window->priv->action_group,
724 "EditPaste");
725
726 /* XFIXES extension not availbale, make
727 * Paste always sensitive */
728 gtk_action_set_sensitive (action, TRUE);
729 }
730 }
731
732 static void
set_sensitivity_according_to_tab(PlumaWindow * window,PlumaTab * tab)733 set_sensitivity_according_to_tab (PlumaWindow *window,
734 PlumaTab *tab)
735 {
736 PlumaDocument *doc;
737 PlumaView *view;
738 GtkAction *action;
739 gboolean b;
740 gboolean state_normal;
741 gboolean editable;
742 PlumaTabState state;
743 GtkClipboard *clipboard;
744 PlumaLockdownMask lockdown;
745 gboolean enable_syntax_highlighting;
746
747 g_return_if_fail (PLUMA_TAB (tab));
748
749 pluma_debug (DEBUG_WINDOW);
750
751 enable_syntax_highlighting = g_settings_get_boolean (window->priv->editor_settings,
752 PLUMA_SETTINGS_SYNTAX_HIGHLIGHTING);
753
754 lockdown = pluma_app_get_lockdown (pluma_app_get_default ());
755
756 state = pluma_tab_get_state (tab);
757 state_normal = (state == PLUMA_TAB_STATE_NORMAL);
758
759 view = pluma_tab_get_view (tab);
760 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
761
762 doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
763
764 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
765 GDK_SELECTION_CLIPBOARD);
766
767 action = gtk_action_group_get_action (window->priv->action_group,
768 "FileSave");
769
770 if (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) {
771 gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc), TRUE);
772 }
773
774 gtk_action_set_sensitive (action,
775 (state_normal ||
776 (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
777 (state == PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
778 !pluma_document_get_readonly (doc) &&
779 !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK) &&
780 (cansave) &&
781 (editable));
782
783 action = gtk_action_group_get_action (window->priv->action_group,
784 "FileSaveAs");
785 gtk_action_set_sensitive (action,
786 (state_normal ||
787 (state == PLUMA_TAB_STATE_SAVING_ERROR) ||
788 (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
789 (state == PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
790 !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
791
792 action = gtk_action_group_get_action (window->priv->action_group,
793 "FileRevert");
794 gtk_action_set_sensitive (action,
795 (state_normal ||
796 (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)) &&
797 !pluma_document_is_untitled (doc));
798
799 action = gtk_action_group_get_action (window->priv->action_group,
800 "FilePrintPreview");
801 gtk_action_set_sensitive (action,
802 state_normal &&
803 !(lockdown & PLUMA_LOCKDOWN_PRINTING));
804
805 action = gtk_action_group_get_action (window->priv->action_group,
806 "FilePrint");
807 gtk_action_set_sensitive (action,
808 (state_normal ||
809 (state == PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
810 !(lockdown & PLUMA_LOCKDOWN_PRINTING));
811
812 action = gtk_action_group_get_action (window->priv->close_action_group,
813 "FileClose");
814
815 gtk_action_set_sensitive (action,
816 (state != PLUMA_TAB_STATE_CLOSING) &&
817 (state != PLUMA_TAB_STATE_SAVING) &&
818 (state != PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW) &&
819 (state != PLUMA_TAB_STATE_PRINTING) &&
820 (state != PLUMA_TAB_STATE_PRINT_PREVIEWING) &&
821 (state != PLUMA_TAB_STATE_SAVING_ERROR));
822
823 action = gtk_action_group_get_action (window->priv->action_group,
824 "EditUndo");
825 gtk_action_set_sensitive (action,
826 state_normal &&
827 gtk_source_buffer_can_undo (GTK_SOURCE_BUFFER (doc)));
828
829 action = gtk_action_group_get_action (window->priv->action_group,
830 "EditRedo");
831 gtk_action_set_sensitive (action,
832 state_normal &&
833 gtk_source_buffer_can_redo (GTK_SOURCE_BUFFER (doc)));
834
835 action = gtk_action_group_get_action (window->priv->action_group,
836 "EditCut");
837 gtk_action_set_sensitive (action,
838 state_normal &&
839 editable &&
840 gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
841
842 action = gtk_action_group_get_action (window->priv->action_group,
843 "EditCopy");
844 gtk_action_set_sensitive (action,
845 (state_normal ||
846 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) &&
847 gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
848
849 action = gtk_action_group_get_action (window->priv->action_group,
850 "EditPaste");
851 if (state_normal && editable)
852 {
853 set_paste_sensitivity_according_to_clipboard (window, clipboard);
854 }
855 else
856 {
857 gtk_action_set_sensitive (action, FALSE);
858 }
859
860 action = gtk_action_group_get_action (window->priv->action_group,
861 "EditDelete");
862 gtk_action_set_sensitive (action,
863 state_normal &&
864 editable &&
865 gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
866
867 action = gtk_action_group_get_action (window->priv->action_group,
868 "SearchFind");
869 gtk_action_set_sensitive (action,
870 (state_normal ||
871 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
872
873 action = gtk_action_group_get_action (window->priv->action_group,
874 "SearchIncrementalSearch");
875 gtk_action_set_sensitive (action,
876 (state_normal ||
877 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
878
879 action = gtk_action_group_get_action (window->priv->action_group,
880 "SearchReplace");
881 gtk_action_set_sensitive (action,
882 state_normal &&
883 editable);
884
885 b = pluma_document_get_can_search_again (doc);
886 action = gtk_action_group_get_action (window->priv->action_group,
887 "SearchFindNext");
888 gtk_action_set_sensitive (action,
889 (state_normal ||
890 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
891
892 action = gtk_action_group_get_action (window->priv->action_group,
893 "SearchFindPrevious");
894 gtk_action_set_sensitive (action,
895 (state_normal ||
896 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
897
898 action = gtk_action_group_get_action (window->priv->action_group,
899 "SearchClearHighlight");
900 gtk_action_set_sensitive (action,
901 (state_normal ||
902 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
903
904 action = gtk_action_group_get_action (window->priv->action_group,
905 "SearchGoToLine");
906 gtk_action_set_sensitive (action,
907 (state_normal ||
908 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
909
910 action = gtk_action_group_get_action (window->priv->action_group,
911 "ViewHighlightMode");
912 gtk_action_set_sensitive (action,
913 (state != PLUMA_TAB_STATE_CLOSING) &&
914 enable_syntax_highlighting);
915
916 update_next_prev_doc_sensitivity (window, tab);
917
918 peas_extension_set_call (window->priv->extensions, "update_state");
919 }
920
921 static void
language_toggled(GtkToggleAction * action,PlumaWindow * window)922 language_toggled (GtkToggleAction *action,
923 PlumaWindow *window)
924 {
925 PlumaDocument *doc;
926 GtkSourceLanguage *lang;
927 const gchar *lang_id;
928
929 if (gtk_toggle_action_get_active (action) == FALSE)
930 return;
931
932 doc = pluma_window_get_active_document (window);
933 if (doc == NULL)
934 return;
935
936 lang_id = gtk_action_get_name (GTK_ACTION (action));
937
938 if (strcmp (lang_id, LANGUAGE_NONE) == 0)
939 {
940 /* Normal (no highlighting) */
941 lang = NULL;
942 }
943 else
944 {
945 lang = gtk_source_language_manager_get_language (pluma_get_language_manager (),
946 lang_id);
947 if (lang == NULL)
948 {
949 g_warning ("Could not get language %s\n", lang_id);
950 }
951 }
952
953 pluma_document_set_language (doc, lang);
954 }
955
956 static gchar *
escape_section_name(const gchar * name)957 escape_section_name (const gchar *name)
958 {
959 gchar *ret;
960
961 ret = g_markup_escape_text (name, -1);
962
963 /* Replace '/' with '-' to avoid problems in xml paths */
964 g_strdelimit (ret, "/", '-');
965
966 return ret;
967 }
968
969 static void
create_language_menu_item(GtkSourceLanguage * lang,gint index,guint ui_id,PlumaWindow * window)970 create_language_menu_item (GtkSourceLanguage *lang,
971 gint index,
972 guint ui_id,
973 PlumaWindow *window)
974 {
975 GtkAction *section_action;
976 GtkRadioAction *action;
977 GtkAction *normal_action;
978 GSList *group;
979 const gchar *section;
980 gchar *escaped_section;
981 const gchar *lang_id;
982 const gchar *lang_name;
983 gchar *escaped_lang_name;
984 gchar *tip;
985 gchar *path;
986
987 section = gtk_source_language_get_section (lang);
988 escaped_section = escape_section_name (section);
989
990 /* check if the section submenu exists or create it */
991 section_action = gtk_action_group_get_action (window->priv->languages_action_group,
992 escaped_section);
993
994 if (section_action == NULL)
995 {
996 gchar *section_name;
997
998 section_name = pluma_utils_escape_underscores (section, -1);
999
1000 section_action = gtk_action_new (escaped_section,
1001 section_name,
1002 NULL,
1003 NULL);
1004
1005 g_free (section_name);
1006
1007 gtk_action_group_add_action (window->priv->languages_action_group,
1008 section_action);
1009 g_object_unref (section_action);
1010
1011 gtk_ui_manager_add_ui (window->priv->manager,
1012 ui_id,
1013 "/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder",
1014 escaped_section,
1015 escaped_section,
1016 GTK_UI_MANAGER_MENU,
1017 FALSE);
1018 }
1019
1020 /* now add the language item to the section */
1021 lang_name = gtk_source_language_get_name (lang);
1022 lang_id = gtk_source_language_get_id (lang);
1023
1024 escaped_lang_name = pluma_utils_escape_underscores (lang_name, -1);
1025
1026 tip = g_strdup_printf (_("Use %s highlight mode"), lang_name);
1027 path = g_strdup_printf ("/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder/%s",
1028 escaped_section);
1029
1030 action = gtk_radio_action_new (lang_id,
1031 escaped_lang_name,
1032 tip,
1033 NULL,
1034 index);
1035
1036 g_free (escaped_lang_name);
1037
1038 /* Action is added with a NULL accel to make the accel overridable */
1039 gtk_action_group_add_action_with_accel (window->priv->languages_action_group,
1040 GTK_ACTION (action),
1041 NULL);
1042 g_object_unref (action);
1043
1044 /* add the action to the same radio group of the "Normal" action */
1045 normal_action = gtk_action_group_get_action (window->priv->languages_action_group,
1046 LANGUAGE_NONE);
1047 group = gtk_radio_action_get_group (GTK_RADIO_ACTION (normal_action));
1048 gtk_radio_action_set_group (action, group);
1049
1050 g_signal_connect (action,
1051 "activate",
1052 G_CALLBACK (language_toggled),
1053 window);
1054
1055 gtk_ui_manager_add_ui (window->priv->manager,
1056 ui_id,
1057 path,
1058 lang_id,
1059 lang_id,
1060 GTK_UI_MANAGER_MENUITEM,
1061 FALSE);
1062
1063 g_free (path);
1064 g_free (tip);
1065 g_free (escaped_section);
1066 }
1067
1068 static void
create_languages_menu(PlumaWindow * window)1069 create_languages_menu (PlumaWindow *window)
1070 {
1071 GtkRadioAction *action_none;
1072 GSList *languages;
1073 GSList *l;
1074 guint id;
1075 gint i;
1076
1077 pluma_debug (DEBUG_WINDOW);
1078
1079 /* add the "Plain Text" item before all the others */
1080
1081 /* Translators: "Plain Text" means that no highlight mode is selected in the
1082 * "View->Highlight Mode" submenu and so syntax highlighting is disabled */
1083 action_none = gtk_radio_action_new (LANGUAGE_NONE, _("Plain Text"),
1084 _("Disable syntax highlighting"),
1085 NULL,
1086 -1);
1087
1088 gtk_action_group_add_action (window->priv->languages_action_group,
1089 GTK_ACTION (action_none));
1090 g_object_unref (action_none);
1091
1092 g_signal_connect (action_none,
1093 "activate",
1094 G_CALLBACK (language_toggled),
1095 window);
1096
1097 id = gtk_ui_manager_new_merge_id (window->priv->manager);
1098
1099 gtk_ui_manager_add_ui (window->priv->manager,
1100 id,
1101 "/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder",
1102 LANGUAGE_NONE,
1103 LANGUAGE_NONE,
1104 GTK_UI_MANAGER_MENUITEM,
1105 TRUE);
1106
1107 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action_none), TRUE);
1108
1109 /* now add all the known languages */
1110 languages = pluma_language_manager_list_languages_sorted (pluma_get_language_manager (),
1111 FALSE);
1112
1113 for (l = languages, i = 0; l != NULL; l = l->next, ++i)
1114 {
1115 create_language_menu_item (l->data,
1116 i,
1117 id,
1118 window);
1119 }
1120
1121 g_slist_free (languages);
1122 }
1123
1124 static void
update_languages_menu(PlumaWindow * window)1125 update_languages_menu (PlumaWindow *window)
1126 {
1127 PlumaDocument *doc;
1128 GList *actions;
1129 GList *l;
1130 GtkAction *action;
1131 GtkSourceLanguage *lang;
1132 const gchar *lang_id;
1133
1134 doc = pluma_window_get_active_document (window);
1135 if (doc == NULL)
1136 return;
1137
1138 lang = pluma_document_get_language (doc);
1139 if (lang != NULL)
1140 lang_id = gtk_source_language_get_id (lang);
1141 else
1142 lang_id = LANGUAGE_NONE;
1143
1144 actions = gtk_action_group_list_actions (window->priv->languages_action_group);
1145
1146 /* prevent recursion */
1147 for (l = actions; l != NULL; l = l->next)
1148 {
1149 g_signal_handlers_block_by_func (GTK_ACTION (l->data),
1150 G_CALLBACK (language_toggled),
1151 window);
1152 }
1153
1154 action = gtk_action_group_get_action (window->priv->languages_action_group,
1155 lang_id);
1156
1157 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1158
1159 for (l = actions; l != NULL; l = l->next)
1160 {
1161 g_signal_handlers_unblock_by_func (GTK_ACTION (l->data),
1162 G_CALLBACK (language_toggled),
1163 window);
1164 }
1165
1166 g_list_free (actions);
1167 }
1168
1169 void
_pluma_recent_add(PlumaWindow * window,const gchar * uri,const gchar * mime)1170 _pluma_recent_add (PlumaWindow *window,
1171 const gchar *uri,
1172 const gchar *mime)
1173 {
1174 GtkRecentManager *recent_manager;
1175 GtkRecentData recent_data;
1176
1177 static gchar *groups[2] = {
1178 "pluma",
1179 NULL
1180 };
1181
1182 recent_manager = gtk_recent_manager_get_default ();
1183
1184 recent_data.display_name = NULL;
1185 recent_data.description = NULL;
1186 recent_data.mime_type = (gchar *) mime;
1187 recent_data.app_name = (gchar *) g_get_application_name ();
1188 recent_data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
1189 recent_data.groups = groups;
1190 recent_data.is_private = FALSE;
1191
1192 gtk_recent_manager_add_full (recent_manager,
1193 uri,
1194 &recent_data);
1195
1196 g_free (recent_data.app_exec);
1197 }
1198
1199 void
_pluma_recent_remove(PlumaWindow * window,const gchar * uri)1200 _pluma_recent_remove (PlumaWindow *window,
1201 const gchar *uri)
1202 {
1203 GtkRecentManager *recent_manager;
1204
1205 recent_manager = gtk_recent_manager_get_default ();
1206
1207 gtk_recent_manager_remove_item (recent_manager, uri, NULL);
1208 }
1209
1210 static void
open_recent_file(const gchar * uri,PlumaWindow * window)1211 open_recent_file (const gchar *uri,
1212 PlumaWindow *window)
1213 {
1214 GSList *uris = NULL;
1215
1216 uris = g_slist_prepend (uris, (gpointer) uri);
1217
1218 if (pluma_commands_load_uris (window, uris, NULL, 0) != 1)
1219 {
1220 _pluma_recent_remove (window, uri);
1221 }
1222
1223 g_slist_free (uris);
1224 }
1225
1226 static void
recent_chooser_item_activated(GtkRecentChooser * chooser,PlumaWindow * window)1227 recent_chooser_item_activated (GtkRecentChooser *chooser,
1228 PlumaWindow *window)
1229 {
1230 gchar *uri;
1231
1232 uri = gtk_recent_chooser_get_current_uri (chooser);
1233
1234 open_recent_file (uri, window);
1235
1236 g_free (uri);
1237 }
1238
1239 static void
recents_menu_activate(GtkAction * action,PlumaWindow * window)1240 recents_menu_activate (GtkAction *action,
1241 PlumaWindow *window)
1242 {
1243 GtkRecentInfo *info;
1244 const gchar *uri;
1245
1246 info = g_object_get_data (G_OBJECT (action), "gtk-recent-info");
1247 g_return_if_fail (info != NULL);
1248
1249 uri = gtk_recent_info_get_uri (info);
1250
1251 open_recent_file (uri, window);
1252 }
1253
1254 static gint
sort_recents_mru(GtkRecentInfo * a,GtkRecentInfo * b)1255 sort_recents_mru (GtkRecentInfo *a, GtkRecentInfo *b)
1256 {
1257 return (gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a));
1258 }
1259
1260 static void update_recent_files_menu (PlumaWindow *window);
1261
1262 static void
recent_manager_changed(GtkRecentManager * manager,PlumaWindow * window)1263 recent_manager_changed (GtkRecentManager *manager,
1264 PlumaWindow *window)
1265 {
1266 /* regenerate the menu when the model changes */
1267 update_recent_files_menu (window);
1268 }
1269
1270 /*
1271 * Manually construct the inline recents list in the File menu.
1272 * Hopefully gtk 2.12 will add support for it.
1273 */
1274 static void
update_recent_files_menu(PlumaWindow * window)1275 update_recent_files_menu (PlumaWindow *window)
1276 {
1277 PlumaWindowPrivate *p = window->priv;
1278 GtkRecentManager *recent_manager;
1279 guint max_recents;
1280 GList *actions, *l, *items;
1281 GList *filtered_items = NULL;
1282 gint i;
1283
1284 pluma_debug (DEBUG_WINDOW);
1285
1286 max_recents = g_settings_get_uint (window->priv->editor_settings, PLUMA_SETTINGS_MAX_RECENTS);
1287
1288 g_return_if_fail (p->recents_action_group != NULL);
1289
1290 if (p->recents_menu_ui_id != 0)
1291 gtk_ui_manager_remove_ui (p->manager, p->recents_menu_ui_id);
1292
1293 actions = gtk_action_group_list_actions (p->recents_action_group);
1294 for (l = actions; l != NULL; l = l->next)
1295 {
1296 g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
1297 G_CALLBACK (recents_menu_activate),
1298 window);
1299 gtk_action_group_remove_action (p->recents_action_group,
1300 GTK_ACTION (l->data));
1301 }
1302 g_list_free (actions);
1303
1304 p->recents_menu_ui_id = gtk_ui_manager_new_merge_id (p->manager);
1305
1306 recent_manager = gtk_recent_manager_get_default ();
1307 items = gtk_recent_manager_get_items (recent_manager);
1308
1309 /* filter */
1310 for (l = items; l != NULL; l = l->next)
1311 {
1312 GtkRecentInfo *info = l->data;
1313
1314 if (!gtk_recent_info_has_group (info, "pluma"))
1315 continue;
1316
1317 filtered_items = g_list_prepend (filtered_items, info);
1318 }
1319
1320 /* sort */
1321 filtered_items = g_list_sort (filtered_items,
1322 (GCompareFunc) sort_recents_mru);
1323
1324 i = 0;
1325 for (l = filtered_items; l != NULL; l = l->next)
1326 {
1327 gchar *action_name;
1328 const gchar *display_name;
1329 gchar *escaped;
1330 gchar *label;
1331 gchar *uri;
1332 gchar *ruri;
1333 gchar *tip;
1334 GtkAction *action;
1335 GtkRecentInfo *info = l->data;
1336
1337 /* clamp */
1338 if (i >= max_recents)
1339 break;
1340
1341 i++;
1342
1343 action_name = g_strdup_printf ("recent-info-%d", i);
1344
1345 display_name = gtk_recent_info_get_display_name (info);
1346 escaped = pluma_utils_escape_underscores (display_name, -1);
1347 if (i >= 10)
1348 label = g_strdup_printf ("%d. %s",
1349 i,
1350 escaped);
1351 else
1352 label = g_strdup_printf ("_%d. %s",
1353 i,
1354 escaped);
1355 g_free (escaped);
1356
1357 /* gtk_recent_info_get_uri_display (info) is buggy and
1358 * works only for local files */
1359 uri = pluma_utils_uri_for_display (gtk_recent_info_get_uri (info));
1360 ruri = pluma_utils_replace_home_dir_with_tilde (uri);
1361 g_free (uri);
1362
1363 /* Translators: %s is a URI */
1364 tip = g_strdup_printf (_("Open '%s'"), ruri);
1365 g_free (ruri);
1366
1367 action = gtk_action_new (action_name,
1368 label,
1369 tip,
1370 NULL);
1371
1372 g_object_set_data_full (G_OBJECT (action),
1373 "gtk-recent-info",
1374 gtk_recent_info_ref (info),
1375 (GDestroyNotify) gtk_recent_info_unref);
1376
1377 g_signal_connect (action,
1378 "activate",
1379 G_CALLBACK (recents_menu_activate),
1380 window);
1381
1382 gtk_action_group_add_action (p->recents_action_group,
1383 action);
1384 g_object_unref (action);
1385
1386 gtk_ui_manager_add_ui (p->manager,
1387 p->recents_menu_ui_id,
1388 "/MenuBar/FileMenu/FileRecentsPlaceholder",
1389 action_name,
1390 action_name,
1391 GTK_UI_MANAGER_MENUITEM,
1392 FALSE);
1393
1394 g_free (action_name);
1395 g_free (label);
1396 g_free (tip);
1397 }
1398
1399 g_list_free (filtered_items);
1400
1401 g_list_free_full (items, (GDestroyNotify) gtk_recent_info_unref);
1402 }
1403
1404 static void
set_non_homogeneus(GtkWidget * widget,gpointer data)1405 set_non_homogeneus (GtkWidget *widget, gpointer data)
1406 {
1407 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1408 }
1409
1410 static void
toolbar_visibility_changed(GtkWidget * toolbar,PlumaWindow * window)1411 toolbar_visibility_changed (GtkWidget *toolbar,
1412 PlumaWindow *window)
1413 {
1414 gboolean visible;
1415 GtkAction *action;
1416
1417 visible = gtk_widget_get_visible (toolbar);
1418
1419 g_settings_set_boolean (window->priv->editor_settings,
1420 PLUMA_SETTINGS_TOOLBAR_VISIBLE, visible);
1421
1422 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
1423 "ViewToolbar");
1424
1425 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
1426 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
1427 }
1428
1429 static GtkWidget *
setup_toolbar_open_button(PlumaWindow * window,GtkWidget * toolbar)1430 setup_toolbar_open_button (PlumaWindow *window,
1431 GtkWidget *toolbar)
1432 {
1433 GtkRecentManager *recent_manager;
1434 GtkRecentFilter *filter;
1435 GtkWidget *toolbar_recent_menu;
1436 GtkToolItem *open_button;
1437 GtkAction *action;
1438 guint max_recents;
1439
1440 recent_manager = gtk_recent_manager_get_default ();
1441
1442 max_recents = g_settings_get_uint (window->priv->editor_settings, PLUMA_SETTINGS_MAX_RECENTS);
1443
1444 /* recent files menu tool button */
1445 toolbar_recent_menu = gtk_recent_chooser_menu_new_for_manager (recent_manager);
1446
1447 gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (toolbar_recent_menu),
1448 FALSE);
1449 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (toolbar_recent_menu),
1450 GTK_RECENT_SORT_MRU);
1451 gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (toolbar_recent_menu),
1452 max_recents);
1453
1454 filter = gtk_recent_filter_new ();
1455 gtk_recent_filter_add_group (filter, "pluma");
1456 gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (toolbar_recent_menu),
1457 filter);
1458
1459 g_signal_connect (toolbar_recent_menu,
1460 "item_activated",
1461 G_CALLBACK (recent_chooser_item_activated),
1462 window);
1463
1464 /* add the custom Open button to the toolbar */
1465 open_button = gtk_menu_tool_button_new (gtk_image_new_from_icon_name ("document-open",
1466 GTK_ICON_SIZE_MENU),
1467 _("Open a file"));
1468
1469 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button),
1470 toolbar_recent_menu);
1471
1472 gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button),
1473 _("Open a recently used file"));
1474
1475 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
1476 "FileOpen");
1477 g_object_set (action,
1478 "is_important", TRUE,
1479 "short_label", _("Open"),
1480 NULL);
1481 gtk_activatable_set_related_action (GTK_ACTIVATABLE (open_button),
1482 action);
1483
1484 gtk_toolbar_insert (GTK_TOOLBAR (toolbar),
1485 open_button,
1486 1);
1487
1488 return toolbar_recent_menu;
1489 }
1490
1491 static void
create_menu_bar_and_toolbar(PlumaWindow * window,GtkWidget * main_box)1492 create_menu_bar_and_toolbar (PlumaWindow *window,
1493 GtkWidget *main_box)
1494 {
1495 GtkActionGroup *action_group;
1496 GtkAction *action;
1497 GtkUIManager *manager;
1498 GtkRecentManager *recent_manager;
1499 GError *error = NULL;
1500
1501 pluma_debug (DEBUG_WINDOW);
1502
1503 manager = gtk_ui_manager_new ();
1504 window->priv->manager = manager;
1505
1506 gtk_window_add_accel_group (GTK_WINDOW (window),
1507 gtk_ui_manager_get_accel_group (manager));
1508
1509 action_group = gtk_action_group_new ("PlumaWindowAlwaysSensitiveActions");
1510 gtk_action_group_set_translation_domain (action_group, NULL);
1511 gtk_action_group_add_actions (action_group,
1512 pluma_always_sensitive_menu_entries,
1513 G_N_ELEMENTS (pluma_always_sensitive_menu_entries),
1514 window);
1515 gtk_action_group_add_toggle_actions (action_group,
1516 pluma_always_sensitive_toggle_menu_entries,
1517 G_N_ELEMENTS (pluma_always_sensitive_toggle_menu_entries),
1518 window);
1519
1520 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1521 g_object_unref (action_group);
1522 window->priv->always_sensitive_action_group = action_group;
1523
1524 action_group = gtk_action_group_new ("PlumaWindowActions");
1525 gtk_action_group_set_translation_domain (action_group, NULL);
1526 gtk_action_group_add_actions (action_group,
1527 pluma_menu_entries,
1528 G_N_ELEMENTS (pluma_menu_entries),
1529 window);
1530 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1531 g_object_unref (action_group);
1532 window->priv->action_group = action_group;
1533
1534 /* set short labels to use in the toolbar */
1535 action = gtk_action_group_get_action (action_group, "FileSave");
1536 g_object_set (action, "short_label", _("Save"), NULL);
1537 action = gtk_action_group_get_action (action_group, "FilePrint");
1538 g_object_set (action, "short_label", _("Print"), NULL);
1539 action = gtk_action_group_get_action (action_group, "SearchFind");
1540 g_object_set (action, "short_label", _("Find"), NULL);
1541 action = gtk_action_group_get_action (action_group, "SearchReplace");
1542 g_object_set (action, "short_label", _("Replace"), NULL);
1543
1544 /* set which actions should have priority on the toolbar */
1545 action = gtk_action_group_get_action (action_group, "FileSave");
1546 g_object_set (action, "is_important", TRUE, NULL);
1547 action = gtk_action_group_get_action (action_group, "EditUndo");
1548 g_object_set (action, "is_important", TRUE, NULL);
1549
1550 action_group = gtk_action_group_new ("PlumaQuitWindowActions");
1551 gtk_action_group_set_translation_domain (action_group, NULL);
1552 gtk_action_group_add_actions (action_group,
1553 pluma_quit_menu_entries,
1554 G_N_ELEMENTS (pluma_quit_menu_entries),
1555 window);
1556
1557 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1558 g_object_unref (action_group);
1559 window->priv->quit_action_group = action_group;
1560
1561 action_group = gtk_action_group_new ("PlumaCloseWindowActions");
1562 gtk_action_group_set_translation_domain (action_group, NULL);
1563 gtk_action_group_add_actions (action_group,
1564 pluma_close_menu_entries,
1565 G_N_ELEMENTS (pluma_close_menu_entries),
1566 window);
1567
1568 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1569 g_object_unref (action_group);
1570 window->priv->close_action_group = action_group;
1571
1572 action_group = gtk_action_group_new ("PlumaWindowPanesActions");
1573 gtk_action_group_set_translation_domain (action_group, NULL);
1574 gtk_action_group_add_toggle_actions (action_group,
1575 pluma_panes_toggle_menu_entries,
1576 G_N_ELEMENTS (pluma_panes_toggle_menu_entries),
1577 window);
1578
1579 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1580 g_object_unref (action_group);
1581 window->priv->panes_action_group = action_group;
1582
1583 /* now load the UI definition */
1584 gtk_ui_manager_add_ui_from_file (manager,
1585 PLUMA_DATADIR "/ui/pluma-ui.xml",
1586 &error);
1587 if (error != NULL)
1588 {
1589 g_warning ("Could not merge %s: %s",
1590 PLUMA_DATADIR "/ui/pluma-ui.xml",
1591 error->message);
1592 g_error_free (error);
1593 }
1594
1595 /* show tooltips in the statusbar */
1596 g_signal_connect (manager,
1597 "connect_proxy",
1598 G_CALLBACK (connect_proxy_cb),
1599 window);
1600 g_signal_connect (manager,
1601 "disconnect_proxy",
1602 G_CALLBACK (disconnect_proxy_cb),
1603 window);
1604
1605 /* recent files menu */
1606 action_group = gtk_action_group_new ("RecentFilesActions");
1607 gtk_action_group_set_translation_domain (action_group, NULL);
1608 window->priv->recents_action_group = action_group;
1609 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1610 g_object_unref (action_group);
1611
1612 recent_manager = gtk_recent_manager_get_default ();
1613 window->priv->recents_handler_id = g_signal_connect (recent_manager,
1614 "changed",
1615 G_CALLBACK (recent_manager_changed),
1616 window);
1617 update_recent_files_menu (window);
1618
1619 /* languages menu */
1620 action_group = gtk_action_group_new ("LanguagesActions");
1621 gtk_action_group_set_translation_domain (action_group, NULL);
1622 window->priv->languages_action_group = action_group;
1623 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1624 g_object_unref (action_group);
1625 create_languages_menu (window);
1626
1627 /* list of open documents menu */
1628 action_group = gtk_action_group_new ("DocumentsListActions");
1629 gtk_action_group_set_translation_domain (action_group, NULL);
1630 window->priv->documents_list_action_group = action_group;
1631 gtk_ui_manager_insert_action_group (manager, action_group, 0);
1632 g_object_unref (action_group);
1633
1634 window->priv->menubar = gtk_ui_manager_get_widget (manager, "/MenuBar");
1635 gtk_box_pack_start (GTK_BOX (main_box),
1636 window->priv->menubar,
1637 FALSE,
1638 FALSE,
1639 0);
1640
1641 window->priv->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar");
1642 gtk_style_context_add_class (gtk_widget_get_style_context (window->priv->toolbar),
1643 GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
1644 gtk_box_pack_start (GTK_BOX (main_box),
1645 window->priv->toolbar,
1646 FALSE,
1647 FALSE,
1648 0);
1649
1650 set_toolbar_style (window, NULL);
1651
1652 window->priv->toolbar_recent_menu = setup_toolbar_open_button (window, window->priv->toolbar);
1653
1654 gtk_container_foreach (GTK_CONTAINER (window->priv->toolbar),
1655 (GtkCallback)set_non_homogeneus,
1656 NULL);
1657
1658 g_signal_connect_after (G_OBJECT (window->priv->toolbar),
1659 "show",
1660 G_CALLBACK (toolbar_visibility_changed),
1661 window);
1662 g_signal_connect_after (G_OBJECT (window->priv->toolbar),
1663 "hide",
1664 G_CALLBACK (toolbar_visibility_changed),
1665 window);
1666 }
1667
1668 static void
documents_list_menu_activate(GtkToggleAction * action,PlumaWindow * window)1669 documents_list_menu_activate (GtkToggleAction *action,
1670 PlumaWindow *window)
1671 {
1672 gint n;
1673
1674 if (gtk_toggle_action_get_active (action) == FALSE)
1675 return;
1676
1677 n = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
1678 gtk_notebook_set_current_page (GTK_NOTEBOOK (window->priv->notebook), n);
1679 }
1680
1681 static gchar *
get_menu_tip_for_tab(PlumaTab * tab)1682 get_menu_tip_for_tab (PlumaTab *tab)
1683 {
1684 PlumaDocument *doc;
1685 gchar *uri;
1686 gchar *ruri;
1687 gchar *tip;
1688
1689 doc = pluma_tab_get_document (tab);
1690
1691 uri = pluma_document_get_uri_for_display (doc);
1692 ruri = pluma_utils_replace_home_dir_with_tilde (uri);
1693 g_free (uri);
1694
1695 /* Translators: %s is a URI */
1696 tip = g_strdup_printf (_("Activate '%s'"), ruri);
1697 g_free (ruri);
1698
1699 return tip;
1700 }
1701
1702 static void
update_documents_list_menu(PlumaWindow * window)1703 update_documents_list_menu (PlumaWindow *window)
1704 {
1705 PlumaWindowPrivate *p = window->priv;
1706 GList *actions, *l;
1707 gint n, i;
1708 guint id;
1709 GSList *group = NULL;
1710
1711 pluma_debug (DEBUG_WINDOW);
1712
1713 g_return_if_fail (p->documents_list_action_group != NULL);
1714
1715 if (p->documents_list_menu_ui_id != 0)
1716 gtk_ui_manager_remove_ui (p->manager,
1717 p->documents_list_menu_ui_id);
1718
1719 actions = gtk_action_group_list_actions (p->documents_list_action_group);
1720 for (l = actions; l != NULL; l = l->next)
1721 {
1722 g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
1723 G_CALLBACK (documents_list_menu_activate),
1724 window);
1725 gtk_action_group_remove_action (p->documents_list_action_group,
1726 GTK_ACTION (l->data));
1727 }
1728 g_list_free (actions);
1729
1730 n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (p->notebook));
1731
1732 id = (n > 0) ? gtk_ui_manager_new_merge_id (p->manager) : 0;
1733
1734 for (i = 0; i < n; i++)
1735 {
1736 GtkWidget *tab;
1737 GtkRadioAction *action;
1738 gchar *action_name;
1739 gchar *tab_name;
1740 gchar *name;
1741 gchar *tip;
1742 gchar *accel;
1743
1744 tab = gtk_notebook_get_nth_page (GTK_NOTEBOOK (p->notebook), i);
1745
1746 /* NOTE: the action is associated to the position of the tab in
1747 * the notebook not to the tab itself! This is needed to work
1748 * around the gtk+ bug #170727: gtk leaves around the accels
1749 * of the action. Since the accel depends on the tab position
1750 * the problem is worked around, action with the same name always
1751 * get the same accel.
1752 */
1753 action_name = g_strdup_printf ("Tab_%d", i);
1754 tab_name = _pluma_tab_get_name (PLUMA_TAB (tab));
1755 name = pluma_utils_escape_underscores (tab_name, -1);
1756 tip = get_menu_tip_for_tab (PLUMA_TAB (tab));
1757
1758 /* alt + 1, 2, 3... 0 to switch to the first ten tabs */
1759 accel = (i < 10) ? g_strdup_printf ("<alt>%d", (i + 1) % 10) : NULL;
1760
1761 action = gtk_radio_action_new (action_name,
1762 name,
1763 tip,
1764 NULL,
1765 i);
1766
1767 if (group != NULL)
1768 gtk_radio_action_set_group (action, group);
1769
1770 /* note that group changes each time we add an action, so it must be updated */
1771 group = gtk_radio_action_get_group (action);
1772
1773 gtk_action_group_add_action_with_accel (p->documents_list_action_group,
1774 GTK_ACTION (action),
1775 accel);
1776
1777 g_signal_connect (action,
1778 "activate",
1779 G_CALLBACK (documents_list_menu_activate),
1780 window);
1781
1782 gtk_ui_manager_add_ui (p->manager,
1783 id,
1784 "/MenuBar/DocumentsMenu/DocumentsListPlaceholder",
1785 action_name, action_name,
1786 GTK_UI_MANAGER_MENUITEM,
1787 FALSE);
1788
1789 if (PLUMA_TAB (tab) == p->active_tab)
1790 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1791
1792 g_object_unref (action);
1793
1794 g_free (action_name);
1795 g_free (tab_name);
1796 g_free (name);
1797 g_free (tip);
1798 g_free (accel);
1799 }
1800
1801 p->documents_list_menu_ui_id = id;
1802 }
1803
1804 /* Returns TRUE if status bar is visible */
1805 static gboolean
set_statusbar_style(PlumaWindow * window,PlumaWindow * origin)1806 set_statusbar_style (PlumaWindow *window,
1807 PlumaWindow *origin)
1808 {
1809 GtkAction *action;
1810 gboolean visible;
1811
1812 if (origin == NULL)
1813 visible = g_settings_get_boolean (window->priv->editor_settings,
1814 PLUMA_SETTINGS_STATUSBAR_VISIBLE);
1815 else
1816 visible = gtk_widget_get_visible (origin->priv->statusbar);
1817
1818 if (visible)
1819 gtk_widget_show (window->priv->statusbar);
1820 else
1821 gtk_widget_hide (window->priv->statusbar);
1822
1823 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
1824 "ViewStatusbar");
1825
1826 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
1827 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
1828
1829 return visible;
1830 }
1831
1832 static void
statusbar_visibility_changed(GtkWidget * statusbar,PlumaWindow * window)1833 statusbar_visibility_changed (GtkWidget *statusbar,
1834 PlumaWindow *window)
1835 {
1836 gboolean visible;
1837 GtkAction *action;
1838
1839 visible = gtk_widget_get_visible (statusbar);
1840
1841 g_settings_set_boolean (window->priv->editor_settings,
1842 PLUMA_SETTINGS_STATUSBAR_VISIBLE, visible);
1843
1844 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
1845 "ViewStatusbar");
1846
1847 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
1848 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
1849 }
1850
1851 static void
tab_width_combo_changed(PlumaStatusComboBox * combo,GtkMenuItem * item,PlumaWindow * window)1852 tab_width_combo_changed (PlumaStatusComboBox *combo,
1853 GtkMenuItem *item,
1854 PlumaWindow *window)
1855 {
1856 PlumaView *view;
1857 guint width_data = 0;
1858
1859 view = pluma_window_get_active_view (window);
1860
1861 if (!view)
1862 return;
1863
1864 width_data = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), TAB_WIDTH_DATA));
1865
1866 if (width_data == 0)
1867 return;
1868
1869 g_signal_handler_block (view, window->priv->tab_width_id);
1870 gtk_source_view_set_tab_width (GTK_SOURCE_VIEW (view), width_data);
1871 g_signal_handler_unblock (view, window->priv->tab_width_id);
1872 }
1873
1874 static void
use_spaces_toggled(GtkCheckMenuItem * item,PlumaWindow * window)1875 use_spaces_toggled (GtkCheckMenuItem *item,
1876 PlumaWindow *window)
1877 {
1878 PlumaView *view;
1879
1880 view = pluma_window_get_active_view (window);
1881
1882 g_signal_handler_block (view, window->priv->spaces_instead_of_tabs_id);
1883 gtk_source_view_set_insert_spaces_instead_of_tabs (GTK_SOURCE_VIEW (view),
1884 gtk_check_menu_item_get_active (item));
1885 g_signal_handler_unblock (view, window->priv->spaces_instead_of_tabs_id);
1886 }
1887
1888 static void
language_combo_changed(PlumaStatusComboBox * combo,GtkMenuItem * item,PlumaWindow * window)1889 language_combo_changed (PlumaStatusComboBox *combo,
1890 GtkMenuItem *item,
1891 PlumaWindow *window)
1892 {
1893 PlumaDocument *doc;
1894 GtkSourceLanguage *language;
1895
1896 doc = pluma_window_get_active_document (window);
1897
1898 if (!doc)
1899 return;
1900
1901 language = GTK_SOURCE_LANGUAGE (g_object_get_data (G_OBJECT (item), LANGUAGE_DATA));
1902
1903 g_signal_handler_block (doc, window->priv->language_changed_id);
1904 pluma_document_set_language (doc, language);
1905 g_signal_handler_unblock (doc, window->priv->language_changed_id);
1906 }
1907
1908 typedef struct
1909 {
1910 const gchar *label;
1911 guint width;
1912 } TabWidthDefinition;
1913
1914 static void
fill_tab_width_combo(PlumaWindow * window)1915 fill_tab_width_combo (PlumaWindow *window)
1916 {
1917 static TabWidthDefinition defs[] = {
1918 {"2", 2},
1919 {"4", 4},
1920 {"8", 8},
1921 {"", 0}, /* custom size */
1922 {NULL, 0}
1923 };
1924
1925 PlumaStatusComboBox *combo = PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo);
1926 guint i = 0;
1927 GtkWidget *item;
1928
1929 while (defs[i].label != NULL)
1930 {
1931 item = gtk_menu_item_new_with_label (defs[i].label);
1932 g_object_set_data (G_OBJECT (item), TAB_WIDTH_DATA, GINT_TO_POINTER (defs[i].width));
1933
1934 pluma_status_combo_box_add_item (combo,
1935 GTK_MENU_ITEM (item),
1936 defs[i].label);
1937
1938 if (defs[i].width != 0)
1939 gtk_widget_show (item);
1940
1941 ++i;
1942 }
1943
1944 item = gtk_separator_menu_item_new ();
1945 pluma_status_combo_box_add_item (combo, GTK_MENU_ITEM (item), NULL);
1946 gtk_widget_show (item);
1947
1948 item = gtk_check_menu_item_new_with_label (_("Use Spaces"));
1949 pluma_status_combo_box_add_item (combo, GTK_MENU_ITEM (item), NULL);
1950 gtk_widget_show (item);
1951
1952 g_signal_connect (item,
1953 "toggled",
1954 G_CALLBACK (use_spaces_toggled),
1955 window);
1956 }
1957
1958 static void
fill_language_combo(PlumaWindow * window)1959 fill_language_combo (PlumaWindow *window)
1960 {
1961 GtkSourceLanguageManager *manager;
1962 GSList *languages;
1963 GSList *item;
1964 GtkWidget *menu_item;
1965 const gchar *name;
1966
1967 manager = pluma_get_language_manager ();
1968 languages = pluma_language_manager_list_languages_sorted (manager, FALSE);
1969
1970 name = _("Plain Text");
1971 menu_item = gtk_menu_item_new_with_label (name);
1972 gtk_widget_show (menu_item);
1973
1974 g_object_set_data (G_OBJECT (menu_item), LANGUAGE_DATA, NULL);
1975 pluma_status_combo_box_add_item (PLUMA_STATUS_COMBO_BOX (window->priv->language_combo),
1976 GTK_MENU_ITEM (menu_item),
1977 name);
1978
1979 for (item = languages; item; item = item->next)
1980 {
1981 GtkSourceLanguage *lang = GTK_SOURCE_LANGUAGE (item->data);
1982
1983 name = gtk_source_language_get_name (lang);
1984 menu_item = gtk_menu_item_new_with_label (name);
1985 gtk_widget_show (menu_item);
1986
1987 g_object_set_data_full (G_OBJECT (menu_item),
1988 LANGUAGE_DATA,
1989 g_object_ref (lang),
1990 (GDestroyNotify)g_object_unref);
1991
1992 pluma_status_combo_box_add_item (PLUMA_STATUS_COMBO_BOX (window->priv->language_combo),
1993 GTK_MENU_ITEM (menu_item),
1994 name);
1995 }
1996
1997 g_slist_free (languages);
1998 }
1999
2000 static void
create_statusbar(PlumaWindow * window,GtkWidget * main_box)2001 create_statusbar (PlumaWindow *window,
2002 GtkWidget *main_box)
2003 {
2004 pluma_debug (DEBUG_WINDOW);
2005
2006 window->priv->statusbar = pluma_statusbar_new ();
2007
2008 window->priv->generic_message_cid = gtk_statusbar_get_context_id
2009 (GTK_STATUSBAR (window->priv->statusbar), "generic_message");
2010 window->priv->tip_message_cid = gtk_statusbar_get_context_id
2011 (GTK_STATUSBAR (window->priv->statusbar), "tip_message");
2012
2013 gtk_box_pack_end (GTK_BOX (main_box),
2014 window->priv->statusbar,
2015 FALSE,
2016 TRUE,
2017 0);
2018
2019 window->priv->tab_width_combo = pluma_status_combo_box_new (_("Tab Width"));
2020 gtk_widget_show (window->priv->tab_width_combo);
2021 gtk_box_pack_end (GTK_BOX (window->priv->statusbar),
2022 window->priv->tab_width_combo,
2023 FALSE,
2024 TRUE,
2025 0);
2026
2027 fill_tab_width_combo (window);
2028
2029 g_signal_connect (G_OBJECT (window->priv->tab_width_combo),
2030 "changed",
2031 G_CALLBACK (tab_width_combo_changed),
2032 window);
2033
2034 window->priv->language_combo = pluma_status_combo_box_new (NULL);
2035 gtk_widget_show (window->priv->language_combo);
2036 gtk_box_pack_end (GTK_BOX (window->priv->statusbar),
2037 window->priv->language_combo,
2038 FALSE,
2039 TRUE,
2040 0);
2041
2042 fill_language_combo (window);
2043
2044 g_signal_connect (G_OBJECT (window->priv->language_combo),
2045 "changed",
2046 G_CALLBACK (language_combo_changed),
2047 window);
2048
2049 g_signal_connect_after (G_OBJECT (window->priv->statusbar),
2050 "show",
2051 G_CALLBACK (statusbar_visibility_changed),
2052 window);
2053 g_signal_connect_after (G_OBJECT (window->priv->statusbar),
2054 "hide",
2055 G_CALLBACK (statusbar_visibility_changed),
2056 window);
2057
2058 set_statusbar_style (window, NULL);
2059 }
2060
2061 static PlumaWindow *
clone_window(PlumaWindow * origin)2062 clone_window (PlumaWindow *origin)
2063 {
2064 PlumaWindow *window;
2065 GdkScreen *screen;
2066 PlumaApp *app;
2067 gint panel_page;
2068
2069 pluma_debug (DEBUG_WINDOW);
2070
2071 app = pluma_app_get_default ();
2072
2073 screen = gtk_window_get_screen (GTK_WINDOW (origin));
2074 window = pluma_app_create_window (app, screen);
2075
2076 if ((origin->priv->window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0)
2077 {
2078 gint w, h;
2079
2080 _pluma_window_get_default_size (&w, &h);
2081 gtk_window_set_default_size (GTK_WINDOW (window), w, h);
2082 gtk_window_maximize (GTK_WINDOW (window));
2083 }
2084 else
2085 {
2086 gtk_window_set_default_size (GTK_WINDOW (window),
2087 origin->priv->width,
2088 origin->priv->height);
2089
2090 gtk_window_unmaximize (GTK_WINDOW (window));
2091 }
2092
2093 if ((origin->priv->window_state & GDK_WINDOW_STATE_STICKY ) != 0)
2094 gtk_window_stick (GTK_WINDOW (window));
2095 else
2096 gtk_window_unstick (GTK_WINDOW (window));
2097
2098 /* set the panes size, the paned position will be set when
2099 * they are mapped */
2100 window->priv->side_panel_size = origin->priv->side_panel_size;
2101 window->priv->bottom_panel_size = origin->priv->bottom_panel_size;
2102
2103 panel_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (origin->priv->side_panel));
2104 _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->side_panel), panel_page);
2105
2106 panel_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (origin->priv->bottom_panel));
2107 _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->bottom_panel), panel_page);
2108
2109 if (gtk_widget_get_visible (origin->priv->side_panel))
2110 gtk_widget_show (window->priv->side_panel);
2111 else
2112 gtk_widget_hide (window->priv->side_panel);
2113
2114 if (gtk_widget_get_visible (origin->priv->bottom_panel))
2115 gtk_widget_show (window->priv->bottom_panel);
2116 else
2117 gtk_widget_hide (window->priv->bottom_panel);
2118
2119 set_statusbar_style (window, origin);
2120 set_toolbar_style (window, origin);
2121
2122 return window;
2123 }
2124
2125 static void
update_cursor_position_statusbar(GtkTextBuffer * buffer,PlumaWindow * window)2126 update_cursor_position_statusbar (GtkTextBuffer *buffer,
2127 PlumaWindow *window)
2128 {
2129 gint row, col;
2130 GtkTextIter iter;
2131 PlumaView *view;
2132
2133 pluma_debug (DEBUG_WINDOW);
2134
2135 if (buffer != GTK_TEXT_BUFFER (pluma_window_get_active_document (window)))
2136 return;
2137
2138 view = pluma_window_get_active_view (window);
2139
2140 gtk_text_buffer_get_iter_at_mark (buffer,
2141 &iter,
2142 gtk_text_buffer_get_insert (buffer));
2143
2144 row = gtk_text_iter_get_line (&iter);
2145
2146 col = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW(view), &iter);
2147
2148 pluma_statusbar_set_cursor_position (PLUMA_STATUSBAR (window->priv->statusbar),
2149 row + 1,
2150 col + 1);
2151 }
2152
2153 static void
update_overwrite_mode_statusbar(GtkTextView * view,PlumaWindow * window)2154 update_overwrite_mode_statusbar (GtkTextView *view,
2155 PlumaWindow *window)
2156 {
2157 if (view != GTK_TEXT_VIEW (pluma_window_get_active_view (window)))
2158 return;
2159
2160 /* Note that we have to use !gtk_text_view_get_overwrite since we
2161 are in the in the signal handler of "toggle overwrite" that is
2162 G_SIGNAL_RUN_LAST
2163 */
2164 pluma_statusbar_set_overwrite (PLUMA_STATUSBAR (window->priv->statusbar),
2165 !gtk_text_view_get_overwrite (view));
2166 }
2167
2168 #define MAX_TITLE_LENGTH 100
2169
2170 static void
set_title(PlumaWindow * window)2171 set_title (PlumaWindow *window)
2172 {
2173 PlumaDocument *doc = NULL;
2174 gchar *name;
2175 gchar *dirname = NULL;
2176 gchar *title = NULL;
2177 gint len;
2178 GtkAction *action;
2179
2180 if (window->priv->active_tab == NULL)
2181 {
2182 gtk_window_set_title (GTK_WINDOW (window), "Pluma");
2183 return;
2184 }
2185
2186 doc = pluma_tab_get_document (window->priv->active_tab);
2187 g_return_if_fail (doc != NULL);
2188
2189 name = pluma_document_get_short_name_for_display (doc);
2190
2191 len = g_utf8_strlen (name, -1);
2192
2193 /* if the name is awfully long, truncate it and be done with it,
2194 * otherwise also show the directory (ellipsized if needed)
2195 */
2196 if (len > MAX_TITLE_LENGTH)
2197 {
2198 gchar *tmp;
2199
2200 tmp = pluma_utils_str_middle_truncate (name, MAX_TITLE_LENGTH);
2201 g_free (name);
2202 name = tmp;
2203 }
2204 else
2205 {
2206 GFile *file;
2207
2208 file = pluma_document_get_location (doc);
2209 if (file != NULL)
2210 {
2211 gchar *str;
2212
2213 str = pluma_utils_location_get_dirname_for_display (file);
2214 g_object_unref (file);
2215
2216 /* use the remaining space for the dir, but use a min of 20 chars
2217 * so that we do not end up with a dirname like "(a...b)".
2218 * This means that in the worst case when the filename is long 99
2219 * we have a title long 99 + 20, but I think it's a rare enough
2220 * case to be acceptable. It's justa darn title afterall :)
2221 */
2222 dirname = pluma_utils_str_middle_truncate (str, MAX (20, MAX_TITLE_LENGTH - len));
2223 g_free (str);
2224 }
2225 }
2226
2227 if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
2228 {
2229 gchar *tmp_name;
2230
2231 tmp_name = g_strdup_printf ("*%s", name);
2232 g_free (name);
2233
2234 name = tmp_name;
2235 cansave = TRUE;
2236 }
2237 else
2238 cansave = FALSE;
2239
2240 if (pluma_document_get_readonly (doc))
2241 {
2242 if (dirname != NULL)
2243 title = g_strdup_printf ("%s [%s] (%s) - Pluma",
2244 name,
2245 _("Read-Only"),
2246 dirname);
2247 else
2248 title = g_strdup_printf ("%s [%s] - Pluma",
2249 name,
2250 _("Read-Only"));
2251 }
2252 else
2253 {
2254 if (dirname != NULL)
2255 title = g_strdup_printf ("%s (%s) - Pluma",
2256 name,
2257 dirname);
2258 else
2259 title = g_strdup_printf ("%s - Pluma",
2260 name);
2261 }
2262
2263 action = gtk_action_group_get_action (window->priv->action_group, "FileSave");
2264 gtk_action_set_sensitive (action, cansave);
2265
2266 gtk_window_set_title (GTK_WINDOW (window), title);
2267
2268 g_free (dirname);
2269 g_free (name);
2270 g_free (title);
2271 }
2272
2273 #undef MAX_TITLE_LENGTH
2274
2275 static void
set_tab_width_item_blocked(PlumaWindow * window,GtkMenuItem * item)2276 set_tab_width_item_blocked (PlumaWindow *window,
2277 GtkMenuItem *item)
2278 {
2279 g_signal_handlers_block_by_func (window->priv->tab_width_combo,
2280 tab_width_combo_changed,
2281 window);
2282
2283 pluma_status_combo_box_set_item (PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo),
2284 item);
2285
2286 g_signal_handlers_unblock_by_func (window->priv->tab_width_combo,
2287 tab_width_combo_changed,
2288 window);
2289 }
2290
2291 static void
spaces_instead_of_tabs_changed(GObject * object,GParamSpec * pspec,PlumaWindow * window)2292 spaces_instead_of_tabs_changed (GObject *object,
2293 GParamSpec *pspec,
2294 PlumaWindow *window)
2295 {
2296 PlumaView *view = PLUMA_VIEW (object);
2297 gboolean active = gtk_source_view_get_insert_spaces_instead_of_tabs (GTK_SOURCE_VIEW (view));
2298 GList *children = pluma_status_combo_box_get_items (PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo));
2299 GtkCheckMenuItem *item;
2300
2301 item = GTK_CHECK_MENU_ITEM (g_list_last (children)->data);
2302
2303 gtk_check_menu_item_set_active (item, active);
2304
2305 g_list_free (children);
2306 }
2307
2308 static void
tab_width_changed(GObject * object,GParamSpec * pspec,PlumaWindow * window)2309 tab_width_changed (GObject *object,
2310 GParamSpec *pspec,
2311 PlumaWindow *window)
2312 {
2313 GList *items;
2314 GList *item;
2315 PlumaStatusComboBox *combo = PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo);
2316 guint new_tab_width;
2317 gboolean found = FALSE;
2318
2319 items = pluma_status_combo_box_get_items (combo);
2320
2321 new_tab_width = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (object));
2322
2323 for (item = items; item; item = item->next)
2324 {
2325 guint tab_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item->data), TAB_WIDTH_DATA));
2326
2327 if (tab_width == new_tab_width)
2328 {
2329 set_tab_width_item_blocked (window, GTK_MENU_ITEM (item->data));
2330 found = TRUE;
2331 }
2332
2333 if (GTK_IS_SEPARATOR_MENU_ITEM (item->next->data))
2334 {
2335 if (!found)
2336 {
2337 /* Set for the last item the custom thing */
2338 gchar *text;
2339
2340 text = g_strdup_printf ("%u", new_tab_width);
2341 pluma_status_combo_box_set_item_text (combo,
2342 GTK_MENU_ITEM (item->data),
2343 text);
2344
2345 gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (item->data))),
2346 text);
2347
2348 set_tab_width_item_blocked (window, GTK_MENU_ITEM (item->data));
2349 gtk_widget_show (GTK_WIDGET (item->data));
2350 }
2351 else
2352 {
2353 gtk_widget_hide (GTK_WIDGET (item->data));
2354 }
2355
2356 break;
2357 }
2358 }
2359
2360 g_list_free (items);
2361 }
2362
2363 static void
language_changed(GObject * object,GParamSpec * pspec,PlumaWindow * window)2364 language_changed (GObject *object,
2365 GParamSpec *pspec,
2366 PlumaWindow *window)
2367 {
2368 GList *items;
2369 GList *item;
2370 PlumaStatusComboBox *combo = PLUMA_STATUS_COMBO_BOX (window->priv->language_combo);
2371 GtkSourceLanguage *new_language;
2372 const gchar *new_id;
2373
2374 items = pluma_status_combo_box_get_items (combo);
2375
2376 new_language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (object));
2377
2378 if (new_language)
2379 new_id = gtk_source_language_get_id (new_language);
2380 else
2381 new_id = NULL;
2382
2383 for (item = items; item; item = item->next)
2384 {
2385 GtkSourceLanguage *lang = g_object_get_data (G_OBJECT (item->data), LANGUAGE_DATA);
2386
2387 if ((new_id == NULL && lang == NULL) ||
2388 (new_id != NULL && lang != NULL && strcmp (gtk_source_language_get_id (lang), new_id) == 0))
2389 {
2390 g_signal_handlers_block_by_func (window->priv->language_combo,
2391 language_combo_changed,
2392 window);
2393
2394 pluma_status_combo_box_set_item (PLUMA_STATUS_COMBO_BOX (window->priv->language_combo),
2395 GTK_MENU_ITEM (item->data));
2396
2397 g_signal_handlers_unblock_by_func (window->priv->language_combo,
2398 language_combo_changed,
2399 window);
2400 }
2401 }
2402
2403 g_list_free (items);
2404 }
2405
2406 static void
notebook_switch_page(GtkNotebook * book,GtkWidget * pg,gint page_num,PlumaWindow * window)2407 notebook_switch_page (GtkNotebook *book,
2408 GtkWidget *pg,
2409 gint page_num,
2410 PlumaWindow *window)
2411 {
2412 PlumaView *view;
2413 PlumaTab *tab;
2414 GtkAction *action;
2415 gchar *action_name;
2416
2417 /* CHECK: I don't know why but it seems notebook_switch_page is called
2418 two times every time the user change the active tab */
2419
2420 tab = PLUMA_TAB (gtk_notebook_get_nth_page (book, page_num));
2421 if (tab == window->priv->active_tab)
2422 return;
2423
2424 if (window->priv->active_tab)
2425 {
2426 if (window->priv->tab_width_id)
2427 {
2428 g_signal_handler_disconnect (pluma_tab_get_view (window->priv->active_tab),
2429 window->priv->tab_width_id);
2430
2431 window->priv->tab_width_id = 0;
2432 }
2433
2434 if (window->priv->spaces_instead_of_tabs_id)
2435 {
2436 g_signal_handler_disconnect (pluma_tab_get_view (window->priv->active_tab),
2437 window->priv->spaces_instead_of_tabs_id);
2438
2439 window->priv->spaces_instead_of_tabs_id = 0;
2440 }
2441 }
2442
2443 /* set the active tab */
2444 window->priv->active_tab = tab;
2445
2446 set_title (window);
2447 set_sensitivity_according_to_tab (window, tab);
2448
2449 /* activate the right item in the documents menu */
2450 action_name = g_strdup_printf ("Tab_%d", page_num);
2451 action = gtk_action_group_get_action (window->priv->documents_list_action_group,
2452 action_name);
2453
2454 /* sometimes the action doesn't exist yet, and the proper action
2455 * is set active during the documents list menu creation
2456 * CHECK: would it be nicer if active_tab was a property and we monitored the notify signal?
2457 */
2458 if (action != NULL)
2459 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2460
2461 g_free (action_name);
2462
2463 /* update the syntax menu */
2464 update_languages_menu (window);
2465
2466 view = pluma_tab_get_view (tab);
2467
2468 /* sync the statusbar */
2469 update_cursor_position_statusbar (GTK_TEXT_BUFFER (pluma_tab_get_document (tab)),
2470 window);
2471 pluma_statusbar_set_overwrite (PLUMA_STATUSBAR (window->priv->statusbar),
2472 gtk_text_view_get_overwrite (GTK_TEXT_VIEW (view)));
2473
2474 gtk_widget_show (window->priv->tab_width_combo);
2475 gtk_widget_show (window->priv->language_combo);
2476
2477 window->priv->tab_width_id = g_signal_connect (view,
2478 "notify::tab-width",
2479 G_CALLBACK (tab_width_changed),
2480 window);
2481 window->priv->spaces_instead_of_tabs_id = g_signal_connect (view,
2482 "notify::insert-spaces-instead-of-tabs",
2483 G_CALLBACK (spaces_instead_of_tabs_changed),
2484 window);
2485
2486 window->priv->language_changed_id = g_signal_connect (pluma_tab_get_document (tab),
2487 "notify::language",
2488 G_CALLBACK (language_changed),
2489 window);
2490
2491 /* call it for the first time */
2492 tab_width_changed (G_OBJECT (view), NULL, window);
2493 spaces_instead_of_tabs_changed (G_OBJECT (view), NULL, window);
2494 language_changed (G_OBJECT (pluma_tab_get_document (tab)), NULL, window);
2495
2496 g_signal_emit (G_OBJECT (window),
2497 signals[ACTIVE_TAB_CHANGED],
2498 0,
2499 window->priv->active_tab);
2500 }
2501
2502 static void
set_sensitivity_according_to_window_state(PlumaWindow * window)2503 set_sensitivity_according_to_window_state (PlumaWindow *window)
2504 {
2505 GtkAction *action;
2506 PlumaLockdownMask lockdown;
2507
2508 lockdown = pluma_app_get_lockdown (pluma_app_get_default ());
2509
2510 /* We disable File->Quit/SaveAll/CloseAll while printing to avoid to have two
2511 operations (save and print/print preview) that uses the message area at
2512 the same time (may be we can remove this limitation in the future) */
2513 /* We disable File->Quit/CloseAll if state is saving since saving cannot be
2514 cancelled (may be we can remove this limitation in the future) */
2515 gtk_action_group_set_sensitive (window->priv->quit_action_group,
2516 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
2517 !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING));
2518
2519 action = gtk_action_group_get_action (window->priv->action_group,
2520 "FileCloseAll");
2521 gtk_action_set_sensitive (action,
2522 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
2523 !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING));
2524
2525 action = gtk_action_group_get_action (window->priv->action_group,
2526 "FileSaveAll");
2527 gtk_action_set_sensitive (action,
2528 !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING) &&
2529 !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
2530
2531 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
2532 "FileNew");
2533 gtk_action_set_sensitive (action,
2534 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
2535
2536 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
2537 "FileOpen");
2538 gtk_action_set_sensitive (action,
2539 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
2540
2541 gtk_action_group_set_sensitive (window->priv->recents_action_group,
2542 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
2543
2544 pluma_notebook_set_close_buttons_sensitive (PLUMA_NOTEBOOK (window->priv->notebook),
2545 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
2546
2547 pluma_notebook_set_tab_drag_and_drop_enabled (PLUMA_NOTEBOOK (window->priv->notebook),
2548 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
2549
2550 if ((window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) != 0)
2551 {
2552 /* TODO: If we really care, Find could be active
2553 * when in SAVING_SESSION state */
2554
2555 if (gtk_action_group_get_sensitive (window->priv->action_group))
2556 gtk_action_group_set_sensitive (window->priv->action_group, FALSE);
2557
2558 if (gtk_action_group_get_sensitive (window->priv->quit_action_group))
2559 gtk_action_group_set_sensitive (window->priv->quit_action_group, FALSE);
2560
2561 if (gtk_action_group_get_sensitive (window->priv->close_action_group))
2562 gtk_action_group_set_sensitive (window->priv->close_action_group, FALSE);
2563 }
2564 else
2565 {
2566 if (!gtk_action_group_get_sensitive (window->priv->action_group))
2567 gtk_action_group_set_sensitive (window->priv->action_group, window->priv->num_tabs > 0);
2568
2569 if (!gtk_action_group_get_sensitive (window->priv->quit_action_group))
2570 gtk_action_group_set_sensitive (window->priv->quit_action_group, window->priv->num_tabs > 0);
2571
2572 if (!gtk_action_group_get_sensitive (window->priv->close_action_group))
2573 gtk_action_group_set_sensitive (window->priv->close_action_group, window->priv->num_tabs > 0);
2574 }
2575 }
2576
2577 static void
update_tab_autosave(GtkWidget * widget,gpointer data)2578 update_tab_autosave (GtkWidget *widget,
2579 gpointer data)
2580 {
2581 PlumaTab *tab = PLUMA_TAB (widget);
2582 gboolean *enabled = (gboolean *) data;
2583
2584 pluma_tab_set_auto_save_enabled (tab, *enabled);
2585 }
2586
2587 void
_pluma_window_set_lockdown(PlumaWindow * window,PlumaLockdownMask lockdown)2588 _pluma_window_set_lockdown (PlumaWindow *window,
2589 PlumaLockdownMask lockdown)
2590 {
2591 PlumaTab *tab;
2592 GtkAction *action;
2593 gboolean autosave;
2594
2595 /* start/stop autosave in each existing tab */
2596 autosave = g_settings_get_boolean (window->priv->editor_settings, PLUMA_SETTINGS_AUTO_SAVE);
2597 gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
2598 update_tab_autosave,
2599 &autosave);
2600
2601 /* update menues wrt the current active tab */
2602 tab = pluma_window_get_active_tab (window);
2603
2604 set_sensitivity_according_to_tab (window, tab);
2605
2606 action = gtk_action_group_get_action (window->priv->action_group,
2607 "FileSaveAll");
2608 gtk_action_set_sensitive (action,
2609 !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING) &&
2610 !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
2611
2612 }
2613
2614 static void
analyze_tab_state(PlumaTab * tab,PlumaWindow * window)2615 analyze_tab_state (PlumaTab *tab,
2616 PlumaWindow *window)
2617 {
2618 PlumaTabState ts;
2619
2620 ts = pluma_tab_get_state (tab);
2621
2622 switch (ts)
2623 {
2624 case PLUMA_TAB_STATE_LOADING:
2625 case PLUMA_TAB_STATE_REVERTING:
2626 window->priv->state |= PLUMA_WINDOW_STATE_LOADING;
2627 break;
2628
2629 case PLUMA_TAB_STATE_SAVING:
2630 window->priv->state |= PLUMA_WINDOW_STATE_SAVING;
2631 break;
2632
2633 case PLUMA_TAB_STATE_PRINTING:
2634 case PLUMA_TAB_STATE_PRINT_PREVIEWING:
2635 window->priv->state |= PLUMA_WINDOW_STATE_PRINTING;
2636 break;
2637
2638 case PLUMA_TAB_STATE_LOADING_ERROR:
2639 case PLUMA_TAB_STATE_REVERTING_ERROR:
2640 case PLUMA_TAB_STATE_SAVING_ERROR:
2641 case PLUMA_TAB_STATE_GENERIC_ERROR:
2642 window->priv->state |= PLUMA_WINDOW_STATE_ERROR;
2643 ++window->priv->num_tabs_with_error;
2644 default:
2645 /* NOP */
2646 break;
2647 }
2648 }
2649
2650 static void
update_window_state(PlumaWindow * window)2651 update_window_state (PlumaWindow *window)
2652 {
2653 PlumaWindowState old_ws;
2654 gint old_num_of_errors;
2655
2656 pluma_debug_message (DEBUG_WINDOW, "Old state: %x", window->priv->state);
2657
2658 old_ws = window->priv->state;
2659 old_num_of_errors = window->priv->num_tabs_with_error;
2660
2661 window->priv->state = old_ws & PLUMA_WINDOW_STATE_SAVING_SESSION;
2662
2663 window->priv->num_tabs_with_error = 0;
2664
2665 gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
2666 (GtkCallback)analyze_tab_state,
2667 window);
2668
2669 pluma_debug_message (DEBUG_WINDOW, "New state: %x", window->priv->state);
2670
2671 if (old_ws != window->priv->state)
2672 {
2673 set_sensitivity_according_to_window_state (window);
2674
2675 pluma_statusbar_set_window_state (PLUMA_STATUSBAR (window->priv->statusbar),
2676 window->priv->state,
2677 window->priv->num_tabs_with_error);
2678
2679 g_object_notify (G_OBJECT (window), "state");
2680 }
2681 else if (old_num_of_errors != window->priv->num_tabs_with_error)
2682 {
2683 pluma_statusbar_set_window_state (PLUMA_STATUSBAR (window->priv->statusbar),
2684 window->priv->state,
2685 window->priv->num_tabs_with_error);
2686 }
2687 }
2688
2689 static void
sync_state(PlumaTab * tab,GParamSpec * pspec,PlumaWindow * window)2690 sync_state (PlumaTab *tab,
2691 GParamSpec *pspec,
2692 PlumaWindow *window)
2693 {
2694 pluma_debug (DEBUG_WINDOW);
2695
2696 update_window_state (window);
2697
2698 if (tab != window->priv->active_tab)
2699 return;
2700
2701 set_sensitivity_according_to_tab (window, tab);
2702
2703 g_signal_emit (G_OBJECT (window), signals[ACTIVE_TAB_STATE_CHANGED], 0);
2704 }
2705
2706 static void
sync_name(PlumaTab * tab,GParamSpec * pspec,PlumaWindow * window)2707 sync_name (PlumaTab *tab,
2708 GParamSpec *pspec,
2709 PlumaWindow *window)
2710 {
2711 GtkAction *action;
2712 gchar *action_name;
2713 gchar *tab_name;
2714 gchar *escaped_name;
2715 gchar *tip;
2716 gint n;
2717 PlumaDocument *doc;
2718
2719 if (tab == window->priv->active_tab)
2720 {
2721 set_title (window);
2722
2723 doc = pluma_tab_get_document (tab);
2724 action = gtk_action_group_get_action (window->priv->action_group,
2725 "FileRevert");
2726 gtk_action_set_sensitive (action, !pluma_document_is_untitled (doc));
2727 }
2728
2729 /* sync the item in the documents list menu */
2730 n = gtk_notebook_page_num (GTK_NOTEBOOK (window->priv->notebook), GTK_WIDGET (tab));
2731
2732 action_name = g_strdup_printf ("Tab_%d", n);
2733 action = gtk_action_group_get_action (window->priv->documents_list_action_group,
2734 action_name);
2735 g_free (action_name);
2736 g_return_if_fail (action != NULL);
2737
2738 tab_name = _pluma_tab_get_name (tab);
2739 escaped_name = pluma_utils_escape_underscores (tab_name, -1);
2740 tip = get_menu_tip_for_tab (tab);
2741
2742 g_object_set (action, "label", escaped_name, NULL);
2743 g_object_set (action, "tooltip", tip, NULL);
2744
2745 g_free (tab_name);
2746 g_free (escaped_name);
2747 g_free (tip);
2748
2749 peas_extension_set_call (window->priv->extensions, "update_state");
2750 }
2751
2752 static PlumaWindow *
get_drop_window(GtkWidget * widget)2753 get_drop_window (GtkWidget *widget)
2754 {
2755 GtkWidget *target_window;
2756
2757 target_window = gtk_widget_get_toplevel (widget);
2758 g_return_val_if_fail (PLUMA_IS_WINDOW (target_window), NULL);
2759
2760 if ((PLUMA_WINDOW(target_window)->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) != 0)
2761 return NULL;
2762
2763 return PLUMA_WINDOW (target_window);
2764 }
2765
2766 static void
load_uris_from_drop(PlumaWindow * window,gchar ** uri_list)2767 load_uris_from_drop (PlumaWindow *window,
2768 gchar **uri_list)
2769 {
2770 GSList *uris = NULL;
2771 gint i;
2772
2773 if (uri_list == NULL)
2774 return;
2775
2776 for (i = 0; uri_list[i] != NULL; ++i)
2777 {
2778 uris = g_slist_prepend (uris, uri_list[i]);
2779 }
2780
2781 uris = g_slist_reverse (uris);
2782 pluma_commands_load_uris (window,
2783 uris,
2784 NULL,
2785 0);
2786
2787 g_slist_free (uris);
2788 }
2789
2790 /* Handle drops on the PlumaWindow */
2791 static void
drag_data_received_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint timestamp,gpointer data)2792 drag_data_received_cb (GtkWidget *widget,
2793 GdkDragContext *context,
2794 gint x,
2795 gint y,
2796 GtkSelectionData *selection_data,
2797 guint info,
2798 guint timestamp,
2799 gpointer data)
2800 {
2801 PlumaWindow *window;
2802 gchar **uri_list;
2803
2804 window = get_drop_window (widget);
2805
2806 if (window == NULL)
2807 return;
2808
2809 if (info == TARGET_URI_LIST)
2810 {
2811 uri_list = pluma_utils_drop_get_uris(selection_data);
2812 load_uris_from_drop (window, uri_list);
2813 g_strfreev (uri_list);
2814 }
2815 }
2816
2817 /* Handle drops on the PlumaView */
2818 static void
drop_uris_cb(GtkWidget * widget,gchar ** uri_list)2819 drop_uris_cb (GtkWidget *widget,
2820 gchar **uri_list)
2821 {
2822 PlumaWindow *window;
2823
2824 window = get_drop_window (widget);
2825
2826 if (window == NULL)
2827 return;
2828
2829 load_uris_from_drop (window, uri_list);
2830 }
2831
2832 static void
fullscreen_controls_show(PlumaWindow * window)2833 fullscreen_controls_show (PlumaWindow *window)
2834 {
2835 GdkScreen *screen;
2836 GdkDisplay *display;
2837 GdkRectangle fs_rect;
2838 gint w, h;
2839
2840 screen = gtk_window_get_screen (GTK_WINDOW (window));
2841 display = gdk_screen_get_display (screen);
2842
2843 gdk_monitor_get_geometry (gdk_display_get_monitor_at_window (display,
2844 gtk_widget_get_window (GTK_WIDGET (window))),
2845 &fs_rect);
2846
2847 gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
2848
2849 gtk_window_resize (GTK_WINDOW (window->priv->fullscreen_controls),
2850 fs_rect.width, h);
2851
2852 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
2853 fs_rect.x, fs_rect.y - h + 1);
2854
2855 gtk_widget_show_all (window->priv->fullscreen_controls);
2856 }
2857
2858 static gboolean
run_fullscreen_animation(gpointer data)2859 run_fullscreen_animation (gpointer data)
2860 {
2861 PlumaWindow *window = PLUMA_WINDOW (data);
2862 GdkScreen *screen;
2863 GdkDisplay *display;
2864 GdkRectangle fs_rect;
2865 gint x, y;
2866
2867 screen = gtk_window_get_screen (GTK_WINDOW (window));
2868 display = gdk_screen_get_display (screen);
2869
2870 gdk_monitor_get_geometry (gdk_display_get_monitor_at_window (display,
2871 gtk_widget_get_window (GTK_WIDGET (window))),
2872 &fs_rect);
2873
2874 gtk_window_get_position (GTK_WINDOW (window->priv->fullscreen_controls),
2875 &x,
2876 &y);
2877
2878 if (window->priv->fullscreen_animation_enter)
2879 {
2880 if (y == fs_rect.y)
2881 {
2882 window->priv->fullscreen_animation_timeout_id = 0;
2883 return FALSE;
2884 }
2885 else
2886 {
2887 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
2888 x, y + 1);
2889 return TRUE;
2890 }
2891 }
2892 else
2893 {
2894 gint w, h;
2895
2896 gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls),
2897 &w, &h);
2898
2899 if (y == fs_rect.y - h + 1)
2900 {
2901 window->priv->fullscreen_animation_timeout_id = 0;
2902 return FALSE;
2903 }
2904 else
2905 {
2906 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
2907 x, y - 1);
2908 return TRUE;
2909 }
2910 }
2911 }
2912
2913 static void
show_hide_fullscreen_toolbar(PlumaWindow * window,gboolean show,gint height)2914 show_hide_fullscreen_toolbar (PlumaWindow *window,
2915 gboolean show,
2916 gint height)
2917 {
2918 GtkSettings *settings;
2919 gboolean enable_animations;
2920
2921 settings = gtk_widget_get_settings (GTK_WIDGET (window));
2922 g_object_get (G_OBJECT (settings),
2923 "gtk-enable-animations",
2924 &enable_animations,
2925 NULL);
2926
2927 if (enable_animations)
2928 {
2929 window->priv->fullscreen_animation_enter = show;
2930
2931 if (window->priv->fullscreen_animation_timeout_id == 0)
2932 {
2933 window->priv->fullscreen_animation_timeout_id =
2934 g_timeout_add (FULLSCREEN_ANIMATION_SPEED,
2935 (GSourceFunc) run_fullscreen_animation,
2936 window);
2937 }
2938 }
2939 else
2940 {
2941 GdkRectangle fs_rect;
2942 GdkScreen *screen;
2943 GdkDisplay *display;
2944
2945 screen = gtk_window_get_screen (GTK_WINDOW (window));
2946 display = gdk_screen_get_display (screen);
2947
2948 gdk_monitor_get_geometry (gdk_display_get_monitor_at_window (display,
2949 gtk_widget_get_window (GTK_WIDGET (window))),
2950 &fs_rect);
2951
2952 if (show)
2953 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
2954 fs_rect.x, fs_rect.y);
2955 else
2956 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
2957 fs_rect.x, fs_rect.y - height + 1);
2958 }
2959
2960 }
2961
2962 static gboolean
on_fullscreen_controls_enter_notify_event(GtkWidget * widget,GdkEventCrossing * event,PlumaWindow * window)2963 on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
2964 GdkEventCrossing *event,
2965 PlumaWindow *window)
2966 {
2967 show_hide_fullscreen_toolbar (window, TRUE, 0);
2968
2969 return FALSE;
2970 }
2971
2972 static gboolean
on_fullscreen_controls_leave_notify_event(GtkWidget * widget,GdkEventCrossing * event,PlumaWindow * window)2973 on_fullscreen_controls_leave_notify_event (GtkWidget *widget,
2974 GdkEventCrossing *event,
2975 PlumaWindow *window)
2976 {
2977 GdkDevice *device;
2978 gint w, h;
2979 gint x, y;
2980
2981 device = gdk_event_get_device ((GdkEvent *)event);
2982
2983 gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
2984 gdk_device_get_position (device, NULL, &x, &y);
2985
2986 /* gtk seems to emit leave notify when clicking on tool items,
2987 * work around it by checking the coordinates
2988 */
2989 if (y >= h)
2990 {
2991 show_hide_fullscreen_toolbar (window, FALSE, h);
2992 }
2993
2994 return FALSE;
2995 }
2996
2997 static void
fullscreen_controls_build(PlumaWindow * window)2998 fullscreen_controls_build (PlumaWindow *window)
2999 {
3000 PlumaWindowPrivate *priv = window->priv;
3001 GtkWidget *toolbar;
3002 GtkAction *action;
3003
3004 if (priv->fullscreen_controls != NULL)
3005 return;
3006
3007 priv->fullscreen_controls = gtk_window_new (GTK_WINDOW_POPUP);
3008
3009 gtk_window_set_transient_for (GTK_WINDOW (priv->fullscreen_controls),
3010 &window->window);
3011
3012 /* popup toolbar */
3013 toolbar = gtk_ui_manager_get_widget (priv->manager, "/FullscreenToolBar");
3014 gtk_container_add (GTK_CONTAINER (priv->fullscreen_controls), toolbar);
3015
3016 action = gtk_action_group_get_action (priv->always_sensitive_action_group,
3017 "LeaveFullscreen");
3018 g_object_set (action, "is-important", TRUE, NULL);
3019
3020 setup_toolbar_open_button (window, toolbar);
3021
3022 gtk_container_foreach (GTK_CONTAINER (toolbar),
3023 (GtkCallback)set_non_homogeneus,
3024 NULL);
3025
3026 /* Set the toolbar style */
3027 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
3028
3029 g_signal_connect (priv->fullscreen_controls, "enter-notify-event",
3030 G_CALLBACK (on_fullscreen_controls_enter_notify_event),
3031 window);
3032 g_signal_connect (priv->fullscreen_controls, "leave-notify-event",
3033 G_CALLBACK (on_fullscreen_controls_leave_notify_event),
3034 window);
3035 }
3036
3037 static void
can_search_again(PlumaDocument * doc,GParamSpec * pspec,PlumaWindow * window)3038 can_search_again (PlumaDocument *doc,
3039 GParamSpec *pspec,
3040 PlumaWindow *window)
3041 {
3042 gboolean sensitive;
3043 GtkAction *action;
3044
3045 if (doc != pluma_window_get_active_document (window))
3046 return;
3047
3048 sensitive = pluma_document_get_can_search_again (doc);
3049
3050 action = gtk_action_group_get_action (window->priv->action_group,
3051 "SearchFindNext");
3052 gtk_action_set_sensitive (action, sensitive);
3053
3054 action = gtk_action_group_get_action (window->priv->action_group,
3055 "SearchFindPrevious");
3056 gtk_action_set_sensitive (action, sensitive);
3057
3058 action = gtk_action_group_get_action (window->priv->action_group,
3059 "SearchClearHighlight");
3060 gtk_action_set_sensitive (action, sensitive);
3061 }
3062
3063 static void
can_undo(PlumaDocument * doc,GParamSpec * pspec,PlumaWindow * window)3064 can_undo (PlumaDocument *doc,
3065 GParamSpec *pspec,
3066 PlumaWindow *window)
3067 {
3068 GtkAction *action;
3069 gboolean sensitive;
3070
3071 sensitive = gtk_source_buffer_can_undo (GTK_SOURCE_BUFFER (doc));
3072
3073 if (doc != pluma_window_get_active_document (window))
3074 return;
3075
3076 action = gtk_action_group_get_action (window->priv->action_group,
3077 "EditUndo");
3078 gtk_action_set_sensitive (action, sensitive);
3079 }
3080
3081 static void
can_redo(PlumaDocument * doc,GParamSpec * pspec,PlumaWindow * window)3082 can_redo (PlumaDocument *doc,
3083 GParamSpec *pspec,
3084 PlumaWindow *window)
3085 {
3086 GtkAction *action;
3087 gboolean sensitive;
3088
3089 sensitive = gtk_source_buffer_can_redo (GTK_SOURCE_BUFFER (doc));
3090
3091 if (doc != pluma_window_get_active_document (window))
3092 return;
3093
3094 action = gtk_action_group_get_action (window->priv->action_group,
3095 "EditRedo");
3096 gtk_action_set_sensitive (action, sensitive);
3097 }
3098
3099 static void
selection_changed(PlumaDocument * doc,GParamSpec * pspec,PlumaWindow * window)3100 selection_changed (PlumaDocument *doc,
3101 GParamSpec *pspec,
3102 PlumaWindow *window)
3103 {
3104 PlumaTab *tab;
3105 PlumaView *view;
3106 GtkAction *action;
3107 PlumaTabState state;
3108 gboolean state_normal;
3109 gboolean editable;
3110
3111 pluma_debug (DEBUG_WINDOW);
3112
3113 if (doc != pluma_window_get_active_document (window))
3114 return;
3115
3116 tab = pluma_tab_get_from_document (doc);
3117 state = pluma_tab_get_state (tab);
3118 state_normal = (state == PLUMA_TAB_STATE_NORMAL);
3119
3120 view = pluma_tab_get_view (tab);
3121 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
3122
3123 action = gtk_action_group_get_action (window->priv->action_group,
3124 "EditCut");
3125 gtk_action_set_sensitive (action,
3126 state_normal &&
3127 editable &&
3128 gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
3129
3130 action = gtk_action_group_get_action (window->priv->action_group,
3131 "EditCopy");
3132 gtk_action_set_sensitive (action,
3133 (state_normal ||
3134 state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) &&
3135 gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
3136
3137 action = gtk_action_group_get_action (window->priv->action_group,
3138 "EditDelete");
3139 gtk_action_set_sensitive (action,
3140 state_normal &&
3141 editable &&
3142 gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
3143
3144 peas_extension_set_call (window->priv->extensions, "update_state");
3145 }
3146
3147 static void
sync_languages_menu(PlumaDocument * doc,GParamSpec * pspec,PlumaWindow * window)3148 sync_languages_menu (PlumaDocument *doc,
3149 GParamSpec *pspec,
3150 PlumaWindow *window)
3151 {
3152 update_languages_menu (window);
3153 peas_extension_set_call (window->priv->extensions, "update_state");
3154 }
3155
3156 static void
readonly_changed(PlumaDocument * doc,GParamSpec * pspec,PlumaWindow * window)3157 readonly_changed (PlumaDocument *doc,
3158 GParamSpec *pspec,
3159 PlumaWindow *window)
3160 {
3161 set_sensitivity_according_to_tab (window, window->priv->active_tab);
3162
3163 sync_name (window->priv->active_tab, NULL, window);
3164
3165 peas_extension_set_call (window->priv->extensions, "update_state");
3166 }
3167
3168 static void
editable_changed(PlumaView * view,GParamSpec * arg1,PlumaWindow * window)3169 editable_changed (PlumaView *view,
3170 GParamSpec *arg1,
3171 PlumaWindow *window)
3172 {
3173 peas_extension_set_call (window->priv->extensions, "update_state");
3174 }
3175
3176 static void
update_sensitivity_according_to_open_tabs(PlumaWindow * window)3177 update_sensitivity_according_to_open_tabs (PlumaWindow *window)
3178 {
3179 GtkAction *action;
3180
3181 /* Set sensitivity */
3182 gtk_action_group_set_sensitive (window->priv->action_group,
3183 window->priv->num_tabs != 0);
3184
3185 action = gtk_action_group_get_action (window->priv->action_group,
3186 "DocumentsMoveToNewWindow");
3187 gtk_action_set_sensitive (action, window->priv->num_tabs > 1);
3188
3189 gtk_action_group_set_sensitive (window->priv->close_action_group,
3190 window->priv->num_tabs != 0);
3191 }
3192
3193 static void
notebook_tab_added(PlumaNotebook * notebook,PlumaTab * tab,PlumaWindow * window)3194 notebook_tab_added (PlumaNotebook *notebook,
3195 PlumaTab *tab,
3196 PlumaWindow *window)
3197 {
3198 PlumaView *view;
3199 PlumaDocument *doc;
3200
3201 pluma_debug (DEBUG_WINDOW);
3202
3203 g_return_if_fail ((window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) == 0);
3204
3205 ++window->priv->num_tabs;
3206
3207 update_sensitivity_according_to_open_tabs (window);
3208
3209 view = pluma_tab_get_view (tab);
3210 doc = pluma_tab_get_document (tab);
3211
3212 /* IMPORTANT: remember to disconnect the signal in notebook_tab_removed
3213 * if a new signal is connected here */
3214
3215 g_signal_connect (tab,
3216 "notify::name",
3217 G_CALLBACK (sync_name),
3218 window);
3219 g_signal_connect (tab,
3220 "notify::state",
3221 G_CALLBACK (sync_state),
3222 window);
3223
3224 g_signal_connect (doc,
3225 "cursor-moved",
3226 G_CALLBACK (update_cursor_position_statusbar),
3227 window);
3228 g_signal_connect (doc,
3229 "notify::can-search-again",
3230 G_CALLBACK (can_search_again),
3231 window);
3232 g_signal_connect (doc,
3233 "notify::can-undo",
3234 G_CALLBACK (can_undo),
3235 window);
3236 g_signal_connect (doc,
3237 "notify::can-redo",
3238 G_CALLBACK (can_redo),
3239 window);
3240 g_signal_connect (doc,
3241 "notify::has-selection",
3242 G_CALLBACK (selection_changed),
3243 window);
3244 g_signal_connect (doc,
3245 "notify::language",
3246 G_CALLBACK (sync_languages_menu),
3247 window);
3248 g_signal_connect (doc,
3249 "notify::read-only",
3250 G_CALLBACK (readonly_changed),
3251 window);
3252 g_signal_connect (view,
3253 "toggle_overwrite",
3254 G_CALLBACK (update_overwrite_mode_statusbar),
3255 window);
3256 g_signal_connect (view,
3257 "notify::editable",
3258 G_CALLBACK (editable_changed),
3259 window);
3260
3261 update_documents_list_menu (window);
3262
3263 g_signal_connect (view,
3264 "drop_uris",
3265 G_CALLBACK (drop_uris_cb),
3266 NULL);
3267
3268 update_window_state (window);
3269
3270 g_signal_emit (G_OBJECT (window), signals[TAB_ADDED], 0, tab);
3271 }
3272
3273 static void
notebook_tab_removed(PlumaNotebook * notebook,PlumaTab * tab,PlumaWindow * window)3274 notebook_tab_removed (PlumaNotebook *notebook,
3275 PlumaTab *tab,
3276 PlumaWindow *window)
3277 {
3278 PlumaView *view;
3279 PlumaDocument *doc;
3280
3281 pluma_debug (DEBUG_WINDOW);
3282
3283 g_return_if_fail ((window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) == 0);
3284
3285 --window->priv->num_tabs;
3286
3287 view = pluma_tab_get_view (tab);
3288 doc = pluma_tab_get_document (tab);
3289
3290 g_signal_handlers_disconnect_by_func (tab,
3291 G_CALLBACK (sync_name),
3292 window);
3293 g_signal_handlers_disconnect_by_func (tab,
3294 G_CALLBACK (sync_state),
3295 window);
3296 g_signal_handlers_disconnect_by_func (doc,
3297 G_CALLBACK (update_cursor_position_statusbar),
3298 window);
3299 g_signal_handlers_disconnect_by_func (doc,
3300 G_CALLBACK (can_search_again),
3301 window);
3302 g_signal_handlers_disconnect_by_func (doc,
3303 G_CALLBACK (can_undo),
3304 window);
3305 g_signal_handlers_disconnect_by_func (doc,
3306 G_CALLBACK (can_redo),
3307 window);
3308 g_signal_handlers_disconnect_by_func (doc,
3309 G_CALLBACK (selection_changed),
3310 window);
3311 g_signal_handlers_disconnect_by_func (doc,
3312 G_CALLBACK (sync_languages_menu),
3313 window);
3314 g_signal_handlers_disconnect_by_func (doc,
3315 G_CALLBACK (readonly_changed),
3316 window);
3317 g_signal_handlers_disconnect_by_func (view,
3318 G_CALLBACK (update_overwrite_mode_statusbar),
3319 window);
3320 g_signal_handlers_disconnect_by_func (view,
3321 G_CALLBACK (editable_changed),
3322 window);
3323 g_signal_handlers_disconnect_by_func (view,
3324 G_CALLBACK (drop_uris_cb),
3325 NULL);
3326
3327 if (window->priv->tab_width_id && tab == pluma_window_get_active_tab (window))
3328 {
3329 g_signal_handler_disconnect (view, window->priv->tab_width_id);
3330 window->priv->tab_width_id = 0;
3331 }
3332
3333 if (window->priv->spaces_instead_of_tabs_id && tab == pluma_window_get_active_tab (window))
3334 {
3335 g_signal_handler_disconnect (view, window->priv->spaces_instead_of_tabs_id);
3336 window->priv->spaces_instead_of_tabs_id = 0;
3337 }
3338
3339 if (window->priv->language_changed_id && tab == pluma_window_get_active_tab (window))
3340 {
3341 g_signal_handler_disconnect (doc, window->priv->language_changed_id);
3342 window->priv->language_changed_id = 0;
3343 }
3344
3345 g_return_if_fail (window->priv->num_tabs >= 0);
3346 if (window->priv->num_tabs == 0)
3347 {
3348 window->priv->active_tab = NULL;
3349
3350 set_title (window);
3351
3352 /* Remove line and col info */
3353 pluma_statusbar_set_cursor_position (PLUMA_STATUSBAR (window->priv->statusbar),
3354 -1,
3355 -1);
3356
3357 pluma_statusbar_clear_overwrite (PLUMA_STATUSBAR (window->priv->statusbar));
3358
3359 /* hide the combos */
3360 gtk_widget_hide (window->priv->tab_width_combo);
3361 gtk_widget_hide (window->priv->language_combo);
3362 }
3363
3364 if (!window->priv->removing_tabs)
3365 {
3366 update_documents_list_menu (window);
3367 update_next_prev_doc_sensitivity_per_window (window);
3368 }
3369 else
3370 {
3371 if (window->priv->num_tabs == 0)
3372 {
3373 update_documents_list_menu (window);
3374 update_next_prev_doc_sensitivity_per_window (window);
3375 }
3376 }
3377
3378 update_sensitivity_according_to_open_tabs (window);
3379
3380 if (window->priv->num_tabs == 0)
3381 {
3382 peas_extension_set_call (window->priv->extensions, "update_state");
3383 }
3384
3385 update_window_state (window);
3386
3387 g_signal_emit (G_OBJECT (window), signals[TAB_REMOVED], 0, tab);
3388 }
3389
3390 static void
notebook_tabs_reordered(PlumaNotebook * notebook,PlumaWindow * window)3391 notebook_tabs_reordered (PlumaNotebook *notebook,
3392 PlumaWindow *window)
3393 {
3394 update_documents_list_menu (window);
3395 update_next_prev_doc_sensitivity_per_window (window);
3396
3397 g_signal_emit (G_OBJECT (window), signals[TABS_REORDERED], 0);
3398 }
3399
3400 static void
notebook_tab_detached(PlumaNotebook * notebook,PlumaTab * tab,PlumaWindow * window)3401 notebook_tab_detached (PlumaNotebook *notebook,
3402 PlumaTab *tab,
3403 PlumaWindow *window)
3404 {
3405 PlumaWindow *new_window;
3406
3407 new_window = clone_window (window);
3408
3409 pluma_notebook_move_tab (notebook,
3410 PLUMA_NOTEBOOK (_pluma_window_get_notebook (new_window)),
3411 tab, 0);
3412
3413 gtk_window_set_position (GTK_WINDOW (new_window), GTK_WIN_POS_MOUSE);
3414
3415 gtk_widget_show (GTK_WIDGET (new_window));
3416 }
3417
3418 static void
notebook_tab_close_request(PlumaNotebook * notebook,PlumaTab * tab,GtkWindow * window)3419 notebook_tab_close_request (PlumaNotebook *notebook,
3420 PlumaTab *tab,
3421 GtkWindow *window)
3422 {
3423 /* Note: we are destroying the tab before the default handler
3424 * seems to be ok, but we need to keep an eye on this. */
3425 _pluma_cmd_file_close_tab (tab, PLUMA_WINDOW (window));
3426 }
3427
3428 static gboolean
show_notebook_popup_menu(GtkNotebook * notebook,PlumaWindow * window,GdkEventButton * event)3429 show_notebook_popup_menu (GtkNotebook *notebook,
3430 PlumaWindow *window,
3431 GdkEventButton *event)
3432 {
3433 GtkWidget *menu;
3434 // GtkAction *action;
3435
3436 menu = gtk_ui_manager_get_widget (window->priv->manager, "/NotebookPopup");
3437 g_return_val_if_fail (menu != NULL, FALSE);
3438
3439 // CHECK do we need this?
3440 #if 0
3441 /* allow extensions to sync when showing the popup */
3442 action = gtk_action_group_get_action (window->priv->action_group,
3443 "NotebookPopupAction");
3444 g_return_val_if_fail (action != NULL, FALSE);
3445 gtk_action_activate (action);
3446 #endif
3447
3448 GtkWidget *tab;
3449 GtkWidget *tab_label;
3450
3451 tab = GTK_WIDGET (pluma_window_get_active_tab (window));
3452 g_return_val_if_fail (tab != NULL, FALSE);
3453
3454 tab_label = gtk_notebook_get_tab_label (notebook, tab);
3455
3456 gtk_menu_popup_at_widget (GTK_MENU (menu),
3457 tab_label,
3458 GDK_GRAVITY_SOUTH_WEST,
3459 GDK_GRAVITY_NORTH_WEST,
3460 (const GdkEvent*) event);
3461
3462 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
3463
3464 return TRUE;
3465 }
3466
3467 static gboolean
notebook_button_press_event(GtkNotebook * notebook,GdkEventButton * event,PlumaWindow * window)3468 notebook_button_press_event (GtkNotebook *notebook,
3469 GdkEventButton *event,
3470 PlumaWindow *window)
3471 {
3472 if (event->type == GDK_BUTTON_PRESS)
3473 {
3474 if (event->button == 3)
3475 return show_notebook_popup_menu (notebook, window, event);
3476
3477 else if (event->button == 2)
3478 {
3479 PlumaTab *tab;
3480 tab = pluma_window_get_active_tab (window);
3481 notebook_tab_close_request (PLUMA_NOTEBOOK (notebook), tab, GTK_WINDOW (window));
3482 }
3483 }
3484 else if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1))
3485 {
3486 pluma_window_create_tab (window, TRUE);
3487 }
3488
3489 return FALSE;
3490 }
3491
3492 static gboolean
notebook_scroll_event(GtkNotebook * notebook,GdkEventScroll * event,PlumaWindow * window)3493 notebook_scroll_event (GtkNotebook *notebook,
3494 GdkEventScroll *event,
3495 PlumaWindow *window)
3496 {
3497 if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT)
3498 {
3499 gtk_notebook_prev_page (notebook);
3500 }
3501 else if (event->direction == GDK_SCROLL_DOWN || event->direction == GDK_SCROLL_RIGHT)
3502 {
3503 gtk_notebook_next_page (notebook);
3504 }
3505
3506 return FALSE;
3507 }
3508
3509 static gboolean
notebook_popup_menu(GtkNotebook * notebook,PlumaWindow * window)3510 notebook_popup_menu (GtkNotebook *notebook,
3511 PlumaWindow *window)
3512 {
3513 /* Only respond if the notebook is the actual focus */
3514 if (PLUMA_IS_NOTEBOOK (gtk_window_get_focus (GTK_WINDOW (window))))
3515 {
3516 return show_notebook_popup_menu (notebook, window, NULL);
3517 }
3518
3519 return FALSE;
3520 }
3521
3522 static void
side_panel_size_allocate(GtkWidget * widget,GtkAllocation * allocation,PlumaWindow * window)3523 side_panel_size_allocate (GtkWidget *widget,
3524 GtkAllocation *allocation,
3525 PlumaWindow *window)
3526 {
3527 window->priv->side_panel_size = allocation->width;
3528 }
3529
3530 static void
bottom_panel_size_allocate(GtkWidget * widget,GtkAllocation * allocation,PlumaWindow * window)3531 bottom_panel_size_allocate (GtkWidget *widget,
3532 GtkAllocation *allocation,
3533 PlumaWindow *window)
3534 {
3535 window->priv->bottom_panel_size = allocation->height;
3536 }
3537
3538 static void
hpaned_restore_position(GtkWidget * widget,PlumaWindow * window)3539 hpaned_restore_position (GtkWidget *widget,
3540 PlumaWindow *window)
3541 {
3542 gint pos;
3543
3544 pluma_debug_message (DEBUG_WINDOW,
3545 "Restoring hpaned position: side panel size %d",
3546 window->priv->side_panel_size);
3547
3548 pos = MAX (100, window->priv->side_panel_size);
3549 gtk_paned_set_position (GTK_PANED (window->priv->hpaned), pos);
3550
3551 /* start monitoring the size */
3552 g_signal_connect (window->priv->side_panel,
3553 "size-allocate",
3554 G_CALLBACK (side_panel_size_allocate),
3555 window);
3556
3557 /* run this only once */
3558 g_signal_handlers_disconnect_by_func (widget, hpaned_restore_position, window);
3559 }
3560
3561 static void
vpaned_restore_position(GtkWidget * widget,PlumaWindow * window)3562 vpaned_restore_position (GtkWidget *widget,
3563 PlumaWindow *window)
3564 {
3565 GtkAllocation allocation;
3566 gint pos;
3567
3568 gtk_widget_get_allocation (widget, &allocation);
3569
3570 pluma_debug_message (DEBUG_WINDOW,
3571 "Restoring vpaned position: bottom panel size %d",
3572 window->priv->bottom_panel_size);
3573
3574 pos = allocation.height - MAX (50, window->priv->bottom_panel_size);
3575 gtk_paned_set_position (GTK_PANED (window->priv->vpaned), pos);
3576
3577 /* start monitoring the size */
3578 g_signal_connect (window->priv->bottom_panel,
3579 "size-allocate",
3580 G_CALLBACK (bottom_panel_size_allocate),
3581 window);
3582
3583 /* run this only once */
3584 g_signal_handlers_disconnect_by_func (widget, vpaned_restore_position, window);
3585 }
3586
3587 static void
side_panel_visibility_changed(GtkWidget * side_panel,PlumaWindow * window)3588 side_panel_visibility_changed (GtkWidget *side_panel,
3589 PlumaWindow *window)
3590 {
3591 gboolean visible;
3592 GtkAction *action;
3593
3594 visible = gtk_widget_get_visible (side_panel);
3595
3596 if (!g_settings_get_boolean (window->priv->editor_settings, "show-tabs-with-side-pane"))
3597 {
3598 if (visible)
3599 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook), FALSE);
3600 else
3601 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook),
3602 g_settings_get_boolean (window->priv->editor_settings, "show-single-tab") ||
3603 (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook)) > 1));
3604 }
3605 else
3606 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook),
3607 g_settings_get_boolean (window->priv->editor_settings, "show-single-tab") ||
3608 (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook)) > 1));
3609
3610 g_settings_set_boolean (window->priv->editor_settings,
3611 PLUMA_SETTINGS_SIDE_PANE_VISIBLE,
3612 visible);
3613
3614 action = gtk_action_group_get_action (window->priv->panes_action_group,
3615 "ViewSidePane");
3616
3617 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
3618 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
3619
3620 /* focus the document */
3621 if (!visible && window->priv->active_tab != NULL)
3622 gtk_widget_grab_focus (GTK_WIDGET (pluma_tab_get_view (PLUMA_TAB (window->priv->active_tab))));
3623 }
3624
3625 static void
create_side_panel(PlumaWindow * window)3626 create_side_panel (PlumaWindow *window)
3627 {
3628 GtkWidget *documents_panel;
3629
3630 pluma_debug (DEBUG_WINDOW);
3631
3632 window->priv->side_panel = pluma_panel_new (GTK_ORIENTATION_VERTICAL);
3633
3634 gtk_paned_pack1 (GTK_PANED (window->priv->hpaned),
3635 window->priv->side_panel,
3636 FALSE,
3637 FALSE);
3638
3639 g_signal_connect_after (window->priv->side_panel,
3640 "show",
3641 G_CALLBACK (side_panel_visibility_changed),
3642 window);
3643 g_signal_connect_after (window->priv->side_panel,
3644 "hide",
3645 G_CALLBACK (side_panel_visibility_changed),
3646 window);
3647
3648 documents_panel = pluma_documents_panel_new (window);
3649 pluma_panel_add_item_with_icon (PLUMA_PANEL (window->priv->side_panel),
3650 documents_panel,
3651 _("Documents"),
3652 "text-x-generic");
3653 }
3654
3655 static void
bottom_panel_visibility_changed(PlumaPanel * bottom_panel,PlumaWindow * window)3656 bottom_panel_visibility_changed (PlumaPanel *bottom_panel,
3657 PlumaWindow *window)
3658 {
3659 gboolean visible;
3660 GtkAction *action;
3661
3662 visible = gtk_widget_get_visible (GTK_WIDGET (bottom_panel));
3663
3664 g_settings_set_boolean (window->priv->editor_settings,
3665 PLUMA_SETTINGS_BOTTOM_PANE_VISIBLE,
3666 visible);
3667
3668 action = gtk_action_group_get_action (window->priv->panes_action_group,
3669 "ViewBottomPane");
3670
3671 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
3672 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
3673
3674 /* focus the document */
3675 if (!visible && window->priv->active_tab != NULL)
3676 gtk_widget_grab_focus (GTK_WIDGET (pluma_tab_get_view (PLUMA_TAB (window->priv->active_tab))));
3677 }
3678
3679 static void
bottom_panel_item_removed(PlumaPanel * panel,GtkWidget * item,PlumaWindow * window)3680 bottom_panel_item_removed (PlumaPanel *panel,
3681 GtkWidget *item,
3682 PlumaWindow *window)
3683 {
3684 if (pluma_panel_get_n_items (panel) == 0)
3685 {
3686 GtkAction *action;
3687
3688 gtk_widget_hide (GTK_WIDGET (panel));
3689
3690 action = gtk_action_group_get_action (window->priv->panes_action_group,
3691 "ViewBottomPane");
3692 gtk_action_set_sensitive (action, FALSE);
3693 }
3694 }
3695
3696 static void
bottom_panel_item_added(PlumaPanel * panel,GtkWidget * item,PlumaWindow * window)3697 bottom_panel_item_added (PlumaPanel *panel,
3698 GtkWidget *item,
3699 PlumaWindow *window)
3700 {
3701 /* if it's the first item added, set the menu item
3702 * sensitive and if needed show the panel */
3703 if (pluma_panel_get_n_items (panel) == 1)
3704 {
3705 GtkAction *action;
3706 gboolean show;
3707
3708 action = gtk_action_group_get_action (window->priv->panes_action_group,
3709 "ViewBottomPane");
3710 gtk_action_set_sensitive (action, TRUE);
3711
3712 show = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
3713 if (show)
3714 gtk_widget_show (GTK_WIDGET (panel));
3715 }
3716 }
3717
3718 static void
create_bottom_panel(PlumaWindow * window)3719 create_bottom_panel (PlumaWindow *window)
3720 {
3721 pluma_debug (DEBUG_WINDOW);
3722
3723 window->priv->bottom_panel = pluma_panel_new (GTK_ORIENTATION_HORIZONTAL);
3724
3725 gtk_paned_pack2 (GTK_PANED (window->priv->vpaned),
3726 window->priv->bottom_panel,
3727 FALSE,
3728 FALSE);
3729
3730 g_signal_connect_after (window->priv->bottom_panel,
3731 "show",
3732 G_CALLBACK (bottom_panel_visibility_changed),
3733 window);
3734 g_signal_connect_after (window->priv->bottom_panel,
3735 "hide",
3736 G_CALLBACK (bottom_panel_visibility_changed),
3737 window);
3738 }
3739
3740 static void
init_panels_visibility(PlumaWindow * window)3741 init_panels_visibility (PlumaWindow *window)
3742 {
3743 gint active_page;
3744 gboolean side_pane_visible;
3745 gboolean bottom_pane_visible;
3746
3747 pluma_debug (DEBUG_WINDOW);
3748
3749 /* side pane */
3750 active_page = g_settings_get_int (window->priv->editor_settings,
3751 PLUMA_SETTINGS_SIDE_PANEL_ACTIVE_PAGE);
3752 _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->side_panel),
3753 active_page);
3754
3755 side_pane_visible = g_settings_get_boolean (window->priv->editor_settings,
3756 PLUMA_SETTINGS_SIDE_PANE_VISIBLE);
3757 bottom_pane_visible = g_settings_get_boolean (window->priv->editor_settings,
3758 PLUMA_SETTINGS_BOTTOM_PANE_VISIBLE);
3759
3760 if (side_pane_visible)
3761
3762 {
3763 gtk_widget_show (window->priv->side_panel);
3764 }
3765
3766 /* bottom pane, it can be empty */
3767 if (pluma_panel_get_n_items (PLUMA_PANEL (window->priv->bottom_panel)) > 0)
3768 {
3769 active_page = g_settings_get_int (window->priv->editor_settings,
3770 PLUMA_SETTINGS_BOTTOM_PANEL_ACTIVE_PAGE);
3771 _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->bottom_panel),
3772 active_page);
3773
3774 if (bottom_pane_visible)
3775 {
3776 gtk_widget_show (window->priv->bottom_panel);
3777 }
3778 }
3779 else
3780 {
3781 GtkAction *action;
3782 action = gtk_action_group_get_action (window->priv->panes_action_group,
3783 "ViewBottomPane");
3784 gtk_action_set_sensitive (action, FALSE);
3785 }
3786
3787 /* start track sensitivity after the initial state is set */
3788 window->priv->bottom_panel_item_removed_handler_id =
3789 g_signal_connect (window->priv->bottom_panel,
3790 "item_removed",
3791 G_CALLBACK (bottom_panel_item_removed),
3792 window);
3793
3794 g_signal_connect (window->priv->bottom_panel,
3795 "item_added",
3796 G_CALLBACK (bottom_panel_item_added),
3797 window);
3798 }
3799
3800 static void
clipboard_owner_change(GtkClipboard * clipboard,GdkEventOwnerChange * event,PlumaWindow * window)3801 clipboard_owner_change (GtkClipboard *clipboard,
3802 GdkEventOwnerChange *event,
3803 PlumaWindow *window)
3804 {
3805 set_paste_sensitivity_according_to_clipboard (window, clipboard);
3806 }
3807
3808 static void
window_realized(GtkWidget * window,gpointer * data)3809 window_realized (GtkWidget *window,
3810 gpointer *data)
3811 {
3812 GtkClipboard *clipboard;
3813
3814 clipboard = gtk_widget_get_clipboard (window, GDK_SELECTION_CLIPBOARD);
3815
3816 g_signal_connect (clipboard,
3817 "owner_change",
3818 G_CALLBACK (clipboard_owner_change),
3819 window);
3820 }
3821
3822 static void
window_unrealized(GtkWidget * window,gpointer * data)3823 window_unrealized (GtkWidget *window,
3824 gpointer *data)
3825 {
3826 GtkClipboard *clipboard;
3827
3828 clipboard = gtk_widget_get_clipboard (window, GDK_SELECTION_CLIPBOARD);
3829
3830 g_signal_handlers_disconnect_by_func (clipboard,
3831 G_CALLBACK (clipboard_owner_change),
3832 window);
3833 }
3834
3835 static void
check_window_is_active(PlumaWindow * window,GParamSpec * property,gpointer useless)3836 check_window_is_active (PlumaWindow *window,
3837 GParamSpec *property,
3838 gpointer useless)
3839 {
3840 if (window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN)
3841 {
3842 if (gtk_window_is_active (GTK_WINDOW (window)))
3843 {
3844 gtk_widget_show (window->priv->fullscreen_controls);
3845 }
3846 else
3847 {
3848 gtk_widget_hide (window->priv->fullscreen_controls);
3849 }
3850 }
3851 }
3852
3853 static void
connect_notebook_signals(PlumaWindow * window,GtkWidget * notebook)3854 connect_notebook_signals (PlumaWindow *window,
3855 GtkWidget *notebook)
3856 {
3857 g_signal_connect (notebook,
3858 "switch-page",
3859 G_CALLBACK (notebook_switch_page),
3860 window);
3861 g_signal_connect (notebook,
3862 "tab-added",
3863 G_CALLBACK (notebook_tab_added),
3864 window);
3865 g_signal_connect (notebook,
3866 "tab-removed",
3867 G_CALLBACK (notebook_tab_removed),
3868 window);
3869 g_signal_connect (notebook,
3870 "tabs-reordered",
3871 G_CALLBACK (notebook_tabs_reordered),
3872 window);
3873 g_signal_connect (notebook,
3874 "tab-detached",
3875 G_CALLBACK (notebook_tab_detached),
3876 window);
3877 g_signal_connect (notebook,
3878 "tab-close-request",
3879 G_CALLBACK (notebook_tab_close_request),
3880 window);
3881 g_signal_connect (notebook,
3882 "button-press-event",
3883 G_CALLBACK (notebook_button_press_event),
3884 window);
3885 g_signal_connect (notebook,
3886 "popup-menu",
3887 G_CALLBACK (notebook_popup_menu),
3888 window);
3889 g_signal_connect (notebook,
3890 "scroll-event",
3891 G_CALLBACK (notebook_scroll_event),
3892 window);
3893 }
3894
3895 static void
add_notebook(PlumaWindow * window,GtkWidget * notebook)3896 add_notebook (PlumaWindow *window,
3897 GtkWidget *notebook)
3898 {
3899 gtk_paned_pack1 (GTK_PANED (window->priv->vpaned),
3900 notebook,
3901 TRUE,
3902 TRUE);
3903
3904 gtk_widget_show (notebook);
3905
3906 gtk_widget_add_events (notebook, GDK_SCROLL_MASK);
3907 connect_notebook_signals (window, notebook);
3908 }
3909
3910 static void
on_extension_added(PeasExtensionSet * extensions,PeasPluginInfo * info,PeasExtension * exten,PlumaWindow * window)3911 on_extension_added (PeasExtensionSet *extensions,
3912 PeasPluginInfo *info,
3913 PeasExtension *exten,
3914 PlumaWindow *window)
3915 {
3916 peas_extension_call (exten, "activate", window);
3917 }
3918
3919 static void
on_extension_removed(PeasExtensionSet * extensions,PeasPluginInfo * info,PeasExtension * exten,PlumaWindow * window)3920 on_extension_removed (PeasExtensionSet *extensions,
3921 PeasPluginInfo *info,
3922 PeasExtension *exten,
3923 PlumaWindow *window)
3924 {
3925 peas_extension_call (exten, "deactivate", window);
3926
3927 /* Ensure update of ui manager, because we suspect it does something
3928 * with expected static strings in the type module (when unloaded the
3929 * strings don't exist anymore, and ui manager updates in an idle
3930 * func) */
3931 gtk_ui_manager_ensure_update (window->priv->manager);
3932 }
3933
3934 static void
pluma_window_init(PlumaWindow * window)3935 pluma_window_init (PlumaWindow *window)
3936 {
3937 GtkWidget *main_box;
3938 GtkTargetList *tl;
3939
3940 pluma_debug (DEBUG_WINDOW);
3941
3942 window->priv = pluma_window_get_instance_private (window);
3943 window->priv->active_tab = NULL;
3944 window->priv->num_tabs = 0;
3945 window->priv->removing_tabs = FALSE;
3946 window->priv->state = PLUMA_WINDOW_STATE_NORMAL;
3947 window->priv->dispose_has_run = FALSE;
3948 window->priv->fullscreen_controls = NULL;
3949 window->priv->fullscreen_animation_timeout_id = 0;
3950 window->priv->editor_settings = g_settings_new (PLUMA_SCHEMA_ID);
3951
3952 window->priv->message_bus = pluma_message_bus_new ();
3953
3954 window->priv->window_group = gtk_window_group_new ();
3955 gtk_window_group_add_window (window->priv->window_group, GTK_WINDOW (window));
3956
3957 GtkStyleContext *context;
3958
3959 context = gtk_widget_get_style_context (GTK_WIDGET (window));
3960 gtk_style_context_add_class (context, "pluma-window");
3961
3962 main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3963 gtk_container_add (GTK_CONTAINER (window), main_box);
3964 gtk_widget_show (main_box);
3965
3966 /* Add menu bar and toolbar bar */
3967 create_menu_bar_and_toolbar (window, main_box);
3968
3969 /* Add status bar */
3970 create_statusbar (window, main_box);
3971
3972 /* Add the main area */
3973 pluma_debug_message (DEBUG_WINDOW, "Add main area");
3974 window->priv->hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
3975 gtk_box_pack_start (GTK_BOX (main_box),
3976 window->priv->hpaned,
3977 TRUE,
3978 TRUE,
3979 0);
3980
3981 window->priv->vpaned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
3982 gtk_paned_pack2 (GTK_PANED (window->priv->hpaned),
3983 window->priv->vpaned,
3984 TRUE,
3985 FALSE);
3986
3987 pluma_debug_message (DEBUG_WINDOW, "Create pluma notebook");
3988 window->priv->notebook = pluma_notebook_new ();
3989 add_notebook (window, window->priv->notebook);
3990
3991 /* side and bottom panels */
3992 create_side_panel (window);
3993 create_bottom_panel (window);
3994
3995 /* panes' state must be restored after panels have been mapped,
3996 * since the bottom pane position depends on the size of the vpaned. */
3997 window->priv->side_panel_size = g_settings_get_int (window->priv->editor_settings,
3998 PLUMA_SETTINGS_SIDE_PANEL_SIZE);
3999 window->priv->bottom_panel_size = g_settings_get_int (window->priv->editor_settings,
4000 PLUMA_SETTINGS_BOTTOM_PANEL_SIZE);
4001
4002 g_signal_connect_after (window->priv->hpaned,
4003 "map",
4004 G_CALLBACK (hpaned_restore_position),
4005 window);
4006 g_signal_connect_after (window->priv->vpaned,
4007 "map",
4008 G_CALLBACK (vpaned_restore_position),
4009 window);
4010
4011 gtk_widget_show (window->priv->hpaned);
4012 gtk_widget_show (window->priv->vpaned);
4013
4014 /* Drag and drop support, set targets to NULL because we add the
4015 default uri_targets below */
4016 gtk_drag_dest_set (GTK_WIDGET (window),
4017 GTK_DEST_DEFAULT_MOTION |
4018 GTK_DEST_DEFAULT_HIGHLIGHT |
4019 GTK_DEST_DEFAULT_DROP,
4020 NULL,
4021 0,
4022 GDK_ACTION_COPY);
4023
4024 /* Add uri targets */
4025 tl = gtk_drag_dest_get_target_list (GTK_WIDGET (window));
4026
4027 if (tl == NULL)
4028 {
4029 tl = gtk_target_list_new (NULL, 0);
4030 gtk_drag_dest_set_target_list (GTK_WIDGET (window), tl);
4031 gtk_target_list_unref (tl);
4032 }
4033
4034 gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
4035
4036 /* connect instead of override, so that we can
4037 * share the cb code with the view */
4038 g_signal_connect (window,
4039 "drag_data_received",
4040 G_CALLBACK (drag_data_received_cb),
4041 NULL);
4042
4043 /* we can get the clipboard only after the widget
4044 * is realized */
4045 g_signal_connect (window,
4046 "realize",
4047 G_CALLBACK (window_realized),
4048 NULL);
4049 g_signal_connect (window,
4050 "unrealize",
4051 G_CALLBACK (window_unrealized),
4052 NULL);
4053
4054 /* Check if the window is active for fullscreen */
4055 g_signal_connect (window,
4056 "notify::is-active",
4057 G_CALLBACK (check_window_is_active),
4058 NULL);
4059
4060 pluma_debug_message (DEBUG_WINDOW, "Update plugins ui");
4061
4062 window->priv->extensions = peas_extension_set_new (PEAS_ENGINE (pluma_plugins_engine_get_default ()),
4063 PLUMA_TYPE_WINDOW_ACTIVATABLE,
4064 "window",
4065 window,
4066 NULL);
4067
4068 g_signal_connect (window->priv->extensions, "extension-added",
4069 G_CALLBACK (on_extension_added),
4070 window);
4071 g_signal_connect (window->priv->extensions, "extension-removed",
4072 G_CALLBACK (on_extension_removed),
4073 window);
4074
4075 peas_extension_set_call (window->priv->extensions, "activate");
4076
4077 /* set visibility of panes.
4078 * This needs to be done after plugins activatation */
4079 init_panels_visibility (window);
4080
4081 update_sensitivity_according_to_open_tabs (window);
4082
4083 pluma_debug_message (DEBUG_WINDOW, "END");
4084 }
4085
4086 /**
4087 * pluma_window_get_active_view:
4088 * @window: a #PlumaWindow
4089 *
4090 * Gets the active #PlumaView.
4091 *
4092 * Returns: (transfer none): the active #PlumaView
4093 */
4094 PlumaView *
pluma_window_get_active_view(PlumaWindow * window)4095 pluma_window_get_active_view (PlumaWindow *window)
4096 {
4097 PlumaView *view;
4098
4099 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4100
4101 if (window->priv->active_tab == NULL)
4102 return NULL;
4103
4104 view = pluma_tab_get_view (PLUMA_TAB (window->priv->active_tab));
4105
4106 return view;
4107 }
4108
4109 /**
4110 * pluma_window_get_active_document:
4111 * @window: a #PlumaWindow
4112 *
4113 * Gets the active #PlumaDocument.
4114 *
4115 * Returns: (transfer none): the active #PlumaDocument
4116 */
4117 PlumaDocument *
pluma_window_get_active_document(PlumaWindow * window)4118 pluma_window_get_active_document (PlumaWindow *window)
4119 {
4120 PlumaView *view;
4121
4122 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4123
4124 view = pluma_window_get_active_view (window);
4125 if (view == NULL)
4126 return NULL;
4127
4128 return PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
4129 }
4130
4131 GtkWidget *
_pluma_window_get_notebook(PlumaWindow * window)4132 _pluma_window_get_notebook (PlumaWindow *window)
4133 {
4134 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4135
4136 return window->priv->notebook;
4137 }
4138
4139 /**
4140 * pluma_window_create_tab:
4141 * @window: a #PlumaWindow
4142 * @jump_to: %TRUE to set the new #PlumaTab as active
4143 *
4144 * Creates a new #PlumaTab and adds the new tab to the #PlumaNotebook.
4145 * In case @jump_to is %TRUE the #PlumaNotebook switches to that new #PlumaTab.
4146 *
4147 * Returns: (transfer none): a new #PlumaTab
4148 */
4149 PlumaTab *
pluma_window_create_tab(PlumaWindow * window,gboolean jump_to)4150 pluma_window_create_tab (PlumaWindow *window,
4151 gboolean jump_to)
4152 {
4153 PlumaTab *tab;
4154
4155 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4156
4157 tab = PLUMA_TAB (_pluma_tab_new ());
4158 gtk_widget_show (GTK_WIDGET (tab));
4159
4160 pluma_notebook_add_tab (PLUMA_NOTEBOOK (window->priv->notebook),
4161 tab,
4162 -1,
4163 jump_to);
4164
4165 if (!gtk_widget_get_visible (GTK_WIDGET (window)))
4166 {
4167 gtk_window_present (GTK_WINDOW (window));
4168 }
4169
4170 return tab;
4171 }
4172
4173 /**
4174 * pluma_window_create_tab_from_uri:
4175 * @window: a #PlumaWindow
4176 * @uri: the uri of the document
4177 * @encoding: a #PlumaEncoding
4178 * @line_pos: the line position to visualize
4179 * @create: %TRUE to create a new document in case @uri does exist
4180 * @jump_to: %TRUE to set the new #PlumaTab as active
4181 *
4182 * Creates a new #PlumaTab loading the document specified by @uri.
4183 * In case @jump_to is %TRUE the #PlumaNotebook swithes to that new #PlumaTab.
4184 * Whether @create is %TRUE, creates a new empty document if location does
4185 * not refer to an existing file
4186 *
4187 * Returns: (transfer none): a new #PlumaTab
4188 */
4189 PlumaTab *
pluma_window_create_tab_from_uri(PlumaWindow * window,const gchar * uri,const PlumaEncoding * encoding,gint line_pos,gboolean create,gboolean jump_to)4190 pluma_window_create_tab_from_uri (PlumaWindow *window,
4191 const gchar *uri,
4192 const PlumaEncoding *encoding,
4193 gint line_pos,
4194 gboolean create,
4195 gboolean jump_to)
4196 {
4197 GtkWidget *tab;
4198
4199 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4200 g_return_val_if_fail (uri != NULL, NULL);
4201
4202 tab = _pluma_tab_new_from_uri (uri,
4203 encoding,
4204 line_pos,
4205 create);
4206 if (tab == NULL)
4207 return NULL;
4208
4209 gtk_widget_show (tab);
4210
4211 pluma_notebook_add_tab (PLUMA_NOTEBOOK (window->priv->notebook),
4212 PLUMA_TAB (tab),
4213 -1,
4214 jump_to);
4215
4216 if (!gtk_widget_get_visible (GTK_WIDGET (window)))
4217 {
4218 gtk_window_present (GTK_WINDOW (window));
4219 }
4220
4221 return PLUMA_TAB (tab);
4222 }
4223
4224 /**
4225 * pluma_window_get_active_tab:
4226 * @window: a PlumaWindow
4227 *
4228 * Gets the active #PlumaTab in the @window.
4229 *
4230 * Returns: (transfer none): the active #PlumaTab in the @window.
4231 */
4232 PlumaTab *
pluma_window_get_active_tab(PlumaWindow * window)4233 pluma_window_get_active_tab (PlumaWindow *window)
4234 {
4235 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4236
4237 return (window->priv->active_tab == NULL) ?
4238 NULL : PLUMA_TAB (window->priv->active_tab);
4239 }
4240
4241 static void
add_document(PlumaTab * tab,GList ** res)4242 add_document (PlumaTab *tab, GList **res)
4243 {
4244 PlumaDocument *doc;
4245
4246 doc = pluma_tab_get_document (tab);
4247
4248 *res = g_list_prepend (*res, doc);
4249 }
4250
4251 /**
4252 * pluma_window_get_documents:
4253 * @window: a #PlumaWindow
4254 *
4255 * Gets a newly allocated list with all the documents in the window.
4256 * This list must be freed.
4257 *
4258 * Returns: (element-type Pluma.Document) (transfer container): a newly
4259 * allocated list with all the documents in the window
4260 */
4261 GList *
pluma_window_get_documents(PlumaWindow * window)4262 pluma_window_get_documents (PlumaWindow *window)
4263 {
4264 GList *res = NULL;
4265
4266 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4267
4268 gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
4269 (GtkCallback)add_document,
4270 &res);
4271
4272 res = g_list_reverse (res);
4273
4274 return res;
4275 }
4276
4277 static void
add_view(PlumaTab * tab,GList ** res)4278 add_view (PlumaTab *tab, GList **res)
4279 {
4280 PlumaView *view;
4281
4282 view = pluma_tab_get_view (tab);
4283
4284 *res = g_list_prepend (*res, view);
4285 }
4286
4287 /**
4288 * pluma_window_get_views:
4289 * @window: a #PlumaWindow
4290 *
4291 * Gets a list with all the views in the window. This list must be freed.
4292 *
4293 * Returns: (element-type Pluma.View) (transfer container): a newly allocated
4294 * list with all the views in the window
4295 */
4296 GList *
pluma_window_get_views(PlumaWindow * window)4297 pluma_window_get_views (PlumaWindow *window)
4298 {
4299 GList *res = NULL;
4300
4301 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4302
4303 gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
4304 (GtkCallback)add_view,
4305 &res);
4306
4307 res = g_list_reverse (res);
4308
4309 return res;
4310 }
4311
4312 /**
4313 * pluma_window_close_tab:
4314 * @window: a #PlumaWindow
4315 * @tab: the #PlumaTab to close
4316 *
4317 * Closes the @tab.
4318 */
4319 void
pluma_window_close_tab(PlumaWindow * window,PlumaTab * tab)4320 pluma_window_close_tab (PlumaWindow *window,
4321 PlumaTab *tab)
4322 {
4323 g_return_if_fail (PLUMA_IS_WINDOW (window));
4324 g_return_if_fail (PLUMA_IS_TAB (tab));
4325 g_return_if_fail ((pluma_tab_get_state (tab) != PLUMA_TAB_STATE_SAVING) &&
4326 (pluma_tab_get_state (tab) != PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW));
4327
4328 pluma_notebook_remove_tab (PLUMA_NOTEBOOK (window->priv->notebook), tab);
4329 }
4330
4331 /**
4332 * pluma_window_close_all_tabs:
4333 * @window: a #PlumaWindow
4334 *
4335 * Closes all opened tabs.
4336 */
4337 void
pluma_window_close_all_tabs(PlumaWindow * window)4338 pluma_window_close_all_tabs (PlumaWindow *window)
4339 {
4340 g_return_if_fail (PLUMA_IS_WINDOW (window));
4341 g_return_if_fail (!(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
4342 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
4343
4344 window->priv->removing_tabs = TRUE;
4345
4346 pluma_notebook_remove_all_tabs (PLUMA_NOTEBOOK (window->priv->notebook));
4347
4348 window->priv->removing_tabs = FALSE;
4349 }
4350
4351 /**
4352 * pluma_window_close_tabs:
4353 * @window: a #PlumaWindow
4354 * @tabs: (element-type Pluma.Tab): a list of #PlumaTab
4355 *
4356 * Closes all tabs specified by @tabs.
4357 */
4358 void
pluma_window_close_tabs(PlumaWindow * window,const GList * tabs)4359 pluma_window_close_tabs (PlumaWindow *window,
4360 const GList *tabs)
4361 {
4362 g_return_if_fail (PLUMA_IS_WINDOW (window));
4363 g_return_if_fail (!(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
4364 !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
4365
4366 if (tabs == NULL)
4367 return;
4368
4369 window->priv->removing_tabs = TRUE;
4370
4371 while (tabs != NULL)
4372 {
4373 if (tabs->next == NULL)
4374 window->priv->removing_tabs = FALSE;
4375
4376 pluma_notebook_remove_tab (PLUMA_NOTEBOOK (window->priv->notebook),
4377 PLUMA_TAB (tabs->data));
4378
4379 tabs = g_list_next (tabs);
4380 }
4381
4382 g_return_if_fail (window->priv->removing_tabs == FALSE);
4383 }
4384
4385 PlumaWindow *
_pluma_window_move_tab_to_new_window(PlumaWindow * window,PlumaTab * tab)4386 _pluma_window_move_tab_to_new_window (PlumaWindow *window,
4387 PlumaTab *tab)
4388 {
4389 PlumaWindow *new_window;
4390
4391 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4392 g_return_val_if_fail (PLUMA_IS_TAB (tab), NULL);
4393 g_return_val_if_fail (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook)) > 1,
4394 NULL);
4395
4396 new_window = clone_window (window);
4397
4398 pluma_notebook_move_tab (PLUMA_NOTEBOOK (window->priv->notebook),
4399 PLUMA_NOTEBOOK (new_window->priv->notebook),
4400 tab,
4401 -1);
4402
4403 gtk_widget_show (GTK_WIDGET (new_window));
4404
4405 return new_window;
4406 }
4407
4408 /**
4409 * pluma_window_set_active_tab:
4410 * @window: a #PlumaWindow
4411 * @tab: a #PlumaTab
4412 *
4413 * Switches to the tab that matches with @tab.
4414 */
4415 void
pluma_window_set_active_tab(PlumaWindow * window,PlumaTab * tab)4416 pluma_window_set_active_tab (PlumaWindow *window,
4417 PlumaTab *tab)
4418 {
4419 gint page_num;
4420
4421 g_return_if_fail (PLUMA_IS_WINDOW (window));
4422 g_return_if_fail (PLUMA_IS_TAB (tab));
4423
4424 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->priv->notebook),
4425 GTK_WIDGET (tab));
4426 g_return_if_fail (page_num != -1);
4427
4428 gtk_notebook_set_current_page (GTK_NOTEBOOK (window->priv->notebook),
4429 page_num);
4430 }
4431
4432 /**
4433 * pluma_window_get_group:
4434 * @window: a #PlumaWindow
4435 *
4436 * Gets the #GtkWindowGroup in which @window resides.
4437 *
4438 * Returns: (transfer none): the #GtkWindowGroup
4439 */
4440 GtkWindowGroup *
pluma_window_get_group(PlumaWindow * window)4441 pluma_window_get_group (PlumaWindow *window)
4442 {
4443 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4444
4445 return window->priv->window_group;
4446 }
4447
4448 gboolean
_pluma_window_is_removing_tabs(PlumaWindow * window)4449 _pluma_window_is_removing_tabs (PlumaWindow *window)
4450 {
4451 g_return_val_if_fail (PLUMA_IS_WINDOW (window), FALSE);
4452
4453 return window->priv->removing_tabs;
4454 }
4455
4456 /**
4457 * pluma_window_get_ui_manager:
4458 * @window: a #PlumaWindow
4459 *
4460 * Gets the #GtkUIManager associated with the @window.
4461 *
4462 * Returns: (transfer none): the #GtkUIManager of the @window.
4463 */
4464 GtkUIManager *
pluma_window_get_ui_manager(PlumaWindow * window)4465 pluma_window_get_ui_manager (PlumaWindow *window)
4466 {
4467 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4468
4469 return window->priv->manager;
4470 }
4471
4472 /**
4473 * pluma_window_get_side_panel:
4474 * @window: a #PlumaWindow
4475 *
4476 * Gets the side #PlumaPanel of the @window.
4477 *
4478 * Returns: (transfer none): the side #PlumaPanel.
4479 */
4480 PlumaPanel *
pluma_window_get_side_panel(PlumaWindow * window)4481 pluma_window_get_side_panel (PlumaWindow *window)
4482 {
4483 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4484
4485 return PLUMA_PANEL (window->priv->side_panel);
4486 }
4487
4488 /**
4489 * pluma_window_get_bottom_panel:
4490 * @window: a #PlumaWindow
4491 *
4492 * Gets the bottom #PlumaPanel of the @window.
4493 *
4494 * Returns: (transfer none): the bottom #PlumaPanel.
4495 */
4496 PlumaPanel *
pluma_window_get_bottom_panel(PlumaWindow * window)4497 pluma_window_get_bottom_panel (PlumaWindow *window)
4498 {
4499 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4500
4501 return PLUMA_PANEL (window->priv->bottom_panel);
4502 }
4503
4504 /**
4505 * pluma_window_get_statusbar:
4506 * @window: a #PlumaWindow
4507 *
4508 * Gets the #PlumaStatusbar of the @window.
4509 *
4510 * Returns: (transfer none): the #PlumaStatusbar of the @window.
4511 */
4512 GtkWidget *
pluma_window_get_statusbar(PlumaWindow * window)4513 pluma_window_get_statusbar (PlumaWindow *window)
4514 {
4515 g_return_val_if_fail (PLUMA_IS_WINDOW (window), 0);
4516
4517 return window->priv->statusbar;
4518 }
4519
4520 /**
4521 * pluma_window_get_state:
4522 * @window: a #PlumaWindow
4523 *
4524 * Retrieves the state of the @window.
4525 *
4526 * Returns: the current #PlumaWindowState of the @window.
4527 */
4528 PlumaWindowState
pluma_window_get_state(PlumaWindow * window)4529 pluma_window_get_state (PlumaWindow *window)
4530 {
4531 g_return_val_if_fail (PLUMA_IS_WINDOW (window), PLUMA_WINDOW_STATE_NORMAL);
4532
4533 return window->priv->state;
4534 }
4535
4536 GFile *
_pluma_window_get_default_location(PlumaWindow * window)4537 _pluma_window_get_default_location (PlumaWindow *window)
4538 {
4539 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4540
4541 return window->priv->default_location != NULL ?
4542 g_object_ref (window->priv->default_location) : NULL;
4543 }
4544
4545 void
_pluma_window_set_default_location(PlumaWindow * window,GFile * location)4546 _pluma_window_set_default_location (PlumaWindow *window,
4547 GFile *location)
4548 {
4549 GFile *dir;
4550
4551 g_return_if_fail (PLUMA_IS_WINDOW (window));
4552 g_return_if_fail (G_IS_FILE (location));
4553
4554 dir = g_file_get_parent (location);
4555 g_return_if_fail (dir != NULL);
4556
4557 if (window->priv->default_location != NULL)
4558 g_object_unref (window->priv->default_location);
4559
4560 window->priv->default_location = dir;
4561 }
4562
4563 /**
4564 * pluma_window_get_unsaved_documents:
4565 * @window: a #PlumaWindow
4566 *
4567 * Gets the list of documents that need to be saved before closing the window.
4568 *
4569 * Returns: (element-type Pluma.Document) (transfer container): a list of
4570 * #PlumaDocument that need to be saved before closing the window
4571 */
4572 GList *
pluma_window_get_unsaved_documents(PlumaWindow * window)4573 pluma_window_get_unsaved_documents (PlumaWindow *window)
4574 {
4575 GList *unsaved_docs = NULL;
4576 GList *tabs;
4577 GList *l;
4578
4579 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4580
4581 tabs = gtk_container_get_children (GTK_CONTAINER (window->priv->notebook));
4582
4583 l = tabs;
4584 while (l != NULL)
4585 {
4586 PlumaTab *tab;
4587
4588 tab = PLUMA_TAB (l->data);
4589
4590 if (!_pluma_tab_can_close (tab))
4591 {
4592 PlumaDocument *doc;
4593
4594 doc = pluma_tab_get_document (tab);
4595 unsaved_docs = g_list_prepend (unsaved_docs, doc);
4596 }
4597
4598 l = g_list_next (l);
4599 }
4600
4601 g_list_free (tabs);
4602
4603 return g_list_reverse (unsaved_docs);
4604 }
4605
4606 void
_pluma_window_set_saving_session_state(PlumaWindow * window,gboolean saving_session)4607 _pluma_window_set_saving_session_state (PlumaWindow *window,
4608 gboolean saving_session)
4609 {
4610 PlumaWindowState old_state;
4611
4612 g_return_if_fail (PLUMA_IS_WINDOW (window));
4613
4614 old_state = window->priv->state;
4615
4616 if (saving_session)
4617 window->priv->state |= PLUMA_WINDOW_STATE_SAVING_SESSION;
4618 else
4619 window->priv->state &= ~PLUMA_WINDOW_STATE_SAVING_SESSION;
4620
4621 if (old_state != window->priv->state)
4622 {
4623 set_sensitivity_according_to_window_state (window);
4624
4625 g_object_notify (G_OBJECT (window), "state");
4626 }
4627 }
4628
4629 static void
hide_notebook_tabs_on_fullscreen(GtkNotebook * notebook,GParamSpec * pspec,PlumaWindow * window)4630 hide_notebook_tabs_on_fullscreen (GtkNotebook *notebook,
4631 GParamSpec *pspec,
4632 PlumaWindow *window)
4633 {
4634 gtk_notebook_set_show_tabs (notebook, FALSE);
4635 }
4636
4637 void
_pluma_window_fullscreen(PlumaWindow * window)4638 _pluma_window_fullscreen (PlumaWindow *window)
4639 {
4640 g_return_if_fail (PLUMA_IS_WINDOW (window));
4641
4642 if (_pluma_window_is_fullscreen (window))
4643 return;
4644
4645 /* Go to fullscreen mode and hide bars */
4646 gtk_window_fullscreen (&window->window);
4647 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook), FALSE);
4648 g_signal_connect (window->priv->notebook, "notify::show-tabs",
4649 G_CALLBACK (hide_notebook_tabs_on_fullscreen), window);
4650
4651 gtk_widget_hide (window->priv->menubar);
4652
4653 g_signal_handlers_block_by_func (window->priv->toolbar,
4654 toolbar_visibility_changed,
4655 window);
4656 gtk_widget_hide (window->priv->toolbar);
4657
4658 g_signal_handlers_block_by_func (window->priv->statusbar,
4659 statusbar_visibility_changed,
4660 window);
4661 gtk_widget_hide (window->priv->statusbar);
4662
4663 fullscreen_controls_build (window);
4664 fullscreen_controls_show (window);
4665 }
4666
4667 void
_pluma_window_unfullscreen(PlumaWindow * window)4668 _pluma_window_unfullscreen (PlumaWindow *window)
4669 {
4670 gboolean visible;
4671 GtkAction *action;
4672
4673 g_return_if_fail (PLUMA_IS_WINDOW (window));
4674
4675 if (!_pluma_window_is_fullscreen (window))
4676 return;
4677
4678 /* Unfullscreen and show bars */
4679 gtk_window_unfullscreen (&window->window);
4680 g_signal_handlers_disconnect_by_func (window->priv->notebook,
4681 hide_notebook_tabs_on_fullscreen,
4682 window);
4683 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook), TRUE);
4684 gtk_widget_show (window->priv->menubar);
4685
4686 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
4687 "ViewToolbar");
4688 visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
4689 if (visible)
4690 gtk_widget_show (window->priv->toolbar);
4691 g_signal_handlers_unblock_by_func (window->priv->toolbar,
4692 toolbar_visibility_changed,
4693 window);
4694
4695 action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
4696 "ViewStatusbar");
4697 visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
4698 if (visible)
4699 gtk_widget_show (window->priv->statusbar);
4700 g_signal_handlers_unblock_by_func (window->priv->statusbar,
4701 statusbar_visibility_changed,
4702 window);
4703
4704 gtk_widget_hide (window->priv->fullscreen_controls);
4705 }
4706
4707 gboolean
_pluma_window_is_fullscreen(PlumaWindow * window)4708 _pluma_window_is_fullscreen (PlumaWindow *window)
4709 {
4710 g_return_val_if_fail (PLUMA_IS_WINDOW (window), FALSE);
4711
4712 return window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN;
4713 }
4714
4715 /**
4716 * pluma_window_get_tab_from_location:
4717 * @window: a #PlumaWindow
4718 * @location: a #GFile
4719 *
4720 * Gets the #PlumaTab that matches with the given @location.
4721 *
4722 * Returns: (transfer none): the #PlumaTab that matches with the given @location.
4723 */
4724 PlumaTab *
pluma_window_get_tab_from_location(PlumaWindow * window,GFile * location)4725 pluma_window_get_tab_from_location (PlumaWindow *window,
4726 GFile *location)
4727 {
4728 GList *tabs;
4729 GList *l;
4730 PlumaTab *ret = NULL;
4731
4732 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4733 g_return_val_if_fail (G_IS_FILE (location), NULL);
4734
4735 tabs = gtk_container_get_children (GTK_CONTAINER (window->priv->notebook));
4736
4737 for (l = tabs; l != NULL; l = g_list_next (l))
4738 {
4739 PlumaDocument *d;
4740 PlumaTab *t;
4741 GFile *f;
4742
4743 t = PLUMA_TAB (l->data);
4744 d = pluma_tab_get_document (t);
4745
4746 f = pluma_document_get_location (d);
4747
4748 if ((f != NULL))
4749 {
4750 gboolean found = g_file_equal (location, f);
4751
4752 g_object_unref (f);
4753
4754 if (found)
4755 {
4756 ret = t;
4757 break;
4758 }
4759 }
4760 }
4761
4762 g_list_free (tabs);
4763
4764 return ret;
4765 }
4766
4767 /**
4768 * pluma_window_get_message_bus:
4769 * @window: a #PlumaWindow
4770 *
4771 * Gets the #PlumaMessageBus associated with @window. The returned reference
4772 * is owned by the window and should not be unreffed.
4773 *
4774 * Return value: (transfer none): the #PlumaMessageBus associated with @window
4775 */
4776 PlumaMessageBus *
pluma_window_get_message_bus(PlumaWindow * window)4777 pluma_window_get_message_bus (PlumaWindow *window)
4778 {
4779 g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
4780
4781 return window->priv->message_bus;
4782 }
4783
4784 void
_pluma_window_get_default_size(gint * width,gint * height)4785 _pluma_window_get_default_size (gint *width, gint *height)
4786 {
4787 g_return_if_fail (width != NULL && height != NULL);
4788
4789 *width = PLUMA_WINDOW_DEFAULT_WIDTH;
4790 *height = PLUMA_WINDOW_DEFAULT_HEIGHT;
4791 }
4792
4793