summaryrefslogtreecommitdiff
path: root/pluma/pluma-window.c
diff options
context:
space:
mode:
Diffstat (limited to 'pluma/pluma-window.c')
-rwxr-xr-xpluma/pluma-window.c4798
1 files changed, 4798 insertions, 0 deletions
diff --git a/pluma/pluma-window.c b/pluma/pluma-window.c
new file mode 100755
index 00000000..2f2024ba
--- /dev/null
+++ b/pluma/pluma-window.c
@@ -0,0 +1,4798 @@
+/*
+ * pluma-window.c
+ * This file is part of pluma
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the pluma Team, 2005. See the AUTHORS file for a
+ * list of people on the pluma Team.
+ * See the ChangeLog files for a list of changes.
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <time.h>
+#include <sys/types.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "pluma-ui.h"
+#include "pluma-window.h"
+#include "pluma-window-private.h"
+#include "pluma-app.h"
+#include "pluma-notebook.h"
+#include "pluma-statusbar.h"
+#include "pluma-utils.h"
+#include "pluma-commands.h"
+#include "pluma-debug.h"
+#include "pluma-language-manager.h"
+#include "pluma-prefs-manager-app.h"
+#include "pluma-panel.h"
+#include "pluma-documents-panel.h"
+#include "pluma-plugins-engine.h"
+#include "pluma-enum-types.h"
+#include "pluma-dirs.h"
+#include "pluma-status-combo-box.h"
+
+#ifdef OS_OSX
+#include "osx/pluma-osx.h"
+#endif
+
+#define LANGUAGE_NONE (const gchar *)"LangNone"
+#define PLUMA_UIFILE "pluma-ui.xml"
+#define TAB_WIDTH_DATA "PlumaWindowTabWidthData"
+#define LANGUAGE_DATA "PlumaWindowLanguageData"
+#define FULLSCREEN_ANIMATION_SPEED 4
+
+#define PLUMA_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object),\
+ PLUMA_TYPE_WINDOW, \
+ PlumaWindowPrivate))
+
+/* Signals */
+enum
+{
+ TAB_ADDED,
+ TAB_REMOVED,
+ TABS_REORDERED,
+ ACTIVE_TAB_CHANGED,
+ ACTIVE_TAB_STATE_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum
+{
+ PROP_0,
+ PROP_STATE
+};
+
+enum
+{
+ TARGET_URI_LIST = 100
+};
+
+G_DEFINE_TYPE(PlumaWindow, pluma_window, GTK_TYPE_WINDOW)
+
+static void recent_manager_changed (GtkRecentManager *manager,
+ PlumaWindow *window);
+
+static void
+pluma_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PlumaWindow *window = PLUMA_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_STATE:
+ g_value_set_enum (value,
+ pluma_window_get_state (window));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+save_panes_state (PlumaWindow *window)
+{
+ gint pane_page;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ if (pluma_prefs_manager_window_size_can_set ())
+ pluma_prefs_manager_set_window_size (window->priv->width,
+ window->priv->height);
+
+ if (pluma_prefs_manager_window_state_can_set ())
+ pluma_prefs_manager_set_window_state (window->priv->window_state);
+
+ if ((window->priv->side_panel_size > 0) &&
+ pluma_prefs_manager_side_panel_size_can_set ())
+ pluma_prefs_manager_set_side_panel_size (
+ window->priv->side_panel_size);
+
+ pane_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (window->priv->side_panel));
+ if (pane_page != 0 &&
+ pluma_prefs_manager_side_panel_active_page_can_set ())
+ pluma_prefs_manager_set_side_panel_active_page (pane_page);
+
+ if ((window->priv->bottom_panel_size > 0) &&
+ pluma_prefs_manager_bottom_panel_size_can_set ())
+ pluma_prefs_manager_set_bottom_panel_size (
+ window->priv->bottom_panel_size);
+
+ pane_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (window->priv->bottom_panel));
+ if (pane_page != 0 &&
+ pluma_prefs_manager_bottom_panel_active_page_can_set ())
+ pluma_prefs_manager_set_bottom_panel_active_page (pane_page);
+}
+
+#ifdef OS_OSX
+static GtkMenuItem *
+ui_manager_menu_item (GtkUIManager *uimanager,
+ const gchar *path)
+{
+ return GTK_MENU_ITEM (gtk_ui_manager_get_widget (uimanager, path));
+}
+
+static void
+add_mac_root_menu (PlumaWindow *window)
+{
+ if (window->priv->mac_menu_group != NULL)
+ {
+ return;
+ }
+
+ window->priv->mac_menu_group = ige_mac_menu_add_app_menu_group ();
+
+ ige_mac_menu_add_app_menu_item (window->priv->mac_menu_group,
+ ui_manager_menu_item (window->priv->manager, "/ui/MenuBar/HelpMenu/HelpAboutMenu"),
+ NULL);
+}
+
+static void
+remove_mac_root_menu (PlumaWindow *window)
+{
+ if (window->priv->mac_menu_group == NULL)
+ {
+ return;
+ }
+
+ ige_mac_menu_remove_app_menu_group (window->priv->mac_menu_group);
+ window->priv->mac_menu_group = NULL;
+}
+
+static gboolean
+pluma_window_focus_in_event (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ add_mac_root_menu (PLUMA_WINDOW (widget));
+ return GTK_WIDGET_CLASS (pluma_window_parent_class)->focus_in_event (widget, event);
+}
+
+static gboolean
+pluma_window_focus_out_event (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ remove_mac_root_menu (PLUMA_WINDOW (widget));
+ return GTK_WIDGET_CLASS (pluma_window_parent_class)->focus_out_event (widget, event);
+}
+#endif
+
+static void
+pluma_window_dispose (GObject *object)
+{
+ PlumaWindow *window;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ window = PLUMA_WINDOW (object);
+
+ /* Stop tracking removal of panes otherwise we always
+ * end up with thinking we had no pane active, since they
+ * should all be removed below */
+ if (window->priv->bottom_panel_item_removed_handler_id != 0)
+ {
+ g_signal_handler_disconnect (window->priv->bottom_panel,
+ window->priv->bottom_panel_item_removed_handler_id);
+ window->priv->bottom_panel_item_removed_handler_id = 0;
+ }
+
+ /* First of all, force collection so that plugins
+ * really drop some of the references.
+ */
+ pluma_plugins_engine_garbage_collect (pluma_plugins_engine_get_default ());
+
+ /* save the panes position and make sure to deactivate plugins
+ * for this window, but only once */
+ if (!window->priv->dispose_has_run)
+ {
+ save_panes_state (window);
+
+ pluma_plugins_engine_deactivate_plugins (pluma_plugins_engine_get_default (),
+ window);
+ window->priv->dispose_has_run = TRUE;
+ }
+
+ if (window->priv->fullscreen_animation_timeout_id != 0)
+ {
+ g_source_remove (window->priv->fullscreen_animation_timeout_id);
+ window->priv->fullscreen_animation_timeout_id = 0;
+ }
+
+ if (window->priv->fullscreen_controls != NULL)
+ {
+ gtk_widget_destroy (window->priv->fullscreen_controls);
+
+ window->priv->fullscreen_controls = NULL;
+ }
+
+ if (window->priv->recents_handler_id != 0)
+ {
+ GtkRecentManager *recent_manager;
+
+ recent_manager = gtk_recent_manager_get_default ();
+ g_signal_handler_disconnect (recent_manager,
+ window->priv->recents_handler_id);
+ window->priv->recents_handler_id = 0;
+ }
+
+ if (window->priv->manager != NULL)
+ {
+ g_object_unref (window->priv->manager);
+ window->priv->manager = NULL;
+ }
+
+ if (window->priv->message_bus != NULL)
+ {
+ g_object_unref (window->priv->message_bus);
+ window->priv->message_bus = NULL;
+ }
+
+ if (window->priv->window_group != NULL)
+ {
+ g_object_unref (window->priv->window_group);
+ window->priv->window_group = NULL;
+ }
+
+ /* Now that there have broken some reference loops,
+ * force collection again.
+ */
+ pluma_plugins_engine_garbage_collect (pluma_plugins_engine_get_default ());
+
+#ifdef OS_OSX
+ remove_mac_root_menu (window);
+#endif
+
+ G_OBJECT_CLASS (pluma_window_parent_class)->dispose (object);
+}
+
+static void
+pluma_window_finalize (GObject *object)
+{
+ PlumaWindow *window;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ window = PLUMA_WINDOW (object);
+
+ if (window->priv->default_location != NULL)
+ g_object_unref (window->priv->default_location);
+
+ G_OBJECT_CLASS (pluma_window_parent_class)->finalize (object);
+}
+
+static gboolean
+pluma_window_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event)
+{
+ PlumaWindow *window = PLUMA_WINDOW (widget);
+
+ window->priv->window_state = event->new_window_state;
+
+ if (event->changed_mask &
+ (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN))
+ {
+ gboolean show;
+
+ show = !(event->new_window_state &
+ (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN));
+
+ _pluma_statusbar_set_has_resize_grip (PLUMA_STATUSBAR (window->priv->statusbar),
+ show);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+pluma_window_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event)
+{
+ PlumaWindow *window = PLUMA_WINDOW (widget);
+
+ window->priv->width = event->width;
+ window->priv->height = event->height;
+
+ return GTK_WIDGET_CLASS (pluma_window_parent_class)->configure_event (widget, event);
+}
+
+/*
+ * GtkWindow catches keybindings for the menu items _before_ passing them to
+ * the focused widget. This is unfortunate and means that pressing ctrl+V
+ * in an entry on a panel ends up pasting text in the TextView.
+ * Here we override GtkWindow's handler to do the same things that it
+ * does, but in the opposite order and then we chain up to the grand
+ * parent handler, skipping gtk_window_key_press_event.
+ */
+static gboolean
+pluma_window_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ static gpointer grand_parent_class = NULL;
+ GtkWindow *window = GTK_WINDOW (widget);
+ gboolean handled = FALSE;
+
+ if (grand_parent_class == NULL)
+ grand_parent_class = g_type_class_peek_parent (pluma_window_parent_class);
+
+ /* handle focus widget key events */
+ if (!handled)
+ handled = gtk_window_propagate_key_event (window, event);
+
+ /* handle mnemonics and accelerators */
+ if (!handled)
+ handled = gtk_window_activate_key (window, event);
+
+ /* Chain up, invokes binding set */
+ if (!handled)
+ handled = GTK_WIDGET_CLASS (grand_parent_class)->key_press_event (widget, event);
+
+ return handled;
+}
+
+static void
+pluma_window_tab_removed (PlumaWindow *window,
+ PlumaTab *tab)
+{
+ pluma_plugins_engine_garbage_collect (pluma_plugins_engine_get_default ());
+}
+
+static void
+pluma_window_class_init (PlumaWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ klass->tab_removed = pluma_window_tab_removed;
+
+ object_class->dispose = pluma_window_dispose;
+ object_class->finalize = pluma_window_finalize;
+ object_class->get_property = pluma_window_get_property;
+
+ widget_class->window_state_event = pluma_window_window_state_event;
+ widget_class->configure_event = pluma_window_configure_event;
+ widget_class->key_press_event = pluma_window_key_press_event;
+
+#ifdef OS_OSX
+ widget_class->focus_in_event = pluma_window_focus_in_event;
+ widget_class->focus_out_event = pluma_window_focus_out_event;
+#endif
+
+ signals[TAB_ADDED] =
+ g_signal_new ("tab_added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (PlumaWindowClass, tab_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ PLUMA_TYPE_TAB);
+ signals[TAB_REMOVED] =
+ g_signal_new ("tab_removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (PlumaWindowClass, tab_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ PLUMA_TYPE_TAB);
+ signals[TABS_REORDERED] =
+ g_signal_new ("tabs_reordered",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (PlumaWindowClass, tabs_reordered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals[ACTIVE_TAB_CHANGED] =
+ g_signal_new ("active_tab_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (PlumaWindowClass, active_tab_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ PLUMA_TYPE_TAB);
+ signals[ACTIVE_TAB_STATE_CHANGED] =
+ g_signal_new ("active_tab_state_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (PlumaWindowClass, active_tab_state_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_object_class_install_property (object_class,
+ PROP_STATE,
+ g_param_spec_flags ("state",
+ "State",
+ "The window's state",
+ PLUMA_TYPE_WINDOW_STATE,
+ PLUMA_WINDOW_STATE_NORMAL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof(PlumaWindowPrivate));
+}
+
+static void
+menu_item_select_cb (GtkMenuItem *proxy,
+ PlumaWindow *window)
+{
+ GtkAction *action;
+ char *message;
+
+ action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy));
+ g_return_if_fail (action != NULL);
+
+ g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
+ if (message)
+ {
+ gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->tip_message_cid, message);
+ g_free (message);
+ }
+}
+
+static void
+menu_item_deselect_cb (GtkMenuItem *proxy,
+ PlumaWindow *window)
+{
+ gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+ window->priv->tip_message_cid);
+}
+
+static void
+connect_proxy_cb (GtkUIManager *manager,
+ GtkAction *action,
+ GtkWidget *proxy,
+ PlumaWindow *window)
+{
+ if (GTK_IS_MENU_ITEM (proxy))
+ {
+ g_signal_connect (proxy, "select",
+ G_CALLBACK (menu_item_select_cb), window);
+ g_signal_connect (proxy, "deselect",
+ G_CALLBACK (menu_item_deselect_cb), window);
+ }
+}
+
+static void
+disconnect_proxy_cb (GtkUIManager *manager,
+ GtkAction *action,
+ GtkWidget *proxy,
+ PlumaWindow *window)
+{
+ if (GTK_IS_MENU_ITEM (proxy))
+ {
+ g_signal_handlers_disconnect_by_func
+ (proxy, G_CALLBACK (menu_item_select_cb), window);
+ g_signal_handlers_disconnect_by_func
+ (proxy, G_CALLBACK (menu_item_deselect_cb), window);
+ }
+}
+
+static void
+apply_toolbar_style (PlumaWindow *window,
+ GtkWidget *toolbar)
+{
+ switch (window->priv->toolbar_style)
+ {
+ case PLUMA_TOOLBAR_SYSTEM:
+ pluma_debug_message (DEBUG_WINDOW, "PLUMA: SYSTEM");
+ gtk_toolbar_unset_style (
+ GTK_TOOLBAR (toolbar));
+ break;
+
+ case PLUMA_TOOLBAR_ICONS:
+ pluma_debug_message (DEBUG_WINDOW, "PLUMA: ICONS");
+ gtk_toolbar_set_style (
+ GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_ICONS);
+ break;
+
+ case PLUMA_TOOLBAR_ICONS_AND_TEXT:
+ pluma_debug_message (DEBUG_WINDOW, "PLUMA: ICONS_AND_TEXT");
+ gtk_toolbar_set_style (
+ GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_BOTH);
+ break;
+
+ case PLUMA_TOOLBAR_ICONS_BOTH_HORIZ:
+ pluma_debug_message (DEBUG_WINDOW, "PLUMA: ICONS_BOTH_HORIZ");
+ gtk_toolbar_set_style (
+ GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_BOTH_HORIZ);
+ break;
+ }
+}
+
+/* Returns TRUE if toolbar is visible */
+static gboolean
+set_toolbar_style (PlumaWindow *window,
+ PlumaWindow *origin)
+{
+ gboolean visible;
+ PlumaToolbarSetting style;
+ GtkAction *action;
+
+ if (origin == NULL)
+ visible = pluma_prefs_manager_get_toolbar_visible ();
+ else
+ visible = GTK_WIDGET_VISIBLE (origin->priv->toolbar);
+
+ /* Set visibility */
+ if (visible)
+ gtk_widget_show (window->priv->toolbar);
+ else
+ gtk_widget_hide (window->priv->toolbar);
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "ViewToolbar");
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+
+ /* Set style */
+ if (origin == NULL)
+ style = pluma_prefs_manager_get_toolbar_buttons_style ();
+ else
+ style = origin->priv->toolbar_style;
+
+ window->priv->toolbar_style = style;
+
+ apply_toolbar_style (window, window->priv->toolbar);
+
+ return visible;
+}
+
+static void
+update_next_prev_doc_sensitivity (PlumaWindow *window,
+ PlumaTab *tab)
+{
+ gint tab_number;
+ GtkNotebook *notebook;
+ GtkAction *action;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ notebook = GTK_NOTEBOOK (_pluma_window_get_notebook (window));
+
+ tab_number = gtk_notebook_page_num (notebook, GTK_WIDGET (tab));
+ g_return_if_fail (tab_number >= 0);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "DocumentsPreviousDocument");
+ gtk_action_set_sensitive (action, tab_number != 0);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "DocumentsNextDocument");
+ gtk_action_set_sensitive (action,
+ tab_number < gtk_notebook_get_n_pages (notebook) - 1);
+}
+
+static void
+update_next_prev_doc_sensitivity_per_window (PlumaWindow *window)
+{
+ PlumaTab *tab;
+ GtkAction *action;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ tab = pluma_window_get_active_tab (window);
+ if (tab != NULL)
+ {
+ update_next_prev_doc_sensitivity (window, tab);
+
+ return;
+ }
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "DocumentsPreviousDocument");
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "DocumentsNextDocument");
+ gtk_action_set_sensitive (action, FALSE);
+
+}
+
+static void
+received_clipboard_contents (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ PlumaWindow *window)
+{
+ gboolean sens;
+ GtkAction *action;
+
+ /* getting clipboard contents is async, so we need to
+ * get the current tab and its state */
+
+ if (window->priv->active_tab != NULL)
+ {
+ PlumaTabState state;
+ gboolean state_normal;
+
+ state = pluma_tab_get_state (window->priv->active_tab);
+ state_normal = (state == PLUMA_TAB_STATE_NORMAL);
+
+ sens = state_normal &&
+ gtk_selection_data_targets_include_text (selection_data);
+ }
+ else
+ {
+ sens = FALSE;
+ }
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditPaste");
+
+ gtk_action_set_sensitive (action, sens);
+
+ g_object_unref (window);
+}
+
+static void
+set_paste_sensitivity_according_to_clipboard (PlumaWindow *window,
+ GtkClipboard *clipboard)
+{
+ GdkDisplay *display;
+
+ display = gtk_clipboard_get_display (clipboard);
+
+ if (gdk_display_supports_selection_notification (display))
+ {
+ gtk_clipboard_request_contents (clipboard,
+ gdk_atom_intern_static_string ("TARGETS"),
+ (GtkClipboardReceivedFunc) received_clipboard_contents,
+ g_object_ref (window));
+ }
+ else
+ {
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditPaste");
+
+ /* XFIXES extension not availbale, make
+ * Paste always sensitive */
+ gtk_action_set_sensitive (action, TRUE);
+ }
+}
+
+static void
+set_sensitivity_according_to_tab (PlumaWindow *window,
+ PlumaTab *tab)
+{
+ PlumaDocument *doc;
+ PlumaView *view;
+ GtkAction *action;
+ gboolean b;
+ gboolean state_normal;
+ gboolean editable;
+ PlumaTabState state;
+ GtkClipboard *clipboard;
+ PlumaLockdownMask lockdown;
+
+ g_return_if_fail (PLUMA_TAB (tab));
+
+ pluma_debug (DEBUG_WINDOW);
+
+ lockdown = pluma_app_get_lockdown (pluma_app_get_default ());
+
+ state = pluma_tab_get_state (tab);
+ state_normal = (state == PLUMA_TAB_STATE_NORMAL);
+
+ view = pluma_tab_get_view (tab);
+ editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
+
+ doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
+ GDK_SELECTION_CLIPBOARD);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileSave");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
+ (state == PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
+ !pluma_document_get_readonly (doc) &&
+ !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileSaveAs");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ (state == PLUMA_TAB_STATE_SAVING_ERROR) ||
+ (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
+ (state == PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
+ !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileRevert");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ (state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)) &&
+ !pluma_document_is_untitled (doc));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FilePrintPreview");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ !(lockdown & PLUMA_LOCKDOWN_PRINTING));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FilePrint");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ (state == PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
+ !(lockdown & PLUMA_LOCKDOWN_PRINTING));
+
+ action = gtk_action_group_get_action (window->priv->close_action_group,
+ "FileClose");
+
+ gtk_action_set_sensitive (action,
+ (state != PLUMA_TAB_STATE_CLOSING) &&
+ (state != PLUMA_TAB_STATE_SAVING) &&
+ (state != PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW) &&
+ (state != PLUMA_TAB_STATE_PRINTING) &&
+ (state != PLUMA_TAB_STATE_PRINT_PREVIEWING) &&
+ (state != PLUMA_TAB_STATE_SAVING_ERROR));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditUndo");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ gtk_source_buffer_can_undo (GTK_SOURCE_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditRedo");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ gtk_source_buffer_can_redo (GTK_SOURCE_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditCut");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ editable &&
+ gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditCopy");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) &&
+ gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditPaste");
+ if (state_normal && editable)
+ {
+ set_paste_sensitivity_according_to_clipboard (window,
+ clipboard);
+ }
+ else
+ {
+ gtk_action_set_sensitive (action, FALSE);
+ }
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditDelete");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ editable &&
+ gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchFind");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchIncrementalSearch");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchReplace");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ editable);
+
+ b = pluma_document_get_can_search_again (doc);
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchFindNext");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchFindPrevious");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchClearHighlight");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) && b);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchGoToLine");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "ViewHighlightMode");
+ gtk_action_set_sensitive (action,
+ (state != PLUMA_TAB_STATE_CLOSING) &&
+ pluma_prefs_manager_get_enable_syntax_highlighting ());
+
+ update_next_prev_doc_sensitivity (window, tab);
+
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+}
+
+static void
+language_toggled (GtkToggleAction *action,
+ PlumaWindow *window)
+{
+ PlumaDocument *doc;
+ GtkSourceLanguage *lang;
+ const gchar *lang_id;
+
+ if (gtk_toggle_action_get_active (action) == FALSE)
+ return;
+
+ doc = pluma_window_get_active_document (window);
+ if (doc == NULL)
+ return;
+
+ lang_id = gtk_action_get_name (GTK_ACTION (action));
+
+ if (strcmp (lang_id, LANGUAGE_NONE) == 0)
+ {
+ /* Normal (no highlighting) */
+ lang = NULL;
+ }
+ else
+ {
+ lang = gtk_source_language_manager_get_language (
+ pluma_get_language_manager (),
+ lang_id);
+ if (lang == NULL)
+ {
+ g_warning ("Could not get language %s\n", lang_id);
+ }
+ }
+
+ pluma_document_set_language (doc, lang);
+}
+
+static gchar *
+escape_section_name (const gchar *name)
+{
+ gchar *ret;
+
+ ret = g_markup_escape_text (name, -1);
+
+ /* Replace '/' with '-' to avoid problems in xml paths */
+ g_strdelimit (ret, "/", '-');
+
+ return ret;
+}
+
+static void
+create_language_menu_item (GtkSourceLanguage *lang,
+ gint index,
+ guint ui_id,
+ PlumaWindow *window)
+{
+ GtkAction *section_action;
+ GtkRadioAction *action;
+ GtkAction *normal_action;
+ GSList *group;
+ const gchar *section;
+ gchar *escaped_section;
+ const gchar *lang_id;
+ const gchar *lang_name;
+ gchar *escaped_lang_name;
+ gchar *tip;
+ gchar *path;
+
+ section = gtk_source_language_get_section (lang);
+ escaped_section = escape_section_name (section);
+
+ /* check if the section submenu exists or create it */
+ section_action = gtk_action_group_get_action (window->priv->languages_action_group,
+ escaped_section);
+
+ if (section_action == NULL)
+ {
+ gchar *section_name;
+
+ section_name = pluma_utils_escape_underscores (section, -1);
+
+ section_action = gtk_action_new (escaped_section,
+ section_name,
+ NULL,
+ NULL);
+
+ g_free (section_name);
+
+ gtk_action_group_add_action (window->priv->languages_action_group,
+ section_action);
+ g_object_unref (section_action);
+
+ gtk_ui_manager_add_ui (window->priv->manager,
+ ui_id,
+ "/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder",
+ escaped_section,
+ escaped_section,
+ GTK_UI_MANAGER_MENU,
+ FALSE);
+ }
+
+ /* now add the language item to the section */
+ lang_name = gtk_source_language_get_name (lang);
+ lang_id = gtk_source_language_get_id (lang);
+
+ escaped_lang_name = pluma_utils_escape_underscores (lang_name, -1);
+
+ tip = g_strdup_printf (_("Use %s highlight mode"), lang_name);
+ path = g_strdup_printf ("/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder/%s",
+ escaped_section);
+
+ action = gtk_radio_action_new (lang_id,
+ escaped_lang_name,
+ tip,
+ NULL,
+ index);
+
+ g_free (escaped_lang_name);
+
+ /* Action is added with a NULL accel to make the accel overridable */
+ gtk_action_group_add_action_with_accel (window->priv->languages_action_group,
+ GTK_ACTION (action),
+ NULL);
+ g_object_unref (action);
+
+ /* add the action to the same radio group of the "Normal" action */
+ normal_action = gtk_action_group_get_action (window->priv->languages_action_group,
+ LANGUAGE_NONE);
+ group = gtk_radio_action_get_group (GTK_RADIO_ACTION (normal_action));
+ gtk_radio_action_set_group (action, group);
+
+ g_signal_connect (action,
+ "activate",
+ G_CALLBACK (language_toggled),
+ window);
+
+ gtk_ui_manager_add_ui (window->priv->manager,
+ ui_id,
+ path,
+ lang_id,
+ lang_id,
+ GTK_UI_MANAGER_MENUITEM,
+ FALSE);
+
+ g_free (path);
+ g_free (tip);
+ g_free (escaped_section);
+}
+
+static void
+create_languages_menu (PlumaWindow *window)
+{
+ GtkRadioAction *action_none;
+ GSList *languages;
+ GSList *l;
+ guint id;
+ gint i;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ /* add the "Plain Text" item before all the others */
+
+ /* Translators: "Plain Text" means that no highlight mode is selected in the
+ * "View->Highlight Mode" submenu and so syntax highlighting is disabled */
+ action_none = gtk_radio_action_new (LANGUAGE_NONE, _("Plain Text"),
+ _("Disable syntax highlighting"),
+ NULL,
+ -1);
+
+ gtk_action_group_add_action (window->priv->languages_action_group,
+ GTK_ACTION (action_none));
+ g_object_unref (action_none);
+
+ g_signal_connect (action_none,
+ "activate",
+ G_CALLBACK (language_toggled),
+ window);
+
+ id = gtk_ui_manager_new_merge_id (window->priv->manager);
+
+ gtk_ui_manager_add_ui (window->priv->manager,
+ id,
+ "/MenuBar/ViewMenu/ViewHighlightModeMenu/LanguagesMenuPlaceholder",
+ LANGUAGE_NONE,
+ LANGUAGE_NONE,
+ GTK_UI_MANAGER_MENUITEM,
+ TRUE);
+
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action_none), TRUE);
+
+ /* now add all the known languages */
+ languages = pluma_language_manager_list_languages_sorted (
+ pluma_get_language_manager (),
+ FALSE);
+
+ for (l = languages, i = 0; l != NULL; l = l->next, ++i)
+ {
+ create_language_menu_item (l->data,
+ i,
+ id,
+ window);
+ }
+
+ g_slist_free (languages);
+}
+
+static void
+update_languages_menu (PlumaWindow *window)
+{
+ PlumaDocument *doc;
+ GList *actions;
+ GList *l;
+ GtkAction *action;
+ GtkSourceLanguage *lang;
+ const gchar *lang_id;
+
+ doc = pluma_window_get_active_document (window);
+ if (doc == NULL)
+ return;
+
+ lang = pluma_document_get_language (doc);
+ if (lang != NULL)
+ lang_id = gtk_source_language_get_id (lang);
+ else
+ lang_id = LANGUAGE_NONE;
+
+ actions = gtk_action_group_list_actions (window->priv->languages_action_group);
+
+ /* prevent recursion */
+ for (l = actions; l != NULL; l = l->next)
+ {
+ g_signal_handlers_block_by_func (GTK_ACTION (l->data),
+ G_CALLBACK (language_toggled),
+ window);
+ }
+
+ action = gtk_action_group_get_action (window->priv->languages_action_group,
+ lang_id);
+
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+ for (l = actions; l != NULL; l = l->next)
+ {
+ g_signal_handlers_unblock_by_func (GTK_ACTION (l->data),
+ G_CALLBACK (language_toggled),
+ window);
+ }
+
+ g_list_free (actions);
+}
+
+void
+_pluma_recent_add (PlumaWindow *window,
+ const gchar *uri,
+ const gchar *mime)
+{
+ GtkRecentManager *recent_manager;
+ GtkRecentData *recent_data;
+
+ static gchar *groups[2] = {
+ "pluma",
+ NULL
+ };
+
+ recent_manager = gtk_recent_manager_get_default ();
+
+ recent_data = g_slice_new (GtkRecentData);
+
+ recent_data->display_name = NULL;
+ recent_data->description = NULL;
+ recent_data->mime_type = (gchar *) mime;
+ recent_data->app_name = (gchar *) g_get_application_name ();
+ recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
+ recent_data->groups = groups;
+ recent_data->is_private = FALSE;
+
+ gtk_recent_manager_add_full (recent_manager,
+ uri,
+ recent_data);
+
+ g_free (recent_data->app_exec);
+
+ g_slice_free (GtkRecentData, recent_data);
+}
+
+void
+_pluma_recent_remove (PlumaWindow *window,
+ const gchar *uri)
+{
+ GtkRecentManager *recent_manager;
+
+ recent_manager = gtk_recent_manager_get_default ();
+
+ gtk_recent_manager_remove_item (recent_manager, uri, NULL);
+}
+
+static void
+open_recent_file (const gchar *uri,
+ PlumaWindow *window)
+{
+ GSList *uris = NULL;
+
+ uris = g_slist_prepend (uris, (gpointer) uri);
+
+ if (pluma_commands_load_uris (window, uris, NULL, 0) != 1)
+ {
+ _pluma_recent_remove (window, uri);
+ }
+
+ g_slist_free (uris);
+}
+
+static void
+recent_chooser_item_activated (GtkRecentChooser *chooser,
+ PlumaWindow *window)
+{
+ gchar *uri;
+
+ uri = gtk_recent_chooser_get_current_uri (chooser);
+
+ open_recent_file (uri, window);
+
+ g_free (uri);
+}
+
+static void
+recents_menu_activate (GtkAction *action,
+ PlumaWindow *window)
+{
+ GtkRecentInfo *info;
+ const gchar *uri;
+
+ info = g_object_get_data (G_OBJECT (action), "gtk-recent-info");
+ g_return_if_fail (info != NULL);
+
+ uri = gtk_recent_info_get_uri (info);
+
+ open_recent_file (uri, window);
+}
+
+static gint
+sort_recents_mru (GtkRecentInfo *a, GtkRecentInfo *b)
+{
+ return (gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a));
+}
+
+static void update_recent_files_menu (PlumaWindow *window);
+
+static void
+recent_manager_changed (GtkRecentManager *manager,
+ PlumaWindow *window)
+{
+ /* regenerate the menu when the model changes */
+ update_recent_files_menu (window);
+}
+
+/*
+ * Manually construct the inline recents list in the File menu.
+ * Hopefully gtk 2.12 will add support for it.
+ */
+static void
+update_recent_files_menu (PlumaWindow *window)
+{
+ PlumaWindowPrivate *p = window->priv;
+ GtkRecentManager *recent_manager;
+ gint max_recents;
+ GList *actions, *l, *items;
+ GList *filtered_items = NULL;
+ gint i;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ max_recents = pluma_prefs_manager_get_max_recents ();
+
+ g_return_if_fail (p->recents_action_group != NULL);
+
+ if (p->recents_menu_ui_id != 0)
+ gtk_ui_manager_remove_ui (p->manager,
+ p->recents_menu_ui_id);
+
+ actions = gtk_action_group_list_actions (p->recents_action_group);
+ for (l = actions; l != NULL; l = l->next)
+ {
+ g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
+ G_CALLBACK (recents_menu_activate),
+ window);
+ gtk_action_group_remove_action (p->recents_action_group,
+ GTK_ACTION (l->data));
+ }
+ g_list_free (actions);
+
+ p->recents_menu_ui_id = gtk_ui_manager_new_merge_id (p->manager);
+
+ recent_manager = gtk_recent_manager_get_default ();
+ items = gtk_recent_manager_get_items (recent_manager);
+
+ /* filter */
+ for (l = items; l != NULL; l = l->next)
+ {
+ GtkRecentInfo *info = l->data;
+
+ if (!gtk_recent_info_has_group (info, "pluma"))
+ continue;
+
+ filtered_items = g_list_prepend (filtered_items, info);
+ }
+
+ /* sort */
+ filtered_items = g_list_sort (filtered_items,
+ (GCompareFunc) sort_recents_mru);
+
+ i = 0;
+ for (l = filtered_items; l != NULL; l = l->next)
+ {
+ gchar *action_name;
+ const gchar *display_name;
+ gchar *escaped;
+ gchar *label;
+ gchar *uri;
+ gchar *ruri;
+ gchar *tip;
+ GtkAction *action;
+ GtkRecentInfo *info = l->data;
+
+ /* clamp */
+ if (i >= max_recents)
+ break;
+
+ i++;
+
+ action_name = g_strdup_printf ("recent-info-%d", i);
+
+ display_name = gtk_recent_info_get_display_name (info);
+ escaped = pluma_utils_escape_underscores (display_name, -1);
+ if (i >= 10)
+ label = g_strdup_printf ("%d. %s",
+ i,
+ escaped);
+ else
+ label = g_strdup_printf ("_%d. %s",
+ i,
+ escaped);
+ g_free (escaped);
+
+ /* gtk_recent_info_get_uri_display (info) is buggy and
+ * works only for local files */
+ uri = pluma_utils_uri_for_display (gtk_recent_info_get_uri (info));
+ ruri = pluma_utils_replace_home_dir_with_tilde (uri);
+ g_free (uri);
+
+ /* Translators: %s is a URI */
+ tip = g_strdup_printf (_("Open '%s'"), ruri);
+ g_free (ruri);
+
+ action = gtk_action_new (action_name,
+ label,
+ tip,
+ NULL);
+
+ g_object_set_data_full (G_OBJECT (action),
+ "gtk-recent-info",
+ gtk_recent_info_ref (info),
+ (GDestroyNotify) gtk_recent_info_unref);
+
+ g_signal_connect (action,
+ "activate",
+ G_CALLBACK (recents_menu_activate),
+ window);
+
+ gtk_action_group_add_action (p->recents_action_group,
+ action);
+ g_object_unref (action);
+
+ gtk_ui_manager_add_ui (p->manager,
+ p->recents_menu_ui_id,
+ "/MenuBar/FileMenu/FileRecentsPlaceholder",
+ action_name,
+ action_name,
+ GTK_UI_MANAGER_MENUITEM,
+ FALSE);
+
+ g_free (action_name);
+ g_free (label);
+ g_free (tip);
+ }
+
+ g_list_free (filtered_items);
+
+ g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
+ g_list_free (items);
+}
+
+static void
+set_non_homogeneus (GtkWidget *widget, gpointer data)
+{
+ gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
+}
+
+static void
+toolbar_visibility_changed (GtkWidget *toolbar,
+ PlumaWindow *window)
+{
+ gboolean visible;
+ GtkAction *action;
+
+ visible = GTK_WIDGET_VISIBLE (toolbar);
+
+ if (pluma_prefs_manager_toolbar_visible_can_set ())
+ pluma_prefs_manager_set_toolbar_visible (visible);
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "ViewToolbar");
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+}
+
+static GtkWidget *
+setup_toolbar_open_button (PlumaWindow *window,
+ GtkWidget *toolbar)
+{
+ GtkRecentManager *recent_manager;
+ GtkRecentFilter *filter;
+ GtkWidget *toolbar_recent_menu;
+ GtkToolItem *open_button;
+ GtkAction *action;
+
+ recent_manager = gtk_recent_manager_get_default ();
+
+ /* recent files menu tool button */
+ toolbar_recent_menu = gtk_recent_chooser_menu_new_for_manager (recent_manager);
+
+ gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (toolbar_recent_menu),
+ FALSE);
+ gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (toolbar_recent_menu),
+ GTK_RECENT_SORT_MRU);
+ gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (toolbar_recent_menu),
+ pluma_prefs_manager_get_max_recents ());
+
+ filter = gtk_recent_filter_new ();
+ gtk_recent_filter_add_group (filter, "pluma");
+ gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (toolbar_recent_menu),
+ filter);
+
+ g_signal_connect (toolbar_recent_menu,
+ "item_activated",
+ G_CALLBACK (recent_chooser_item_activated),
+ window);
+
+ /* add the custom Open button to the toolbar */
+ open_button = gtk_menu_tool_button_new_from_stock (GTK_STOCK_OPEN);
+ gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button),
+ toolbar_recent_menu);
+
+ gtk_tool_item_set_tooltip_text (open_button, _("Open a file"));
+ gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button),
+ _("Open a recently used file"));
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "FileOpen");
+ g_object_set (action,
+ "is_important", TRUE,
+ "short_label", _("Open"),
+ NULL);
+ gtk_activatable_set_related_action (GTK_ACTIVATABLE (open_button),
+ action);
+
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar),
+ open_button,
+ 1);
+
+ return toolbar_recent_menu;
+}
+
+static void
+create_menu_bar_and_toolbar (PlumaWindow *window,
+ GtkWidget *main_box)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GtkUIManager *manager;
+ GtkRecentManager *recent_manager;
+ GError *error = NULL;
+ gchar *ui_file;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ manager = gtk_ui_manager_new ();
+ window->priv->manager = manager;
+
+ gtk_window_add_accel_group (GTK_WINDOW (window),
+ gtk_ui_manager_get_accel_group (manager));
+
+ action_group = gtk_action_group_new ("PlumaWindowAlwaysSensitiveActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group,
+ pluma_always_sensitive_menu_entries,
+ G_N_ELEMENTS (pluma_always_sensitive_menu_entries),
+ window);
+ gtk_action_group_add_toggle_actions (action_group,
+ pluma_always_sensitive_toggle_menu_entries,
+ G_N_ELEMENTS (pluma_always_sensitive_toggle_menu_entries),
+ window);
+
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+ window->priv->always_sensitive_action_group = action_group;
+
+ action_group = gtk_action_group_new ("PlumaWindowActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group,
+ pluma_menu_entries,
+ G_N_ELEMENTS (pluma_menu_entries),
+ window);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+ window->priv->action_group = action_group;
+
+ /* set short labels to use in the toolbar */
+ action = gtk_action_group_get_action (action_group, "FileSave");
+ g_object_set (action, "short_label", _("Save"), NULL);
+ action = gtk_action_group_get_action (action_group, "FilePrint");
+ g_object_set (action, "short_label", _("Print"), NULL);
+ action = gtk_action_group_get_action (action_group, "SearchFind");
+ g_object_set (action, "short_label", _("Find"), NULL);
+ action = gtk_action_group_get_action (action_group, "SearchReplace");
+ g_object_set (action, "short_label", _("Replace"), NULL);
+
+ /* set which actions should have priority on the toolbar */
+ action = gtk_action_group_get_action (action_group, "FileSave");
+ g_object_set (action, "is_important", TRUE, NULL);
+ action = gtk_action_group_get_action (action_group, "EditUndo");
+ g_object_set (action, "is_important", TRUE, NULL);
+
+ action_group = gtk_action_group_new ("PlumaQuitWindowActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group,
+ pluma_quit_menu_entries,
+ G_N_ELEMENTS (pluma_quit_menu_entries),
+ window);
+
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+ window->priv->quit_action_group = action_group;
+
+ action_group = gtk_action_group_new ("PlumaCloseWindowActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group,
+ pluma_close_menu_entries,
+ G_N_ELEMENTS (pluma_close_menu_entries),
+ window);
+
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+ window->priv->close_action_group = action_group;
+
+ action_group = gtk_action_group_new ("PlumaWindowPanesActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_toggle_actions (action_group,
+ pluma_panes_toggle_menu_entries,
+ G_N_ELEMENTS (pluma_panes_toggle_menu_entries),
+ window);
+
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+ window->priv->panes_action_group = action_group;
+
+ /* now load the UI definition */
+ ui_file = pluma_dirs_get_ui_file (PLUMA_UIFILE);
+ gtk_ui_manager_add_ui_from_file (manager, ui_file, &error);
+ if (error != NULL)
+ {
+ g_warning ("Could not merge %s: %s", ui_file, error->message);
+ g_error_free (error);
+ }
+ g_free (ui_file);
+
+#if !GTK_CHECK_VERSION (2, 17, 4)
+ /* merge page setup menu manually since we cannot have conditional
+ * sections in pluma-ui.xml */
+ {
+ guint merge_id;
+ PlumaLockdownMask lockdown;
+
+ merge_id = gtk_ui_manager_new_merge_id (manager);
+ gtk_ui_manager_add_ui (manager,
+ merge_id,
+ "/MenuBar/FileMenu/FileOps_5",
+ "FilePageSetupMenu",
+ "FilePageSetup",
+ GTK_UI_MANAGER_MENUITEM,
+ FALSE);
+
+ lockdown = pluma_app_get_lockdown (pluma_app_get_default ());
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FilePageSetup");
+ gtk_action_set_sensitive (action,
+ !(lockdown & PLUMA_LOCKDOWN_PRINT_SETUP));
+ }
+#endif
+
+ /* show tooltips in the statusbar */
+ g_signal_connect (manager,
+ "connect_proxy",
+ G_CALLBACK (connect_proxy_cb),
+ window);
+ g_signal_connect (manager,
+ "disconnect_proxy",
+ G_CALLBACK (disconnect_proxy_cb),
+ window);
+
+ /* recent files menu */
+ action_group = gtk_action_group_new ("RecentFilesActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ window->priv->recents_action_group = action_group;
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+
+ recent_manager = gtk_recent_manager_get_default ();
+ window->priv->recents_handler_id = g_signal_connect (recent_manager,
+ "changed",
+ G_CALLBACK (recent_manager_changed),
+ window);
+ update_recent_files_menu (window);
+
+ /* languages menu */
+ action_group = gtk_action_group_new ("LanguagesActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ window->priv->languages_action_group = action_group;
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+ create_languages_menu (window);
+
+ /* list of open documents menu */
+ action_group = gtk_action_group_new ("DocumentsListActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ window->priv->documents_list_action_group = action_group;
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+
+ window->priv->menubar = gtk_ui_manager_get_widget (manager, "/MenuBar");
+ gtk_box_pack_start (GTK_BOX (main_box),
+ window->priv->menubar,
+ FALSE,
+ FALSE,
+ 0);
+
+ window->priv->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar");
+ gtk_box_pack_start (GTK_BOX (main_box),
+ window->priv->toolbar,
+ FALSE,
+ FALSE,
+ 0);
+
+ set_toolbar_style (window, NULL);
+
+ window->priv->toolbar_recent_menu = setup_toolbar_open_button (window,
+ window->priv->toolbar);
+
+ gtk_container_foreach (GTK_CONTAINER (window->priv->toolbar),
+ (GtkCallback)set_non_homogeneus,
+ NULL);
+
+ g_signal_connect_after (G_OBJECT (window->priv->toolbar),
+ "show",
+ G_CALLBACK (toolbar_visibility_changed),
+ window);
+ g_signal_connect_after (G_OBJECT (window->priv->toolbar),
+ "hide",
+ G_CALLBACK (toolbar_visibility_changed),
+ window);
+}
+
+static void
+documents_list_menu_activate (GtkToggleAction *action,
+ PlumaWindow *window)
+{
+ gint n;
+
+ if (gtk_toggle_action_get_active (action) == FALSE)
+ return;
+
+ n = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (window->priv->notebook), n);
+}
+
+static gchar *
+get_menu_tip_for_tab (PlumaTab *tab)
+{
+ PlumaDocument *doc;
+ gchar *uri;
+ gchar *ruri;
+ gchar *tip;
+
+ doc = pluma_tab_get_document (tab);
+
+ uri = pluma_document_get_uri_for_display (doc);
+ ruri = pluma_utils_replace_home_dir_with_tilde (uri);
+ g_free (uri);
+
+ /* Translators: %s is a URI */
+ tip = g_strdup_printf (_("Activate '%s'"), ruri);
+ g_free (ruri);
+
+ return tip;
+}
+
+static void
+update_documents_list_menu (PlumaWindow *window)
+{
+ PlumaWindowPrivate *p = window->priv;
+ GList *actions, *l;
+ gint n, i;
+ guint id;
+ GSList *group = NULL;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ g_return_if_fail (p->documents_list_action_group != NULL);
+
+ if (p->documents_list_menu_ui_id != 0)
+ gtk_ui_manager_remove_ui (p->manager,
+ p->documents_list_menu_ui_id);
+
+ actions = gtk_action_group_list_actions (p->documents_list_action_group);
+ for (l = actions; l != NULL; l = l->next)
+ {
+ g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
+ G_CALLBACK (documents_list_menu_activate),
+ window);
+ gtk_action_group_remove_action (p->documents_list_action_group,
+ GTK_ACTION (l->data));
+ }
+ g_list_free (actions);
+
+ n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (p->notebook));
+
+ id = (n > 0) ? gtk_ui_manager_new_merge_id (p->manager) : 0;
+
+ for (i = 0; i < n; i++)
+ {
+ GtkWidget *tab;
+ GtkRadioAction *action;
+ gchar *action_name;
+ gchar *tab_name;
+ gchar *name;
+ gchar *tip;
+ gchar *accel;
+
+ tab = gtk_notebook_get_nth_page (GTK_NOTEBOOK (p->notebook), i);
+
+ /* NOTE: the action is associated to the position of the tab in
+ * the notebook not to the tab itself! This is needed to work
+ * around the gtk+ bug #170727: gtk leaves around the accels
+ * of the action. Since the accel depends on the tab position
+ * the problem is worked around, action with the same name always
+ * get the same accel.
+ */
+ action_name = g_strdup_printf ("Tab_%d", i);
+ tab_name = _pluma_tab_get_name (PLUMA_TAB (tab));
+ name = pluma_utils_escape_underscores (tab_name, -1);
+ tip = get_menu_tip_for_tab (PLUMA_TAB (tab));
+
+ /* alt + 1, 2, 3... 0 to switch to the first ten tabs */
+ accel = (i < 10) ? g_strdup_printf ("<alt>%d", (i + 1) % 10) : NULL;
+
+ action = gtk_radio_action_new (action_name,
+ name,
+ tip,
+ NULL,
+ i);
+
+ if (group != NULL)
+ gtk_radio_action_set_group (action, group);
+
+ /* note that group changes each time we add an action, so it must be updated */
+ group = gtk_radio_action_get_group (action);
+
+ gtk_action_group_add_action_with_accel (p->documents_list_action_group,
+ GTK_ACTION (action),
+ accel);
+
+ g_signal_connect (action,
+ "activate",
+ G_CALLBACK (documents_list_menu_activate),
+ window);
+
+ gtk_ui_manager_add_ui (p->manager,
+ id,
+ "/MenuBar/DocumentsMenu/DocumentsListPlaceholder",
+ action_name, action_name,
+ GTK_UI_MANAGER_MENUITEM,
+ FALSE);
+
+ if (PLUMA_TAB (tab) == p->active_tab)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+ g_object_unref (action);
+
+ g_free (action_name);
+ g_free (tab_name);
+ g_free (name);
+ g_free (tip);
+ g_free (accel);
+ }
+
+ p->documents_list_menu_ui_id = id;
+}
+
+/* Returns TRUE if status bar is visible */
+static gboolean
+set_statusbar_style (PlumaWindow *window,
+ PlumaWindow *origin)
+{
+ GtkAction *action;
+
+ gboolean visible;
+
+ if (origin == NULL)
+ visible = pluma_prefs_manager_get_statusbar_visible ();
+ else
+ visible = GTK_WIDGET_VISIBLE (origin->priv->statusbar);
+
+ if (visible)
+ gtk_widget_show (window->priv->statusbar);
+ else
+ gtk_widget_hide (window->priv->statusbar);
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "ViewStatusbar");
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+
+ return visible;
+}
+
+static void
+statusbar_visibility_changed (GtkWidget *statusbar,
+ PlumaWindow *window)
+{
+ gboolean visible;
+ GtkAction *action;
+
+ visible = GTK_WIDGET_VISIBLE (statusbar);
+
+ if (pluma_prefs_manager_statusbar_visible_can_set ())
+ pluma_prefs_manager_set_statusbar_visible (visible);
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "ViewStatusbar");
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+}
+
+static void
+tab_width_combo_changed (PlumaStatusComboBox *combo,
+ GtkMenuItem *item,
+ PlumaWindow *window)
+{
+ PlumaView *view;
+ guint width_data = 0;
+
+ view = pluma_window_get_active_view (window);
+
+ if (!view)
+ return;
+
+ width_data = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), TAB_WIDTH_DATA));
+
+ if (width_data == 0)
+ return;
+
+ g_signal_handler_block (view, window->priv->tab_width_id);
+ gtk_source_view_set_tab_width (GTK_SOURCE_VIEW (view), width_data);
+ g_signal_handler_unblock (view, window->priv->tab_width_id);
+}
+
+static void
+use_spaces_toggled (GtkCheckMenuItem *item,
+ PlumaWindow *window)
+{
+ PlumaView *view;
+
+ view = pluma_window_get_active_view (window);
+
+ g_signal_handler_block (view, window->priv->spaces_instead_of_tabs_id);
+ gtk_source_view_set_insert_spaces_instead_of_tabs (
+ GTK_SOURCE_VIEW (view),
+ gtk_check_menu_item_get_active (item));
+ g_signal_handler_unblock (view, window->priv->spaces_instead_of_tabs_id);
+}
+
+static void
+language_combo_changed (PlumaStatusComboBox *combo,
+ GtkMenuItem *item,
+ PlumaWindow *window)
+{
+ PlumaDocument *doc;
+ GtkSourceLanguage *language;
+
+ doc = pluma_window_get_active_document (window);
+
+ if (!doc)
+ return;
+
+ language = GTK_SOURCE_LANGUAGE (g_object_get_data (G_OBJECT (item), LANGUAGE_DATA));
+
+ g_signal_handler_block (doc, window->priv->language_changed_id);
+ pluma_document_set_language (doc, language);
+ g_signal_handler_unblock (doc, window->priv->language_changed_id);
+}
+
+typedef struct
+{
+ const gchar *label;
+ guint width;
+} TabWidthDefinition;
+
+static void
+fill_tab_width_combo (PlumaWindow *window)
+{
+ static TabWidthDefinition defs[] = {
+ {"2", 2},
+ {"4", 4},
+ {"8", 8},
+ {"", 0}, /* custom size */
+ {NULL, 0}
+ };
+
+ PlumaStatusComboBox *combo = PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo);
+ guint i = 0;
+ GtkWidget *item;
+
+ while (defs[i].label != NULL)
+ {
+ item = gtk_menu_item_new_with_label (defs[i].label);
+ g_object_set_data (G_OBJECT (item), TAB_WIDTH_DATA, GINT_TO_POINTER (defs[i].width));
+
+ pluma_status_combo_box_add_item (combo,
+ GTK_MENU_ITEM (item),
+ defs[i].label);
+
+ if (defs[i].width != 0)
+ gtk_widget_show (item);
+
+ ++i;
+ }
+
+ item = gtk_separator_menu_item_new ();
+ pluma_status_combo_box_add_item (combo, GTK_MENU_ITEM (item), NULL);
+ gtk_widget_show (item);
+
+ item = gtk_check_menu_item_new_with_label (_("Use Spaces"));
+ pluma_status_combo_box_add_item (combo, GTK_MENU_ITEM (item), NULL);
+ gtk_widget_show (item);
+
+ g_signal_connect (item,
+ "toggled",
+ G_CALLBACK (use_spaces_toggled),
+ window);
+}
+
+static void
+fill_language_combo (PlumaWindow *window)
+{
+ GtkSourceLanguageManager *manager;
+ GSList *languages;
+ GSList *item;
+ GtkWidget *menu_item;
+ const gchar *name;
+
+ manager = pluma_get_language_manager ();
+ languages = pluma_language_manager_list_languages_sorted (manager, FALSE);
+
+ name = _("Plain Text");
+ menu_item = gtk_menu_item_new_with_label (name);
+ gtk_widget_show (menu_item);
+
+ g_object_set_data (G_OBJECT (menu_item), LANGUAGE_DATA, NULL);
+ pluma_status_combo_box_add_item (PLUMA_STATUS_COMBO_BOX (window->priv->language_combo),
+ GTK_MENU_ITEM (menu_item),
+ name);
+
+ for (item = languages; item; item = item->next)
+ {
+ GtkSourceLanguage *lang = GTK_SOURCE_LANGUAGE (item->data);
+
+ name = gtk_source_language_get_name (lang);
+ menu_item = gtk_menu_item_new_with_label (name);
+ gtk_widget_show (menu_item);
+
+ g_object_set_data_full (G_OBJECT (menu_item),
+ LANGUAGE_DATA,
+ g_object_ref (lang),
+ (GDestroyNotify)g_object_unref);
+
+ pluma_status_combo_box_add_item (PLUMA_STATUS_COMBO_BOX (window->priv->language_combo),
+ GTK_MENU_ITEM (menu_item),
+ name);
+ }
+
+ g_slist_free (languages);
+}
+
+static void
+create_statusbar (PlumaWindow *window,
+ GtkWidget *main_box)
+{
+ pluma_debug (DEBUG_WINDOW);
+
+ window->priv->statusbar = pluma_statusbar_new ();
+
+ window->priv->generic_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (window->priv->statusbar), "generic_message");
+ window->priv->tip_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (window->priv->statusbar), "tip_message");
+
+ gtk_box_pack_end (GTK_BOX (main_box),
+ window->priv->statusbar,
+ FALSE,
+ TRUE,
+ 0);
+
+ window->priv->tab_width_combo = pluma_status_combo_box_new (_("Tab Width"));
+ gtk_widget_show (window->priv->tab_width_combo);
+ gtk_box_pack_end (GTK_BOX (window->priv->statusbar),
+ window->priv->tab_width_combo,
+ FALSE,
+ TRUE,
+ 0);
+
+ fill_tab_width_combo (window);
+
+ g_signal_connect (G_OBJECT (window->priv->tab_width_combo),
+ "changed",
+ G_CALLBACK (tab_width_combo_changed),
+ window);
+
+ window->priv->language_combo = pluma_status_combo_box_new (NULL);
+ gtk_widget_show (window->priv->language_combo);
+ gtk_box_pack_end (GTK_BOX (window->priv->statusbar),
+ window->priv->language_combo,
+ FALSE,
+ TRUE,
+ 0);
+
+ fill_language_combo (window);
+
+ g_signal_connect (G_OBJECT (window->priv->language_combo),
+ "changed",
+ G_CALLBACK (language_combo_changed),
+ window);
+
+ g_signal_connect_after (G_OBJECT (window->priv->statusbar),
+ "show",
+ G_CALLBACK (statusbar_visibility_changed),
+ window);
+ g_signal_connect_after (G_OBJECT (window->priv->statusbar),
+ "hide",
+ G_CALLBACK (statusbar_visibility_changed),
+ window);
+
+ set_statusbar_style (window, NULL);
+}
+
+static PlumaWindow *
+clone_window (PlumaWindow *origin)
+{
+ PlumaWindow *window;
+ GdkScreen *screen;
+ PlumaApp *app;
+ gint panel_page;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ app = pluma_app_get_default ();
+
+ screen = gtk_window_get_screen (GTK_WINDOW (origin));
+ window = pluma_app_create_window (app, screen);
+
+ if ((origin->priv->window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0)
+ {
+ gint w, h;
+
+ pluma_prefs_manager_get_default_window_size (&w, &h);
+ gtk_window_set_default_size (GTK_WINDOW (window), w, h);
+ gtk_window_maximize (GTK_WINDOW (window));
+ }
+ else
+ {
+ gtk_window_set_default_size (GTK_WINDOW (window),
+ origin->priv->width,
+ origin->priv->height);
+
+ gtk_window_unmaximize (GTK_WINDOW (window));
+ }
+
+ if ((origin->priv->window_state & GDK_WINDOW_STATE_STICKY ) != 0)
+ gtk_window_stick (GTK_WINDOW (window));
+ else
+ gtk_window_unstick (GTK_WINDOW (window));
+
+ /* set the panes size, the paned position will be set when
+ * they are mapped */
+ window->priv->side_panel_size = origin->priv->side_panel_size;
+ window->priv->bottom_panel_size = origin->priv->bottom_panel_size;
+
+ panel_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (origin->priv->side_panel));
+ _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->side_panel),
+ panel_page);
+
+ panel_page = _pluma_panel_get_active_item_id (PLUMA_PANEL (origin->priv->bottom_panel));
+ _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->bottom_panel),
+ panel_page);
+
+ if (GTK_WIDGET_VISIBLE (origin->priv->side_panel))
+ gtk_widget_show (window->priv->side_panel);
+ else
+ gtk_widget_hide (window->priv->side_panel);
+
+ if (GTK_WIDGET_VISIBLE (origin->priv->bottom_panel))
+ gtk_widget_show (window->priv->bottom_panel);
+ else
+ gtk_widget_hide (window->priv->bottom_panel);
+
+ set_statusbar_style (window, origin);
+ set_toolbar_style (window, origin);
+
+ return window;
+}
+
+static void
+update_cursor_position_statusbar (GtkTextBuffer *buffer,
+ PlumaWindow *window)
+{
+ gint row, col;
+ GtkTextIter iter;
+ GtkTextIter start;
+ guint tab_size;
+ PlumaView *view;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ if (buffer != GTK_TEXT_BUFFER (pluma_window_get_active_document (window)))
+ return;
+
+ view = pluma_window_get_active_view (window);
+
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &iter,
+ gtk_text_buffer_get_insert (buffer));
+
+ row = gtk_text_iter_get_line (&iter);
+
+ start = iter;
+ gtk_text_iter_set_line_offset (&start, 0);
+ col = 0;
+
+ tab_size = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+
+ while (!gtk_text_iter_equal (&start, &iter))
+ {
+ /* FIXME: Are we Unicode compliant here? */
+ if (gtk_text_iter_get_char (&start) == '\t')
+
+ col += (tab_size - (col % tab_size));
+ else
+ ++col;
+
+ gtk_text_iter_forward_char (&start);
+ }
+
+ pluma_statusbar_set_cursor_position (
+ PLUMA_STATUSBAR (window->priv->statusbar),
+ row + 1,
+ col + 1);
+}
+
+static void
+update_overwrite_mode_statusbar (GtkTextView *view,
+ PlumaWindow *window)
+{
+ if (view != GTK_TEXT_VIEW (pluma_window_get_active_view (window)))
+ return;
+
+ /* Note that we have to use !gtk_text_view_get_overwrite since we
+ are in the in the signal handler of "toggle overwrite" that is
+ G_SIGNAL_RUN_LAST
+ */
+ pluma_statusbar_set_overwrite (
+ PLUMA_STATUSBAR (window->priv->statusbar),
+ !gtk_text_view_get_overwrite (view));
+}
+
+#define MAX_TITLE_LENGTH 100
+
+static void
+set_title (PlumaWindow *window)
+{
+ PlumaDocument *doc = NULL;
+ gchar *name;
+ gchar *dirname = NULL;
+ gchar *title = NULL;
+ gint len;
+
+ if (window->priv->active_tab == NULL)
+ {
+#ifdef OS_OSX
+ pluma_osx_set_window_title (window, "pluma", NULL);
+#else
+ gtk_window_set_title (GTK_WINDOW (window), "pluma");
+#endif
+ return;
+ }
+
+ doc = pluma_tab_get_document (window->priv->active_tab);
+ g_return_if_fail (doc != NULL);
+
+ name = pluma_document_get_short_name_for_display (doc);
+
+ len = g_utf8_strlen (name, -1);
+
+ /* if the name is awfully long, truncate it and be done with it,
+ * otherwise also show the directory (ellipsized if needed)
+ */
+ if (len > MAX_TITLE_LENGTH)
+ {
+ gchar *tmp;
+
+ tmp = pluma_utils_str_middle_truncate (name,
+ MAX_TITLE_LENGTH);
+ g_free (name);
+ name = tmp;
+ }
+ else
+ {
+ GFile *file;
+
+ file = pluma_document_get_location (doc);
+ if (file != NULL)
+ {
+ gchar *str;
+
+ str = pluma_utils_location_get_dirname_for_display (file);
+ g_object_unref (file);
+
+ /* use the remaining space for the dir, but use a min of 20 chars
+ * so that we do not end up with a dirname like "(a...b)".
+ * This means that in the worst case when the filename is long 99
+ * we have a title long 99 + 20, but I think it's a rare enough
+ * case to be acceptable. It's justa darn title afterall :)
+ */
+ dirname = pluma_utils_str_middle_truncate (str,
+ MAX (20, MAX_TITLE_LENGTH - len));
+ g_free (str);
+ }
+ }
+
+ if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
+ {
+ gchar *tmp_name;
+
+ tmp_name = g_strdup_printf ("*%s", name);
+ g_free (name);
+
+ name = tmp_name;
+ }
+
+ if (pluma_document_get_readonly (doc))
+ {
+ if (dirname != NULL)
+ title = g_strdup_printf ("%s [%s] (%s) - pluma",
+ name,
+ _("Read-Only"),
+ dirname);
+ else
+ title = g_strdup_printf ("%s [%s] - pluma",
+ name,
+ _("Read-Only"));
+ }
+ else
+ {
+ if (dirname != NULL)
+ title = g_strdup_printf ("%s (%s) - pluma",
+ name,
+ dirname);
+ else
+ title = g_strdup_printf ("%s - pluma",
+ name);
+ }
+
+#ifdef OS_OSX
+ pluma_osx_set_window_title (window, title, doc);
+#else
+ gtk_window_set_title (GTK_WINDOW (window), title);
+#endif
+
+ g_free (dirname);
+ g_free (name);
+ g_free (title);
+}
+
+#undef MAX_TITLE_LENGTH
+
+static void
+set_tab_width_item_blocked (PlumaWindow *window,
+ GtkMenuItem *item)
+{
+ g_signal_handlers_block_by_func (window->priv->tab_width_combo,
+ tab_width_combo_changed,
+ window);
+
+ pluma_status_combo_box_set_item (PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo),
+ item);
+
+ g_signal_handlers_unblock_by_func (window->priv->tab_width_combo,
+ tab_width_combo_changed,
+ window);
+}
+
+static void
+spaces_instead_of_tabs_changed (GObject *object,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ PlumaView *view = PLUMA_VIEW (object);
+ gboolean active = gtk_source_view_get_insert_spaces_instead_of_tabs (
+ GTK_SOURCE_VIEW (view));
+ GList *children = pluma_status_combo_box_get_items (
+ PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo));
+ GtkCheckMenuItem *item;
+
+ item = GTK_CHECK_MENU_ITEM (g_list_last (children)->data);
+
+ gtk_check_menu_item_set_active (item, active);
+
+ g_list_free (children);
+}
+
+static void
+tab_width_changed (GObject *object,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ GList *items;
+ GList *item;
+ PlumaStatusComboBox *combo = PLUMA_STATUS_COMBO_BOX (window->priv->tab_width_combo);
+ guint new_tab_width;
+ gboolean found = FALSE;
+
+ items = pluma_status_combo_box_get_items (combo);
+
+ new_tab_width = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (object));
+
+ for (item = items; item; item = item->next)
+ {
+ guint tab_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item->data), TAB_WIDTH_DATA));
+
+ if (tab_width == new_tab_width)
+ {
+ set_tab_width_item_blocked (window, GTK_MENU_ITEM (item->data));
+ found = TRUE;
+ }
+
+ if (GTK_IS_SEPARATOR_MENU_ITEM (item->next->data))
+ {
+ if (!found)
+ {
+ /* Set for the last item the custom thing */
+ gchar *text;
+
+ text = g_strdup_printf ("%u", new_tab_width);
+ pluma_status_combo_box_set_item_text (combo,
+ GTK_MENU_ITEM (item->data),
+ text);
+
+ gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (item->data))),
+ text);
+
+ set_tab_width_item_blocked (window, GTK_MENU_ITEM (item->data));
+ gtk_widget_show (GTK_WIDGET (item->data));
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET (item->data));
+ }
+
+ break;
+ }
+ }
+
+ g_list_free (items);
+}
+
+static void
+language_changed (GObject *object,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ GList *items;
+ GList *item;
+ PlumaStatusComboBox *combo = PLUMA_STATUS_COMBO_BOX (window->priv->language_combo);
+ GtkSourceLanguage *new_language;
+ const gchar *new_id;
+
+ items = pluma_status_combo_box_get_items (combo);
+
+ new_language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (object));
+
+ if (new_language)
+ new_id = gtk_source_language_get_id (new_language);
+ else
+ new_id = NULL;
+
+ for (item = items; item; item = item->next)
+ {
+ GtkSourceLanguage *lang = g_object_get_data (G_OBJECT (item->data), LANGUAGE_DATA);
+
+ if ((new_id == NULL && lang == NULL) ||
+ (new_id != NULL && lang != NULL && strcmp (gtk_source_language_get_id (lang),
+ new_id) == 0))
+ {
+ g_signal_handlers_block_by_func (window->priv->language_combo,
+ language_combo_changed,
+ window);
+
+ pluma_status_combo_box_set_item (PLUMA_STATUS_COMBO_BOX (window->priv->language_combo),
+ GTK_MENU_ITEM (item->data));
+
+ g_signal_handlers_unblock_by_func (window->priv->language_combo,
+ language_combo_changed,
+ window);
+ }
+ }
+
+ g_list_free (items);
+}
+
+static void
+notebook_switch_page (GtkNotebook *book,
+ GtkNotebookPage *pg,
+ gint page_num,
+ PlumaWindow *window)
+{
+ PlumaView *view;
+ PlumaTab *tab;
+ GtkAction *action;
+ gchar *action_name;
+
+ /* CHECK: I don't know why but it seems notebook_switch_page is called
+ two times every time the user change the active tab */
+
+ tab = PLUMA_TAB (gtk_notebook_get_nth_page (book, page_num));
+ if (tab == window->priv->active_tab)
+ return;
+
+ if (window->priv->active_tab)
+ {
+ if (window->priv->tab_width_id)
+ {
+ g_signal_handler_disconnect (pluma_tab_get_view (window->priv->active_tab),
+ window->priv->tab_width_id);
+
+ window->priv->tab_width_id = 0;
+ }
+
+ if (window->priv->spaces_instead_of_tabs_id)
+ {
+ g_signal_handler_disconnect (pluma_tab_get_view (window->priv->active_tab),
+ window->priv->spaces_instead_of_tabs_id);
+
+ window->priv->spaces_instead_of_tabs_id = 0;
+ }
+ }
+
+ /* set the active tab */
+ window->priv->active_tab = tab;
+
+ set_title (window);
+ set_sensitivity_according_to_tab (window, tab);
+
+ /* activate the right item in the documents menu */
+ action_name = g_strdup_printf ("Tab_%d", page_num);
+ action = gtk_action_group_get_action (window->priv->documents_list_action_group,
+ action_name);
+
+ /* sometimes the action doesn't exist yet, and the proper action
+ * is set active during the documents list menu creation
+ * CHECK: would it be nicer if active_tab was a property and we monitored the notify signal?
+ */
+ if (action != NULL)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+ g_free (action_name);
+
+ /* update the syntax menu */
+ update_languages_menu (window);
+
+ view = pluma_tab_get_view (tab);
+
+ /* sync the statusbar */
+ update_cursor_position_statusbar (GTK_TEXT_BUFFER (pluma_tab_get_document (tab)),
+ window);
+ pluma_statusbar_set_overwrite (PLUMA_STATUSBAR (window->priv->statusbar),
+ gtk_text_view_get_overwrite (GTK_TEXT_VIEW (view)));
+
+ gtk_widget_show (window->priv->tab_width_combo);
+ gtk_widget_show (window->priv->language_combo);
+
+ window->priv->tab_width_id = g_signal_connect (view,
+ "notify::tab-width",
+ G_CALLBACK (tab_width_changed),
+ window);
+ window->priv->spaces_instead_of_tabs_id = g_signal_connect (view,
+ "notify::insert-spaces-instead-of-tabs",
+ G_CALLBACK (spaces_instead_of_tabs_changed),
+ window);
+
+ window->priv->language_changed_id = g_signal_connect (pluma_tab_get_document (tab),
+ "notify::language",
+ G_CALLBACK (language_changed),
+ window);
+
+ /* call it for the first time */
+ tab_width_changed (G_OBJECT (view), NULL, window);
+ spaces_instead_of_tabs_changed (G_OBJECT (view), NULL, window);
+ language_changed (G_OBJECT (pluma_tab_get_document (tab)), NULL, window);
+
+ g_signal_emit (G_OBJECT (window),
+ signals[ACTIVE_TAB_CHANGED],
+ 0,
+ window->priv->active_tab);
+}
+
+static void
+set_sensitivity_according_to_window_state (PlumaWindow *window)
+{
+ GtkAction *action;
+ PlumaLockdownMask lockdown;
+
+ lockdown = pluma_app_get_lockdown (pluma_app_get_default ());
+
+ /* We disable File->Quit/SaveAll/CloseAll while printing to avoid to have two
+ operations (save and print/print preview) that uses the message area at
+ the same time (may be we can remove this limitation in the future) */
+ /* We disable File->Quit/CloseAll if state is saving since saving cannot be
+ cancelled (may be we can remove this limitation in the future) */
+ gtk_action_group_set_sensitive (window->priv->quit_action_group,
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
+ !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileCloseAll");
+ gtk_action_set_sensitive (action,
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
+ !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileSaveAll");
+ gtk_action_set_sensitive (action,
+ !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING) &&
+ !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "FileNew");
+ gtk_action_set_sensitive (action,
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "FileOpen");
+ gtk_action_set_sensitive (action,
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ gtk_action_group_set_sensitive (window->priv->recents_action_group,
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ pluma_notebook_set_close_buttons_sensitive (PLUMA_NOTEBOOK (window->priv->notebook),
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ pluma_notebook_set_tab_drag_and_drop_enabled (PLUMA_NOTEBOOK (window->priv->notebook),
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ if ((window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) != 0)
+ {
+ /* TODO: If we really care, Find could be active
+ * when in SAVING_SESSION state */
+
+ if (gtk_action_group_get_sensitive (window->priv->action_group))
+ gtk_action_group_set_sensitive (window->priv->action_group,
+ FALSE);
+ if (gtk_action_group_get_sensitive (window->priv->quit_action_group))
+ gtk_action_group_set_sensitive (window->priv->quit_action_group,
+ FALSE);
+ if (gtk_action_group_get_sensitive (window->priv->close_action_group))
+ gtk_action_group_set_sensitive (window->priv->close_action_group,
+ FALSE);
+ }
+ else
+ {
+ if (!gtk_action_group_get_sensitive (window->priv->action_group))
+ gtk_action_group_set_sensitive (window->priv->action_group,
+ window->priv->num_tabs > 0);
+ if (!gtk_action_group_get_sensitive (window->priv->quit_action_group))
+ gtk_action_group_set_sensitive (window->priv->quit_action_group,
+ window->priv->num_tabs > 0);
+ if (!gtk_action_group_get_sensitive (window->priv->close_action_group))
+ {
+#ifdef OS_OSX
+ /* On OS X, File Close is always sensitive */
+ gtk_action_group_set_sensitive (window->priv->close_action_group,
+ TRUE);
+#else
+ gtk_action_group_set_sensitive (window->priv->close_action_group,
+ window->priv->num_tabs > 0);
+#endif
+ }
+ }
+}
+
+static void
+update_tab_autosave (GtkWidget *widget,
+ gpointer data)
+{
+ PlumaTab *tab = PLUMA_TAB (widget);
+ gboolean *enabled = (gboolean *) data;
+
+ pluma_tab_set_auto_save_enabled (tab, *enabled);
+}
+
+void
+_pluma_window_set_lockdown (PlumaWindow *window,
+ PlumaLockdownMask lockdown)
+{
+ PlumaTab *tab;
+ GtkAction *action;
+ gboolean autosave;
+
+ /* start/stop autosave in each existing tab */
+ autosave = pluma_prefs_manager_get_auto_save ();
+ gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
+ update_tab_autosave,
+ &autosave);
+
+ /* update menues wrt the current active tab */
+ tab = pluma_window_get_active_tab (window);
+
+ set_sensitivity_according_to_tab (window, tab);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileSaveAll");
+ gtk_action_set_sensitive (action,
+ !(window->priv->state & PLUMA_WINDOW_STATE_PRINTING) &&
+ !(lockdown & PLUMA_LOCKDOWN_SAVE_TO_DISK));
+
+#if !GTK_CHECK_VERSION (2, 17, 4)
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FilePageSetup");
+ gtk_action_set_sensitive (action,
+ !(lockdown & PLUMA_LOCKDOWN_PRINT_SETUP));
+#endif
+}
+
+static void
+analyze_tab_state (PlumaTab *tab,
+ PlumaWindow *window)
+{
+ PlumaTabState ts;
+
+ ts = pluma_tab_get_state (tab);
+
+ switch (ts)
+ {
+ case PLUMA_TAB_STATE_LOADING:
+ case PLUMA_TAB_STATE_REVERTING:
+ window->priv->state |= PLUMA_WINDOW_STATE_LOADING;
+ break;
+
+ case PLUMA_TAB_STATE_SAVING:
+ window->priv->state |= PLUMA_WINDOW_STATE_SAVING;
+ break;
+
+ case PLUMA_TAB_STATE_PRINTING:
+ case PLUMA_TAB_STATE_PRINT_PREVIEWING:
+ window->priv->state |= PLUMA_WINDOW_STATE_PRINTING;
+ break;
+
+ case PLUMA_TAB_STATE_LOADING_ERROR:
+ case PLUMA_TAB_STATE_REVERTING_ERROR:
+ case PLUMA_TAB_STATE_SAVING_ERROR:
+ case PLUMA_TAB_STATE_GENERIC_ERROR:
+ window->priv->state |= PLUMA_WINDOW_STATE_ERROR;
+ ++window->priv->num_tabs_with_error;
+ default:
+ /* NOP */
+ break;
+ }
+}
+
+static void
+update_window_state (PlumaWindow *window)
+{
+ PlumaWindowState old_ws;
+ gint old_num_of_errors;
+
+ pluma_debug_message (DEBUG_WINDOW, "Old state: %x", window->priv->state);
+
+ old_ws = window->priv->state;
+ old_num_of_errors = window->priv->num_tabs_with_error;
+
+ window->priv->state = old_ws & PLUMA_WINDOW_STATE_SAVING_SESSION;
+
+ window->priv->num_tabs_with_error = 0;
+
+ gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
+ (GtkCallback)analyze_tab_state,
+ window);
+
+ pluma_debug_message (DEBUG_WINDOW, "New state: %x", window->priv->state);
+
+ if (old_ws != window->priv->state)
+ {
+ set_sensitivity_according_to_window_state (window);
+
+ pluma_statusbar_set_window_state (PLUMA_STATUSBAR (window->priv->statusbar),
+ window->priv->state,
+ window->priv->num_tabs_with_error);
+
+ g_object_notify (G_OBJECT (window), "state");
+ }
+ else if (old_num_of_errors != window->priv->num_tabs_with_error)
+ {
+ pluma_statusbar_set_window_state (PLUMA_STATUSBAR (window->priv->statusbar),
+ window->priv->state,
+ window->priv->num_tabs_with_error);
+ }
+}
+
+static void
+sync_state (PlumaTab *tab,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ pluma_debug (DEBUG_WINDOW);
+
+ update_window_state (window);
+
+ if (tab != window->priv->active_tab)
+ return;
+
+ set_sensitivity_according_to_tab (window, tab);
+
+ g_signal_emit (G_OBJECT (window), signals[ACTIVE_TAB_STATE_CHANGED], 0);
+}
+
+static void
+sync_name (PlumaTab *tab,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ GtkAction *action;
+ gchar *action_name;
+ gchar *tab_name;
+ gchar *escaped_name;
+ gchar *tip;
+ gint n;
+ PlumaDocument *doc;
+
+ if (tab == window->priv->active_tab)
+ {
+ set_title (window);
+
+ doc = pluma_tab_get_document (tab);
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "FileRevert");
+ gtk_action_set_sensitive (action,
+ !pluma_document_is_untitled (doc));
+ }
+
+ /* sync the item in the documents list menu */
+ n = gtk_notebook_page_num (GTK_NOTEBOOK (window->priv->notebook),
+ GTK_WIDGET (tab));
+ action_name = g_strdup_printf ("Tab_%d", n);
+ action = gtk_action_group_get_action (window->priv->documents_list_action_group,
+ action_name);
+ g_return_if_fail (action != NULL);
+
+ tab_name = _pluma_tab_get_name (tab);
+ escaped_name = pluma_utils_escape_underscores (tab_name, -1);
+ tip = get_menu_tip_for_tab (tab);
+
+ g_object_set (action, "label", escaped_name, NULL);
+ g_object_set (action, "tooltip", tip, NULL);
+
+ g_free (action_name);
+ g_free (tab_name);
+ g_free (escaped_name);
+ g_free (tip);
+
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+}
+
+static PlumaWindow *
+get_drop_window (GtkWidget *widget)
+{
+ GtkWidget *target_window;
+
+ target_window = gtk_widget_get_toplevel (widget);
+ g_return_val_if_fail (PLUMA_IS_WINDOW (target_window), NULL);
+
+ if ((PLUMA_WINDOW(target_window)->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) != 0)
+ return NULL;
+
+ return PLUMA_WINDOW (target_window);
+}
+
+static void
+load_uris_from_drop (PlumaWindow *window,
+ gchar **uri_list)
+{
+ GSList *uris = NULL;
+ gint i;
+
+ if (uri_list == NULL)
+ return;
+
+ for (i = 0; uri_list[i] != NULL; ++i)
+ {
+ uris = g_slist_prepend (uris, uri_list[i]);
+ }
+
+ uris = g_slist_reverse (uris);
+ pluma_commands_load_uris (window,
+ uris,
+ NULL,
+ 0);
+
+ g_slist_free (uris);
+}
+
+/* Handle drops on the PlumaWindow */
+static void
+drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint timestamp,
+ gpointer data)
+{
+ PlumaWindow *window;
+ gchar **uri_list;
+
+ window = get_drop_window (widget);
+
+ if (window == NULL)
+ return;
+
+ if (info == TARGET_URI_LIST)
+ {
+ uri_list = pluma_utils_drop_get_uris(selection_data);
+ load_uris_from_drop (window, uri_list);
+ g_strfreev (uri_list);
+ }
+}
+
+/* Handle drops on the PlumaView */
+static void
+drop_uris_cb (GtkWidget *widget,
+ gchar **uri_list)
+{
+ PlumaWindow *window;
+
+ window = get_drop_window (widget);
+
+ if (window == NULL)
+ return;
+
+ load_uris_from_drop (window, uri_list);
+}
+
+static void
+fullscreen_controls_show (PlumaWindow *window)
+{
+ GdkScreen *screen;
+ GdkRectangle fs_rect;
+ gint w, h;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (GTK_WIDGET (window))),
+ &fs_rect);
+
+ gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
+
+ gtk_window_resize (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.width, h);
+
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.x, fs_rect.y - h + 1);
+
+ gtk_widget_show_all (window->priv->fullscreen_controls);
+}
+
+static gboolean
+run_fullscreen_animation (gpointer data)
+{
+ PlumaWindow *window = PLUMA_WINDOW (data);
+ GdkScreen *screen;
+ GdkRectangle fs_rect;
+ gint x, y;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (GTK_WIDGET (window))),
+ &fs_rect);
+
+ gtk_window_get_position (GTK_WINDOW (window->priv->fullscreen_controls),
+ &x, &y);
+
+ if (window->priv->fullscreen_animation_enter)
+ {
+ if (y == fs_rect.y)
+ {
+ window->priv->fullscreen_animation_timeout_id = 0;
+ return FALSE;
+ }
+ else
+ {
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ x, y + 1);
+ return TRUE;
+ }
+ }
+ else
+ {
+ gint w, h;
+
+ gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls),
+ &w, &h);
+
+ if (y == fs_rect.y - h + 1)
+ {
+ window->priv->fullscreen_animation_timeout_id = 0;
+ return FALSE;
+ }
+ else
+ {
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ x, y - 1);
+ return TRUE;
+ }
+ }
+}
+
+static void
+show_hide_fullscreen_toolbar (PlumaWindow *window,
+ gboolean show,
+ gint height)
+{
+ GtkSettings *settings;
+ gboolean enable_animations;
+
+ settings = gtk_widget_get_settings (GTK_WIDGET (window));
+ g_object_get (G_OBJECT (settings),
+ "gtk-enable-animations",
+ &enable_animations,
+ NULL);
+
+ if (enable_animations)
+ {
+ window->priv->fullscreen_animation_enter = show;
+
+ if (window->priv->fullscreen_animation_timeout_id == 0)
+ {
+ window->priv->fullscreen_animation_timeout_id =
+ g_timeout_add (FULLSCREEN_ANIMATION_SPEED,
+ (GSourceFunc) run_fullscreen_animation,
+ window);
+ }
+ }
+ else
+ {
+ GdkRectangle fs_rect;
+ GdkScreen *screen;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (GTK_WIDGET (window))),
+ &fs_rect);
+
+ if (show)
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.x, fs_rect.y);
+ else
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.x, fs_rect.y - height + 1);
+ }
+
+}
+
+static gboolean
+on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event,
+ PlumaWindow *window)
+{
+ show_hide_fullscreen_toolbar (window, TRUE, 0);
+
+ return FALSE;
+}
+
+static gboolean
+on_fullscreen_controls_leave_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event,
+ PlumaWindow *window)
+{
+ GdkDisplay *display;
+ GdkScreen *screen;
+ gint w, h;
+ gint x, y;
+
+ display = gdk_display_get_default ();
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+
+ gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
+ gdk_display_get_pointer (display, &screen, &x, &y, NULL);
+
+ /* gtk seems to emit leave notify when clicking on tool items,
+ * work around it by checking the coordinates
+ */
+ if (y >= h)
+ {
+ show_hide_fullscreen_toolbar (window, FALSE, h);
+ }
+
+ return FALSE;
+}
+
+static void
+fullscreen_controls_build (PlumaWindow *window)
+{
+ PlumaWindowPrivate *priv = window->priv;
+ GtkWidget *toolbar;
+ GtkWidget *toolbar_recent_menu;
+ GtkAction *action;
+
+ if (priv->fullscreen_controls != NULL)
+ return;
+
+ priv->fullscreen_controls = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_window_set_transient_for (GTK_WINDOW (priv->fullscreen_controls),
+ &window->window);
+
+ /* popup toolbar */
+ toolbar = gtk_ui_manager_get_widget (priv->manager, "/FullscreenToolBar");
+ gtk_container_add (GTK_CONTAINER (priv->fullscreen_controls),
+ toolbar);
+
+ action = gtk_action_group_get_action (priv->always_sensitive_action_group,
+ "LeaveFullscreen");
+ g_object_set (action, "is-important", TRUE, NULL);
+
+ toolbar_recent_menu = setup_toolbar_open_button (window, toolbar);
+
+ gtk_container_foreach (GTK_CONTAINER (toolbar),
+ (GtkCallback)set_non_homogeneus,
+ NULL);
+
+ /* Set the toolbar style */
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_BOTH_HORIZ);
+
+ g_signal_connect (priv->fullscreen_controls, "enter-notify-event",
+ G_CALLBACK (on_fullscreen_controls_enter_notify_event),
+ window);
+ g_signal_connect (priv->fullscreen_controls, "leave-notify-event",
+ G_CALLBACK (on_fullscreen_controls_leave_notify_event),
+ window);
+}
+
+static void
+can_search_again (PlumaDocument *doc,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ gboolean sensitive;
+ GtkAction *action;
+
+ if (doc != pluma_window_get_active_document (window))
+ return;
+
+ sensitive = pluma_document_get_can_search_again (doc);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchFindNext");
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchFindPrevious");
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "SearchClearHighlight");
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+can_undo (PlumaDocument *doc,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ GtkAction *action;
+ gboolean sensitive;
+
+ sensitive = gtk_source_buffer_can_undo (GTK_SOURCE_BUFFER (doc));
+
+ if (doc != pluma_window_get_active_document (window))
+ return;
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditUndo");
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+can_redo (PlumaDocument *doc,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ GtkAction *action;
+ gboolean sensitive;
+
+ sensitive = gtk_source_buffer_can_redo (GTK_SOURCE_BUFFER (doc));
+
+ if (doc != pluma_window_get_active_document (window))
+ return;
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditRedo");
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+selection_changed (PlumaDocument *doc,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ PlumaTab *tab;
+ PlumaView *view;
+ GtkAction *action;
+ PlumaTabState state;
+ gboolean state_normal;
+ gboolean editable;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ if (doc != pluma_window_get_active_document (window))
+ return;
+
+ tab = pluma_tab_get_from_document (doc);
+ state = pluma_tab_get_state (tab);
+ state_normal = (state == PLUMA_TAB_STATE_NORMAL);
+
+ view = pluma_tab_get_view (tab);
+ editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditCut");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ editable &&
+ gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditCopy");
+ gtk_action_set_sensitive (action,
+ (state_normal ||
+ state == PLUMA_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) &&
+ gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "EditDelete");
+ gtk_action_set_sensitive (action,
+ state_normal &&
+ editable &&
+ gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
+
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+}
+
+static void
+sync_languages_menu (PlumaDocument *doc,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ update_languages_menu (window);
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+}
+
+static void
+readonly_changed (PlumaDocument *doc,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ set_sensitivity_according_to_tab (window, window->priv->active_tab);
+
+ sync_name (window->priv->active_tab, NULL, window);
+
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+}
+
+static void
+editable_changed (PlumaView *view,
+ GParamSpec *arg1,
+ PlumaWindow *window)
+{
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+}
+
+static void
+update_sensitivity_according_to_open_tabs (PlumaWindow *window)
+{
+ GtkAction *action;
+
+ /* Set sensitivity */
+ gtk_action_group_set_sensitive (window->priv->action_group,
+ window->priv->num_tabs != 0);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "DocumentsMoveToNewWindow");
+ gtk_action_set_sensitive (action,
+ window->priv->num_tabs > 1);
+
+ /* Do not set close action insensitive on OS X */
+#ifndef OS_OSX
+ gtk_action_group_set_sensitive (window->priv->close_action_group,
+ window->priv->num_tabs != 0);
+#endif
+}
+
+static void
+notebook_tab_added (PlumaNotebook *notebook,
+ PlumaTab *tab,
+ PlumaWindow *window)
+{
+ PlumaView *view;
+ PlumaDocument *doc;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ g_return_if_fail ((window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) == 0);
+
+ ++window->priv->num_tabs;
+
+ update_sensitivity_according_to_open_tabs (window);
+
+ view = pluma_tab_get_view (tab);
+ doc = pluma_tab_get_document (tab);
+
+ /* IMPORTANT: remember to disconnect the signal in notebook_tab_removed
+ * if a new signal is connected here */
+
+ g_signal_connect (tab,
+ "notify::name",
+ G_CALLBACK (sync_name),
+ window);
+ g_signal_connect (tab,
+ "notify::state",
+ G_CALLBACK (sync_state),
+ window);
+
+ g_signal_connect (doc,
+ "cursor-moved",
+ G_CALLBACK (update_cursor_position_statusbar),
+ window);
+ g_signal_connect (doc,
+ "notify::can-search-again",
+ G_CALLBACK (can_search_again),
+ window);
+ g_signal_connect (doc,
+ "notify::can-undo",
+ G_CALLBACK (can_undo),
+ window);
+ g_signal_connect (doc,
+ "notify::can-redo",
+ G_CALLBACK (can_redo),
+ window);
+ g_signal_connect (doc,
+ "notify::has-selection",
+ G_CALLBACK (selection_changed),
+ window);
+ g_signal_connect (doc,
+ "notify::language",
+ G_CALLBACK (sync_languages_menu),
+ window);
+ g_signal_connect (doc,
+ "notify::read-only",
+ G_CALLBACK (readonly_changed),
+ window);
+ g_signal_connect (view,
+ "toggle_overwrite",
+ G_CALLBACK (update_overwrite_mode_statusbar),
+ window);
+ g_signal_connect (view,
+ "notify::editable",
+ G_CALLBACK (editable_changed),
+ window);
+
+ update_documents_list_menu (window);
+
+ g_signal_connect (view,
+ "drop_uris",
+ G_CALLBACK (drop_uris_cb),
+ NULL);
+
+ update_window_state (window);
+
+ g_signal_emit (G_OBJECT (window), signals[TAB_ADDED], 0, tab);
+}
+
+static void
+notebook_tab_removed (PlumaNotebook *notebook,
+ PlumaTab *tab,
+ PlumaWindow *window)
+{
+ PlumaView *view;
+ PlumaDocument *doc;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ g_return_if_fail ((window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION) == 0);
+
+ --window->priv->num_tabs;
+
+ view = pluma_tab_get_view (tab);
+ doc = pluma_tab_get_document (tab);
+
+ g_signal_handlers_disconnect_by_func (tab,
+ G_CALLBACK (sync_name),
+ window);
+ g_signal_handlers_disconnect_by_func (tab,
+ G_CALLBACK (sync_state),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (update_cursor_position_statusbar),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (can_search_again),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (can_undo),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (can_redo),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (selection_changed),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (sync_languages_menu),
+ window);
+ g_signal_handlers_disconnect_by_func (doc,
+ G_CALLBACK (readonly_changed),
+ window);
+ g_signal_handlers_disconnect_by_func (view,
+ G_CALLBACK (update_overwrite_mode_statusbar),
+ window);
+ g_signal_handlers_disconnect_by_func (view,
+ G_CALLBACK (editable_changed),
+ window);
+ g_signal_handlers_disconnect_by_func (view,
+ G_CALLBACK (drop_uris_cb),
+ NULL);
+
+ if (window->priv->tab_width_id && tab == pluma_window_get_active_tab (window))
+ {
+ g_signal_handler_disconnect (view, window->priv->tab_width_id);
+ window->priv->tab_width_id = 0;
+ }
+
+ if (window->priv->spaces_instead_of_tabs_id && tab == pluma_window_get_active_tab (window))
+ {
+ g_signal_handler_disconnect (view, window->priv->spaces_instead_of_tabs_id);
+ window->priv->spaces_instead_of_tabs_id = 0;
+ }
+
+ if (window->priv->language_changed_id && tab == pluma_window_get_active_tab (window))
+ {
+ g_signal_handler_disconnect (doc, window->priv->language_changed_id);
+ window->priv->language_changed_id = 0;
+ }
+
+ g_return_if_fail (window->priv->num_tabs >= 0);
+ if (window->priv->num_tabs == 0)
+ {
+ window->priv->active_tab = NULL;
+
+ set_title (window);
+
+ /* Remove line and col info */
+ pluma_statusbar_set_cursor_position (
+ PLUMA_STATUSBAR (window->priv->statusbar),
+ -1,
+ -1);
+
+ pluma_statusbar_clear_overwrite (
+ PLUMA_STATUSBAR (window->priv->statusbar));
+
+ /* hide the combos */
+ gtk_widget_hide (window->priv->tab_width_combo);
+ gtk_widget_hide (window->priv->language_combo);
+ }
+
+ if (!window->priv->removing_tabs)
+ {
+ update_documents_list_menu (window);
+ update_next_prev_doc_sensitivity_per_window (window);
+ }
+ else
+ {
+ if (window->priv->num_tabs == 0)
+ {
+ update_documents_list_menu (window);
+ update_next_prev_doc_sensitivity_per_window (window);
+ }
+ }
+
+ update_sensitivity_according_to_open_tabs (window);
+
+ if (window->priv->num_tabs == 0)
+ {
+ pluma_plugins_engine_update_plugins_ui (pluma_plugins_engine_get_default (),
+ window);
+ }
+
+ update_window_state (window);
+
+ g_signal_emit (G_OBJECT (window), signals[TAB_REMOVED], 0, tab);
+}
+
+static void
+notebook_tabs_reordered (PlumaNotebook *notebook,
+ PlumaWindow *window)
+{
+ update_documents_list_menu (window);
+ update_next_prev_doc_sensitivity_per_window (window);
+
+ g_signal_emit (G_OBJECT (window), signals[TABS_REORDERED], 0);
+}
+
+static void
+notebook_tab_detached (PlumaNotebook *notebook,
+ PlumaTab *tab,
+ PlumaWindow *window)
+{
+ PlumaWindow *new_window;
+
+ new_window = clone_window (window);
+
+ pluma_notebook_move_tab (notebook,
+ PLUMA_NOTEBOOK (_pluma_window_get_notebook (new_window)),
+ tab, 0);
+
+ gtk_window_set_position (GTK_WINDOW (new_window),
+ GTK_WIN_POS_MOUSE);
+
+ gtk_widget_show (GTK_WIDGET (new_window));
+}
+
+static void
+notebook_tab_close_request (PlumaNotebook *notebook,
+ PlumaTab *tab,
+ GtkWindow *window)
+{
+ /* Note: we are destroying the tab before the default handler
+ * seems to be ok, but we need to keep an eye on this. */
+ _pluma_cmd_file_close_tab (tab, PLUMA_WINDOW (window));
+}
+
+static gboolean
+show_notebook_popup_menu (GtkNotebook *notebook,
+ PlumaWindow *window,
+ GdkEventButton *event)
+{
+ GtkWidget *menu;
+// GtkAction *action;
+
+ menu = gtk_ui_manager_get_widget (window->priv->manager, "/NotebookPopup");
+ g_return_val_if_fail (menu != NULL, FALSE);
+
+// CHECK do we need this?
+#if 0
+ /* allow extensions to sync when showing the popup */
+ action = gtk_action_group_get_action (window->priv->action_group,
+ "NotebookPopupAction");
+ g_return_val_if_fail (action != NULL, FALSE);
+ gtk_action_activate (action);
+#endif
+ if (event != NULL)
+ {
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+ NULL, NULL,
+ event->button, event->time);
+ }
+ else
+ {
+ GtkWidget *tab;
+ GtkWidget *tab_label;
+
+ tab = GTK_WIDGET (pluma_window_get_active_tab (window));
+ g_return_val_if_fail (tab != NULL, FALSE);
+
+ tab_label = gtk_notebook_get_tab_label (notebook, tab);
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+ pluma_utils_menu_position_under_widget, tab_label,
+ 0, gtk_get_current_event_time ());
+
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+notebook_button_press_event (GtkNotebook *notebook,
+ GdkEventButton *event,
+ PlumaWindow *window)
+{
+ if (GDK_BUTTON_PRESS == event->type && 3 == event->button)
+ {
+ return show_notebook_popup_menu (notebook, window, event);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+notebook_popup_menu (GtkNotebook *notebook,
+ PlumaWindow *window)
+{
+ /* Only respond if the notebook is the actual focus */
+ if (PLUMA_IS_NOTEBOOK (gtk_window_get_focus (GTK_WINDOW (window))))
+ {
+ return show_notebook_popup_menu (notebook, window, NULL);
+ }
+
+ return FALSE;
+}
+
+static void
+side_panel_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation,
+ PlumaWindow *window)
+{
+ window->priv->side_panel_size = allocation->width;
+}
+
+static void
+bottom_panel_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation,
+ PlumaWindow *window)
+{
+ window->priv->bottom_panel_size = allocation->height;
+}
+
+static void
+hpaned_restore_position (GtkWidget *widget,
+ PlumaWindow *window)
+{
+ gint pos;
+
+ pluma_debug_message (DEBUG_WINDOW,
+ "Restoring hpaned position: side panel size %d",
+ window->priv->side_panel_size);
+
+ pos = MAX (100, window->priv->side_panel_size);
+ gtk_paned_set_position (GTK_PANED (window->priv->hpaned), pos);
+
+ /* start monitoring the size */
+ g_signal_connect (window->priv->side_panel,
+ "size-allocate",
+ G_CALLBACK (side_panel_size_allocate),
+ window);
+
+ /* run this only once */
+ g_signal_handlers_disconnect_by_func (widget, hpaned_restore_position, window);
+}
+
+static void
+vpaned_restore_position (GtkWidget *widget,
+ PlumaWindow *window)
+{
+ gint pos;
+
+ pluma_debug_message (DEBUG_WINDOW,
+ "Restoring vpaned position: bottom panel size %d",
+ window->priv->bottom_panel_size);
+
+ pos = widget->allocation.height -
+ MAX (50, window->priv->bottom_panel_size);
+ gtk_paned_set_position (GTK_PANED (window->priv->vpaned), pos);
+
+ /* start monitoring the size */
+ g_signal_connect (window->priv->bottom_panel,
+ "size-allocate",
+ G_CALLBACK (bottom_panel_size_allocate),
+ window);
+
+ /* run this only once */
+ g_signal_handlers_disconnect_by_func (widget, vpaned_restore_position, window);
+}
+
+static void
+side_panel_visibility_changed (GtkWidget *side_panel,
+ PlumaWindow *window)
+{
+ gboolean visible;
+ GtkAction *action;
+
+ visible = GTK_WIDGET_VISIBLE (side_panel);
+
+ if (pluma_prefs_manager_side_pane_visible_can_set ())
+ pluma_prefs_manager_set_side_pane_visible (visible);
+
+ action = gtk_action_group_get_action (window->priv->panes_action_group,
+ "ViewSidePane");
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+
+ /* focus the document */
+ if (!visible && window->priv->active_tab != NULL)
+ gtk_widget_grab_focus (GTK_WIDGET (
+ pluma_tab_get_view (PLUMA_TAB (window->priv->active_tab))));
+}
+
+static void
+create_side_panel (PlumaWindow *window)
+{
+ GtkWidget *documents_panel;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ window->priv->side_panel = pluma_panel_new (GTK_ORIENTATION_VERTICAL);
+
+ gtk_paned_pack1 (GTK_PANED (window->priv->hpaned),
+ window->priv->side_panel,
+ FALSE,
+ FALSE);
+
+ g_signal_connect_after (window->priv->side_panel,
+ "show",
+ G_CALLBACK (side_panel_visibility_changed),
+ window);
+ g_signal_connect_after (window->priv->side_panel,
+ "hide",
+ G_CALLBACK (side_panel_visibility_changed),
+ window);
+
+ documents_panel = pluma_documents_panel_new (window);
+ pluma_panel_add_item_with_stock_icon (PLUMA_PANEL (window->priv->side_panel),
+ documents_panel,
+ _("Documents"),
+ GTK_STOCK_FILE);
+}
+
+static void
+bottom_panel_visibility_changed (PlumaPanel *bottom_panel,
+ PlumaWindow *window)
+{
+ gboolean visible;
+ GtkAction *action;
+
+ visible = GTK_WIDGET_VISIBLE (bottom_panel);
+
+ if (pluma_prefs_manager_bottom_panel_visible_can_set ())
+ pluma_prefs_manager_set_bottom_panel_visible (visible);
+
+ action = gtk_action_group_get_action (window->priv->panes_action_group,
+ "ViewBottomPane");
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) != visible)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
+
+ /* focus the document */
+ if (!visible && window->priv->active_tab != NULL)
+ gtk_widget_grab_focus (GTK_WIDGET (
+ pluma_tab_get_view (PLUMA_TAB (window->priv->active_tab))));
+}
+
+static void
+bottom_panel_item_removed (PlumaPanel *panel,
+ GtkWidget *item,
+ PlumaWindow *window)
+{
+ if (pluma_panel_get_n_items (panel) == 0)
+ {
+ GtkAction *action;
+
+ gtk_widget_hide (GTK_WIDGET (panel));
+
+ action = gtk_action_group_get_action (window->priv->panes_action_group,
+ "ViewBottomPane");
+ gtk_action_set_sensitive (action, FALSE);
+ }
+}
+
+static void
+bottom_panel_item_added (PlumaPanel *panel,
+ GtkWidget *item,
+ PlumaWindow *window)
+{
+ /* if it's the first item added, set the menu item
+ * sensitive and if needed show the panel */
+ if (pluma_panel_get_n_items (panel) == 1)
+ {
+ GtkAction *action;
+ gboolean show;
+
+ action = gtk_action_group_get_action (window->priv->panes_action_group,
+ "ViewBottomPane");
+ gtk_action_set_sensitive (action, TRUE);
+
+ show = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (show)
+ gtk_widget_show (GTK_WIDGET (panel));
+ }
+}
+
+static void
+create_bottom_panel (PlumaWindow *window)
+{
+ pluma_debug (DEBUG_WINDOW);
+
+ window->priv->bottom_panel = pluma_panel_new (GTK_ORIENTATION_HORIZONTAL);
+
+ gtk_paned_pack2 (GTK_PANED (window->priv->vpaned),
+ window->priv->bottom_panel,
+ FALSE,
+ FALSE);
+
+ g_signal_connect_after (window->priv->bottom_panel,
+ "show",
+ G_CALLBACK (bottom_panel_visibility_changed),
+ window);
+ g_signal_connect_after (window->priv->bottom_panel,
+ "hide",
+ G_CALLBACK (bottom_panel_visibility_changed),
+ window);
+}
+
+static void
+init_panels_visibility (PlumaWindow *window)
+{
+ gint active_page;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ /* side pane */
+ active_page = pluma_prefs_manager_get_side_panel_active_page ();
+ _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->side_panel),
+ active_page);
+
+ if (pluma_prefs_manager_get_side_pane_visible ())
+ {
+ gtk_widget_show (window->priv->side_panel);
+ }
+
+ /* bottom pane, it can be empty */
+ if (pluma_panel_get_n_items (PLUMA_PANEL (window->priv->bottom_panel)) > 0)
+ {
+ active_page = pluma_prefs_manager_get_bottom_panel_active_page ();
+ _pluma_panel_set_active_item_by_id (PLUMA_PANEL (window->priv->bottom_panel),
+ active_page);
+
+ if (pluma_prefs_manager_get_bottom_panel_visible ())
+ {
+ gtk_widget_show (window->priv->bottom_panel);
+ }
+ }
+ else
+ {
+ GtkAction *action;
+ action = gtk_action_group_get_action (window->priv->panes_action_group,
+ "ViewBottomPane");
+ gtk_action_set_sensitive (action, FALSE);
+ }
+
+ /* start track sensitivity after the initial state is set */
+ window->priv->bottom_panel_item_removed_handler_id =
+ g_signal_connect (window->priv->bottom_panel,
+ "item_removed",
+ G_CALLBACK (bottom_panel_item_removed),
+ window);
+
+ g_signal_connect (window->priv->bottom_panel,
+ "item_added",
+ G_CALLBACK (bottom_panel_item_added),
+ window);
+}
+
+static void
+clipboard_owner_change (GtkClipboard *clipboard,
+ GdkEventOwnerChange *event,
+ PlumaWindow *window)
+{
+ set_paste_sensitivity_according_to_clipboard (window,
+ clipboard);
+}
+
+static void
+window_realized (GtkWidget *window,
+ gpointer *data)
+{
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (window,
+ GDK_SELECTION_CLIPBOARD);
+
+ g_signal_connect (clipboard,
+ "owner_change",
+ G_CALLBACK (clipboard_owner_change),
+ window);
+}
+
+static void
+window_unrealized (GtkWidget *window,
+ gpointer *data)
+{
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (window,
+ GDK_SELECTION_CLIPBOARD);
+
+ g_signal_handlers_disconnect_by_func (clipboard,
+ G_CALLBACK (clipboard_owner_change),
+ window);
+}
+
+static void
+check_window_is_active (PlumaWindow *window,
+ GParamSpec *property,
+ gpointer useless)
+{
+ if (window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN)
+ {
+ if (gtk_window_is_active (GTK_WINDOW (window)))
+ {
+ gtk_widget_show (window->priv->fullscreen_controls);
+ }
+ else
+ {
+ gtk_widget_hide (window->priv->fullscreen_controls);
+ }
+ }
+}
+
+#ifdef OS_OSX
+static void
+setup_mac_menu (PlumaWindow *window)
+{
+ GtkAction *action;
+
+ gtk_widget_hide (window->priv->menubar);
+ action = gtk_ui_manager_get_action (window->priv->manager, "/ui/MenuBar/HelpMenu/HelpAboutMenu");
+
+ gtk_action_set_label (action, _("About pluma"));
+
+ ige_mac_menu_set_menu_bar (GTK_MENU_SHELL (window->priv->menubar));
+ ige_mac_menu_set_quit_menu_item (ui_manager_menu_item (window->priv->manager, "/ui/MenuBar/FileMenu/FileQuitMenu"));
+
+ ige_mac_menu_set_preferences_menu_item (ui_manager_menu_item (window->priv->manager, "/ui/MenuBar/EditMenu/EditPreferencesMenu"));
+
+ add_mac_root_menu (window);
+ ige_mac_menu_connect_window_key_handler (GTK_WINDOW (window));
+}
+#endif
+
+static void
+connect_notebook_signals (PlumaWindow *window,
+ GtkWidget *notebook)
+{
+ g_signal_connect (notebook,
+ "switch-page",
+ G_CALLBACK (notebook_switch_page),
+ window);
+ g_signal_connect (notebook,
+ "tab-added",
+ G_CALLBACK (notebook_tab_added),
+ window);
+ g_signal_connect (notebook,
+ "tab-removed",
+ G_CALLBACK (notebook_tab_removed),
+ window);
+ g_signal_connect (notebook,
+ "tabs-reordered",
+ G_CALLBACK (notebook_tabs_reordered),
+ window);
+ g_signal_connect (notebook,
+ "tab-detached",
+ G_CALLBACK (notebook_tab_detached),
+ window);
+ g_signal_connect (notebook,
+ "tab-close-request",
+ G_CALLBACK (notebook_tab_close_request),
+ window);
+ g_signal_connect (notebook,
+ "button-press-event",
+ G_CALLBACK (notebook_button_press_event),
+ window);
+ g_signal_connect (notebook,
+ "popup-menu",
+ G_CALLBACK (notebook_popup_menu),
+ window);
+}
+
+static void
+add_notebook (PlumaWindow *window,
+ GtkWidget *notebook)
+{
+ gtk_paned_pack1 (GTK_PANED (window->priv->vpaned),
+ notebook,
+ TRUE,
+ TRUE);
+
+ gtk_widget_show (notebook);
+
+ connect_notebook_signals (window, notebook);
+}
+
+static void
+pluma_window_init (PlumaWindow *window)
+{
+ GtkWidget *main_box;
+ GtkTargetList *tl;
+
+ pluma_debug (DEBUG_WINDOW);
+
+ window->priv = PLUMA_WINDOW_GET_PRIVATE (window);
+ window->priv->active_tab = NULL;
+ window->priv->num_tabs = 0;
+ window->priv->removing_tabs = FALSE;
+ window->priv->state = PLUMA_WINDOW_STATE_NORMAL;
+ window->priv->dispose_has_run = FALSE;
+ window->priv->fullscreen_controls = NULL;
+ window->priv->fullscreen_animation_timeout_id = 0;
+
+ window->priv->message_bus = pluma_message_bus_new ();
+
+ window->priv->window_group = gtk_window_group_new ();
+ gtk_window_group_add_window (window->priv->window_group, GTK_WINDOW (window));
+
+ main_box = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), main_box);
+ gtk_widget_show (main_box);
+
+ /* Add menu bar and toolbar bar */
+ create_menu_bar_and_toolbar (window, main_box);
+
+ /* Add status bar */
+ create_statusbar (window, main_box);
+
+ /* Add the main area */
+ pluma_debug_message (DEBUG_WINDOW, "Add main area");
+ window->priv->hpaned = gtk_hpaned_new ();
+ gtk_box_pack_start (GTK_BOX (main_box),
+ window->priv->hpaned,
+ TRUE,
+ TRUE,
+ 0);
+
+ window->priv->vpaned = gtk_vpaned_new ();
+ gtk_paned_pack2 (GTK_PANED (window->priv->hpaned),
+ window->priv->vpaned,
+ TRUE,
+ FALSE);
+
+ pluma_debug_message (DEBUG_WINDOW, "Create pluma notebook");
+ window->priv->notebook = pluma_notebook_new ();
+ add_notebook (window, window->priv->notebook);
+
+ /* side and bottom panels */
+ create_side_panel (window);
+ create_bottom_panel (window);
+
+ /* panes' state must be restored after panels have been mapped,
+ * since the bottom pane position depends on the size of the vpaned. */
+ window->priv->side_panel_size = pluma_prefs_manager_get_side_panel_size ();
+ window->priv->bottom_panel_size = pluma_prefs_manager_get_bottom_panel_size ();
+
+ g_signal_connect_after (window->priv->hpaned,
+ "map",
+ G_CALLBACK (hpaned_restore_position),
+ window);
+ g_signal_connect_after (window->priv->vpaned,
+ "map",
+ G_CALLBACK (vpaned_restore_position),
+ window);
+
+ gtk_widget_show (window->priv->hpaned);
+ gtk_widget_show (window->priv->vpaned);
+
+ /* Drag and drop support, set targets to NULL because we add the
+ default uri_targets below */
+ gtk_drag_dest_set (GTK_WIDGET (window),
+ GTK_DEST_DEFAULT_MOTION |
+ GTK_DEST_DEFAULT_HIGHLIGHT |
+ GTK_DEST_DEFAULT_DROP,
+ NULL,
+ 0,
+ GDK_ACTION_COPY);
+
+ /* Add uri targets */
+ tl = gtk_drag_dest_get_target_list (GTK_WIDGET (window));
+
+ if (tl == NULL)
+ {
+ tl = gtk_target_list_new (NULL, 0);
+ gtk_drag_dest_set_target_list (GTK_WIDGET (window), tl);
+ gtk_target_list_unref (tl);
+ }
+
+ gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
+
+ /* connect instead of override, so that we can
+ * share the cb code with the view */
+ g_signal_connect (window,
+ "drag_data_received",
+ G_CALLBACK (drag_data_received_cb),
+ NULL);
+
+ /* we can get the clipboard only after the widget
+ * is realized */
+ g_signal_connect (window,
+ "realize",
+ G_CALLBACK (window_realized),
+ NULL);
+ g_signal_connect (window,
+ "unrealize",
+ G_CALLBACK (window_unrealized),
+ NULL);
+
+ /* Check if the window is active for fullscreen */
+ g_signal_connect (window,
+ "notify::is-active",
+ G_CALLBACK (check_window_is_active),
+ NULL);
+
+ pluma_debug_message (DEBUG_WINDOW, "Update plugins ui");
+
+ pluma_plugins_engine_activate_plugins (pluma_plugins_engine_get_default (),
+ window);
+
+ /* set visibility of panes.
+ * This needs to be done after plugins activatation */
+ init_panels_visibility (window);
+
+ update_sensitivity_according_to_open_tabs (window);
+
+#ifdef OS_OSX
+ setup_mac_menu (window);
+#endif
+
+ pluma_debug_message (DEBUG_WINDOW, "END");
+}
+
+/**
+ * pluma_window_get_active_view:
+ * @window: a #PlumaWindow
+ *
+ * Gets the active #PlumaView.
+ *
+ * Returns: the active #PlumaView
+ */
+PlumaView *
+pluma_window_get_active_view (PlumaWindow *window)
+{
+ PlumaView *view;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ if (window->priv->active_tab == NULL)
+ return NULL;
+
+ view = pluma_tab_get_view (PLUMA_TAB (window->priv->active_tab));
+
+ return view;
+}
+
+/**
+ * pluma_window_get_active_document:
+ * @window: a #PlumaWindow
+ *
+ * Gets the active #PlumaDocument.
+ *
+ * Returns: the active #PlumaDocument
+ */
+PlumaDocument *
+pluma_window_get_active_document (PlumaWindow *window)
+{
+ PlumaView *view;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ view = pluma_window_get_active_view (window);
+ if (view == NULL)
+ return NULL;
+
+ return PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+}
+
+GtkWidget *
+_pluma_window_get_notebook (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return window->priv->notebook;
+}
+
+/**
+ * pluma_window_create_tab:
+ * @window: a #PlumaWindow
+ * @jump_to: %TRUE to set the new #PlumaTab as active
+ *
+ * Creates a new #PlumaTab and adds the new tab to the #PlumaNotebook.
+ * In case @jump_to is %TRUE the #PlumaNotebook switches to that new #PlumaTab.
+ *
+ * Returns: a new #PlumaTab
+ */
+PlumaTab *
+pluma_window_create_tab (PlumaWindow *window,
+ gboolean jump_to)
+{
+ PlumaTab *tab;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ tab = PLUMA_TAB (_pluma_tab_new ());
+ gtk_widget_show (GTK_WIDGET (tab));
+
+ pluma_notebook_add_tab (PLUMA_NOTEBOOK (window->priv->notebook),
+ tab,
+ -1,
+ jump_to);
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ {
+ gtk_window_present (GTK_WINDOW (window));
+ }
+
+ return tab;
+}
+
+/**
+ * pluma_window_create_tab_from_uri:
+ * @window: a #PlumaWindow
+ * @uri: the uri of the document
+ * @encoding: a #PlumaEncoding
+ * @line_pos: the line position to visualize
+ * @create: %TRUE to create a new document in case @uri does exist
+ * @jump_to: %TRUE to set the new #PlumaTab as active
+ *
+ * Creates a new #PlumaTab loading the document specified by @uri.
+ * In case @jump_to is %TRUE the #PlumaNotebook swithes to that new #PlumaTab.
+ * Whether @create is %TRUE, creates a new empty document if location does
+ * not refer to an existing file
+ *
+ * Returns: a new #PlumaTab
+ */
+PlumaTab *
+pluma_window_create_tab_from_uri (PlumaWindow *window,
+ const gchar *uri,
+ const PlumaEncoding *encoding,
+ gint line_pos,
+ gboolean create,
+ gboolean jump_to)
+{
+ GtkWidget *tab;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ tab = _pluma_tab_new_from_uri (uri,
+ encoding,
+ line_pos,
+ create);
+ if (tab == NULL)
+ return NULL;
+
+ gtk_widget_show (tab);
+
+ pluma_notebook_add_tab (PLUMA_NOTEBOOK (window->priv->notebook),
+ PLUMA_TAB (tab),
+ -1,
+ jump_to);
+
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ {
+ gtk_window_present (GTK_WINDOW (window));
+ }
+
+ return PLUMA_TAB (tab);
+}
+
+/**
+ * pluma_window_get_active_tab:
+ * @window: a PlumaWindow
+ *
+ * Gets the active #PlumaTab in the @window.
+ *
+ * Returns: the active #PlumaTab in the @window.
+ */
+PlumaTab *
+pluma_window_get_active_tab (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return (window->priv->active_tab == NULL) ?
+ NULL : PLUMA_TAB (window->priv->active_tab);
+}
+
+static void
+add_document (PlumaTab *tab, GList **res)
+{
+ PlumaDocument *doc;
+
+ doc = pluma_tab_get_document (tab);
+
+ *res = g_list_prepend (*res, doc);
+}
+
+/**
+ * pluma_window_get_documents:
+ * @window: a #PlumaWindow
+ *
+ * Gets a newly allocated list with all the documents in the window.
+ * This list must be freed.
+ *
+ * Returns: a newly allocated list with all the documents in the window
+ */
+GList *
+pluma_window_get_documents (PlumaWindow *window)
+{
+ GList *res = NULL;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
+ (GtkCallback)add_document,
+ &res);
+
+ res = g_list_reverse (res);
+
+ return res;
+}
+
+static void
+add_view (PlumaTab *tab, GList **res)
+{
+ PlumaView *view;
+
+ view = pluma_tab_get_view (tab);
+
+ *res = g_list_prepend (*res, view);
+}
+
+/**
+ * pluma_window_get_views:
+ * @window: a #PlumaWindow
+ *
+ * Gets a list with all the views in the window. This list must be freed.
+ *
+ * Returns: a newly allocated list with all the views in the window
+ */
+GList *
+pluma_window_get_views (PlumaWindow *window)
+{
+ GList *res = NULL;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
+ (GtkCallback)add_view,
+ &res);
+
+ res = g_list_reverse (res);
+
+ return res;
+}
+
+/**
+ * pluma_window_close_tab:
+ * @window: a #PlumaWindow
+ * @tab: the #PlumaTab to close
+ *
+ * Closes the @tab.
+ */
+void
+pluma_window_close_tab (PlumaWindow *window,
+ PlumaTab *tab)
+{
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+ g_return_if_fail (PLUMA_IS_TAB (tab));
+ g_return_if_fail ((pluma_tab_get_state (tab) != PLUMA_TAB_STATE_SAVING) &&
+ (pluma_tab_get_state (tab) != PLUMA_TAB_STATE_SHOWING_PRINT_PREVIEW));
+
+ pluma_notebook_remove_tab (PLUMA_NOTEBOOK (window->priv->notebook),
+ tab);
+}
+
+/**
+ * pluma_window_close_all_tabs:
+ * @window: a #PlumaWindow
+ *
+ * Closes all opened tabs.
+ */
+void
+pluma_window_close_all_tabs (PlumaWindow *window)
+{
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+ g_return_if_fail (!(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ window->priv->removing_tabs = TRUE;
+
+ pluma_notebook_remove_all_tabs (PLUMA_NOTEBOOK (window->priv->notebook));
+
+ window->priv->removing_tabs = FALSE;
+}
+
+/**
+ * pluma_window_close_tabs:
+ * @window: a #PlumaWindow
+ * @tabs: a list of #PlumaTab
+ *
+ * Closes all tabs specified by @tabs.
+ */
+void
+pluma_window_close_tabs (PlumaWindow *window,
+ const GList *tabs)
+{
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+ g_return_if_fail (!(window->priv->state & PLUMA_WINDOW_STATE_SAVING) &&
+ !(window->priv->state & PLUMA_WINDOW_STATE_SAVING_SESSION));
+
+ if (tabs == NULL)
+ return;
+
+ window->priv->removing_tabs = TRUE;
+
+ while (tabs != NULL)
+ {
+ if (tabs->next == NULL)
+ window->priv->removing_tabs = FALSE;
+
+ pluma_notebook_remove_tab (PLUMA_NOTEBOOK (window->priv->notebook),
+ PLUMA_TAB (tabs->data));
+
+ tabs = g_list_next (tabs);
+ }
+
+ g_return_if_fail (window->priv->removing_tabs == FALSE);
+}
+
+PlumaWindow *
+_pluma_window_move_tab_to_new_window (PlumaWindow *window,
+ PlumaTab *tab)
+{
+ PlumaWindow *new_window;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (PLUMA_IS_TAB (tab), NULL);
+ g_return_val_if_fail (gtk_notebook_get_n_pages (
+ GTK_NOTEBOOK (window->priv->notebook)) > 1,
+ NULL);
+
+ new_window = clone_window (window);
+
+ pluma_notebook_move_tab (PLUMA_NOTEBOOK (window->priv->notebook),
+ PLUMA_NOTEBOOK (new_window->priv->notebook),
+ tab,
+ -1);
+
+ gtk_widget_show (GTK_WIDGET (new_window));
+
+ return new_window;
+}
+
+/**
+ * pluma_window_set_active_tab:
+ * @window: a #PlumaWindow
+ * @tab: a #PlumaTab
+ *
+ * Switches to the tab that matches with @tab.
+ */
+void
+pluma_window_set_active_tab (PlumaWindow *window,
+ PlumaTab *tab)
+{
+ gint page_num;
+
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+ g_return_if_fail (PLUMA_IS_TAB (tab));
+
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->priv->notebook),
+ GTK_WIDGET (tab));
+ g_return_if_fail (page_num != -1);
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (window->priv->notebook),
+ page_num);
+}
+
+/**
+ * pluma_window_get_group:
+ * @window: a #PlumaWindow
+ *
+ * Gets the #GtkWindowGroup in which @window resides.
+ *
+ * Returns: the #GtkWindowGroup
+ */
+GtkWindowGroup *
+pluma_window_get_group (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return window->priv->window_group;
+}
+
+gboolean
+_pluma_window_is_removing_tabs (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), FALSE);
+
+ return window->priv->removing_tabs;
+}
+
+/**
+ * pluma_window_get_ui_manager:
+ * @window: a #PlumaWindow
+ *
+ * Gets the #GtkUIManager associated with the @window.
+ *
+ * Returns: the #GtkUIManager of the @window.
+ */
+GtkUIManager *
+pluma_window_get_ui_manager (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return window->priv->manager;
+}
+
+/**
+ * pluma_window_get_side_panel:
+ * @window: a #PlumaWindow
+ *
+ * Gets the side #PlumaPanel of the @window.
+ *
+ * Returns: the side #PlumaPanel.
+ */
+PlumaPanel *
+pluma_window_get_side_panel (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return PLUMA_PANEL (window->priv->side_panel);
+}
+
+/**
+ * pluma_window_get_bottom_panel:
+ * @window: a #PlumaWindow
+ *
+ * Gets the bottom #PlumaPanel of the @window.
+ *
+ * Returns: the bottom #PlumaPanel.
+ */
+PlumaPanel *
+pluma_window_get_bottom_panel (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return PLUMA_PANEL (window->priv->bottom_panel);
+}
+
+/**
+ * pluma_window_get_statusbar:
+ * @window: a #PlumaWindow
+ *
+ * Gets the #PlumaStatusbar of the @window.
+ *
+ * Returns: the #PlumaStatusbar of the @window.
+ */
+GtkWidget *
+pluma_window_get_statusbar (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), 0);
+
+ return window->priv->statusbar;
+}
+
+/**
+ * pluma_window_get_state:
+ * @window: a #PlumaWindow
+ *
+ * Retrieves the state of the @window.
+ *
+ * Returns: the current #PlumaWindowState of the @window.
+ */
+PlumaWindowState
+pluma_window_get_state (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), PLUMA_WINDOW_STATE_NORMAL);
+
+ return window->priv->state;
+}
+
+GFile *
+_pluma_window_get_default_location (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return window->priv->default_location != NULL ?
+ g_object_ref (window->priv->default_location) : NULL;
+}
+
+void
+_pluma_window_set_default_location (PlumaWindow *window,
+ GFile *location)
+{
+ GFile *dir;
+
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+ g_return_if_fail (G_IS_FILE (location));
+
+ dir = g_file_get_parent (location);
+ g_return_if_fail (dir != NULL);
+
+ if (window->priv->default_location != NULL)
+ g_object_unref (window->priv->default_location);
+
+ window->priv->default_location = dir;
+}
+
+/**
+ * pluma_window_get_unsaved_documents:
+ * @window: a #PlumaWindow
+ *
+ * Gets the list of documents that need to be saved before closing the window.
+ *
+ * Returns: a list of #PlumaDocument that need to be saved before closing the window
+ */
+GList *
+pluma_window_get_unsaved_documents (PlumaWindow *window)
+{
+ GList *unsaved_docs = NULL;
+ GList *tabs;
+ GList *l;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ tabs = gtk_container_get_children (GTK_CONTAINER (window->priv->notebook));
+
+ l = tabs;
+ while (l != NULL)
+ {
+ PlumaTab *tab;
+
+ tab = PLUMA_TAB (l->data);
+
+ if (!_pluma_tab_can_close (tab))
+ {
+ PlumaDocument *doc;
+
+ doc = pluma_tab_get_document (tab);
+ unsaved_docs = g_list_prepend (unsaved_docs, doc);
+ }
+
+ l = g_list_next (l);
+ }
+
+ g_list_free (tabs);
+
+ return g_list_reverse (unsaved_docs);
+}
+
+void
+_pluma_window_set_saving_session_state (PlumaWindow *window,
+ gboolean saving_session)
+{
+ PlumaWindowState old_state;
+
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+
+ old_state = window->priv->state;
+
+ if (saving_session)
+ window->priv->state |= PLUMA_WINDOW_STATE_SAVING_SESSION;
+ else
+ window->priv->state &= ~PLUMA_WINDOW_STATE_SAVING_SESSION;
+
+ if (old_state != window->priv->state)
+ {
+ set_sensitivity_according_to_window_state (window);
+
+ g_object_notify (G_OBJECT (window), "state");
+ }
+}
+
+static void
+hide_notebook_tabs_on_fullscreen (GtkNotebook *notebook,
+ GParamSpec *pspec,
+ PlumaWindow *window)
+{
+ gtk_notebook_set_show_tabs (notebook, FALSE);
+}
+
+void
+_pluma_window_fullscreen (PlumaWindow *window)
+{
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+
+ if (_pluma_window_is_fullscreen (window))
+ return;
+
+ /* Go to fullscreen mode and hide bars */
+ gtk_window_fullscreen (&window->window);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook), FALSE);
+ g_signal_connect (window->priv->notebook, "notify::show-tabs",
+ G_CALLBACK (hide_notebook_tabs_on_fullscreen), window);
+
+ gtk_widget_hide (window->priv->menubar);
+
+ g_signal_handlers_block_by_func (window->priv->toolbar,
+ toolbar_visibility_changed,
+ window);
+ gtk_widget_hide (window->priv->toolbar);
+
+ g_signal_handlers_block_by_func (window->priv->statusbar,
+ statusbar_visibility_changed,
+ window);
+ gtk_widget_hide (window->priv->statusbar);
+
+ fullscreen_controls_build (window);
+ fullscreen_controls_show (window);
+}
+
+void
+_pluma_window_unfullscreen (PlumaWindow *window)
+{
+ gboolean visible;
+ GtkAction *action;
+
+ g_return_if_fail (PLUMA_IS_WINDOW (window));
+
+ if (!_pluma_window_is_fullscreen (window))
+ return;
+
+ /* Unfullscreen and show bars */
+ gtk_window_unfullscreen (&window->window);
+ g_signal_handlers_disconnect_by_func (window->priv->notebook,
+ hide_notebook_tabs_on_fullscreen,
+ window);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->priv->notebook), TRUE);
+ gtk_widget_show (window->priv->menubar);
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "ViewToolbar");
+ visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (visible)
+ gtk_widget_show (window->priv->toolbar);
+ g_signal_handlers_unblock_by_func (window->priv->toolbar,
+ toolbar_visibility_changed,
+ window);
+
+ action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
+ "ViewStatusbar");
+ visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (visible)
+ gtk_widget_show (window->priv->statusbar);
+ g_signal_handlers_unblock_by_func (window->priv->statusbar,
+ statusbar_visibility_changed,
+ window);
+
+ gtk_widget_hide (window->priv->fullscreen_controls);
+}
+
+gboolean
+_pluma_window_is_fullscreen (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), FALSE);
+
+ return window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN;
+}
+
+/**
+ * pluma_window_get_tab_from_location:
+ * @window: a #PlumaWindow
+ * @location: a #GFile
+ *
+ * Gets the #PlumaTab that matches with the given @location.
+ *
+ * Returns: the #PlumaTab that matches with the given @location.
+ */
+PlumaTab *
+pluma_window_get_tab_from_location (PlumaWindow *window,
+ GFile *location)
+{
+ GList *tabs;
+ GList *l;
+ PlumaTab *ret = NULL;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+
+ tabs = gtk_container_get_children (GTK_CONTAINER (window->priv->notebook));
+
+ for (l = tabs; l != NULL; l = g_list_next (l))
+ {
+ PlumaDocument *d;
+ PlumaTab *t;
+ GFile *f;
+
+ t = PLUMA_TAB (l->data);
+ d = pluma_tab_get_document (t);
+
+ f = pluma_document_get_location (d);
+
+ if ((f != NULL))
+ {
+ gboolean found = g_file_equal (location, f);
+
+ g_object_unref (f);
+
+ if (found)
+ {
+ ret = t;
+ break;
+ }
+ }
+ }
+
+ g_list_free (tabs);
+
+ return ret;
+}
+
+/**
+ * pluma_window_get_message_bus:
+ * @window: a #PlumaWindow
+ *
+ * Gets the #PlumaMessageBus associated with @window. The returned reference
+ * is owned by the window and should not be unreffed.
+ *
+ * Return value: the #PlumaMessageBus associated with @window
+ */
+PlumaMessageBus *
+pluma_window_get_message_bus (PlumaWindow *window)
+{
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+
+ return window->priv->message_bus;
+}
+
+/**
+ * pluma_window_get_tab_from_uri:
+ * @window: a #PlumaWindow
+ * @uri: the uri to get the #PlumaTab
+ *
+ * Gets the #PlumaTab that matches @uri.
+ *
+ * Returns: the #PlumaTab associated with @uri.
+ *
+ * Deprecated: 2.24: Use pluma_window_get_tab_from_location() instead.
+ */
+PlumaTab *
+pluma_window_get_tab_from_uri (PlumaWindow *window,
+ const gchar *uri)
+{
+ GFile *f;
+ PlumaTab *tab;
+
+ g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ f = g_file_new_for_uri (uri);
+ tab = pluma_window_get_tab_from_location (window, f);
+ g_object_unref (f);
+
+ return tab;
+}