[gedit] Add a fake notebook stack switcher



commit 09a7f9f3eba48f0d0ba58772921f70fa290c2e0a
Author: Paolo Borelli <pborelli gnome org>
Date:   Thu May 1 16:22:04 2014 +0200

    Add a fake notebook stack switcher
    
    Add a stack switcher that it is actually implemented with a notebook
    and empty pages. This is needed to make the bottom pane switcher look
    like a real notebook but expose GtkStack in the API.
    Hopefully this will be replaced by a real tabs stack switcher in Gtk.

 gedit/Makefile.am                     |    2 +
 gedit/gedit-notebook-stack-switcher.c |  345 +++++++++++++++++++++++++++++++++
 gedit/gedit-notebook-stack-switcher.h |   71 +++++++
 gedit/gedit-window.ui                 |    2 +-
 4 files changed, 419 insertions(+), 1 deletions(-)
---
diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index 71e19f2..23152c5 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -114,6 +114,7 @@ gedit_NOINST_H_FILES =                              \
        gedit/gedit-multi-notebook.h            \
        gedit/gedit-notebook.h                  \
        gedit/gedit-notebook-popup-menu.h       \
+       gedit/gedit-notebook-stack-switcher.h   \
        gedit/gedit-plugins-engine.h            \
        gedit/gedit-preferences-dialog.h        \
        gedit/gedit-print-job.h                 \
@@ -191,6 +192,7 @@ gedit_libgedit_c_files =                    \
        gedit/gedit-multi-notebook.c            \
        gedit/gedit-notebook.c                  \
        gedit/gedit-notebook-popup-menu.c       \
+       gedit/gedit-notebook-stack-switcher.c   \
        gedit/gedit-plugins-engine.c            \
        gedit/gedit-preferences-dialog.c        \
        gedit/gedit-print-job.c                 \
