From ba429d344132c088177e853cce8ff7181570b221 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 19:42:51 +0200 Subject: Adding upstream version 44.2. Signed-off-by: Daniel Baumann --- gedit/gedit-multi-notebook.c | 1125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1125 insertions(+) create mode 100644 gedit/gedit-multi-notebook.c (limited to 'gedit/gedit-multi-notebook.c') diff --git a/gedit/gedit-multi-notebook.c b/gedit/gedit-multi-notebook.c new file mode 100644 index 0000000..46d75ed --- /dev/null +++ b/gedit/gedit-multi-notebook.c @@ -0,0 +1,1125 @@ +/* + * gedit-multi-notebook.c + * This file is part of gedit + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * gedit 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. + * + * gedit 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 gedit; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gedit-multi-notebook.h" + +#include "gedit-enum-types-private.h" +#include "gedit-settings.h" +#include "gedit-tab-private.h" +#include "gedit-tab.h" + +struct _GeditMultiNotebookPrivate +{ + GtkWidget *active_notebook; + GList *notebooks; + gint total_tabs; + + GeditTab *active_tab; + + GeditNotebookShowTabsModeType show_tabs_mode; + GSettings *ui_settings; + + guint show_tabs : 1; + guint removing_notebook : 1; +}; + +enum +{ + PROP_0, + PROP_ACTIVE_NOTEBOOK, + PROP_ACTIVE_TAB, + PROP_SHOW_TABS_MODE, + LAST_PROP +}; + +static GParamSpec *properties[LAST_PROP]; + +enum +{ + NOTEBOOK_ADDED, + NOTEBOOK_REMOVED, + TAB_ADDED, + TAB_REMOVED, + SWITCH_TAB, + TAB_CLOSE_REQUEST, + CREATE_WINDOW, + PAGE_REORDERED, + SHOW_POPUP_MENU, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE_WITH_PRIVATE (GeditMultiNotebook, gedit_multi_notebook, GTK_TYPE_GRID) + +static void remove_notebook (GeditMultiNotebook *mnb, + GtkWidget *notebook); + +static void update_tabs_visibility (GeditMultiNotebook *mnb); + +static void +gedit_multi_notebook_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object); + + switch (prop_id) + { + case PROP_ACTIVE_NOTEBOOK: + g_value_set_object (value, + mnb->priv->active_notebook); + break; + case PROP_ACTIVE_TAB: + g_value_set_object (value, + mnb->priv->active_tab); + break; + case PROP_SHOW_TABS_MODE: + g_value_set_enum (value, + mnb->priv->show_tabs_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_multi_notebook_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object); + + switch (prop_id) + { + case PROP_SHOW_TABS_MODE: + mnb->priv->show_tabs_mode = g_value_get_enum (value); + update_tabs_visibility (mnb); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_multi_notebook_dispose (GObject *object) +{ + GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object); + + g_clear_object (&mnb->priv->ui_settings); + + G_OBJECT_CLASS (gedit_multi_notebook_parent_class)->dispose (object); +} + +static void +gedit_multi_notebook_finalize (GObject *object) +{ + GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object); + + g_list_free (mnb->priv->notebooks); + + G_OBJECT_CLASS (gedit_multi_notebook_parent_class)->finalize (object); +} + +static void +gedit_multi_notebook_class_init (GeditMultiNotebookClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gedit_multi_notebook_dispose; + object_class->finalize = gedit_multi_notebook_finalize; + object_class->get_property = gedit_multi_notebook_get_property; + object_class->set_property = gedit_multi_notebook_set_property; + + properties[PROP_ACTIVE_NOTEBOOK] = + g_param_spec_object ("active-notebook", + "Active Notebook", + "The Active Notebook", + GEDIT_TYPE_NOTEBOOK, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_ACTIVE_TAB] = + g_param_spec_object ("active-tab", + "Active Tab", + "The Active Tab", + GEDIT_TYPE_TAB, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_SHOW_TABS_MODE] = + g_param_spec_enum ("show-tabs-mode", + "Show Tabs Mode", + "When tabs should be shown", + GEDIT_TYPE_NOTEBOOK_SHOW_TABS_MODE_TYPE, + GEDIT_NOTEBOOK_SHOW_TABS_ALWAYS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, LAST_PROP, properties); + + signals[NOTEBOOK_ADDED] = + g_signal_new ("notebook-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, notebook_added), + NULL, NULL, NULL, + G_TYPE_NONE, + 1, + GEDIT_TYPE_NOTEBOOK); + signals[NOTEBOOK_REMOVED] = + g_signal_new ("notebook-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, notebook_removed), + NULL, NULL, NULL, + G_TYPE_NONE, + 1, + GEDIT_TYPE_NOTEBOOK); + signals[TAB_ADDED] = + g_signal_new ("tab-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, tab_added), + NULL, NULL, NULL, + G_TYPE_NONE, + 2, + GEDIT_TYPE_NOTEBOOK, + GEDIT_TYPE_TAB); + signals[TAB_REMOVED] = + g_signal_new ("tab-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, tab_removed), + NULL, NULL, NULL, + G_TYPE_NONE, + 2, + GEDIT_TYPE_NOTEBOOK, + GEDIT_TYPE_TAB); + signals[SWITCH_TAB] = + g_signal_new ("switch-tab", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, switch_tab), + NULL, NULL, NULL, + G_TYPE_NONE, + 4, + GEDIT_TYPE_NOTEBOOK, + GEDIT_TYPE_TAB, + GEDIT_TYPE_NOTEBOOK, + GEDIT_TYPE_TAB); + signals[TAB_CLOSE_REQUEST] = + g_signal_new ("tab-close-request", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, tab_close_request), + NULL, NULL, NULL, + G_TYPE_NONE, + 2, + GEDIT_TYPE_NOTEBOOK, + GEDIT_TYPE_TAB); + signals[CREATE_WINDOW] = + g_signal_new ("create-window", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, create_window), + NULL, NULL, NULL, + GTK_TYPE_NOTEBOOK, 4, + GEDIT_TYPE_NOTEBOOK, GTK_TYPE_WIDGET, + G_TYPE_INT, G_TYPE_INT); + signals[PAGE_REORDERED] = + g_signal_new ("page-reordered", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, page_reordered), + NULL, NULL, NULL, + G_TYPE_NONE, + 3, + GEDIT_TYPE_NOTEBOOK, GTK_TYPE_WIDGET, + G_TYPE_INT); + signals[SHOW_POPUP_MENU] = + g_signal_new ("show-popup-menu", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeditMultiNotebookClass, show_popup_menu), + NULL, NULL, NULL, + G_TYPE_NONE, + 2, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE, + GEDIT_TYPE_TAB); +} + +static void +notebook_show_popup_menu (GtkNotebook *notebook, + GdkEvent *event, + GeditTab *tab, + GeditMultiNotebook *mnb) +{ + g_signal_emit (G_OBJECT (mnb), signals[SHOW_POPUP_MENU], 0, event, tab); +} + +static void +notebook_tab_close_request (GeditNotebook *notebook, + GeditTab *tab, + GeditMultiNotebook *mnb) +{ + g_signal_emit (G_OBJECT (mnb), signals[TAB_CLOSE_REQUEST], 0, + notebook, tab); +} + +static GtkNotebook * +notebook_create_window (GeditNotebook *notebook, + GtkWidget *child, + gint x, + gint y, + GeditMultiNotebook *mnb) +{ + GtkNotebook *dest_notebook; + + g_signal_emit (G_OBJECT (mnb), signals[CREATE_WINDOW], 0, + notebook, child, x, y, &dest_notebook); + + return dest_notebook; +} + +static void +notebook_page_reordered (GeditNotebook *notebook, + GtkWidget *child, + guint page_num, + GeditMultiNotebook *mnb) +{ + g_signal_emit (G_OBJECT (mnb), signals[PAGE_REORDERED], 0, notebook, + child, page_num); +} + +static void +set_active_tab (GeditMultiNotebook *mnb, + GeditTab *tab) +{ + mnb->priv->active_tab = tab; + g_object_notify_by_pspec (G_OBJECT (mnb), properties[PROP_ACTIVE_TAB]); +} + +static void +notebook_page_removed (GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + GeditMultiNotebook *mnb) +{ + GeditTab *tab = GEDIT_TAB (child); + guint num_tabs; + gboolean last_notebook; + + --mnb->priv->total_tabs; + num_tabs = gtk_notebook_get_n_pages (notebook); + last_notebook = (mnb->priv->notebooks->next == NULL); + + if (mnb->priv->total_tabs == 0) + { + set_active_tab (mnb, NULL); + } + + g_signal_emit (G_OBJECT (mnb), signals[TAB_REMOVED], 0, notebook, tab); + + /* Not last notebook but last tab of the notebook, this means we have + to remove the current notebook */ + if (num_tabs == 0 && !mnb->priv->removing_notebook && + !last_notebook) + { + remove_notebook (mnb, GTK_WIDGET (notebook)); + } + + update_tabs_visibility (mnb); +} + +static void +notebook_page_added (GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + GeditMultiNotebook *mnb) +{ + GeditTab *tab = GEDIT_TAB (child); + + ++mnb->priv->total_tabs; + + update_tabs_visibility (mnb); + + g_signal_emit (G_OBJECT (mnb), signals[TAB_ADDED], 0, notebook, tab); +} + +static void +notebook_switch_page (GtkNotebook *book, + GtkWidget *pg, + gint page_num, + GeditMultiNotebook *mnb) +{ + GeditTab *tab; + + /* When we switch a tab from a notebook that it is not the active one + the switch page is emitted before the set focus, so we do this check + and we avoid to call switch page twice */ + if (GTK_WIDGET (book) != mnb->priv->active_notebook) + return; + + /* 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 = GEDIT_TAB (gtk_notebook_get_nth_page (book, page_num)); + if (tab != mnb->priv->active_tab) + { + GeditTab *old_tab; + + old_tab = mnb->priv->active_tab; + set_active_tab (mnb, tab); + g_signal_emit (G_OBJECT (mnb), signals[SWITCH_TAB], 0, + mnb->priv->active_notebook, old_tab, + book, tab); + } +} + +/* We need to figure out if the any of the internal widget of the notebook + has got the focus to set the active notebook */ +static void +notebook_set_focus (GtkContainer *container, + GtkWidget *widget, + GeditMultiNotebook *mnb) +{ + if (GEDIT_IS_NOTEBOOK (container) && + GTK_WIDGET (container) != mnb->priv->active_notebook) + { + gint page_num; + + mnb->priv->active_notebook = GTK_WIDGET (container); + + page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (container)); + notebook_switch_page (GTK_NOTEBOOK (container), NULL, + page_num, mnb); + + g_object_notify_by_pspec (G_OBJECT (mnb), properties[PROP_ACTIVE_NOTEBOOK]); + } +} + +static void +show_tabs_changed (GObject *object, + GParamSpec *pspec, + gpointer *data) +{ + update_tabs_visibility (GEDIT_MULTI_NOTEBOOK (data)); +} + +static void +update_tabs_visibility (GeditMultiNotebook *mnb) +{ + gboolean show_tabs; + GList *l; + + if (mnb->priv->notebooks == NULL) + return; + + if (!mnb->priv->show_tabs) + { + show_tabs = FALSE; + } + else if (mnb->priv->notebooks->next == NULL) /* only one notebook */ + { + switch (mnb->priv->show_tabs_mode) + { + case GEDIT_NOTEBOOK_SHOW_TABS_NEVER: + show_tabs = FALSE; + break; + case GEDIT_NOTEBOOK_SHOW_TABS_AUTO: + show_tabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (mnb->priv->notebooks->data)) > 1; + break; + case GEDIT_NOTEBOOK_SHOW_TABS_ALWAYS: + default: + show_tabs = TRUE; + break; + } + } + else + { + show_tabs = (mnb->priv->show_tabs_mode != GEDIT_NOTEBOOK_SHOW_TABS_NEVER); + } + + g_signal_handlers_block_by_func (mnb, show_tabs_changed, NULL); + + for (l = mnb->priv->notebooks; l != NULL; l = l->next) + { + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (l->data), show_tabs); + } + + g_signal_handlers_unblock_by_func (mnb, show_tabs_changed, NULL); +} + +static void +connect_notebook_signals (GeditMultiNotebook *mnb, + GtkWidget *notebook) +{ + g_signal_connect (notebook, + "set-focus-child", + G_CALLBACK (notebook_set_focus), + mnb); + g_signal_connect (notebook, + "page-added", + G_CALLBACK (notebook_page_added), + mnb); + g_signal_connect (notebook, + "page-removed", + G_CALLBACK (notebook_page_removed), + mnb); + g_signal_connect (notebook, + "switch-page", + G_CALLBACK (notebook_switch_page), + mnb); + g_signal_connect (notebook, + "page-reordered", + G_CALLBACK (notebook_page_reordered), + mnb); + g_signal_connect (notebook, + "create-window", + G_CALLBACK (notebook_create_window), + mnb); + g_signal_connect (notebook, + "tab-close-request", + G_CALLBACK (notebook_tab_close_request), + mnb); + g_signal_connect (notebook, + "show-popup-menu", + G_CALLBACK (notebook_show_popup_menu), + mnb); + g_signal_connect (notebook, + "notify::show-tabs", + G_CALLBACK (show_tabs_changed), + mnb); +} + +static void +disconnect_notebook_signals (GeditMultiNotebook *mnb, + GtkWidget *notebook) +{ + g_signal_handlers_disconnect_by_func (notebook, notebook_set_focus, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_switch_page, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_page_added, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_page_removed, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_page_reordered, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_create_window, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_tab_close_request, + mnb); + g_signal_handlers_disconnect_by_func (notebook, notebook_show_popup_menu, + mnb); + g_signal_handlers_disconnect_by_func (notebook, show_tabs_changed, + mnb); +} + +static void +add_notebook (GeditMultiNotebook *mnb, + GtkWidget *notebook, + gboolean main_container) +{ + gtk_widget_set_hexpand (notebook, TRUE); + gtk_widget_set_vexpand (notebook, TRUE); + + if (main_container) + { + gtk_container_add (GTK_CONTAINER (mnb), notebook); + + mnb->priv->notebooks = g_list_append (mnb->priv->notebooks, + notebook); + } + else + { + GtkWidget *paned; + GtkWidget *parent; + GtkAllocation allocation; + GtkWidget *active_notebook = mnb->priv->active_notebook; + gint active_nb_pos; + + paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_show (paned); + + /* First we remove the active container from its parent to make + this we add a ref to it*/ + g_object_ref (active_notebook); + parent = gtk_widget_get_parent (active_notebook); + gtk_widget_get_allocation (active_notebook, &allocation); + + gtk_container_remove (GTK_CONTAINER (parent), active_notebook); + gtk_container_add (GTK_CONTAINER (parent), paned); + + gtk_paned_pack1 (GTK_PANED (paned), active_notebook, TRUE, FALSE); + g_object_unref (active_notebook); + + gtk_paned_pack2 (GTK_PANED (paned), notebook, FALSE, FALSE); + + /* We need to set the new paned in the right place */ + gtk_paned_set_position (GTK_PANED (paned), + allocation.width / 2); + + active_nb_pos = g_list_index (mnb->priv->notebooks, + active_notebook); + mnb->priv->notebooks = g_list_insert (mnb->priv->notebooks, + notebook, + active_nb_pos + 1); + } + + gtk_widget_show (notebook); + + connect_notebook_signals (mnb, notebook); + + g_signal_emit (G_OBJECT (mnb), signals[NOTEBOOK_ADDED], 0, notebook); +} + +static void +remove_notebook (GeditMultiNotebook *mnb, + GtkWidget *notebook) +{ + GtkWidget *parent; + GtkWidget *grandpa; + GList *children; + GtkWidget *new_notebook; + GList *current; + + if (mnb->priv->notebooks->next == NULL) + { + g_warning ("You are trying to remove the main notebook"); + return; + } + + current = g_list_find (mnb->priv->notebooks, + notebook); + + if (current->next != NULL) + { + new_notebook = GTK_WIDGET (current->next->data); + } + else + { + new_notebook = GTK_WIDGET (mnb->priv->notebooks->data); + } + + parent = gtk_widget_get_parent (notebook); + + /* Now we destroy the widget, we get the children of parent and we destroy + parent too as the parent is an useless paned. Finally we add the child + into the grand parent */ + g_object_ref (notebook); + mnb->priv->removing_notebook = TRUE; + + gtk_widget_destroy (notebook); + + mnb->priv->notebooks = g_list_remove (mnb->priv->notebooks, + notebook); + + mnb->priv->removing_notebook = FALSE; + + children = gtk_container_get_children (GTK_CONTAINER (parent)); + if (children->next != NULL) + { + g_warning ("The parent is not a paned"); + return; + } + grandpa = gtk_widget_get_parent (parent); + + g_object_ref (children->data); + gtk_container_remove (GTK_CONTAINER (parent), + GTK_WIDGET (children->data)); + gtk_widget_destroy (parent); + gtk_container_add (GTK_CONTAINER (grandpa), + GTK_WIDGET (children->data)); + g_object_unref (children->data); + g_list_free (children); + + disconnect_notebook_signals (mnb, notebook); + + g_signal_emit (G_OBJECT (mnb), signals[NOTEBOOK_REMOVED], 0, notebook); + g_object_unref (notebook); + + /* Let's make the active notebook grab the focus */ + gtk_widget_grab_focus (new_notebook); +} + +static void +gedit_multi_notebook_init (GeditMultiNotebook *mnb) +{ + GeditMultiNotebookPrivate *priv; + + mnb->priv = gedit_multi_notebook_get_instance_private (mnb); + priv = mnb->priv; + + priv->removing_notebook = FALSE; + + gtk_orientable_set_orientation (GTK_ORIENTABLE (mnb), + GTK_ORIENTATION_VERTICAL); + + priv->show_tabs_mode = GEDIT_NOTEBOOK_SHOW_TABS_ALWAYS; + priv->show_tabs = TRUE; + + priv->ui_settings = g_settings_new ("org.gnome.gedit.preferences.ui"); + g_settings_bind (priv->ui_settings, + GEDIT_SETTINGS_SHOW_TABS_MODE, + mnb, + "show-tabs-mode", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + priv->active_notebook = gedit_notebook_new (); + add_notebook (mnb, priv->active_notebook, TRUE); +} + +GeditMultiNotebook * +gedit_multi_notebook_new () +{ + return g_object_new (GEDIT_TYPE_MULTI_NOTEBOOK, NULL); +} + +GeditNotebook * +gedit_multi_notebook_get_active_notebook (GeditMultiNotebook *mnb) +{ + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL); + + return GEDIT_NOTEBOOK (mnb->priv->active_notebook); +} + +gint +gedit_multi_notebook_get_n_notebooks (GeditMultiNotebook *mnb) +{ + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), 0); + + return g_list_length (mnb->priv->notebooks); +} + +GeditNotebook * +gedit_multi_notebook_get_nth_notebook (GeditMultiNotebook *mnb, + gint notebook_num) +{ + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL); + + return g_list_nth_data (mnb->priv->notebooks, notebook_num); +} + +GeditNotebook * +gedit_multi_notebook_get_notebook_for_tab (GeditMultiNotebook *mnb, + GeditTab *tab) +{ + GList *l; + gint page_num; + + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL); + g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL); + + l = mnb->priv->notebooks; + + do + { + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (l->data), + GTK_WIDGET (tab)); + if (page_num != -1) + break; + + l = g_list_next (l); + } while (l != NULL && page_num == -1); + + g_return_val_if_fail (page_num != -1, NULL); + + return GEDIT_NOTEBOOK (l->data); +} + +gint +gedit_multi_notebook_get_notebook_num (GeditMultiNotebook *mnb, + GeditNotebook *notebook) +{ + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), -1); + g_return_val_if_fail (GEDIT_IS_NOTEBOOK (notebook), -1); + + return g_list_index (mnb->priv->notebooks, notebook); +} + +gint +gedit_multi_notebook_get_n_tabs (GeditMultiNotebook *mnb) +{ + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), 0); + + return mnb->priv->total_tabs; +} + +gint +gedit_multi_notebook_get_page_num (GeditMultiNotebook *mnb, + GeditTab *tab) +{ + GList *l; + gint real_page_num = 0; + + for (l = mnb->priv->notebooks; l != NULL; l = g_list_next (l)) + { + gint page_num; + + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (l->data), + GTK_WIDGET (tab)); + + if (page_num != -1) + { + real_page_num += page_num; + break; + } + + real_page_num += gtk_notebook_get_n_pages (GTK_NOTEBOOK (l->data)); + } + + return real_page_num; +} + +GeditTab * +gedit_multi_notebook_get_active_tab (GeditMultiNotebook *mnb) +{ + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL); + + return (mnb->priv->active_tab == NULL) ? + NULL : GEDIT_TAB (mnb->priv->active_tab); +} + +void +gedit_multi_notebook_set_active_tab (GeditMultiNotebook *mnb, + GeditTab *tab) +{ + GList *l; + gint page_num; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + g_return_if_fail (GEDIT_IS_TAB (tab) || tab == NULL); + + /* use plain C cast since the active tab can be null */ + if (tab == (GeditTab *) mnb->priv->active_tab) + { + return; + } + + if (tab == NULL) + { + set_active_tab (mnb, NULL); + return; + } + + l = mnb->priv->notebooks; + + do + { + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (l->data), + GTK_WIDGET (tab)); + if (page_num != -1) + break; + + l = g_list_next (l); + } while (l != NULL && page_num == -1); + + g_return_if_fail (page_num != -1); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (l->data), page_num); + + if (GTK_WIDGET (l->data) != mnb->priv->active_notebook) + { + gtk_widget_grab_focus (GTK_WIDGET (l->data)); + } +} + +void +gedit_multi_notebook_set_current_page (GeditMultiNotebook *mnb, + gint page_num) +{ + GList *l; + gint pages = 0; + gint single_num = page_num; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + for (l = mnb->priv->notebooks; l != NULL; l = g_list_next (l)) + { + gint p; + + p = gtk_notebook_get_n_pages (GTK_NOTEBOOK (l->data)); + pages += p; + + if ((pages - 1) >= page_num) + break; + + single_num -= p; + } + + if (l == NULL) + return; + + if (GTK_WIDGET (l->data) != mnb->priv->active_notebook) + { + gtk_widget_grab_focus (GTK_WIDGET (l->data)); + } + + gtk_notebook_set_current_page (GTK_NOTEBOOK (l->data), single_num); +} + +GList * +gedit_multi_notebook_get_all_tabs (GeditMultiNotebook *mnb) +{ + GList *nbs; + GList *ret = NULL; + + g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL); + + for (nbs = mnb->priv->notebooks; nbs != NULL; nbs = g_list_next (nbs)) + { + GList *l, *children; + + children = gtk_container_get_children (GTK_CONTAINER (nbs->data)); + + for (l = children; l != NULL; l = g_list_next (l)) + { + ret = g_list_prepend (ret, l->data); + } + + g_list_free (children); + } + + ret = g_list_reverse (ret); + + return ret; +} + +void +gedit_multi_notebook_close_tabs (GeditMultiNotebook *mnb, + const GList *tabs) +{ + GList *l; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + for (l = (GList *)tabs; l != NULL; l = g_list_next (l)) + { + GList *nbs; + + for (nbs = mnb->priv->notebooks; nbs != NULL; nbs = g_list_next (nbs)) + { + gint n; + + n = gtk_notebook_page_num (GTK_NOTEBOOK (nbs->data), + GTK_WIDGET (l->data)); + + if (n != -1) + { + gtk_container_remove (GTK_CONTAINER (nbs->data), + GTK_WIDGET (l->data)); + break; + } + } + } +} + +/** + * gedit_multi_notebook_close_all_tabs: + * @mnb: a #GeditMultiNotebook + * + * Closes all opened tabs. + */ +void +gedit_multi_notebook_close_all_tabs (GeditMultiNotebook *mnb) +{ + GList *nbs, *l; + + g_return_if_fail (GEDIT_MULTI_NOTEBOOK (mnb)); + + /* We copy the list because the main one is going to have the items + removed */ + nbs = g_list_copy (mnb->priv->notebooks); + + for (l = nbs; l != NULL; l = g_list_next (l)) + { + gedit_notebook_remove_all_tabs (GEDIT_NOTEBOOK (l->data)); + } + + g_list_free (nbs); +} + +void +gedit_multi_notebook_add_new_notebook (GeditMultiNotebook *mnb) +{ + GtkWidget *notebook; + GeditTab *tab; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + notebook = gedit_notebook_new (); + add_notebook (mnb, notebook, FALSE); + + tab = _gedit_tab_new (); + gtk_widget_show (GTK_WIDGET (tab)); + + /* When gtk_notebook_insert_page is called the focus is set in + the notebook, we don't want this to happen until the page is added. + Also we don't want to call switch_page when we add the tab + but when we switch the notebook. */ + g_signal_handlers_block_by_func (notebook, notebook_set_focus, mnb); + g_signal_handlers_block_by_func (notebook, notebook_switch_page, mnb); + + gedit_notebook_add_tab (GEDIT_NOTEBOOK (notebook), + tab, + -1, + TRUE); + + g_signal_handlers_unblock_by_func (notebook, notebook_switch_page, mnb); + g_signal_handlers_unblock_by_func (notebook, notebook_set_focus, mnb); + + notebook_set_focus (GTK_CONTAINER (notebook), NULL, mnb); +} + +void +gedit_multi_notebook_add_new_notebook_with_tab (GeditMultiNotebook *mnb, + GeditTab *tab) +{ + GtkWidget *notebook; + GeditNotebook *old_notebook; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + g_return_if_fail (GEDIT_IS_TAB (tab)); + + notebook = gedit_notebook_new (); + add_notebook (mnb, notebook, FALSE); + + old_notebook = gedit_multi_notebook_get_notebook_for_tab (mnb, tab); + + /* When gtk_notebook_insert_page is called the focus is set in + the notebook, we don't want this to happen until the page is added. + Also we don't want to call switch_page when we add the tab + but when we switch the notebook. */ + g_signal_handlers_block_by_func (old_notebook, notebook_set_focus, mnb); + g_signal_handlers_block_by_func (old_notebook, notebook_switch_page, mnb); + + gedit_notebook_move_tab (old_notebook, + GEDIT_NOTEBOOK (notebook), + tab, + -1); + + g_signal_handlers_unblock_by_func (old_notebook, notebook_switch_page, mnb); + g_signal_handlers_unblock_by_func (old_notebook, notebook_set_focus, mnb); + + notebook_set_focus (GTK_CONTAINER (notebook), NULL, mnb); +} + +void +gedit_multi_notebook_remove_active_notebook (GeditMultiNotebook *mnb) +{ + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + gedit_notebook_remove_all_tabs (GEDIT_NOTEBOOK (mnb->priv->active_notebook)); +} + +void +gedit_multi_notebook_previous_notebook (GeditMultiNotebook *mnb) +{ + GList *current; + GtkWidget *notebook; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + current = g_list_find (mnb->priv->notebooks, + mnb->priv->active_notebook); + + if (current->prev != NULL) + notebook = GTK_WIDGET (current->prev->data); + else + notebook = GTK_WIDGET (g_list_last (mnb->priv->notebooks)->data); + + gtk_widget_grab_focus (notebook); +} + +void +gedit_multi_notebook_next_notebook (GeditMultiNotebook *mnb) +{ + GList *current; + GtkWidget *notebook; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + current = g_list_find (mnb->priv->notebooks, + mnb->priv->active_notebook); + + if (current->next != NULL) + notebook = GTK_WIDGET (current->next->data); + else + notebook = GTK_WIDGET (mnb->priv->notebooks->data); + + gtk_widget_grab_focus (notebook); +} + +void +gedit_multi_notebook_foreach_notebook (GeditMultiNotebook *mnb, + GtkCallback callback, + gpointer callback_data) +{ + GList *l; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + for (l = mnb->priv->notebooks; l != NULL; l = g_list_next (l)) + { + callback (GTK_WIDGET (l->data), callback_data); + } +} + +void +gedit_multi_notebook_foreach_tab (GeditMultiNotebook *mnb, + GtkCallback callback, + gpointer callback_data) +{ + GList *nb; + + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + for (nb = mnb->priv->notebooks; nb != NULL; nb = g_list_next (nb)) + { + GList *l, *children; + + children = gtk_container_get_children (GTK_CONTAINER (nb->data)); + + for (l = children; l != NULL; l = g_list_next (l)) + { + callback (GTK_WIDGET (l->data), callback_data); + } + + g_list_free (children); + } +} + +/* We only use this to hide tabs in fullscreen mode so for now + * we do not have a real property etc. + */ +void +_gedit_multi_notebook_set_show_tabs (GeditMultiNotebook *mnb, + gboolean show) +{ + g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb)); + + mnb->priv->show_tabs = show != FALSE; + + update_tabs_visibility (mnb); +} + +/* ex:set ts=8 noet: */ -- cgit v1.2.3