[anjuta] libanjuta: Add AnjutaTabber widget which allows to use native looking tabs in gdl window titles
- From: Johannes Schmid <jhs src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta] libanjuta: Add AnjutaTabber widget which allows to use native looking tabs in gdl window titles
- Date: Mon, 5 Apr 2010 17:08:35 +0000 (UTC)
commit 62c61319d4230b76f5996cbbe8333a741231f9b9
Author: Johannes Schmid <jhs gnome org>
Date: Mon Apr 5 14:25:27 2010 +0200
libanjuta: Add AnjutaTabber widget which allows to use native looking tabs in gdl window titles
libanjuta/Makefile.am | 7 +-
libanjuta/anjuta-tabber.c | 504 +++++++++++++++++++++++++++++++++++++++++++++
libanjuta/anjuta-tabber.h | 57 +++++
3 files changed, 566 insertions(+), 2 deletions(-)
---
diff --git a/libanjuta/Makefile.am b/libanjuta/Makefile.am
index 15994d5..2a8742d 100644
--- a/libanjuta/Makefile.am
+++ b/libanjuta/Makefile.am
@@ -83,7 +83,9 @@ libanjuta_la_SOURCES= \
anjuta-command-queue.c \
anjuta-command-queue.h \
anjuta-project.c \
- anjuta-project.h
+ anjuta-project.h \
+ anjuta-tabber.c \
+ anjuta-tabber.h
if HAVE_PLUGIN_GLADE
@@ -143,7 +145,8 @@ libanjuta_include = \
anjuta-version.h \
gbf-project.h \
anjuta-project.h \
- anjuta-command-queue.h
+ anjuta-command-queue.h \
+ anjuta-tabber.h
libanjutainclude_HEADERS = \
$(libanjuta_include) \
diff --git a/libanjuta/anjuta-tabber.c b/libanjuta/anjuta-tabber.c
new file mode 100644
index 0000000..13c9860
--- /dev/null
+++ b/libanjuta/anjuta-tabber.c
@@ -0,0 +1,504 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta-notebook-tabber
+ * Copyright (C) Johannes Schmid 2010 <jhs gnome org>
+ *
+ * anjuta-notebook-tabber 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * anjuta-notebook-tabber 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/>.
+ */
+
+#include "anjuta-tabber.h"
+
+struct _AnjutaTabberPriv
+{
+ GtkNotebook* notebook;
+ GList* children;
+ gint active_page;
+
+ GdkWindow* event_window;
+};
+
+enum
+{
+ PROP_0,
+ PROP_NOTEBOOK
+};
+
+#define ANJUTA_TABBER_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), ANJUTA_TYPE_TABBER, AnjutaTabberPriv))
+
+
+G_DEFINE_TYPE (AnjutaTabber, anjuta_tabber, GTK_TYPE_CONTAINER);
+
+static void
+anjuta_tabber_init (AnjutaTabber *object)
+{
+ AnjutaTabber* tabber = ANJUTA_TABBER (object);
+ tabber->priv = ANJUTA_TABBER_GET_PRIVATE (tabber);
+ tabber->priv->children = NULL;
+ tabber->priv->active_page = 0;
+
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET(tabber), GTK_NO_WINDOW);
+}
+
+static void
+anjuta_tabber_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (anjuta_tabber_parent_class)->finalize (object);
+}
+
+/**
+ * anjuta_tabber_notebook_page_removed:
+ *
+ * Called when a page is removed from the associated notebook. Removes
+ * the tab for this page
+ */
+static void
+anjuta_tabber_notebook_page_removed (GtkNotebook* notebook,
+ GtkWidget* notebook_child,
+ gint page_num,
+ AnjutaTabber* tabber)
+{
+ GtkWidget* child = g_list_nth_data (tabber->priv->children, page_num);
+ gtk_container_remove (GTK_CONTAINER (tabber), child);
+}
+
+static void
+anjuta_tabber_notebook_switch_page (GtkNotebook* notebook,
+ GtkNotebookPage* page,
+ guint page_num,
+ AnjutaTabber* tabber)
+{
+ tabber->priv->active_page = page_num;
+ gtk_widget_queue_draw (GTK_WIDGET (tabber));
+}
+
+/**
+ * anjuta_tabber_connect_notebook:
+ *
+ * Connect signals to associated notebook
+ *
+ */
+static void
+anjuta_tabber_connect_notebook (AnjutaTabber* tabber)
+{
+ g_signal_connect (tabber->priv->notebook, "page-removed",
+ G_CALLBACK(anjuta_tabber_notebook_page_removed), tabber);
+ g_signal_connect (tabber->priv->notebook, "switch-page",
+ G_CALLBACK(anjuta_tabber_notebook_switch_page), tabber);
+
+}
+
+static void
+anjuta_tabber_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (object));
+
+ AnjutaTabber* tabber = ANJUTA_TABBER (object);
+
+ switch (prop_id)
+ {
+ case PROP_NOTEBOOK:
+ tabber->priv->notebook = g_value_get_object (value);
+ anjuta_tabber_connect_notebook (tabber);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+anjuta_tabber_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (object));
+
+ switch (prop_id)
+ {
+ case PROP_NOTEBOOK:
+ g_value_set_object (value, object);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * anjuta_tabber_get_padding:
+ * @widget: a AnjutaTabber widget
+ *
+ * Receives the padding from the widget style
+ *
+ * Returns: the padding used for the tabs
+ */
+static gint
+anjuta_tabber_get_padding(GtkWidget* widget)
+{
+ gint focus_width;
+ gint tab_border = gtk_container_get_border_width (GTK_CONTAINER(widget));
+ gint padding;
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ NULL);
+
+ padding = 2 * (focus_width + tab_border);
+ return padding;
+}
+
+static void
+anjuta_tabber_size_request(GtkWidget* widget, GtkRequisition* req)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (widget));
+
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+ GList* child;
+ gint padding = anjuta_tabber_get_padding (widget);
+
+ for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
+ {
+ GtkRequisition child_req;
+ gtk_widget_size_request (GTK_WIDGET (child->data), &child_req);
+ req->width += child_req.width + 2 * widget->style->xthickness + padding;
+ req->height = MAX(req->height, child_req.height + 2 * widget->style->ythickness);
+ }
+}
+
+static void
+anjuta_tabber_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (widget));
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+
+ GList* child;
+ gint x = allocation->x;
+ gint y = allocation->y;
+ gint padding = anjuta_tabber_get_padding (widget);
+ gint child_width;
+ gint n_children = g_list_length (tabber->priv->children);
+
+ widget->allocation = *allocation;
+
+
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ gdk_window_move_resize (tabber->priv->event_window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+ if (GTK_WIDGET_MAPPED (widget))
+ gdk_window_show_unraised (tabber->priv->event_window);
+ }
+
+ if (n_children > 0)
+ {
+ child_width = allocation->width / n_children - padding -
+ (2 * widget->style->xthickness);
+
+ for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
+ {
+ GtkRequisition child_req;
+ GtkAllocation child_alloc;
+ gtk_widget_get_child_requisition (GTK_WIDGET (child->data), &child_req);
+
+ child_alloc.width = child_width;
+ child_alloc.height = MAX(child_req.height, allocation->height);
+ child_alloc.x = x + widget->style->xthickness;
+ child_alloc.y = y + widget->style->ythickness;
+
+ gtk_widget_size_allocate (GTK_WIDGET (child->data), &child_alloc);
+ x += child_alloc.width + 2 * widget->style->xthickness + padding;
+ }
+ }
+}
+
+static gboolean
+anjuta_tabber_expose_event (GtkWidget* widget, GdkEventExpose *event)
+{
+ g_return_val_if_fail (ANJUTA_IS_TABBER (widget), FALSE);
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+ GList* child;
+ gint padding = anjuta_tabber_get_padding (widget);
+
+ for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
+ {
+ GtkAllocation alloc;
+ GtkStateType state = (g_list_nth (tabber->priv->children, tabber->priv->active_page) == child) ?
+ GTK_STATE_NORMAL : GTK_STATE_ACTIVE;
+ gtk_widget_get_allocation (GTK_WIDGET (child->data), &alloc);
+
+ alloc.x -= widget->style->xthickness;
+ alloc.y -= widget->style->ythickness;
+ alloc.width += widget->style->xthickness + padding;
+ alloc.height += widget->style->ythickness;
+
+ gtk_paint_extension (widget->style, widget->window,
+ state, GTK_SHADOW_OUT,
+ NULL, widget, "tab",
+ alloc.x,
+ alloc.y,
+ alloc.width,
+ alloc.height,
+ GTK_POS_BOTTOM);
+ gtk_container_propagate_expose (GTK_CONTAINER (tabber),
+ GTK_WIDGET(child->data), event);
+ }
+ return FALSE;
+}
+
+/**
+ * anjuta_tabber_get_widget_coordintes
+ * @widget: widget for the coordinates
+ * @event: event to get coordinates from
+ * @x: return location for x coordinate
+ * @y: return location for y coordinate
+ *
+ * Returns: TRUE if coordinates were set, FALSE otherwise
+ */
+static gboolean
+anjuta_tabber_get_widget_coordinates (GtkWidget *widget,
+ GdkEvent *event,
+ gint *x,
+ gint *y)
+{
+ GdkWindow *window = ((GdkEventAny *)event)->window;
+ gdouble tx, ty;
+
+ if (!gdk_event_get_coords (event, &tx, &ty))
+ return FALSE;
+
+ while (window && window != widget->window)
+ {
+ gint window_x, window_y;
+
+ gdk_window_get_position (window, &window_x, &window_y);
+ tx += window_x;
+ ty += window_y;
+
+ window = gdk_window_get_parent (window);
+ }
+
+ if (window)
+ {
+ *x = tx;
+ *y = ty;
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+anjuta_tabber_button_press_event (GtkWidget* widget, GdkEventButton* event)
+{
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+ GList* child;
+
+ if (event->button == 1)
+ {
+ gint x, y;
+ if (!anjuta_tabber_get_widget_coordinates (widget, (GdkEvent*) event, &x, &y))
+ return FALSE;
+
+ for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
+ {
+ GtkAllocation alloc;
+ gtk_widget_get_allocation (GTK_WIDGET (child->data), &alloc);
+
+ g_message ("Event: %d %d", x, y);
+ g_message ("alloc: %d %d %d %d", alloc.x, alloc.y, alloc.width, alloc.height);
+
+ if (alloc.x <= event->x && (alloc.x + alloc.width) >= event->x &&
+ alloc.y <= event->y && (alloc.y + alloc.height) >= event->y)
+ {
+ gint page = g_list_position (tabber->priv->children, child);
+ gtk_notebook_set_current_page (tabber->priv->notebook, page);
+ g_message ("Switched to page %d!", page);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+anjuta_tabber_realize (GtkWidget *widget)
+{
+ GdkWindowAttr attributes;
+ GtkAllocation allocation;
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ widget->window = gtk_widget_get_parent_window (widget);
+ g_object_ref (widget->window);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK);
+
+ tabber->priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, GDK_WA_X | GDK_WA_Y);
+ gdk_window_set_user_data (tabber->priv->event_window, tabber);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+}
+
+static void
+anjuta_tabber_unrealize (GtkWidget *widget)
+{
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+ gdk_window_set_user_data (tabber->priv->event_window, NULL);
+ gdk_window_destroy (tabber->priv->event_window);
+ tabber->priv->event_window = NULL;
+
+ GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->unrealize (widget);
+}
+
+static void
+anjuta_tabber_map (GtkWidget* widget)
+{
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+ GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+
+ gdk_window_show_unraised (tabber->priv->event_window);
+
+ GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->map (widget);
+}
+
+static void
+anjuta_tabber_unmap (GtkWidget* widget)
+{
+ AnjutaTabber* tabber = ANJUTA_TABBER (widget);
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+
+ gdk_window_hide (tabber->priv->event_window);
+
+ GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->unmap (widget);
+
+}
+
+static void
+anjuta_tabber_add (GtkContainer* container, GtkWidget* widget)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (container));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ AnjutaTabber* tabber = ANJUTA_TABBER (container);
+
+ tabber->priv->children = g_list_append (tabber->priv->children, widget);
+ gtk_widget_set_parent (widget, GTK_WIDGET (tabber));
+}
+
+static void
+anjuta_tabber_remove (GtkContainer* container, GtkWidget* widget)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (container));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ AnjutaTabber* tabber = ANJUTA_TABBER (container);
+ gboolean visible = GTK_WIDGET_VISIBLE (widget);
+
+ gtk_widget_unparent (widget);
+ tabber->priv->children = g_list_remove (tabber->priv->children, widget);
+
+ if (visible)
+ gtk_widget_queue_resize (GTK_WIDGET (tabber));
+}
+
+static void
+anjuta_tabber_forall (GtkContainer* container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ g_return_if_fail (ANJUTA_IS_TABBER (container));
+ AnjutaTabber* tabber = ANJUTA_TABBER (container);
+ GList* child;
+ for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
+ {
+ (* callback) (GTK_WIDGET(child->data), callback_data);
+ }
+}
+
+static void
+anjuta_tabber_class_init (AnjutaTabberClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass* container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = anjuta_tabber_finalize;
+ object_class->set_property = anjuta_tabber_set_property;
+ object_class->get_property = anjuta_tabber_get_property;
+
+ widget_class->size_request = anjuta_tabber_size_request;
+ widget_class->size_allocate = anjuta_tabber_size_allocate;
+ widget_class->expose_event = anjuta_tabber_expose_event;
+ widget_class->button_press_event = anjuta_tabber_button_press_event;
+ widget_class->realize = anjuta_tabber_realize;
+ widget_class->unrealize = anjuta_tabber_unrealize;
+ widget_class->map = anjuta_tabber_map;
+ widget_class->unmap = anjuta_tabber_unmap;
+
+ container_class->add = anjuta_tabber_add;
+ container_class->remove = anjuta_tabber_remove;
+ container_class->forall = anjuta_tabber_forall;
+
+ g_object_class_install_property (object_class,
+ PROP_NOTEBOOK,
+ g_param_spec_object ("notebook",
+ "a GtkNotebook",
+ "GtkNotebook the tabber is associated with",
+ G_TYPE_OBJECT,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
+
+ g_type_class_add_private (klass, sizeof (AnjutaTabberPriv));
+}
+
+/**
+ * anjuta_tabber_new:
+ * @notebook: the GtkNotebook the tabber should be associated with
+ *
+ * Creates a new AnjutaTabber widget
+ *
+ * Returns: newly created AnjutaTabber widget
+ */
+GtkWidget* anjuta_tabber_new (GtkNotebook* notebook)
+{
+ GtkWidget* tabber;
+ tabber = GTK_WIDGET (g_object_new (ANJUTA_TYPE_TABBER, "notebook", notebook, NULL));
+
+ return tabber;
+}
+
+/**
+ * anjuta_tabber_add_tab:
+ * @tabber: a AnjutaTabber widget
+ * @tab_label: widget used as tab label
+ *
+ * Adds a tab to the AnjutaTabber widget
+ */
+void anjuta_tabber_add_tab (AnjutaTabber* tabber, GtkWidget* tab_label)
+{
+ gtk_container_add (GTK_CONTAINER (tabber), tab_label);
+}
diff --git a/libanjuta/anjuta-tabber.h b/libanjuta/anjuta-tabber.h
new file mode 100644
index 0000000..54cb9c4
--- /dev/null
+++ b/libanjuta/anjuta-tabber.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta-notebook-tabber
+ * Copyright (C) Johannes Schmid 2010 <jhs gnome org>
+ *
+ * anjuta-notebook-tabber 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * anjuta-notebook-tabber 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 _ANJUTA_TABBER_H_
+#define _ANJUTA_TABBER_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ANJUTA_TYPE_TABBER (anjuta_tabber_get_type ())
+#define ANJUTA_TABBER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANJUTA_TYPE_TABBER, AnjutaTabber))
+#define ANJUTA_TABBER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANJUTA_TYPE_TABBER, AnjutaTabberClass))
+#define ANJUTA_IS_TABBER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANJUTA_TYPE_TABBER))
+#define ANJUTA_IS_TABBER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANJUTA_TYPE_TABBER))
+#define ANJUTA_TABBER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANJUTA_TYPE_TABBER, AnjutaTabberClass))
+
+typedef struct _AnjutaTabberClass AnjutaTabberClass;
+typedef struct _AnjutaTabber AnjutaTabber;
+typedef struct _AnjutaTabberPriv AnjutaTabberPriv;
+
+struct _AnjutaTabberClass
+{
+ GtkContainerClass parent_class;
+};
+
+struct _AnjutaTabber
+{
+ GtkContainer parent_instance;
+
+ AnjutaTabberPriv* priv;
+};
+
+GType anjuta_tabber_get_type (void) G_GNUC_CONST;
+
+GtkWidget* anjuta_tabber_new (GtkNotebook* notebook);
+void anjuta_tabber_add_tab (AnjutaTabber* tabber, GtkWidget* tab_label);
+
+G_END_DECLS
+
+#endif /* _ANJUTA_TABBER_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]