diff --git a/gedit/gedit-notebook-stack-switcher.c b/gedit/gedit-notebook-stack-switcher.c
new file mode 100644
index 0000000..a0cc449
--- /dev/null
+++ b/gedit/gedit-notebook-stack-switcher.c
@@ -0,0 +1,345 @@
+/*
+ * gedit-notebook-stack-switcher.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Paolo Borelli
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include "gedit-notebook-stack-switcher.h"
+
+/*
+ * This widget is a rather ugly kludge: it uses a GtkNotebook full of empty
+ * pages to create a stack switcher for the bottom pane. This is needed
+ * because we want to expose GtkStack in the API but we want the tabs styled
+ * as notebook tabs. Hopefully Gtk itself will grow a "tabs" stack switcher...
+ */
+
+struct _GeditNotebookStackSwitcherPrivate
+{
+       GtkWidget *notebook;
+       GtkStack *stack;
+};
+
+enum {
+       PROP_0,
+       PROP_STACK
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GeditNotebookStackSwitcher, gedit_notebook_stack_switcher, GTK_TYPE_BIN)
+
+static void
+gedit_notebook_stack_switcher_init (GeditNotebookStackSwitcher *switcher)
+{
+       GeditNotebookStackSwitcherPrivate *priv;
+
+       priv = gedit_notebook_stack_switcher_get_instance_private (switcher);
+       switcher->priv = priv;
+
+       priv->notebook = gtk_notebook_new ();
+
+       gtk_notebook_set_tab_pos (GTK_NOTEBOOK (priv->notebook), GTK_POS_BOTTOM);
+       gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
+       gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
+       gtk_container_set_border_width (GTK_CONTAINER (priv->notebook), 0);
+
+       gtk_widget_show (priv->notebook);
+       gtk_container_add (GTK_CONTAINER (switcher), priv->notebook);
+}
+
+static GtkWidget *
+find_notebook_child (GeditNotebookStackSwitcher *switcher,
+                    GtkWidget                  *stack_child)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+       GList *pages;
+       GList *p;
+       GtkWidget *ret = NULL;
+
+       if (stack_child == NULL)
+       {
+               return NULL;
+       }
+
+       pages = gtk_container_get_children (GTK_CONTAINER (priv->notebook));
+       for (p = pages; p != NULL; p = p->next)
+       {
+               GtkWidget *child;
+
+               child = g_object_get_data (p->data, "stack-child");
+               if (stack_child == child)
+               {
+                       ret = p->data;
+                       break;
+               }
+       }
+
+       g_list_free (pages);
+
+       return ret;
+}
+
+static void
+sync_label (GeditNotebookStackSwitcher *switcher,
+           GtkWidget                  *stack_child,
+           GtkWidget                  *notebook_child)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+
+       if (stack_child != NULL && notebook_child != NULL)
+       {
+               gchar *title;
+
+               gtk_widget_set_visible (notebook_child,
+                                       gtk_widget_get_visible (stack_child));
+
+               gtk_container_child_get (GTK_CONTAINER (priv->stack), stack_child,
+                                        "title", &title,
+                                        NULL);
+
+               gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (priv->notebook),
+                                                notebook_child,
+                                                title);
+
+               g_free (title);
+       }
+}
+
+static void
+on_child_prop_changed (GtkWidget                  *widget,
+                       GParamSpec                 *pspec,
+                       GeditNotebookStackSwitcher *switcher)
+{
+       GtkWidget *nb_child;
+
+       nb_child = find_notebook_child (switcher, widget);
+       sync_label (switcher, widget, nb_child);
+}
+
+static void
+on_child_changed (GtkWidget                  *widget,
+                  GParamSpec                 *pspec,
+                  GeditNotebookStackSwitcher *switcher)
+{
+       GtkWidget *child;
+       GtkWidget *nb_child;
+
+       child = gtk_stack_get_visible_child (GTK_STACK (widget));
+       nb_child = find_notebook_child (switcher, child);
+       sync_label (switcher, child, nb_child);
+}
+
+static void
+on_stack_child_added (GtkStack                   *stack,
+                      GtkWidget                  *widget,
+                      GeditNotebookStackSwitcher *switcher)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+       GtkWidget *dummy;
+
+       dummy = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+       g_object_set_data (G_OBJECT (dummy), "stack-child", widget);
+       gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+                                 dummy,
+                                 NULL);
+
+       g_signal_connect (widget, "notify::visible",
+                         G_CALLBACK (on_child_prop_changed), switcher);
+       g_signal_connect (widget, "child-notify::title",
+                         G_CALLBACK (on_child_prop_changed), switcher);
+
+       sync_label (switcher, widget, dummy);
+}
+
+static void
+on_stack_child_removed (GtkStack                   *stack,
+                        GtkWidget                  *widget,
+                        GeditNotebookStackSwitcher *switcher)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+       GtkWidget *nb_child;
+
+       g_signal_handlers_disconnect_by_func (widget, on_child_prop_changed, switcher);
+
+       nb_child = find_notebook_child (switcher, widget);
+       gtk_container_remove (GTK_CONTAINER (priv->notebook), nb_child);
+}
+
+static void
+on_notebook_switch_page (GtkNotebook                *notebook,
+                         GtkWidget                  *page,
+                         guint                       page_num,
+                         GeditNotebookStackSwitcher *switcher)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+       GtkWidget *child;
+
+       child = g_object_get_data (G_OBJECT (page), "stack-child");
+       if (child != NULL)
+       {
+               gtk_stack_set_visible_child (priv->stack, child);
+       }
+}
+
+static void
+disconnect_signals (GeditNotebookStackSwitcher *switcher)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+
+       g_signal_handlers_disconnect_by_func (priv->stack, on_stack_child_added, switcher);
+       g_signal_handlers_disconnect_by_func (priv->stack, on_stack_child_removed, switcher);
+       g_signal_handlers_disconnect_by_func (priv->stack, on_child_changed, switcher);
+       g_signal_handlers_disconnect_by_func (priv->stack, disconnect_signals, switcher);
+       g_signal_handlers_disconnect_by_func (priv->notebook, on_notebook_switch_page, switcher);
+}
+
+static void
+connect_signals (GeditNotebookStackSwitcher *switcher)
+{
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+
+       g_signal_connect (priv->stack, "add",
+                         G_CALLBACK (on_stack_child_added), switcher);
+       g_signal_connect (priv->stack, "remove",
+                         G_CALLBACK (on_stack_child_removed), switcher);
+       g_signal_connect (priv->stack, "notify::visible-child",
+                         G_CALLBACK (on_child_changed), switcher);
+       g_signal_connect_swapped (priv->stack, "destroy",
+                                 G_CALLBACK (disconnect_signals), switcher);
+       g_signal_connect (priv->notebook, "switch-page",
+                         G_CALLBACK (on_notebook_switch_page), switcher);
+}
+
+void
+gedit_notebook_stack_switcher_set_stack (GeditNotebookStackSwitcher *switcher,
+                                         GtkStack                   *stack)
+{
+       GeditNotebookStackSwitcherPrivate *priv;
+
+       g_return_if_fail (GEDIT_IS_NOTEBOOK_STACK_SWITCHER (switcher));
+       g_return_if_fail (stack == NULL || GTK_IS_STACK (stack));
+
+       priv = switcher->priv;
+
+       if (priv->stack == stack)
+               return;
+
+       if (priv->stack)
+       {
+               disconnect_signals (switcher);
+               g_clear_object (&priv->stack);
+       }
+
+       if (stack)
+       {
+               priv->stack = g_object_ref (stack);
+               connect_signals (switcher);
+       }
+
+       g_object_notify (G_OBJECT (switcher), "stack");
+}
+
+GtkStack *
+gedit_notebook_stack_switcher_get_stack (GeditNotebookStackSwitcher *switcher)
+{
+       g_return_val_if_fail (GEDIT_IS_NOTEBOOK_STACK_SWITCHER (switcher), NULL);
+
+       return switcher->priv->stack;
+}
+
+static void
+gedit_notebook_stack_switcher_get_property (GObject    *object,
+                                            guint       prop_id,
+                                            GValue     *value,
+                                            GParamSpec *pspec)
+{
+       GeditNotebookStackSwitcher *switcher = GEDIT_NOTEBOOK_STACK_SWITCHER (object);
+       GeditNotebookStackSwitcherPrivate *priv = switcher->priv;
+
+       switch (prop_id)
+       {
+               case PROP_STACK:
+                       g_value_set_object (value, priv->stack);
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+gedit_notebook_stack_switcher_set_property (GObject      *object,
+                                            guint         prop_id,
+                                            const GValue *value,
+                                            GParamSpec   *pspec)
+{
+       GeditNotebookStackSwitcher *switcher = GEDIT_NOTEBOOK_STACK_SWITCHER (object);
+
+       switch (prop_id)
+       {
+               case PROP_STACK:
+                       gedit_notebook_stack_switcher_set_stack (switcher, g_value_get_object (value));
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+gedit_notebook_stack_switcher_dispose (GObject *object)
+{
+       GeditNotebookStackSwitcher *switcher = GEDIT_NOTEBOOK_STACK_SWITCHER (object);
+
+       gedit_notebook_stack_switcher_set_stack (switcher, NULL);
+
+       G_OBJECT_CLASS (gedit_notebook_stack_switcher_parent_class)->dispose (object);
+}
+
+static void
+gedit_notebook_stack_switcher_class_init (GeditNotebookStackSwitcherClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->get_property = gedit_notebook_stack_switcher_get_property;
+       object_class->set_property = gedit_notebook_stack_switcher_set_property;
+       object_class->dispose = gedit_notebook_stack_switcher_dispose;
+
+       g_object_class_install_property (object_class,
+                                        PROP_STACK,
+                                        g_param_spec_object ("stack",
+                                                             "Stack",
+                                                             "Stack",
+                                                             GTK_TYPE_STACK,
+                                                             G_PARAM_READWRITE |
+                                                             G_PARAM_CONSTRUCT));
+}
+
+GtkWidget *
+gedit_notebook_stack_switcher_new (void)
+{
+       return g_object_new (GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER, NULL);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/gedit/gedit-notebook-stack-switcher.h b/gedit/gedit-notebook-stack-switcher.h
new file mode 100644
index 0000000..96cca0d
--- /dev/null
+++ b/gedit/gedit-notebook-stack-switcher.h
@@ -0,0 +1,71 @@
+/*
+ * gedit-notebook-stack-switcher.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Paolo Borelli
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GEDIT_NOTEBOOK_STACK_SWITCHER_H__
+#define __GEDIT_NOTEBOOK_STACK_SWITCHER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER             (gedit_notebook_stack_switcher_get_type())
+#define GEDIT_NOTEBOOK_STACK_SWITCHER(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), 
GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER, GeditNotebookStackSwitcher))
+#define GEDIT_NOTEBOOK_STACK_SWITCHER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), 
GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER, GeditNotebookStackSwitcherClass))
+#define GEDIT_IS_NOTEBOOK_STACK_SWITCHER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), 
GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER))
+#define GEDIT_IS_NOTEBOOK_STACK_SWITCHER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER))
+#define GEDIT_NOTEBOOK_STACK_SWITCHER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), 
GEDIT_TYPE_NOTEBOOK_STACK_SWITCHER, GeditNotebookStackSwitcherClass))
+
+typedef struct _GeditNotebookStackSwitcher        GeditNotebookStackSwitcher;
+typedef struct _GeditNotebookStackSwitcherClass   GeditNotebookStackSwitcherClass;
+typedef struct _GeditNotebookStackSwitcherPrivate GeditNotebookStackSwitcherPrivate;
+
+struct _GeditNotebookStackSwitcher
+{
+       GtkBin parent;
+
+       /*< private >*/
+       GeditNotebookStackSwitcherPrivate *priv;
+};
+
+struct _GeditNotebookStackSwitcherClass
+{
+       GtkBinClass parent_class;
+
+       /* Padding for future expansion */
+       void (*_gedit_reserved1) (void);
+       void (*_gedit_reserved2) (void);
+       void (*_gedit_reserved3) (void);
+       void (*_gedit_reserved4) (void);
+};
+
+GType           gedit_notebook_stack_switcher_get_type   (void) G_GNUC_CONST;
+
+GtkWidget      *gedit_notebook_stack_switcher_new        (void);
+
+void            gedit_notebook_stack_switcher_set_stack  (GeditNotebookStackSwitcher *switcher,
+                                                          GtkStack                   *stack);
+
+GtkStack       *gedit_notebook_stack_switcher_get_stack  (GeditNotebookStackSwitcher *switcher);
+
+G_END_DECLS
+
+#endif  /* __GEDIT_NOTEBOOK_STACK_SWITCHER_H__  */
+
+/* ex:set ts=8 noet: */
diff --git a/gedit/gedit-window.ui b/gedit/gedit-window.ui
index ee7dc73..6e19771 100644
--- a/gedit/gedit-window.ui
+++ b/gedit/gedit-window.ui
@@ -226,7 +226,7 @@
                                   </packing>
                                 </child>
                                 <child>
-                                  <object class="GtkStackSwitcher" id="bottom_panel_stack_switcher">
+                                  <object class="GeditNotebookStackSwitcher" 
id="bottom_panel_stack_switcher">
                                     <property name="visible">True</property>
                                     <property name="stack">bottom_panel</property>
                                     <style>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]