libgeetk r2 - in trunk: . gridview ribbon



Author: aruiz
Date: Mon Jul 21 19:46:42 2008
New Revision: 2
URL: http://svn.gnome.org/viewvc/libgeetk?rev=2&view=rev

Log:

21-07-2008 Alberto Ruiz <aruiz gnome org>
	* Initial import from Frederik's <scumm_fredo gmx net> work.



Added:
   trunk/ChangeLog
   trunk/MAINTAINERS
   trunk/README
   trunk/gridview/
   trunk/gridview/Makefile
   trunk/gridview/demo_plain_c.c
   trunk/gridview/gridview.c
   trunk/gridview/gridview.h
   trunk/gridview/gridview.vala
   trunk/ribbon/
   trunk/ribbon/Makefile
   trunk/ribbon/README
   trunk/ribbon/application-button.vala
   trunk/ribbon/application-menu-item.vala
   trunk/ribbon/application-menu.vala
   trunk/ribbon/base-button.vala
   trunk/ribbon/button.vala
   trunk/ribbon/color-scheme.vala
   trunk/ribbon/extra-event-box.vala
   trunk/ribbon/gallery-popup-window.vala
   trunk/ribbon/gallery.vala
   trunk/ribbon/group-style.vala
   trunk/ribbon/helpers.vala
   trunk/ribbon/quick-access-toolbar.vala
   trunk/ribbon/ribbon-group.vala
   trunk/ribbon/ribbon.vala
   trunk/ribbon/sample-tile.vala
   trunk/ribbon/sample.vala
   trunk/ribbon/synthetic-window.vala
   trunk/ribbon/theme.vala
   trunk/ribbon/tile.vala
   trunk/ribbon/toggle-button.vala
   trunk/ribbon/tool-box.vala
   trunk/ribbon/tool-pack.vala

Added: trunk/MAINTAINERS
==============================================================================
--- (empty file)
+++ trunk/MAINTAINERS	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,3 @@
+Alberto Ruiz
+E-mail: aruiz gnome org
+Userid: aruiz

Added: trunk/README
==============================================================================
--- (empty file)
+++ trunk/README	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,3 @@
+A collection of various Gtk+ widgets written in Vala[0], pretty much like libsexy, but with a sexier language.
+
+[0] http://www.vala-project.org/

Added: trunk/gridview/Makefile
==============================================================================
--- (empty file)
+++ trunk/gridview/Makefile	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,28 @@
+NULL = 
+
+VALAC = valac
+CC = gcc
+CFLAGS = -g -O2
+
+GRIDVIEW_LIBS = `pkg-config gtk+-2.0 --libs` `pkg-config gee-1.0 --libs`
+GRIDVIEW_CFLAGS = `pkg-config gtk+-2.0 --cflags` `pkg-config gee-1.0 --cflags`
+
+gridviewdemo: gridview.o demo_plain_c.o
+	$(CC) gridview.o demo_plain_c.o -o gridviewdemo $(GRIDVIEW_LIBS)
+
+gridview.c: gridview.vala
+	$(VALAC) -C --pkg gee-1.0 --pkg gtk+-2.0 --pkg gdk-2.0 --disable-non-null $^
+
+gridview.o: gridview.c
+	$(CC) -c $(CFLAGS) $(GRIDVIEW_CFLAGS) $^ -o $@
+
+demo_plain_c.o: demo_plain_c.c
+	$(CC) -c $(CFLAGS) $(GRIDVIEW_CFLAGS) $^ -o $@
+
+clean:
+	rm -f *.o
+	rm -f gridviewdemo
+
+valaclean: clean
+	rm -f gridview.h
+	rm -f gridview.c

Added: trunk/gridview/demo_plain_c.c
==============================================================================
--- (empty file)
+++ trunk/gridview/demo_plain_c.c	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,170 @@
+#include <gtk/gtk.h>
+
+#include "gridview.h"
+
+static const char* DEMO_DATA = "OpenVista is a cost-effective, open, trusted "
+	"and complete EHR which enhances patient safety, increases clinical and "
+	"operational efficiency and provides an opportunity to improve quality of "
+	"care delivery. Healthcare provider organizations are encouraged to access "
+	"this software and see first hand how our commercialized version of the "
+	"Veterans Affairs' FOIA VistA can be leveraged outside of the VA to "
+	"support the goal of higher quality healthcare. We anticipate that an open "
+	"source approach will assist in revolutionizing healthcare by enabling "
+	"many more healthcare delivery organizations to successfully adopt such "
+	"technology for the benefit of their patients and their businesses. "
+	"Medsphere is focused on developing an open source community centered on "
+	"Medsphere OpenVistaÂ. We welcome your participation in OpenVista "
+	"projects. If you have an idea on how to improve quality, enhance "
+	"functionality, or accelerate innovation in OpenVista we encourage and "
+	"welcome your input -- please join our mailing lists.";
+
+static const gint n_columns = 5;
+
+GtkGridView* grid_view = NULL;
+
+static void on_orientation_combo_box_changed (GtkComboBox* s)
+{
+	g_return_if_fail (s == NULL || GTK_IS_COMBO_BOX (s));
+
+	gtk_grid_view_set_orientation (grid_view,
+	                               (gtk_combo_box_get_active (s) == 0)
+	                                 ? GTK_ORIENTATION_VERTICAL
+	                                 : GTK_ORIENTATION_HORIZONTAL);
+}
+
+
+static void on_row_headers_spin_button_value_changed (GtkSpinButton* s)
+{
+	g_return_if_fail (s == NULL || GTK_IS_SPIN_BUTTON (s));
+
+	gtk_grid_view_set_n_row_headers (grid_view,
+	                                 gtk_spin_button_get_value_as_int (s));
+}
+
+
+static void on_col_headers_spin_button_value_changed (GtkSpinButton* s)
+{
+	g_return_if_fail (s == NULL || GTK_IS_SPIN_BUTTON (s));
+
+	gtk_grid_view_set_n_col_headers (grid_view,
+	                                 gtk_spin_button_get_value_as_int (s));
+}
+
+
+int main (int argc, char ** argv)
+{
+	GtkWidget* win;
+	GtkWidget* vbox;
+	GtkWidget* hbox;
+	GtkComboBox* orientation_combo_box;
+	GtkSpinButton* row_headers_spin_button;
+	GtkSpinButton* col_headers_spin_button;
+	GtkListStore* store;
+	GtkTreeIter tree_iter;
+	GType* type_array;
+	char** words;
+	int i;
+
+	gtk_init (&argc, &argv);
+
+	win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_resize (GTK_WINDOW (win), 640, 480);
+	g_signal_connect (GTK_OBJECT (win), "destroy",
+	                  G_CALLBACK (gtk_main_quit), NULL);
+
+	vbox = gtk_vbox_new (FALSE, 6);
+	gtk_container_add (GTK_CONTAINER (win), GTK_WIDGET (vbox));
+
+	type_array = g_new (GType, n_columns);
+	for (i = 0; i < n_columns; i++) {
+		type_array[i] = G_TYPE_STRING;
+	}
+
+	words = g_strsplit (DEMO_DATA, " ", 0);
+	store = gtk_list_store_newv (n_columns, type_array);
+	gtk_list_store_append (store, &tree_iter);
+
+	for (i = 0; words[i] != NULL; i++) {
+		GValue val = {0};
+		int col = i % n_columns;
+		g_value_init (&val, G_TYPE_STRING);
+		g_value_set_string (&val, words[i]);
+		gtk_list_store_set_value (store, &tree_iter, col, &val);
+		if (col == n_columns - 1) {
+			gtk_list_store_append (store, &tree_iter);
+		}
+	}
+
+	grid_view = gtk_grid_view_new ();
+	gtk_grid_view_set_hscrollbar_policy (grid_view, GTK_POLICY_AUTOMATIC);
+	gtk_grid_view_set_vscrollbar_policy (grid_view, GTK_POLICY_AUTOMATIC);
+	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (grid_view), TRUE, TRUE, 0);
+
+	for (i = 0; i < n_columns; i++) {
+		GtkCellRenderer* renderer = gtk_cell_renderer_text_new ();
+		GtkRenderAttribute attrs[] = { {"text", i} };
+		gtk_grid_view_append_column_with_attributes (grid_view, renderer,
+		                                             attrs, 1);
+	}
+
+	gtk_grid_view_set_model (grid_view, GTK_TREE_MODEL (store));
+	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (gtk_hseparator_new ()),
+	                    FALSE, FALSE, 0);
+	hbox = gtk_hbox_new (FALSE, 6);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox),
+	                    GTK_WIDGET (gtk_label_new ("Orientation:")),
+	                    FALSE, FALSE, 0);
+
+	orientation_combo_box = (GtkComboBox*) gtk_combo_box_new_text ();
+	gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (orientation_combo_box),
+	                    FALSE, FALSE, 0);
+	gtk_combo_box_append_text (orientation_combo_box, "Vertical");
+	gtk_combo_box_append_text (orientation_combo_box, "Horizontal");
+	gtk_combo_box_set_active (orientation_combo_box, 0);
+
+	g_signal_connect (orientation_combo_box, "changed",
+	                  G_CALLBACK (on_orientation_combo_box_changed), NULL);
+
+	gtk_box_pack_start (GTK_BOX (hbox),
+	                    GTK_WIDGET (gtk_label_new ("Row Headers:")),
+	                    FALSE, FALSE, 0);
+
+	row_headers_spin_button = (GtkSpinButton*)
+	           gtk_spin_button_new_with_range (0.0, (double) n_columns, 1.0);
+
+	gtk_spin_button_set_value (row_headers_spin_button,
+	                   (double) gtk_grid_view_get_n_row_headers (grid_view));
+
+	g_signal_connect (GTK_EDITABLE (row_headers_spin_button), "changed",
+	                  G_CALLBACK (on_row_headers_spin_button_value_changed),
+	                  NULL);
+
+	gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (row_headers_spin_button),
+	                    FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox),
+	                    GTK_WIDGET (gtk_label_new ("Col Headers:")),
+	                    FALSE, FALSE, 0);
+
+	col_headers_spin_button = (GtkSpinButton*) gtk_spin_button_new_with_range (
+	    0.0,
+	    (double) gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL),
+	    1.0);
+
+	gtk_spin_button_set_value (col_headers_spin_button,
+	                     (double) gtk_grid_view_get_n_col_headers (grid_view));
+
+	g_signal_connect (GTK_EDITABLE (col_headers_spin_button), "changed",
+	                  G_CALLBACK (on_col_headers_spin_button_value_changed),
+	                  NULL);
+
+	gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (col_headers_spin_button),
+	                    FALSE, FALSE, 0);
+
+	gtk_widget_show_all (win);
+
+	gtk_main ();
+
+	return 0;
+}
+

Added: trunk/gridview/gridview.c
==============================================================================
--- (empty file)
+++ trunk/gridview/gridview.c	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,2813 @@
+/* 
+ * Medsphere.Widgets
+ * Copyright (C) 2007 Medsphere Systems Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gridview.h"
+#include <gee/hashmap.h>
+#include <gee/map.h>
+#include <gee/arraylist.h>
+#include <gee/list.h>
+#include <gee/collection.h>
+#include <string.h>
+
+
+#define GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR (gtk_grid_view_linked_scrollbar_get_type ())
+#define GTK_GRID_VIEW_LINKED_SCROLLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR, GtkGridViewLinkedScrollbar))
+#define GTK_GRID_VIEW_LINKED_SCROLLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR, GtkGridViewLinkedScrollbarClass))
+#define GTK_GRID_VIEW_IS_LINKED_SCROLLBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR))
+#define GTK_GRID_VIEW_IS_LINKED_SCROLLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR))
+#define GTK_GRID_VIEW_LINKED_SCROLLBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR, GtkGridViewLinkedScrollbarClass))
+
+typedef struct _GtkGridViewLinkedScrollbar GtkGridViewLinkedScrollbar;
+typedef struct _GtkGridViewLinkedScrollbarClass GtkGridViewLinkedScrollbarClass;
+typedef struct _GtkGridViewLinkedScrollbarPrivate GtkGridViewLinkedScrollbarPrivate;
+
+struct _GtkGridViewLinkedScrollbar {
+	GObject parent_instance;
+	GtkGridViewLinkedScrollbarPrivate * priv;
+};
+
+struct _GtkGridViewLinkedScrollbarClass {
+	GObjectClass parent_class;
+};
+
+
+
+struct _GtkGridSelectionPrivate {
+	GtkGridView* _gv;
+	GtkTreePath* _path;
+	GtkGridViewColumn* _col;
+};
+
+#define GTK_GRID_SELECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_GRID_SELECTION, GtkGridSelectionPrivate))
+enum  {
+	GTK_GRID_SELECTION_DUMMY_PROPERTY,
+	GTK_GRID_SELECTION_GV,
+	GTK_GRID_SELECTION_HAS_SELECTION
+};
+static void gtk_grid_selection_on_grid_view_columns_changed (GtkGridSelection* self);
+static GtkGridView* gtk_grid_selection_get_gv (GtkGridSelection* self);
+static void gtk_grid_selection_set_gv (GtkGridSelection* self, GtkGridView* value);
+static void _gtk_grid_selection_on_grid_view_columns_changed_gtk_grid_view_columns_changed (GtkGridView* _sender, gpointer self);
+static GObject * gtk_grid_selection_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties);
+static gpointer gtk_grid_selection_parent_class = NULL;
+static void gtk_grid_selection_dispose (GObject * obj);
+struct _GtkGridViewColumnPrivate {
+	gboolean _visible;
+	GtkCellRenderer* _header_renderer;
+	GtkCellRenderer* _field_renderer;
+	GeeMap* _header_attrs;
+	GeeMap* _field_attrs;
+	GtkGridCellDataFunc _df;
+	gpointer _df_target;
+	GtkGridCellDataFunc _hdf;
+	gpointer _hdf_target;
+};
+
+#define GTK_GRID_VIEW_COLUMN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_GRID_VIEW_COLUMN, GtkGridViewColumnPrivate))
+enum  {
+	GTK_GRID_VIEW_COLUMN_DUMMY_PROPERTY,
+	GTK_GRID_VIEW_COLUMN_VISIBLE,
+	GTK_GRID_VIEW_COLUMN_FIELD_RENDERER,
+	GTK_GRID_VIEW_COLUMN_HEADER_RENDERER
+};
+static void gtk_grid_view_column_set_field_renderer (GtkGridViewColumn* self, GtkCellRenderer* value);
+static gpointer gtk_grid_view_column_parent_class = NULL;
+static void gtk_grid_view_column_dispose (GObject * obj);
+struct _GtkGridViewPrivate {
+	GeeList* _children;
+	GtkTreeModel* _model;
+	GtkOrientation _orientation;
+	GeeList* _columns;
+	GeeList* _visible;
+	GeeList* _widths;
+	GeeList* _heights;
+	gint c_span;
+	gint r_span;
+	gint _drag_col;
+	GtkViewport* tvp;
+	GtkViewport* lvp;
+	GtkViewport* fvp;
+	GtkDrawingArea* cda;
+	GtkDrawingArea* tda;
+	GtkDrawingArea* lda;
+	GtkDrawingArea* fda;
+	GtkScrollbar* hbar;
+	GtkScrollbar* vbar;
+	GtkPolicyType _hbar_policy;
+	GtkPolicyType _vbar_policy;
+	GtkGridViewScrollbarSpan _hbar_span;
+	GtkGridViewScrollbarSpan _vbar_span;
+	GtkGridSelection* _selection;
+	GtkTreePath* _prev_sel_path;
+	GtkGridViewColumn* _prev_sel_col;
+};
+
+#define GTK_GRID_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_GRID_VIEW, GtkGridViewPrivate))
+enum  {
+	GTK_GRID_VIEW_DUMMY_PROPERTY,
+	GTK_GRID_VIEW_MODEL,
+	GTK_GRID_VIEW_COLUMNS,
+	GTK_GRID_VIEW_HSCROLLBAR_POLICY,
+	GTK_GRID_VIEW_VSCROLLBAR_POLICY,
+	GTK_GRID_VIEW_HSCROLLBAR_SPAN,
+	GTK_GRID_VIEW_VSCROLLBAR_SPAN,
+	GTK_GRID_VIEW_ORIENTATION,
+	GTK_GRID_VIEW_SELECTION,
+	GTK_GRID_VIEW_N_ROW_HEADERS,
+	GTK_GRID_VIEW_N_COL_HEADERS
+};
+static GdkCursor* gtk_grid_view_DRAG_CURSOR;
+static void _gtk_grid_view_on_column_visibility_changed_gtk_grid_view_column_visibility_changed (GtkGridViewColumn* _sender, gpointer self);
+static void gtk_grid_view_real_add (GtkContainer* base, GtkWidget* w);
+static void gtk_grid_view_real_remove (GtkContainer* base, GtkWidget* w);
+static void gtk_grid_view_real_forall (GtkContainer* base, gboolean i, GtkCallback cb, void* cb_target);
+static void gtk_grid_view_real_size_request (GtkWidget* base, GtkRequisition* r);
+static void gtk_grid_view_real_size_allocate (GtkWidget* base, GdkRectangle* a);
+static void gtk_grid_view_on_model_row_changed (GtkGridView* self, GtkTreeModel* m, GtkTreePath* path, GtkTreeIter* iter);
+static void gtk_grid_view_on_model_row_deleted (GtkGridView* self, GtkTreeModel* m, GtkTreePath* path);
+static void gtk_grid_view_on_model_row_inserted (GtkGridView* self, GtkTreeModel* m, GtkTreePath* path);
+static void gtk_grid_view_on_model_rows_reordered (GtkGridView* self, GtkTreeModel* m);
+static void gtk_grid_view_on_style_set (GtkGridView* self, GtkGridView* s, GtkStyle* style);
+static void gtk_grid_view_on_state_changed (GtkGridView* self, GtkGridView* s, GtkStateType previous_state);
+static gboolean gtk_grid_view_on_focus_in_event (GtkGridView* self, GtkGridView* s, GdkEventFocus* event);
+static gboolean gtk_grid_view_on_focus_out_event (GtkGridView* self, GtkGridView* s, GdkEventFocus* event);
+static gboolean gtk_grid_view_on_button_press_event (GtkGridView* self, GtkGridView* s, GdkEventButton* event);
+static gboolean gtk_grid_view_on_key_press_event (GtkGridView* self, GtkGridView* s, GdkEventKey* event);
+static void gtk_grid_view_on_selection_changed (GtkGridView* self, GtkGridSelection* s);
+static gboolean gtk_grid_view_on_cda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event);
+static gboolean gtk_grid_view_on_tda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event);
+static gboolean gtk_grid_view_on_lda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event);
+static gboolean gtk_grid_view_on_fda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event);
+static gboolean gtk_grid_view_on_yheader_motion_notify_event (GtkGridView* self, GtkDrawingArea* da, GdkEventMotion* event);
+static gboolean gtk_grid_view_on_yheader_button_press_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event);
+static gboolean gtk_grid_view_on_yheader_button_release_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event);
+static void gtk_grid_view_on_fda_style_set (GtkGridView* self, GtkDrawingArea* da, GtkStyle* style);
+static void gtk_grid_view_on_fda_realized (GtkGridView* self, GtkDrawingArea* da);
+static gboolean gtk_grid_view_on_fda_button_press_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event);
+static gboolean gtk_grid_view_on_lda_button_press_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event);
+static void gtk_grid_view_on_column_visibility_changed (GtkGridView* self, GtkGridViewColumn* changed_col);
+static void gtk_grid_view_translate_coords (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, gint* x, gint* y);
+static gboolean gtk_grid_view_translate_coords_b (GtkGridView* self, gint x, gint y, GtkTreePath** path, GtkGridViewColumn** col);
+static void gtk_grid_view_update_drawing_area_size_requests (GtkGridView* self);
+static void gtk_grid_view_measure_cell (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col);
+static void gtk_grid_view_rebuild_dimensions (GtkGridView* self);
+static GdkRectangle gtk_grid_view_cell_rect (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, GtkWidget** widget);
+static void gtk_grid_view_invalidate_cell_rect (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col);
+static gint gtk_grid_view_column_x (GtkGridView* self, gint x);
+static gint gtk_grid_view_row_y (GtkGridView* self, gint y);
+static gint gtk_grid_view_drag_x (GtkGridView* self, gint x);
+static void gtk_grid_view_draw_cell (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, GdkRectangle* clip_);
+static void _gtk_grid_view_on_model_row_changed_gtk_tree_model_row_changed (GtkTreeModel* _sender, GtkTreePath* path, GtkTreeIter* iter, gpointer self);
+static void _gtk_grid_view_on_model_row_deleted_gtk_tree_model_row_deleted (GtkTreeModel* _sender, GtkTreePath* path, gpointer self);
+static void _gtk_grid_view_on_model_row_inserted_gtk_tree_model_row_inserted (GtkTreeModel* _sender, GtkTreePath* path, GtkTreeIter* iter, gpointer self);
+static void _gtk_grid_view_on_model_rows_reordered_gtk_tree_model_rows_reordered (GtkTreeModel* _sender, GtkTreePath* path, GtkTreeIter* iter, void* new_order, gpointer self);
+static gint gtk_grid_view_get_x_span (GtkGridView* self);
+static gint gtk_grid_view_get_y_span (GtkGridView* self);
+static gint gtk_grid_view_get_left_width (GtkGridView* self);
+static gint gtk_grid_view_get_top_height (GtkGridView* self);
+static gint gtk_grid_view_get_field_width (GtkGridView* self);
+static gint gtk_grid_view_get_field_height (GtkGridView* self);
+static void _gtk_grid_view_on_style_set_gtk_widget_style_set (GtkGridView* _sender, GtkStyle* previous_style, gpointer self);
+static void _gtk_grid_view_on_state_changed_gtk_widget_state_changed (GtkGridView* _sender, GtkStateType previous_state, gpointer self);
+static gboolean _gtk_grid_view_on_focus_in_event_gtk_widget_focus_in_event (GtkGridView* _sender, GdkEventFocus* event, gpointer self);
+static gboolean _gtk_grid_view_on_focus_out_event_gtk_widget_focus_out_event (GtkGridView* _sender, GdkEventFocus* event, gpointer self);
+static gboolean _gtk_grid_view_on_button_press_event_gtk_widget_button_press_event (GtkGridView* _sender, GdkEventButton* event, gpointer self);
+static gboolean _gtk_grid_view_on_key_press_event_gtk_widget_key_press_event (GtkGridView* _sender, GdkEventKey* event, gpointer self);
+static void _gtk_grid_view_on_selection_changed_gtk_grid_selection_changed (GtkGridSelection* _sender, gpointer self);
+static gboolean _gtk_grid_view_on_cda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self);
+static gboolean _gtk_grid_view_on_yheader_motion_notify_event_gtk_widget_motion_notify_event (GtkDrawingArea* _sender, GdkEventMotion* event, gpointer self);
+static gboolean _gtk_grid_view_on_yheader_button_press_event_gtk_widget_button_press_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self);
+static gboolean _gtk_grid_view_on_yheader_button_release_event_gtk_widget_button_release_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self);
+static gboolean _gtk_grid_view_on_tda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self);
+static gboolean _gtk_grid_view_on_lda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self);
+static gboolean _gtk_grid_view_on_lda_button_press_event_gtk_widget_button_press_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self);
+static void _gtk_grid_view_on_fda_style_set_gtk_widget_style_set (GtkDrawingArea* _sender, GtkStyle* previous_style, gpointer self);
+static void _gtk_grid_view_on_fda_realized_gtk_widget_realize (GtkDrawingArea* _sender, gpointer self);
+static gboolean _gtk_grid_view_on_fda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self);
+static gboolean _gtk_grid_view_on_fda_button_press_event_gtk_widget_button_press_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self);
+static GObject * gtk_grid_view_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties);
+struct _GtkGridViewLinkedScrollbarPrivate {
+	GtkScrollbar* _scrollbar;
+};
+
+#define GTK_GRID_VIEW_LINKED_SCROLLBAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR, GtkGridViewLinkedScrollbarPrivate))
+enum  {
+	GTK_GRID_VIEW_LINKED_SCROLLBAR_DUMMY_PROPERTY,
+	GTK_GRID_VIEW_LINKED_SCROLLBAR_SCROLLBAR
+};
+static GtkGridViewLinkedScrollbar* gtk_grid_view_linked_scrollbar_new (GtkScrollbar* sb);
+static gboolean _gtk_grid_view_linked_scrollbar_on_linked_widget_scroll_event_gtk_widget_scroll_event (GtkWidget* _sender, GdkEventScroll* event, gpointer self);
+static void gtk_grid_view_linked_scrollbar_link (GtkGridViewLinkedScrollbar* self, GtkWidget* widget);
+static void gtk_grid_view_linked_scrollbar_link_all (GtkGridViewLinkedScrollbar* self, GtkWidget** widgets, int widgets_length1);
+static gboolean gtk_grid_view_linked_scrollbar_on_linked_widget_scroll_event (GtkGridViewLinkedScrollbar* self, GtkWidget* w, GdkEventScroll* event);
+static GtkScrollbar* gtk_grid_view_linked_scrollbar_get_scrollbar (GtkGridViewLinkedScrollbar* self);
+static void gtk_grid_view_linked_scrollbar_set_scrollbar (GtkGridViewLinkedScrollbar* self, GtkScrollbar* value);
+static gpointer gtk_grid_view_linked_scrollbar_parent_class = NULL;
+static void gtk_grid_view_linked_scrollbar_dispose (GObject * obj);
+static GType gtk_grid_view_linked_scrollbar_get_type (void);
+static gpointer gtk_grid_view_parent_class = NULL;
+static void gtk_grid_view_dispose (GObject * obj);
+static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func);
+
+
+
+GtkGridSelection* gtk_grid_selection_new (GtkGridView* g) {
+	GParameter * __params;
+	GParameter * __params_it;
+	GtkGridSelection * self;
+	g_return_val_if_fail (g == NULL || GTK_IS_GRID_VIEW (g), NULL);
+	__params = g_new0 (GParameter, 1);
+	__params_it = __params;
+	__params_it->name = "gv";
+	g_value_init (&__params_it->value, GTK_TYPE_GRID_VIEW);
+	g_value_set_object (&__params_it->value, g);
+	__params_it++;
+	self = g_object_newv (GTK_TYPE_GRID_SELECTION, __params_it - __params, __params);
+	while (__params_it > __params) {
+		--__params_it;
+		g_value_unset (&__params_it->value);
+	}
+	g_free (__params);
+	return self;
+}
+
+
+gboolean gtk_grid_selection_select_cell (GtkGridSelection* self, GtkTreePath* path, GtkGridViewColumn* col) {
+	GtkGridViewColumn* _tmp4;
+	GtkGridViewColumn* _tmp3;
+	g_return_val_if_fail (GTK_IS_GRID_SELECTION (self), FALSE);
+	g_return_val_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col), FALSE);
+	if (!gtk_grid_view_get_selectable (self->priv->_gv, path, col)) {
+		return FALSE;
+	}
+	if (path != NULL) {
+		GtkTreePath* _tmp1;
+		_tmp1 = NULL;
+		self->priv->_path = (_tmp1 = gtk_tree_path_copy (path), (self->priv->_path == NULL ? NULL : (self->priv->_path = (gtk_tree_path_free (self->priv->_path), NULL))), _tmp1);
+	} else {
+		GtkTreePath* _tmp2;
+		_tmp2 = NULL;
+		self->priv->_path = (_tmp2 = NULL, (self->priv->_path == NULL ? NULL : (self->priv->_path = (gtk_tree_path_free (self->priv->_path), NULL))), _tmp2);
+	}
+	_tmp4 = NULL;
+	_tmp3 = NULL;
+	self->priv->_col = (_tmp4 = (_tmp3 = col, (_tmp3 == NULL ? NULL : g_object_ref (_tmp3))), (self->priv->_col == NULL ? NULL : (self->priv->_col = (g_object_unref (self->priv->_col), NULL))), _tmp4);
+	g_signal_emit_by_name (G_OBJECT (self), "changed");
+	return TRUE;
+}
+
+
+void gtk_grid_selection_deselect (GtkGridSelection* self) {
+	GtkTreePath* _tmp0;
+	GtkGridViewColumn* _tmp1;
+	g_return_if_fail (GTK_IS_GRID_SELECTION (self));
+	_tmp0 = NULL;
+	self->priv->_path = (_tmp0 = NULL, (self->priv->_path == NULL ? NULL : (self->priv->_path = (gtk_tree_path_free (self->priv->_path), NULL))), _tmp0);
+	_tmp1 = NULL;
+	self->priv->_col = (_tmp1 = NULL, (self->priv->_col == NULL ? NULL : (self->priv->_col = (g_object_unref (self->priv->_col), NULL))), _tmp1);
+	g_signal_emit_by_name (G_OBJECT (self), "changed");
+}
+
+
+gboolean gtk_grid_selection_get_selected (GtkGridSelection* self, GtkTreePath** path, GtkGridViewColumn** col) {
+	GtkGridViewColumn* _tmp3;
+	GtkGridViewColumn* _tmp2;
+	g_return_val_if_fail (GTK_IS_GRID_SELECTION (self), FALSE);
+	(*path) = NULL;
+	(*col) = NULL;
+	if (self->priv->_path != NULL) {
+		GtkTreePath* _tmp0;
+		_tmp0 = NULL;
+		(*path) = (_tmp0 = gtk_tree_path_copy (self->priv->_path), ((*path) == NULL ? NULL : ((*path) = (gtk_tree_path_free ((*path)), NULL))), _tmp0);
+	} else {
+		GtkTreePath* _tmp1;
+		_tmp1 = NULL;
+		(*path) = (_tmp1 = NULL, ((*path) == NULL ? NULL : ((*path) = (gtk_tree_path_free ((*path)), NULL))), _tmp1);
+	}
+	_tmp3 = NULL;
+	_tmp2 = NULL;
+	(*col) = (_tmp3 = (_tmp2 = self->priv->_col, (_tmp2 == NULL ? NULL : g_object_ref (_tmp2))), ((*col) == NULL ? NULL : ((*col) = (g_object_unref ((*col)), NULL))), _tmp3);
+	return gtk_grid_selection_get_has_selection (self);
+}
+
+
+static void gtk_grid_selection_on_grid_view_columns_changed (GtkGridSelection* self) {
+	g_return_if_fail (GTK_IS_GRID_SELECTION (self));
+	if (self->priv->_path == NULL && self->priv->_col == NULL) {
+		return;
+	}
+	if (array_index_of (((GObject**) (gtk_grid_view_get_columns (self->priv->_gv))), -1, G_OBJECT (self->priv->_col)) < 0) {
+		gtk_grid_selection_deselect (self);
+	}
+}
+
+
+static GtkGridView* gtk_grid_selection_get_gv (GtkGridSelection* self) {
+	g_return_val_if_fail (GTK_IS_GRID_SELECTION (self), NULL);
+	return self->priv->_gv;
+}
+
+
+static void gtk_grid_selection_set_gv (GtkGridSelection* self, GtkGridView* value) {
+	GtkGridView* _tmp2;
+	GtkGridView* _tmp1;
+	g_return_if_fail (GTK_IS_GRID_SELECTION (self));
+	_tmp2 = NULL;
+	_tmp1 = NULL;
+	self->priv->_gv = (_tmp2 = (_tmp1 = value, (_tmp1 == NULL ? NULL : g_object_ref (_tmp1))), (self->priv->_gv == NULL ? NULL : (self->priv->_gv = (g_object_unref (self->priv->_gv), NULL))), _tmp2);
+	g_object_notify (((GObject *) (self)), "gv");
+}
+
+
+gboolean gtk_grid_selection_get_has_selection (GtkGridSelection* self) {
+	g_return_val_if_fail (GTK_IS_GRID_SELECTION (self), FALSE);
+	return self->priv->_path != NULL && self->priv->_col != NULL;
+}
+
+
+static void _gtk_grid_selection_on_grid_view_columns_changed_gtk_grid_view_columns_changed (GtkGridView* _sender, gpointer self) {
+	gtk_grid_selection_on_grid_view_columns_changed (self);
+}
+
+
+static GObject * gtk_grid_selection_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties) {
+	GObject * obj;
+	GtkGridSelectionClass * klass;
+	GObjectClass * parent_class;
+	GtkGridSelection * self;
+	klass = GTK_GRID_SELECTION_CLASS (g_type_class_peek (GTK_TYPE_GRID_SELECTION));
+	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
+	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
+	self = GTK_GRID_SELECTION (obj);
+	{
+		g_signal_connect_object (self->priv->_gv, "columns-changed", ((GCallback) (_gtk_grid_selection_on_grid_view_columns_changed_gtk_grid_view_columns_changed)), self, 0);
+	}
+	return obj;
+}
+
+
+static void gtk_grid_selection_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
+	GtkGridSelection * self;
+	self = GTK_GRID_SELECTION (object);
+	switch (property_id) {
+		case GTK_GRID_SELECTION_GV:
+		g_value_set_object (value, gtk_grid_selection_get_gv (self));
+		break;
+		case GTK_GRID_SELECTION_HAS_SELECTION:
+		g_value_set_boolean (value, gtk_grid_selection_get_has_selection (self));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_selection_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) {
+	GtkGridSelection * self;
+	self = GTK_GRID_SELECTION (object);
+	switch (property_id) {
+		case GTK_GRID_SELECTION_GV:
+		gtk_grid_selection_set_gv (self, g_value_get_object (value));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_selection_class_init (GtkGridSelectionClass * klass) {
+	gtk_grid_selection_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GtkGridSelectionPrivate));
+	G_OBJECT_CLASS (klass)->get_property = gtk_grid_selection_get_property;
+	G_OBJECT_CLASS (klass)->set_property = gtk_grid_selection_set_property;
+	G_OBJECT_CLASS (klass)->constructor = gtk_grid_selection_constructor;
+	G_OBJECT_CLASS (klass)->dispose = gtk_grid_selection_dispose;
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_SELECTION_GV, g_param_spec_object ("gv", "gv", "gv", GTK_TYPE_GRID_VIEW, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_SELECTION_HAS_SELECTION, g_param_spec_boolean ("has-selection", "has-selection", "has-selection", FALSE, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+	g_signal_new ("changed", GTK_TYPE_GRID_SELECTION, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+
+static void gtk_grid_selection_instance_init (GtkGridSelection * self) {
+	self->priv = GTK_GRID_SELECTION_GET_PRIVATE (self);
+	self->priv->_path = NULL;
+	self->priv->_col = NULL;
+}
+
+
+static void gtk_grid_selection_dispose (GObject * obj) {
+	GtkGridSelection * self;
+	self = GTK_GRID_SELECTION (obj);
+	(self->priv->_gv == NULL ? NULL : (self->priv->_gv = (g_object_unref (self->priv->_gv), NULL)));
+	(self->priv->_path == NULL ? NULL : (self->priv->_path = (gtk_tree_path_free (self->priv->_path), NULL)));
+	(self->priv->_col == NULL ? NULL : (self->priv->_col = (g_object_unref (self->priv->_col), NULL)));
+	G_OBJECT_CLASS (gtk_grid_selection_parent_class)->dispose (obj);
+}
+
+
+GType gtk_grid_selection_get_type (void) {
+	static GType gtk_grid_selection_type_id = 0;
+	if (G_UNLIKELY (gtk_grid_selection_type_id == 0)) {
+		static const GTypeInfo g_define_type_info = { sizeof (GtkGridSelectionClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gtk_grid_selection_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GtkGridSelection), 0, (GInstanceInitFunc) gtk_grid_selection_instance_init };
+		gtk_grid_selection_type_id = g_type_register_static (G_TYPE_OBJECT, "GtkGridSelection", &g_define_type_info, 0);
+	}
+	return gtk_grid_selection_type_id;
+}
+
+
+GtkGridViewColumn* gtk_grid_view_column_new (GtkCellRenderer* r) {
+	GParameter * __params;
+	GParameter * __params_it;
+	GtkGridViewColumn * self;
+	g_return_val_if_fail (r == NULL || GTK_IS_CELL_RENDERER (r), NULL);
+	__params = g_new0 (GParameter, 1);
+	__params_it = __params;
+	__params_it->name = "field-renderer";
+	g_value_init (&__params_it->value, GTK_TYPE_CELL_RENDERER);
+	g_value_set_object (&__params_it->value, r);
+	__params_it++;
+	self = g_object_newv (GTK_TYPE_GRID_VIEW_COLUMN, __params_it - __params, __params);
+	while (__params_it > __params) {
+		--__params_it;
+		g_value_unset (&__params_it->value);
+	}
+	g_free (__params);
+	return self;
+}
+
+
+/* XXX-VALA: currently arrays can't get passed to construction methods,
+           since array properties are not supported yet
+           (Vala Bug #536706), so we provide a setter*/
+void gtk_grid_view_column_set_field_attrs (GtkGridViewColumn* self, GtkRenderAttribute* a, int a_length1) {
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	{
+		GtkRenderAttribute* attr_collection;
+		int attr_collection_length1;
+		int attr_it;
+		attr_collection = a;
+		attr_collection_length1 = a_length1;
+		g_assert (a_length1 != -1);
+		for (attr_it = 0; attr_it < a_length1; attr_it = attr_it + 1) {
+			GtkRenderAttribute attr;
+			attr = attr_collection[attr_it];
+			{
+				gee_map_set (self->priv->_field_attrs, attr.property, GINT_TO_POINTER (attr.column));
+			}
+		}
+	}
+}
+
+
+/* XXX-VALA: no delegate properties yet (Vala Bug #543879)
+public GridCellDataFunc cell_data_func {
+set { _df = value; }
+}*/
+void gtk_grid_view_column_set_cell_data_func (GtkGridViewColumn* self, GtkGridCellDataFunc func, void* func_target) {
+	GtkGridCellDataFunc _tmp0;
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	self->priv->_df = (_tmp0 = func, self->priv->_df_target = func_target, _tmp0);
+}
+
+
+/* XXX-VALA: no delegate properties yet (Vala Bug #543879)
+public GridCellDataFunc header_cell_data_func {
+set { _hdf = value; }
+}*/
+void gtk_grid_view_column_set_header_cell_data_func (GtkGridViewColumn* self, GtkGridCellDataFunc func, void* func_target) {
+	GtkGridCellDataFunc _tmp0;
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	self->priv->_hdf = (_tmp0 = func, self->priv->_hdf_target = func_target, _tmp0);
+}
+
+
+void gtk_grid_view_column_set_header_renderer (GtkGridViewColumn* self, GtkCellRenderer* r, GtkRenderAttribute* a, int a_length1) {
+	GtkCellRenderer* _tmp1;
+	GtkCellRenderer* _tmp0;
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	g_return_if_fail (r == NULL || GTK_IS_CELL_RENDERER (r));
+	_tmp1 = NULL;
+	_tmp0 = NULL;
+	self->priv->_header_renderer = (_tmp1 = (_tmp0 = r, (_tmp0 == NULL ? NULL : g_object_ref (_tmp0))), (self->priv->_header_renderer == NULL ? NULL : (self->priv->_header_renderer = (g_object_unref (self->priv->_header_renderer), NULL))), _tmp1);
+	{
+		GtkRenderAttribute* attr_collection;
+		int attr_collection_length1;
+		int attr_it;
+		attr_collection = a;
+		attr_collection_length1 = a_length1;
+		g_assert (a_length1 != -1);
+		for (attr_it = 0; attr_it < a_length1; attr_it = attr_it + 1) {
+			GtkRenderAttribute attr;
+			attr = attr_collection[attr_it];
+			{
+				gee_map_set (self->priv->_header_attrs, attr.property, GINT_TO_POINTER (attr.column));
+			}
+		}
+	}
+}
+
+
+void gtk_grid_view_column_cell_set_cell_data (GtkGridViewColumn* self, GtkTreeModel* m, GtkTreeIter* i, gboolean h) {
+	GeeMap* attrs;
+	GtkCellRenderer* r;
+	GValue v = {0};
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	g_return_if_fail (m == NULL || GTK_IS_TREE_MODEL (m));
+	attrs = NULL;
+	r = NULL;
+	if (h && self->priv->_header_renderer != NULL) {
+		GtkCellRenderer* _tmp1;
+		GtkCellRenderer* _tmp0;
+		GeeMap* _tmp3;
+		GeeMap* _tmp2;
+		_tmp1 = NULL;
+		_tmp0 = NULL;
+		r = (_tmp1 = (_tmp0 = self->priv->_header_renderer, (_tmp0 == NULL ? NULL : g_object_ref (_tmp0))), (r == NULL ? NULL : (r = (g_object_unref (r), NULL))), _tmp1);
+		_tmp3 = NULL;
+		_tmp2 = NULL;
+		attrs = (_tmp3 = (_tmp2 = self->priv->_header_attrs, (_tmp2 == NULL ? NULL : g_object_ref (_tmp2))), (attrs == NULL ? NULL : (attrs = (g_object_unref (attrs), NULL))), _tmp3);
+	} else {
+		GtkCellRenderer* _tmp5;
+		GtkCellRenderer* _tmp4;
+		GeeMap* _tmp7;
+		GeeMap* _tmp6;
+		_tmp5 = NULL;
+		_tmp4 = NULL;
+		r = (_tmp5 = (_tmp4 = self->priv->_field_renderer, (_tmp4 == NULL ? NULL : g_object_ref (_tmp4))), (r == NULL ? NULL : (r = (g_object_unref (r), NULL))), _tmp5);
+		_tmp7 = NULL;
+		_tmp6 = NULL;
+		attrs = (_tmp7 = (_tmp6 = self->priv->_field_attrs, (_tmp6 == NULL ? NULL : g_object_ref (_tmp6))), (attrs == NULL ? NULL : (attrs = (g_object_unref (attrs), NULL))), _tmp7);
+	}
+	{
+		GeeSet* prop_collection;
+		GeeIterator* prop_it;
+		prop_collection = gee_map_get_keys (attrs);
+		prop_it = gee_iterable_iterator (GEE_ITERABLE (prop_collection));
+		while (gee_iterator_next (prop_it)) {
+			char* prop;
+			prop = ((char*) (gee_iterator_get (prop_it)));
+			{
+				/* XXX-VALA parameter v should be out instead of ref*/
+				gtk_tree_model_get_value (m, &(*i), GPOINTER_TO_INT (GPOINTER_TO_INT (gee_map_get (attrs, prop))), &v);
+				/* XXX-VALA set_property () is missing in glib.vapi*/
+				g_object_set_property (G_OBJECT (r), prop, &v);
+				prop = (g_free (prop), NULL);
+			}
+		}
+		(prop_it == NULL ? NULL : (prop_it = (g_object_unref (prop_it), NULL)));
+		(prop_collection == NULL ? NULL : (prop_collection = (g_object_unref (prop_collection), NULL)));
+	}
+	if (h && self->priv->_hdf != NULL) {
+		self->priv->_hdf (self, r, m, &(*i), self->priv->_hdf_target);
+	} else {
+		if (self->priv->_df != NULL) {
+			self->priv->_df (self, r, m, &(*i), self->priv->_df_target);
+		}
+	}
+	(attrs == NULL ? NULL : (attrs = (g_object_unref (attrs), NULL)));
+	(r == NULL ? NULL : (r = (g_object_unref (r), NULL)));
+}
+
+
+gboolean gtk_grid_view_column_get_visible (GtkGridViewColumn* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW_COLUMN (self), FALSE);
+	return self->priv->_visible;
+}
+
+
+void gtk_grid_view_column_set_visible (GtkGridViewColumn* self, gboolean value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	if (self->priv->_visible == value) {
+		return;
+	}
+	self->priv->_visible = value;
+	g_signal_emit_by_name (G_OBJECT (self), "visibility-changed");
+	g_object_notify (((GObject *) (self)), "visible");
+}
+
+
+GtkCellRenderer* gtk_grid_view_column_get_field_renderer (GtkGridViewColumn* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW_COLUMN (self), NULL);
+	return self->priv->_field_renderer;
+}
+
+
+static void gtk_grid_view_column_set_field_renderer (GtkGridViewColumn* self, GtkCellRenderer* value) {
+	GtkCellRenderer* _tmp2;
+	GtkCellRenderer* _tmp1;
+	g_return_if_fail (GTK_IS_GRID_VIEW_COLUMN (self));
+	_tmp2 = NULL;
+	_tmp1 = NULL;
+	self->priv->_field_renderer = (_tmp2 = (_tmp1 = value, (_tmp1 == NULL ? NULL : g_object_ref (_tmp1))), (self->priv->_field_renderer == NULL ? NULL : (self->priv->_field_renderer = (g_object_unref (self->priv->_field_renderer), NULL))), _tmp2);
+	g_object_notify (((GObject *) (self)), "field-renderer");
+}
+
+
+GtkCellRenderer* gtk_grid_view_column_get_header_renderer (GtkGridViewColumn* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW_COLUMN (self), NULL);
+	return self->priv->_header_renderer;
+}
+
+
+static void gtk_grid_view_column_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
+	GtkGridViewColumn * self;
+	self = GTK_GRID_VIEW_COLUMN (object);
+	switch (property_id) {
+		case GTK_GRID_VIEW_COLUMN_VISIBLE:
+		g_value_set_boolean (value, gtk_grid_view_column_get_visible (self));
+		break;
+		case GTK_GRID_VIEW_COLUMN_FIELD_RENDERER:
+		g_value_set_object (value, gtk_grid_view_column_get_field_renderer (self));
+		break;
+		case GTK_GRID_VIEW_COLUMN_HEADER_RENDERER:
+		g_value_set_object (value, gtk_grid_view_column_get_header_renderer (self));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_view_column_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) {
+	GtkGridViewColumn * self;
+	self = GTK_GRID_VIEW_COLUMN (object);
+	switch (property_id) {
+		case GTK_GRID_VIEW_COLUMN_VISIBLE:
+		gtk_grid_view_column_set_visible (self, g_value_get_boolean (value));
+		break;
+		case GTK_GRID_VIEW_COLUMN_FIELD_RENDERER:
+		gtk_grid_view_column_set_field_renderer (self, g_value_get_object (value));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_view_column_class_init (GtkGridViewColumnClass * klass) {
+	gtk_grid_view_column_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GtkGridViewColumnPrivate));
+	G_OBJECT_CLASS (klass)->get_property = gtk_grid_view_column_get_property;
+	G_OBJECT_CLASS (klass)->set_property = gtk_grid_view_column_set_property;
+	G_OBJECT_CLASS (klass)->dispose = gtk_grid_view_column_dispose;
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_COLUMN_VISIBLE, g_param_spec_boolean ("visible", "visible", "visible", FALSE, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_COLUMN_FIELD_RENDERER, g_param_spec_object ("field-renderer", "field-renderer", "field-renderer", GTK_TYPE_CELL_RENDERER, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_COLUMN_HEADER_RENDERER, g_param_spec_object ("header-renderer", "header-renderer", "header-renderer", GTK_TYPE_CELL_RENDERER, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+	g_signal_new ("visibility_changed", GTK_TYPE_GRID_VIEW_COLUMN, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+
+static void gtk_grid_view_column_instance_init (GtkGridViewColumn * self) {
+	self->priv = GTK_GRID_VIEW_COLUMN_GET_PRIVATE (self);
+	self->priv->_visible = TRUE;
+	self->priv->_header_attrs = GEE_MAP (gee_hash_map_new (G_TYPE_STRING, ((GBoxedCopyFunc) (g_strdup)), g_free, G_TYPE_INT, NULL, NULL, g_str_hash, g_str_equal, g_direct_equal));
+	self->priv->_field_attrs = GEE_MAP (gee_hash_map_new (G_TYPE_STRING, ((GBoxedCopyFunc) (g_strdup)), g_free, G_TYPE_INT, NULL, NULL, g_str_hash, g_str_equal, g_direct_equal));
+	self->priv->_df = NULL;
+	self->priv->_hdf = NULL;
+}
+
+
+static void gtk_grid_view_column_dispose (GObject * obj) {
+	GtkGridViewColumn * self;
+	self = GTK_GRID_VIEW_COLUMN (obj);
+	(self->priv->_header_renderer == NULL ? NULL : (self->priv->_header_renderer = (g_object_unref (self->priv->_header_renderer), NULL)));
+	(self->priv->_field_renderer == NULL ? NULL : (self->priv->_field_renderer = (g_object_unref (self->priv->_field_renderer), NULL)));
+	(self->priv->_header_attrs == NULL ? NULL : (self->priv->_header_attrs = (g_object_unref (self->priv->_header_attrs), NULL)));
+	(self->priv->_field_attrs == NULL ? NULL : (self->priv->_field_attrs = (g_object_unref (self->priv->_field_attrs), NULL)));
+	G_OBJECT_CLASS (gtk_grid_view_column_parent_class)->dispose (obj);
+}
+
+
+GType gtk_grid_view_column_get_type (void) {
+	static GType gtk_grid_view_column_type_id = 0;
+	if (G_UNLIKELY (gtk_grid_view_column_type_id == 0)) {
+		static const GTypeInfo g_define_type_info = { sizeof (GtkGridViewColumnClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gtk_grid_view_column_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GtkGridViewColumn), 0, (GInstanceInitFunc) gtk_grid_view_column_instance_init };
+		gtk_grid_view_column_type_id = g_type_register_static (G_TYPE_OBJECT, "GtkGridViewColumn", &g_define_type_info, 0);
+	}
+	return gtk_grid_view_column_type_id;
+}
+
+
+
+GType gtk_grid_view_scrollbar_span_get_type (void) {
+	static GType gtk_grid_view_scrollbar_span_type_id = 0;
+	if (G_UNLIKELY (gtk_grid_view_scrollbar_span_type_id == 0)) {
+		static const GEnumValue values[] = {{GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_GAP, "GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_GAP", "header-gap"}, {GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_OVERLAP, "GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_OVERLAP", "header-overlap"}, {GTK_GRID_VIEW_SCROLLBAR_SPAN_FULL, "GTK_GRID_VIEW_SCROLLBAR_SPAN_FULL", "full"}, {0, NULL, NULL}};
+		gtk_grid_view_scrollbar_span_type_id = g_enum_register_static ("GtkGridViewScrollbarSpan", values);
+	}
+	return gtk_grid_view_scrollbar_span_type_id;
+}
+
+
+static void _gtk_grid_view_on_column_visibility_changed_gtk_grid_view_column_visibility_changed (GtkGridViewColumn* _sender, gpointer self) {
+	gtk_grid_view_on_column_visibility_changed (self, _sender);
+}
+
+
+void gtk_grid_view_append_column (GtkGridView* self, GtkGridViewColumn* col) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col));
+	g_signal_connect_object (col, "visibility-changed", ((GCallback) (_gtk_grid_view_on_column_visibility_changed_gtk_grid_view_column_visibility_changed)), self, 0);
+	if (gtk_grid_view_column_get_visible (col)) {
+		GtkTreeIter i = {0};
+		gboolean _tmp0;
+		if (self->priv->_orientation == GTK_ORIENTATION_VERTICAL) {
+			gee_collection_add (GEE_COLLECTION (self->priv->_widths), GINT_TO_POINTER (0));
+		} else {
+			gee_collection_add (GEE_COLLECTION (self->priv->_heights), GINT_TO_POINTER (0));
+		}
+		gee_collection_add (GEE_COLLECTION (self->priv->_visible), col);
+		if (self->priv->_model != NULL && gtk_tree_model_get_iter_first (self->priv->_model, &i)) {
+			do {
+				GtkTreePath* path;
+				path = gtk_tree_model_get_path (self->priv->_model, &i);
+				gtk_grid_view_measure_cell (self, path, col);
+				(path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL)));
+			} while (gtk_tree_model_iter_next (self->priv->_model, &i));
+		}
+		if ((g_object_get (G_OBJECT (GTK_WIDGET (self)), "visible", &_tmp0, NULL), _tmp0)) {
+			gtk_grid_view_update_drawing_area_size_requests (self);
+		}
+	}
+	gee_collection_add (GEE_COLLECTION (self->priv->_columns), col);
+	g_signal_emit_by_name (G_OBJECT (self), "columns-changed");
+}
+
+
+GtkGridViewColumn* gtk_grid_view_append_column_with_attributes (GtkGridView* self, GtkCellRenderer* r, GtkRenderAttribute* a, int a_length1) {
+	GtkGridViewColumn* col;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
+	g_return_val_if_fail (r == NULL || GTK_IS_CELL_RENDERER (r), NULL);
+	col = gtk_grid_view_column_new (r);
+	gtk_grid_view_column_set_field_attrs (col, a, a_length1);
+	gtk_grid_view_append_column (self, col);
+	return col;
+}
+
+
+GtkGridViewColumn* gtk_grid_view_append_column_with_data_func (GtkGridView* self, GtkCellRenderer* r, GtkGridCellDataFunc f, void* f_target) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
+	g_return_val_if_fail (r == NULL || GTK_IS_CELL_RENDERER (r), NULL);
+	return gtk_grid_view_append_column_with_header (self, r, f, f_target, NULL, NULL, NULL);
+}
+
+
+GtkGridViewColumn* gtk_grid_view_append_column_with_header (GtkGridView* self, GtkCellRenderer* r, GtkGridCellDataFunc f, void* f_target, GtkCellRenderer* hr, GtkGridCellDataFunc hf, void* hf_target) {
+	GtkGridViewColumn* col;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
+	g_return_val_if_fail (r == NULL || GTK_IS_CELL_RENDERER (r), NULL);
+	g_return_val_if_fail (hr == NULL || GTK_IS_CELL_RENDERER (hr), NULL);
+	col = gtk_grid_view_column_new (r);
+	gtk_grid_view_column_set_cell_data_func (col, f, f_target);
+	if (hr != NULL) {
+		gtk_grid_view_column_set_header_renderer (col, hr, NULL, 0);
+		gtk_grid_view_column_set_header_cell_data_func (col, hf, hf_target);
+	}
+	gtk_grid_view_append_column (self, col);
+	return col;
+}
+
+
+gint gtk_grid_view_remove_column (GtkGridView* self, GtkGridViewColumn* col) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	g_return_val_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col), 0);
+	if (!gee_collection_contains (GEE_COLLECTION (self->priv->_columns), col)) {
+		g_warning ("gridview.vala:592: Trying to remove non-existent column");
+		return gee_collection_get_size (GEE_COLLECTION (self->priv->_columns));
+	}
+	if (gtk_grid_view_column_get_visible (col)) {
+		if (self->priv->_orientation == GTK_ORIENTATION_VERTICAL) {
+			gee_list_remove_at (self->priv->_widths, gee_list_index_of (self->priv->_visible, col));
+		} else {
+			gee_list_remove_at (self->priv->_heights, gee_list_index_of (self->priv->_visible, col));
+		}
+		gee_collection_remove (GEE_COLLECTION (self->priv->_visible), col);
+		gtk_grid_view_update_drawing_area_size_requests (self);
+	}
+	gee_collection_remove (GEE_COLLECTION (self->priv->_columns), col);
+	g_signal_emit_by_name (G_OBJECT (self), "columns-changed");
+	return gee_collection_get_size (GEE_COLLECTION (self->priv->_columns));
+}
+
+
+gboolean gtk_grid_view_get_selectable (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col) {
+	GtkTreeIter i = {0};
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col), FALSE);
+	return col != NULL && gee_collection_contains (GEE_COLLECTION (self->priv->_columns), col) && gtk_grid_view_column_get_visible (col) && gee_list_index_of (self->priv->_visible, col) >= self->priv->r_span && path != NULL && gtk_tree_path_get_indices (path)[0] >= self->priv->c_span && gtk_tree_model_get_iter (self->priv->_model, &i, path);
+}
+
+
+void gtk_grid_view_scroll_to_cell (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, gboolean a, float ra, float ca) {
+	GtkAdjustment* adj;
+	GtkWidget* widget;
+	GtkWidget* _tmp2;
+	GdkRectangle _tmp1 = {0};
+	GtkWidget* _tmp0;
+	GdkRectangle rect;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col));
+	adj = NULL;
+	widget = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	rect = (_tmp1 = gtk_grid_view_cell_rect (self, path, col, &_tmp0), widget = (_tmp2 = _tmp0, (widget == NULL ? NULL : (widget = (g_object_unref (widget), NULL))), _tmp2), _tmp1);
+	if (widget == GTK_WIDGET (self->priv->tda) || widget == GTK_WIDGET (self->priv->fda)) {
+		GtkAdjustment* _tmp4;
+		GtkAdjustment* _tmp3;
+		_tmp4 = NULL;
+		_tmp3 = NULL;
+		adj = (_tmp4 = (_tmp3 = gtk_viewport_get_hadjustment (self->priv->fvp), (_tmp3 == NULL ? NULL : g_object_ref (_tmp3))), (adj == NULL ? NULL : (adj = (g_object_unref (adj), NULL))), _tmp4);
+		if (a) {
+			double _tmp7;
+			double _tmp6;
+			double _tmp5;
+			gtk_adjustment_set_value (adj, MIN ((g_object_get (G_OBJECT (adj), "upper", &_tmp5, NULL), _tmp5) - (g_object_get (G_OBJECT (adj), "page-size", &_tmp6, NULL), _tmp6), (rect.x + rect.width / 2) - (g_object_get (G_OBJECT (adj), "page-size", &_tmp7, NULL), _tmp7) * ra));
+		} else {
+			if (rect.x < gtk_adjustment_get_value (adj) || rect.width > GTK_WIDGET (self->priv->fvp)->allocation.width) {
+				gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) - (gtk_adjustment_get_value (adj) - rect.x));
+			} else {
+				if (gdk_rect_right (&rect) > GTK_WIDGET (self->priv->fvp)->allocation.width + gtk_adjustment_get_value (adj)) {
+					gtk_adjustment_set_value (adj, ((double) (gdk_rect_right (&rect) - GTK_WIDGET (self->priv->fvp)->allocation.width)));
+				}
+			}
+		}
+	}
+	if (widget == GTK_WIDGET (self->priv->lda) || widget == GTK_WIDGET (self->priv->fda)) {
+		GtkAdjustment* _tmp9;
+		GtkAdjustment* _tmp8;
+		_tmp9 = NULL;
+		_tmp8 = NULL;
+		adj = (_tmp9 = (_tmp8 = gtk_viewport_get_vadjustment (self->priv->fvp), (_tmp8 == NULL ? NULL : g_object_ref (_tmp8))), (adj == NULL ? NULL : (adj = (g_object_unref (adj), NULL))), _tmp9);
+		if (a) {
+			double _tmp12;
+			double _tmp11;
+			double _tmp10;
+			gtk_adjustment_set_value (adj, MIN ((g_object_get (G_OBJECT (adj), "upper", &_tmp10, NULL), _tmp10) - (g_object_get (G_OBJECT (adj), "page-size", &_tmp11, NULL), _tmp11), (rect.y + rect.height / 2) - (g_object_get (G_OBJECT (adj), "page-size", &_tmp12, NULL), _tmp12) * ca));
+		} else {
+			if (rect.y < gtk_adjustment_get_value (adj) || rect.height > GTK_WIDGET (self->priv->fvp)->allocation.height) {
+				gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) - (gtk_adjustment_get_value (adj) - rect.y));
+			} else {
+				if (gdk_rect_bottom (&rect) > GTK_WIDGET (self->priv->fvp)->allocation.height + gtk_adjustment_get_value (adj)) {
+					gtk_adjustment_set_value (adj, ((double) (gdk_rect_bottom (&rect) - GTK_WIDGET (self->priv->fvp)->allocation.height)));
+				}
+			}
+		}
+	}
+	(adj == NULL ? NULL : (adj = (g_object_unref (adj), NULL)));
+	(widget == NULL ? NULL : (widget = (g_object_unref (widget), NULL)));
+}
+
+
+static void gtk_grid_view_real_add (GtkContainer* base, GtkWidget* w) {
+	GtkGridView * self;
+	self = GTK_GRID_VIEW (base);
+	g_return_if_fail (w == NULL || GTK_IS_WIDGET (w));
+	gtk_widget_set_parent (w, GTK_WIDGET (self));
+	gee_collection_add (GEE_COLLECTION (self->priv->_children), w);
+}
+
+
+static void gtk_grid_view_real_remove (GtkContainer* base, GtkWidget* w) {
+	GtkGridView * self;
+	self = GTK_GRID_VIEW (base);
+	g_return_if_fail (w == NULL || GTK_IS_WIDGET (w));
+	if (w != NULL) {
+		gee_collection_remove (GEE_COLLECTION (self->priv->_children), w);
+		gtk_widget_unparent (w);
+	}
+}
+
+
+static void gtk_grid_view_real_forall (GtkContainer* base, gboolean i, GtkCallback cb, void* cb_target) {
+	GtkGridView * self;
+	self = GTK_GRID_VIEW (base);
+	{
+		GeeList* widget_collection;
+		int widget_it;
+		widget_collection = self->priv->_children;
+		for (widget_it = 0; widget_it < gee_collection_get_size (GEE_COLLECTION (widget_collection)); widget_it = widget_it + 1) {
+			GtkWidget* widget;
+			widget = ((GtkWidget*) (gee_list_get (GEE_LIST (widget_collection), widget_it)));
+			{
+				cb (widget, cb_target);
+				(widget == NULL ? NULL : (widget = (g_object_unref (widget), NULL)));
+			}
+		}
+	}
+}
+
+
+static void gtk_grid_view_real_size_request (GtkWidget* base, GtkRequisition* r) {
+	GtkGridView * self;
+	GtkRequisition bar_req = {0};
+	self = GTK_GRID_VIEW (base);
+	/**
+	 * XXX: this doesn't change when the visibility of a scrollbar
+	 *      changes.
+	 **/
+	gtk_widget_size_request (GTK_WIDGET (self->priv->vbar), &bar_req);
+	(*r).width = gtk_grid_view_get_left_width (self) + (GPOINTER_TO_INT ((gtk_grid_view_get_x_span (self) < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)) ? GPOINTER_TO_INT (gee_list_get (self->priv->_widths, gtk_grid_view_get_x_span (self))) : 0))) + ((gint) (gtk_container_get_border_width (GTK_CONTAINER (self)))) + bar_req.width;
+	gtk_widget_size_request (GTK_WIDGET (self->priv->hbar), &bar_req);
+	(*r).height = gtk_grid_view_get_top_height (self) + (GPOINTER_TO_INT ((gtk_grid_view_get_y_span (self) < gee_collection_get_size (GEE_COLLECTION (self->priv->_heights)) ? GPOINTER_TO_INT (gee_list_get (self->priv->_heights, gtk_grid_view_get_y_span (self))) : 0))) + ((gint) (gtk_container_get_border_width (GTK_CONTAINER (self)))) + bar_req.height;
+}
+
+
+/**
+ * we need to call queue_draw () on each of the drawing areas to avoid
+ * some nasty unpainted rect artifacts on win32
+ **/
+static void gtk_grid_view_real_size_allocate (GtkWidget* base, GdkRectangle* a) {
+	GtkGridView * self;
+	GtkRequisition hbar_r = {0};
+	GtkRequisition vbar_r = {0};
+	gboolean hbar_v;
+	gboolean vbar_v;
+	gboolean _tmp2;
+	gboolean _tmp3;
+	GdkRectangle wa = {0};
+	GdkRectangle _tmp4 = {0};
+	GdkRectangle _tmp5 = {0};
+	gint gap;
+	gboolean _tmp6;
+	gboolean _tmp8;
+	self = GTK_GRID_VIEW (base);
+	GTK_WIDGET (self)->allocation = ((GtkAllocation) ((*a)));
+	gtk_widget_size_request (GTK_WIDGET (self->priv->hbar), &hbar_r);
+	gtk_widget_size_request (GTK_WIDGET (self->priv->vbar), &vbar_r);
+	/**
+	 * tmp variables to store the scrollbar visibilities, as flipping
+	 * the .visible property can cause infinite size_allocate () loop
+	 **/
+	hbar_v = FALSE;
+	vbar_v = FALSE;
+	hbar_v = self->priv->_hbar_policy == GTK_POLICY_ALWAYS || (self->priv->_hbar_policy == GTK_POLICY_AUTOMATIC && gtk_grid_view_get_left_width (self) + gtk_grid_view_get_field_width (self) + gtk_container_get_border_width (GTK_CONTAINER (self)) > (*a).width);
+	vbar_v = self->priv->_vbar_policy == GTK_POLICY_ALWAYS || (self->priv->_vbar_policy == GTK_POLICY_AUTOMATIC && gtk_grid_view_get_top_height (self) + gtk_grid_view_get_field_height (self) + gtk_container_get_border_width (GTK_CONTAINER (self)) + ((hbar_v ? hbar_r.height : 0)) > (*a).height);
+	if (!vbar_v) {
+		GtkRequisition _tmp0 = {0};
+		vbar_r = (memset (&_tmp0, 0, sizeof (GtkRequisition)), _tmp0);
+	} else {
+		/**
+		 * the horizontal space used to show the vbar may now
+		 * cause the hbar to be needed
+		 **/
+		hbar_v = self->priv->_hbar_policy == GTK_POLICY_ALWAYS || (self->priv->_hbar_policy == GTK_POLICY_AUTOMATIC && gtk_grid_view_get_left_width (self) + gtk_grid_view_get_field_width (self) + gtk_container_get_border_width (GTK_CONTAINER (self)) + vbar_r.width > (*a).width);
+	}
+	if (!hbar_v) {
+		GtkRequisition _tmp1 = {0};
+		hbar_r = (memset (&_tmp1, 0, sizeof (GtkRequisition)), _tmp1);
+	}
+	g_object_set (GTK_WIDGET (self->priv->hbar), "visible", hbar_v, NULL);
+	g_object_set (GTK_WIDGET (self->priv->vbar), "visible", vbar_v, NULL);
+	wa.x = (*a).x;
+	wa.y = (*a).y;
+	wa.width = gtk_grid_view_get_left_width (self);
+	wa.height = gtk_grid_view_get_top_height (self);
+	gtk_widget_size_allocate (GTK_WIDGET (self->priv->cda), &wa);
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->cda));
+	wa.x = gdk_rect_right ((_tmp4 = ((GdkRectangle) (GTK_WIDGET (self->priv->cda)->allocation)), &_tmp4));
+	wa.y = (*a).y;
+	wa.width = (*a).width - gtk_grid_view_get_left_width (self) - ((gint) (gtk_container_get_border_width (GTK_CONTAINER (self)))) - ((self->priv->_vbar_span != GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_OVERLAP ? vbar_r.width : 0));
+	wa.height = gtk_grid_view_get_top_height (self);
+	gtk_widget_size_allocate (GTK_WIDGET (self->priv->tvp), &wa);
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->tvp));
+	wa.x = (*a).x;
+	wa.y = gdk_rect_bottom ((_tmp5 = ((GdkRectangle) (GTK_WIDGET (self->priv->cda)->allocation)), &_tmp5));
+	wa.width = gtk_grid_view_get_left_width (self);
+	wa.height = (*a).height - gtk_grid_view_get_top_height (self) - ((gint) (gtk_container_get_border_width (GTK_CONTAINER (self)))) - ((self->priv->_hbar_span != GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_OVERLAP ? hbar_r.height : 0));
+	gtk_widget_size_allocate (GTK_WIDGET (self->priv->lvp), &wa);
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->lvp));
+	wa.x = (*a).x + gtk_grid_view_get_left_width (self);
+	wa.y = (*a).y + gtk_grid_view_get_top_height (self);
+	wa.width = (*a).width - gtk_grid_view_get_left_width (self) - ((gint) (gtk_container_get_border_width (GTK_CONTAINER (self)))) - vbar_r.width;
+	wa.height = (*a).height - gtk_grid_view_get_top_height (self) - ((gint) (gtk_container_get_border_width (GTK_CONTAINER (self)))) - hbar_r.height;
+	gtk_widget_size_allocate (GTK_WIDGET (self->priv->fvp), &wa);
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->fvp));
+	gap = 0;
+	if ((g_object_get (G_OBJECT (GTK_WIDGET (self->priv->hbar)), "visible", &_tmp6, NULL), _tmp6)) {
+		GdkRectangle _tmp7 = {0};
+		gap = (self->priv->_hbar_span == GTK_GRID_VIEW_SCROLLBAR_SPAN_FULL ? 0 : gtk_grid_view_get_left_width (self));
+		wa.x = (*a).x + gap;
+		wa.y = gdk_rect_bottom ((_tmp7 = ((GdkRectangle) ((*a))), &_tmp7)) - hbar_r.height;
+		wa.width = (*a).width - gap - vbar_r.width;
+		wa.height = hbar_r.height;
+		gtk_widget_size_allocate (GTK_WIDGET (self->priv->hbar), &wa);
+	}
+	if ((g_object_get (G_OBJECT (GTK_WIDGET (self->priv->vbar)), "visible", &_tmp8, NULL), _tmp8)) {
+		GdkRectangle _tmp9 = {0};
+		gap = (self->priv->_vbar_span == GTK_GRID_VIEW_SCROLLBAR_SPAN_FULL ? 0 : gtk_grid_view_get_top_height (self));
+		wa.x = gdk_rect_right ((_tmp9 = ((GdkRectangle) ((*a))), &_tmp9)) - vbar_r.width;
+		wa.y = (*a).y + gap;
+		wa.width = vbar_r.width;
+		wa.height = (*a).height - gap - hbar_r.height;
+		gtk_widget_size_allocate (GTK_WIDGET (self->priv->vbar), &wa);
+	}
+}
+
+
+static void gtk_grid_view_on_model_row_changed (GtkGridView* self, GtkTreeModel* m, GtkTreePath* path, GtkTreeIter* iter) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (m == NULL || GTK_IS_TREE_MODEL (m));
+	{
+		GeeList* col_collection;
+		int col_it;
+		col_collection = self->priv->_visible;
+		for (col_it = 0; col_it < gee_collection_get_size (GEE_COLLECTION (col_collection)); col_it = col_it + 1) {
+			GtkGridViewColumn* col;
+			col = ((GtkGridViewColumn*) (gee_list_get (GEE_LIST (col_collection), col_it)));
+			{
+				GtkTreePath* p;
+				/* We don't just use the path directly,
+				 as for some bloody reason the path.depth
+				 gets corrupted on win32 randomly resulting 
+				 in depths of 10923461, and things go boom.*/
+				p = gtk_tree_model_get_path (self->priv->_model, &(*iter));
+				gtk_grid_view_measure_cell (self, p, col);
+				gtk_grid_view_invalidate_cell_rect (self, p, col);
+				(col == NULL ? NULL : (col = (g_object_unref (col), NULL)));
+				(p == NULL ? NULL : (p = (gtk_tree_path_free (p), NULL)));
+			}
+		}
+	}
+	gtk_grid_view_update_drawing_area_size_requests (self);
+}
+
+
+static void gtk_grid_view_on_model_row_deleted (GtkGridView* self, GtkTreeModel* m, GtkTreePath* path) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (m == NULL || GTK_IS_TREE_MODEL (m));
+	if (self->priv->_orientation == GTK_ORIENTATION_VERTICAL) {
+		gee_list_remove_at (self->priv->_heights, gtk_tree_path_get_indices (path)[0]);
+	} else {
+		gee_list_remove_at (self->priv->_widths, gtk_tree_path_get_indices (path)[0]);
+	}
+	gtk_grid_view_update_drawing_area_size_requests (self);
+}
+
+
+static void gtk_grid_view_on_model_row_inserted (GtkGridView* self, GtkTreeModel* m, GtkTreePath* path) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (m == NULL || GTK_IS_TREE_MODEL (m));
+	if (self->priv->_orientation == GTK_ORIENTATION_VERTICAL) {
+		gee_list_insert (self->priv->_heights, gtk_tree_path_get_indices (path)[0], GINT_TO_POINTER (0));
+	} else {
+		gee_list_insert (self->priv->_widths, gtk_tree_path_get_indices (path)[0], GINT_TO_POINTER (0));
+	}
+}
+
+
+static void gtk_grid_view_on_model_rows_reordered (GtkGridView* self, GtkTreeModel* m) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (m == NULL || GTK_IS_TREE_MODEL (m));
+}
+
+
+/* XXX*/
+static void gtk_grid_view_on_style_set (GtkGridView* self, GtkGridView* s, GtkStyle* style) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (s == NULL || GTK_IS_GRID_VIEW (s));
+	g_return_if_fail (style == NULL || GTK_IS_STYLE (style));
+	gtk_grid_view_rebuild_dimensions (self);
+}
+
+
+static void gtk_grid_view_on_state_changed (GtkGridView* self, GtkGridView* s, GtkStateType previous_state) {
+	GdkRectangle ir = {0};
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (s == NULL || GTK_IS_GRID_VIEW (s));
+	ir.x = 0;
+	ir.y = 0;
+	ir.width = GTK_WIDGET (self->priv->cda)->allocation.width;
+	ir.height = GTK_WIDGET (self->priv->cda)->allocation.height;
+	gdk_window_invalidate_rect (GTK_WIDGET (self->priv->cda)->window, &ir, TRUE);
+	ir.x = 0;
+	ir.y = 0;
+	ir.width = GTK_WIDGET (self->priv->tda)->allocation.width;
+	ir.height = GTK_WIDGET (self->priv->tda)->allocation.height;
+	gdk_window_invalidate_rect (GTK_WIDGET (self->priv->tda)->window, &ir, TRUE);
+	ir.x = 0;
+	ir.y = 0;
+	ir.width = GTK_WIDGET (self->priv->lda)->allocation.width;
+	ir.height = GTK_WIDGET (self->priv->lda)->allocation.height;
+	gdk_window_invalidate_rect (GTK_WIDGET (self->priv->lda)->window, &ir, TRUE);
+	ir.x = 0;
+	ir.y = 0;
+	ir.width = GTK_WIDGET (self->priv->fda)->allocation.width;
+	ir.height = GTK_WIDGET (self->priv->fda)->allocation.height;
+	gdk_window_invalidate_rect (GTK_WIDGET (self->priv->fda)->window, &ir, TRUE);
+}
+
+
+static gboolean gtk_grid_view_on_focus_in_event (GtkGridView* self, GtkGridView* s, GdkEventFocus* event) {
+	GtkTreePath* spath;
+	GtkGridViewColumn* scol;
+	GtkGridViewColumn* _tmp5;
+	gboolean _tmp4;
+	GtkGridViewColumn* _tmp3;
+	GtkTreePath* _tmp2;
+	gboolean _tmp1;
+	GtkTreePath* _tmp0;
+	gboolean _tmp6;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (s == NULL || GTK_IS_GRID_VIEW (s), FALSE);
+	spath = NULL;
+	scol = NULL;
+	_tmp5 = NULL;
+	_tmp3 = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	if ((_tmp4 = (_tmp1 = gtk_grid_selection_get_selected (self->priv->_selection, &_tmp0, &_tmp3), spath = (_tmp2 = _tmp0, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp2), _tmp1), scol = (_tmp5 = _tmp3, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp5), _tmp4)) {
+		gtk_grid_view_invalidate_cell_rect (self, spath, scol);
+	}
+	return (_tmp6 = FALSE, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp6);
+}
+
+
+static gboolean gtk_grid_view_on_focus_out_event (GtkGridView* self, GtkGridView* s, GdkEventFocus* event) {
+	GtkTreePath* spath;
+	GtkGridViewColumn* scol;
+	GtkGridViewColumn* _tmp5;
+	gboolean _tmp4;
+	GtkGridViewColumn* _tmp3;
+	GtkTreePath* _tmp2;
+	gboolean _tmp1;
+	GtkTreePath* _tmp0;
+	gboolean _tmp6;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (s == NULL || GTK_IS_GRID_VIEW (s), FALSE);
+	spath = NULL;
+	scol = NULL;
+	_tmp5 = NULL;
+	_tmp3 = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	if ((_tmp4 = (_tmp1 = gtk_grid_selection_get_selected (self->priv->_selection, &_tmp0, &_tmp3), spath = (_tmp2 = _tmp0, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp2), _tmp1), scol = (_tmp5 = _tmp3, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp5), _tmp4)) {
+		gtk_grid_view_invalidate_cell_rect (self, spath, scol);
+	}
+	return (_tmp6 = FALSE, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp6);
+}
+
+
+static gboolean gtk_grid_view_on_button_press_event (GtkGridView* self, GtkGridView* s, GdkEventButton* event) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (s == NULL || GTK_IS_GRID_VIEW (s), FALSE);
+	gtk_widget_grab_focus (GTK_WIDGET (self));
+	return FALSE;
+}
+
+
+static gboolean gtk_grid_view_on_key_press_event (GtkGridView* self, GtkGridView* s, GdkEventKey* event) {
+	GtkTreePath* spath;
+	GtkGridViewColumn* scol;
+	GtkGridViewColumn* _tmp5;
+	gboolean _tmp4;
+	GtkGridViewColumn* _tmp3;
+	GtkTreePath* _tmp2;
+	gboolean _tmp1;
+	GtkTreePath* _tmp0;
+	gint x;
+	gint y;
+	guint _tmp8;
+	GtkGridViewColumn* _tmp14;
+	gboolean _tmp13;
+	GtkGridViewColumn* _tmp12;
+	GtkTreePath* _tmp11;
+	gboolean _tmp10;
+	GtkTreePath* _tmp9;
+	gboolean _tmp15;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (s == NULL || GTK_IS_GRID_VIEW (s), FALSE);
+	spath = NULL;
+	scol = NULL;
+	_tmp5 = NULL;
+	_tmp3 = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	if (!(_tmp4 = (_tmp1 = gtk_grid_selection_get_selected (self->priv->_selection, &_tmp0, &_tmp3), spath = (_tmp2 = _tmp0, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp2), _tmp1), scol = (_tmp5 = _tmp3, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp5), _tmp4)) {
+		gboolean _tmp6;
+		return (_tmp6 = FALSE, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp6);
+	}
+	x = 0;
+	y = 0;
+	gtk_grid_view_translate_coords (self, spath, scol, &x, &y);
+	_tmp8 = (*event).keyval;
+	if (_tmp8 == GDK_KEY_UP)
+	do {
+		y = y - (1);
+		break;
+	} while (0); else if (_tmp8 == GDK_KEY_DOWN)
+	do {
+		y = y + (1);
+		break;
+	} while (0); else if (_tmp8 == GDK_KEY_LEFT)
+	do {
+		x = x - (1);
+		break;
+	} while (0); else if (_tmp8 == GDK_KEY_RIGHT)
+	do {
+		x = x + (1);
+		break;
+	} while (0); else
+	do {
+		gboolean _tmp7;
+		return (_tmp7 = FALSE, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp7);
+	} while (0);
+	_tmp14 = NULL;
+	_tmp12 = NULL;
+	_tmp11 = NULL;
+	_tmp9 = NULL;
+	if ((_tmp13 = (_tmp10 = gtk_grid_view_translate_coords_b (self, x, y, &_tmp9, &_tmp12), spath = (_tmp11 = _tmp9, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp11), _tmp10), scol = (_tmp14 = _tmp12, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp14), _tmp13) && gtk_grid_selection_select_cell (self->priv->_selection, spath, scol)) {
+		gtk_grid_view_scroll_to_cell (self, spath, scol, FALSE, ((float) (0)), ((float) (0)));
+	}
+	return (_tmp15 = TRUE, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp15);
+}
+
+
+static void gtk_grid_view_on_selection_changed (GtkGridView* self, GtkGridSelection* s) {
+	GtkTreePath* spath;
+	GtkGridViewColumn* scol;
+	GtkGridViewColumn* _tmp5;
+	gboolean _tmp4;
+	GtkGridViewColumn* _tmp3;
+	GtkTreePath* _tmp2;
+	gboolean _tmp1;
+	GtkTreePath* _tmp0;
+	GtkGridViewColumn* _tmp9;
+	GtkGridViewColumn* _tmp8;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (s == NULL || GTK_IS_GRID_SELECTION (s));
+	if (self->priv->_model != NULL && gtk_grid_view_get_selectable (self, self->priv->_prev_sel_path, self->priv->_prev_sel_col)) {
+		gtk_grid_view_invalidate_cell_rect (self, self->priv->_prev_sel_path, self->priv->_prev_sel_col);
+	}
+	spath = NULL;
+	scol = NULL;
+	_tmp5 = NULL;
+	_tmp3 = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	if ((_tmp4 = (_tmp1 = gtk_grid_selection_get_selected (self->priv->_selection, &_tmp0, &_tmp3), spath = (_tmp2 = _tmp0, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp2), _tmp1), scol = (_tmp5 = _tmp3, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp5), _tmp4)) {
+		gtk_grid_view_invalidate_cell_rect (self, spath, scol);
+	}
+	if (spath != NULL) {
+		GtkTreePath* _tmp6;
+		_tmp6 = NULL;
+		self->priv->_prev_sel_path = (_tmp6 = gtk_tree_path_copy (spath), (self->priv->_prev_sel_path == NULL ? NULL : (self->priv->_prev_sel_path = (gtk_tree_path_free (self->priv->_prev_sel_path), NULL))), _tmp6);
+	} else {
+		GtkTreePath* _tmp7;
+		_tmp7 = NULL;
+		self->priv->_prev_sel_path = (_tmp7 = NULL, (self->priv->_prev_sel_path == NULL ? NULL : (self->priv->_prev_sel_path = (gtk_tree_path_free (self->priv->_prev_sel_path), NULL))), _tmp7);
+	}
+	_tmp9 = NULL;
+	_tmp8 = NULL;
+	self->priv->_prev_sel_col = (_tmp9 = (_tmp8 = scol, (_tmp8 == NULL ? NULL : g_object_ref (_tmp8))), (self->priv->_prev_sel_col == NULL ? NULL : (self->priv->_prev_sel_col = (g_object_unref (self->priv->_prev_sel_col), NULL))), _tmp9);
+	(spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL)));
+	(scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL)));
+}
+
+
+static gboolean gtk_grid_view_on_cda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event) {
+	GtkGridViewColumn* col;
+	GtkTreePath* path;
+	gboolean _tmp7;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	if (self->priv->_model == NULL) {
+		return FALSE;
+	}
+	col = NULL;
+	path = NULL;
+	{
+		gint x;
+		x = 0;
+		for (; x < gtk_grid_view_get_x_span (self); x++) {
+			{
+				gint y;
+				y = 0;
+				for (; y < gtk_grid_view_get_y_span (self); y++) {
+					GtkGridViewColumn* _tmp6;
+					gboolean _tmp5;
+					GtkGridViewColumn* _tmp4;
+					GtkTreePath* _tmp3;
+					gboolean _tmp2;
+					GtkTreePath* _tmp1;
+					_tmp6 = NULL;
+					_tmp4 = NULL;
+					_tmp3 = NULL;
+					_tmp1 = NULL;
+					if ((_tmp5 = (_tmp2 = gtk_grid_view_translate_coords_b (self, x, y, &_tmp1, &_tmp4), path = (_tmp3 = _tmp1, (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp3), _tmp2), col = (_tmp6 = _tmp4, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), _tmp6), _tmp5)) {
+						gtk_grid_view_draw_cell (self, path, col, &(*event).area);
+					}
+				}
+			}
+		}
+	}
+	return (_tmp7 = FALSE, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp7);
+}
+
+
+static gboolean gtk_grid_view_on_tda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event) {
+	GtkGridViewColumn* col;
+	GtkTreePath* path;
+	gboolean _tmp7;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	if (self->priv->_model == NULL) {
+		return FALSE;
+	}
+	col = NULL;
+	path = NULL;
+	{
+		gint x;
+		x = gtk_grid_view_get_x_span (self);
+		for (; x < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)); x++) {
+			{
+				gint y;
+				y = 0;
+				for (; y < gtk_grid_view_get_y_span (self); y++) {
+					GtkGridViewColumn* _tmp6;
+					gboolean _tmp5;
+					GtkGridViewColumn* _tmp4;
+					GtkTreePath* _tmp3;
+					gboolean _tmp2;
+					GtkTreePath* _tmp1;
+					_tmp6 = NULL;
+					_tmp4 = NULL;
+					_tmp3 = NULL;
+					_tmp1 = NULL;
+					if ((_tmp5 = (_tmp2 = gtk_grid_view_translate_coords_b (self, x, y, &_tmp1, &_tmp4), path = (_tmp3 = _tmp1, (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp3), _tmp2), col = (_tmp6 = _tmp4, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), _tmp6), _tmp5)) {
+						gtk_grid_view_draw_cell (self, path, col, &(*event).area);
+					}
+				}
+			}
+		}
+	}
+	return (_tmp7 = FALSE, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp7);
+}
+
+
+static gboolean gtk_grid_view_on_lda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event) {
+	GtkGridViewColumn* col;
+	GtkTreePath* path;
+	gboolean _tmp7;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	if (self->priv->_model == NULL) {
+		return FALSE;
+	}
+	col = NULL;
+	path = NULL;
+	{
+		gint x;
+		x = 0;
+		for (; x < gtk_grid_view_get_x_span (self); x++) {
+			{
+				gint y;
+				y = gtk_grid_view_get_y_span (self);
+				for (; y < gee_collection_get_size (GEE_COLLECTION (self->priv->_heights)); y++) {
+					GtkGridViewColumn* _tmp6;
+					gboolean _tmp5;
+					GtkGridViewColumn* _tmp4;
+					GtkTreePath* _tmp3;
+					gboolean _tmp2;
+					GtkTreePath* _tmp1;
+					_tmp6 = NULL;
+					_tmp4 = NULL;
+					_tmp3 = NULL;
+					_tmp1 = NULL;
+					if ((_tmp5 = (_tmp2 = gtk_grid_view_translate_coords_b (self, x, y, &_tmp1, &_tmp4), path = (_tmp3 = _tmp1, (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp3), _tmp2), col = (_tmp6 = _tmp4, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), _tmp6), _tmp5)) {
+						gtk_grid_view_draw_cell (self, path, col, &(*event).area);
+					}
+				}
+			}
+		}
+	}
+	return (_tmp7 = FALSE, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp7);
+}
+
+
+static gboolean gtk_grid_view_on_fda_expose_event (GtkGridView* self, GtkDrawingArea* da, GdkEventExpose* event) {
+	GtkGridViewColumn* col;
+	GtkTreePath* path;
+	gboolean _tmp7;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	if (self->priv->_model == NULL) {
+		return FALSE;
+	}
+	col = NULL;
+	path = NULL;
+	{
+		gint x;
+		x = gtk_grid_view_get_x_span (self);
+		for (; x < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)); x++) {
+			{
+				gint y;
+				y = gtk_grid_view_get_y_span (self);
+				for (; y < gee_collection_get_size (GEE_COLLECTION (self->priv->_heights)); y++) {
+					GtkGridViewColumn* _tmp6;
+					gboolean _tmp5;
+					GtkGridViewColumn* _tmp4;
+					GtkTreePath* _tmp3;
+					gboolean _tmp2;
+					GtkTreePath* _tmp1;
+					_tmp6 = NULL;
+					_tmp4 = NULL;
+					_tmp3 = NULL;
+					_tmp1 = NULL;
+					if ((_tmp5 = (_tmp2 = gtk_grid_view_translate_coords_b (self, x, y, &_tmp1, &_tmp4), path = (_tmp3 = _tmp1, (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp3), _tmp2), col = (_tmp6 = _tmp4, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), _tmp6), _tmp5)) {
+						gtk_grid_view_draw_cell (self, path, col, &(*event).area);
+					}
+				}
+			}
+		}
+	}
+	return (_tmp7 = FALSE, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp7);
+}
+
+
+static gboolean gtk_grid_view_on_yheader_motion_notify_event (GtkGridView* self, GtkDrawingArea* da, GdkEventMotion* event) {
+	gint x;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	x = ((gint) ((*event).x));
+	if (da == self->priv->tda) {
+		x = x + (gtk_grid_view_get_left_width (self));
+	}
+	gdk_window_set_cursor (GTK_WIDGET (da)->window, (self->priv->_drag_col >= 0 || gtk_grid_view_drag_x (self, x) >= 0 ? gtk_grid_view_DRAG_CURSOR : NULL));
+	if (self->priv->_drag_col >= 0 && x > gtk_grid_view_column_x (self, self->priv->_drag_col) + 12) {
+		gint prev_width;
+		GtkRequisition vbar_req = {0};
+		gboolean _tmp0;
+		prev_width = GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_widths, self->priv->_drag_col)));
+		gee_list_set (self->priv->_widths, self->priv->_drag_col, GINT_TO_POINTER (x - gtk_grid_view_column_x (self, self->priv->_drag_col)));
+		/**
+		 * make sure that we don't cause the grid's size request
+		 * to increase
+		 **/
+		gtk_widget_size_request (GTK_WIDGET (self->priv->vbar), &vbar_req);
+		if (self->priv->_drag_col <= gtk_grid_view_get_x_span (self) && gtk_grid_view_column_x (self, gtk_grid_view_get_x_span (self)) + GPOINTER_TO_INT (gee_list_get (self->priv->_widths, gtk_grid_view_get_x_span (self))) + (GPOINTER_TO_INT ((gtk_grid_view_get_x_span (self) + 1 < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)) ? GPOINTER_TO_INT (gee_list_get (self->priv->_widths, gtk_grid_view_get_x_span (self) + 1)) : 0))) + gtk_container_get_border_width (GTK_CONTAINER (self)) + (((g_object_get (G_OBJECT (GTK_WIDGET (self->priv->vbar)), "visible", &_tmp0, NULL), _tmp0) ? vbar_req.width : 0)) + 6 >= GTK_WIDGET (self)->allocation.width) {
+			gee_list_set (self->priv->_widths, self->priv->_drag_col, GINT_TO_POINTER (prev_width));
+			return FALSE;
+		}
+		gtk_grid_view_update_drawing_area_size_requests (self);
+	}
+	return FALSE;
+}
+
+
+static gboolean gtk_grid_view_on_yheader_button_press_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event) {
+	gint x;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	x = ((gint) ((*event).x));
+	if (da == self->priv->tda) {
+		x = x + (gtk_grid_view_get_left_width (self));
+	}
+	self->priv->_drag_col = gtk_grid_view_drag_x (self, x);
+	/* make the headers eat clicks, so that when you
+	 override button_press in classes using GridView, you
+	 don't get spurious clicks.*/
+	return TRUE;
+}
+
+
+static gboolean gtk_grid_view_on_yheader_button_release_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	self->priv->_drag_col = -1;
+	return FALSE;
+}
+
+
+static void gtk_grid_view_on_fda_style_set (GtkGridView* self, GtkDrawingArea* da, GtkStyle* style) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da));
+	g_return_if_fail (style == NULL || GTK_IS_STYLE (style));
+	if ((GTK_WIDGET_FLAGS (GTK_WIDGET (self->priv->fda)) & GTK_REALIZED) != 0) {
+		GdkColor _tmp0 = {0};
+		gdk_window_set_background (GTK_WIDGET (self->priv->fda)->window, (_tmp0 = gtk_widget_get_style (GTK_WIDGET (self->priv->fda))->base[((gint) (GTK_WIDGET (self->priv->fda)->state))], &_tmp0));
+	}
+}
+
+
+static void gtk_grid_view_on_fda_realized (GtkGridView* self, GtkDrawingArea* da) {
+	GdkColor _tmp0 = {0};
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da));
+	gdk_window_set_background (GTK_WIDGET (self->priv->fda)->window, (_tmp0 = gtk_widget_get_style (GTK_WIDGET (self->priv->fda))->base[((gint) (GTK_WIDGET (self->priv->fda)->state))], &_tmp0));
+}
+
+
+static gboolean gtk_grid_view_on_fda_button_press_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event) {
+	gint x;
+	gint y;
+	GtkGridViewColumn* col;
+	GtkGridViewColumn* scol;
+	GtkTreePath* path;
+	GtkTreePath* spath;
+	GtkGridViewColumn* _tmp6;
+	gboolean _tmp5;
+	GtkGridViewColumn* _tmp4;
+	GtkTreePath* _tmp3;
+	gboolean _tmp2;
+	GtkTreePath* _tmp1;
+	GtkGridViewColumn* _tmp12;
+	gboolean _tmp11;
+	GtkGridViewColumn* _tmp10;
+	GtkTreePath* _tmp9;
+	gboolean _tmp8;
+	GtkTreePath* _tmp7;
+	gboolean _tmp13;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	if ((*event).y > gtk_grid_view_get_field_height (self)) {
+		return FALSE;
+	}
+	x = gtk_grid_view_get_x_span (self);
+	y = gtk_grid_view_get_y_span (self);
+	while (x < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)) && ((gint) ((*event).x)) > gtk_grid_view_column_x (self, x) - gtk_grid_view_get_left_width (self)) {
+		x++;
+	}
+	while (((gint) ((*event).y)) > gtk_grid_view_row_y (self, y) - gtk_grid_view_get_top_height (self)) {
+		y++;
+	}
+	col = NULL;
+	scol = NULL;
+	path = NULL;
+	spath = NULL;
+	_tmp6 = NULL;
+	_tmp4 = NULL;
+	_tmp3 = NULL;
+	_tmp1 = NULL;
+	_tmp5 = (_tmp2 = gtk_grid_view_translate_coords_b (self, x - 1, y - 1, &_tmp1, &_tmp4), path = (_tmp3 = _tmp1, (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp3), _tmp2);
+	col = (_tmp6 = _tmp4, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), _tmp6);
+	_tmp5;
+	_tmp12 = NULL;
+	_tmp10 = NULL;
+	_tmp9 = NULL;
+	_tmp7 = NULL;
+	_tmp11 = (_tmp8 = gtk_grid_selection_get_selected (self->priv->_selection, &_tmp7, &_tmp10), spath = (_tmp9 = _tmp7, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp9), _tmp8);
+	scol = (_tmp12 = _tmp10, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp12);
+	_tmp11;
+	if (spath != NULL && gtk_tree_path_compare (path, spath) == 0 && col == scol && ((*event).state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
+		gtk_grid_selection_deselect (self->priv->_selection);
+	} else {
+		gtk_grid_selection_select_cell (self->priv->_selection, path, col);
+		gtk_grid_view_scroll_to_cell (self, path, col, FALSE, ((float) (0)), ((float) (0)));
+	}
+	return (_tmp13 = FALSE, (col == NULL ? NULL : (col = (g_object_unref (col), NULL))), (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp13);
+}
+
+
+/* make the headers eat clicks, so that when you override
+ button_press in classes using GridView, you don't get
+ spurious clicks.*/
+static gboolean gtk_grid_view_on_lda_button_press_event (GtkGridView* self, GtkDrawingArea* da, GdkEventButton* event) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	g_return_val_if_fail (da == NULL || GTK_IS_DRAWING_AREA (da), FALSE);
+	return TRUE;
+}
+
+
+static void gtk_grid_view_on_column_visibility_changed (GtkGridView* self, GtkGridViewColumn* changed_col) {
+	gint vc;
+	GeeList* _tmp0;
+	GeeList* dimensions;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (changed_col == NULL || GTK_IS_GRID_VIEW_COLUMN (changed_col));
+	vc = 0;
+	_tmp0 = NULL;
+	dimensions = (_tmp0 = (self->priv->_orientation == GTK_ORIENTATION_VERTICAL ? self->priv->_widths : self->priv->_heights), (_tmp0 == NULL ? NULL : g_object_ref (_tmp0)));
+	if (gtk_grid_view_column_get_visible (changed_col)) {
+		GtkTreeIter i = {0};
+		gee_collection_clear (GEE_COLLECTION (self->priv->_visible));
+		{
+			GeeList* col_collection;
+			int col_it;
+			col_collection = self->priv->_columns;
+			for (col_it = 0; col_it < gee_collection_get_size (GEE_COLLECTION (col_collection)); col_it = col_it + 1) {
+				GtkGridViewColumn* col;
+				col = ((GtkGridViewColumn*) (gee_list_get (GEE_LIST (col_collection), col_it)));
+				{
+					if (gtk_grid_view_column_get_visible (col)) {
+						gee_collection_add (GEE_COLLECTION (self->priv->_visible), col);
+					}
+					(col == NULL ? NULL : (col = (g_object_unref (col), NULL)));
+				}
+			}
+		}
+		vc = gee_list_index_of (self->priv->_visible, changed_col);
+		gee_list_insert (dimensions, vc, GINT_TO_POINTER (0));
+		if (self->priv->_model != NULL && gtk_tree_model_get_iter_first (self->priv->_model, &i)) {
+			do {
+				GtkTreePath* path;
+				path = gtk_tree_model_get_path (self->priv->_model, &i);
+				gtk_grid_view_measure_cell (self, path, changed_col);
+				(path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL)));
+			} while (gtk_tree_model_iter_next (self->priv->_model, &i));
+		}
+	} else {
+		vc = gee_list_index_of (self->priv->_visible, changed_col);
+		if (gee_collection_get_size (GEE_COLLECTION (dimensions)) > vc) {
+			gee_list_remove_at (dimensions, vc);
+		}
+		gee_collection_remove (GEE_COLLECTION (self->priv->_visible), changed_col);
+	}
+	gtk_grid_view_update_drawing_area_size_requests (self);
+	(dimensions == NULL ? NULL : (dimensions = (g_object_unref (dimensions), NULL)));
+}
+
+
+static void gtk_grid_view_translate_coords (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, gint* x, gint* y) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col));
+	if (self->priv->_orientation == GTK_ORIENTATION_VERTICAL) {
+		(*x) = gee_list_index_of (self->priv->_visible, col);
+		(*y) = gtk_tree_path_get_indices (path)[0];
+	} else {
+		(*x) = gtk_tree_path_get_indices (path)[0];
+		(*y) = gee_list_index_of (self->priv->_visible, col);
+	}
+}
+
+
+/* XXX-VALA: find a better name*/
+static gboolean gtk_grid_view_translate_coords_b (GtkGridView* self, gint x, gint y, GtkTreePath** path, GtkGridViewColumn** col) {
+	gint c;
+	gint r;
+	GtkTreeIter i = {0};
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
+	(*path) = NULL;
+	(*col) = NULL;
+	c = (self->priv->_orientation == GTK_ORIENTATION_VERTICAL ? x : y);
+	r = (self->priv->_orientation == GTK_ORIENTATION_VERTICAL ? y : x);
+	if (c >= gee_collection_get_size (GEE_COLLECTION (self->priv->_visible)) || !gtk_tree_model_iter_nth_child (self->priv->_model, &i, NULL, r)) {
+		GtkGridViewColumn* _tmp0;
+		GtkTreePath* _tmp1;
+		_tmp0 = NULL;
+		(*col) = (_tmp0 = NULL, ((*col) == NULL ? NULL : ((*col) = (g_object_unref ((*col)), NULL))), _tmp0);
+		_tmp1 = NULL;
+		(*path) = (_tmp1 = NULL, ((*path) == NULL ? NULL : ((*path) = (gtk_tree_path_free ((*path)), NULL))), _tmp1);
+		return FALSE;
+	} else {
+		GtkGridViewColumn* _tmp3;
+		GtkTreePath* _tmp5;
+		char* _tmp4;
+		_tmp3 = NULL;
+		(*col) = (_tmp3 = ((GtkGridViewColumn*) (gee_list_get (self->priv->_visible, c))), ((*col) == NULL ? NULL : ((*col) = (g_object_unref ((*col)), NULL))), _tmp3);
+		_tmp5 = NULL;
+		_tmp4 = NULL;
+		(*path) = (_tmp5 = gtk_tree_path_new_from_string ((_tmp4 = g_strdup_printf ("%i", r))), ((*path) == NULL ? NULL : ((*path) = (gtk_tree_path_free ((*path)), NULL))), _tmp5);
+		_tmp4 = (g_free (_tmp4), NULL);
+		return TRUE;
+	}
+}
+
+
+static void gtk_grid_view_update_drawing_area_size_requests (GtkGridView* self) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	gtk_widget_set_size_request (GTK_WIDGET (self->priv->cda), gtk_grid_view_get_left_width (self), gtk_grid_view_get_top_height (self));
+	gtk_widget_set_size_request (GTK_WIDGET (self->priv->tda), gtk_grid_view_get_field_width (self), gtk_grid_view_get_top_height (self));
+	gtk_widget_set_size_request (GTK_WIDGET (self->priv->lda), gtk_grid_view_get_left_width (self), gtk_grid_view_get_field_height (self));
+	gtk_widget_set_size_request (GTK_WIDGET (self->priv->fda), gtk_grid_view_get_field_width (self), gtk_grid_view_get_field_height (self));
+}
+
+
+static void gtk_grid_view_measure_cell (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col) {
+	gint w;
+	gint h;
+	gint x;
+	gint y;
+	gint x_offset;
+	gint y_offset;
+	GtkTreeIter i = {0};
+	gboolean header;
+	GdkRectangle _tmp0 = {0};
+	GdkRectangle rect;
+	GtkCellRenderer* _tmp1;
+	GtkCellRenderer* renderer;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col));
+	w = 0;
+	h = 0;
+	x = 0;
+	y = 0;
+	x_offset = 0;
+	y_offset = 0;
+	header = gtk_tree_path_get_indices (path)[0] < self->priv->c_span;
+	rect = (memset (&_tmp0, 0, sizeof (GdkRectangle)), _tmp0);
+	_tmp1 = NULL;
+	renderer = (_tmp1 = (header && gtk_grid_view_column_get_header_renderer (col) != NULL ? gtk_grid_view_column_get_header_renderer (col) : gtk_grid_view_column_get_field_renderer (col)), (_tmp1 == NULL ? NULL : g_object_ref (_tmp1)));
+	gtk_tree_model_get_iter (self->priv->_model, &i, path);
+	gtk_grid_view_column_cell_set_cell_data (col, self->priv->_model, &i, header);
+	/* XXX-VALA: vapi change: parameter 'rect' should be ref*/
+	gtk_cell_renderer_get_size (renderer, GTK_WIDGET (self), &rect, &x_offset, &y_offset, &w, &h);
+	gtk_grid_view_translate_coords (self, path, col, &x, &y);
+	gee_list_set (self->priv->_widths, x, GINT_TO_POINTER (MAX (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_widths, x))), w + 20)));
+	gee_list_set (self->priv->_heights, y, GINT_TO_POINTER (MAX (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_heights, y))), h + 4)));
+	(renderer == NULL ? NULL : (renderer = (g_object_unref (renderer), NULL)));
+}
+
+
+static void gtk_grid_view_rebuild_dimensions (GtkGridView* self) {
+	gint x;
+	gint y;
+	GtkTreeIter i = {0};
+	GtkTreePath* path;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	gee_collection_clear (GEE_COLLECTION (self->priv->_widths));
+	gee_collection_clear (GEE_COLLECTION (self->priv->_heights));
+	x = 0;
+	y = 0;
+	path = NULL;
+	if (self->priv->_model != NULL && gtk_tree_model_get_iter_first (self->priv->_model, &i)) {
+		do {
+			{
+				GeeList* col_collection;
+				int col_it;
+				col_collection = self->priv->_visible;
+				for (col_it = 0; col_it < gee_collection_get_size (GEE_COLLECTION (col_collection)); col_it = col_it + 1) {
+					GtkGridViewColumn* col;
+					col = ((GtkGridViewColumn*) (gee_list_get (GEE_LIST (col_collection), col_it)));
+					{
+						GtkTreePath* _tmp0;
+						_tmp0 = NULL;
+						path = (_tmp0 = gtk_tree_model_get_path (self->priv->_model, &i), (path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL))), _tmp0);
+						gtk_grid_view_translate_coords (self, path, col, &x, &y);
+						if (x == gee_collection_get_size (GEE_COLLECTION (self->priv->_widths))) {
+							gee_collection_add (GEE_COLLECTION (self->priv->_widths), GINT_TO_POINTER (0));
+						}
+						if (y == gee_collection_get_size (GEE_COLLECTION (self->priv->_heights))) {
+							gee_collection_add (GEE_COLLECTION (self->priv->_heights), GINT_TO_POINTER (0));
+						}
+						gtk_grid_view_measure_cell (self, path, col);
+						(col == NULL ? NULL : (col = (g_object_unref (col), NULL)));
+					}
+				}
+			}
+		} while (gtk_tree_model_iter_next (self->priv->_model, &i));
+	}
+	gtk_grid_view_update_drawing_area_size_requests (self);
+	(path == NULL ? NULL : (path = (gtk_tree_path_free (path), NULL)));
+}
+
+
+static GdkRectangle gtk_grid_view_cell_rect (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, GtkWidget** widget) {
+	gint x;
+	gint y;
+	GdkRectangle rect = {0};
+	0;
+	0;
+	(*widget) = NULL;
+	x = 0;
+	y = 0;
+	gtk_grid_view_translate_coords (self, path, col, &x, &y);
+	rect.x = gtk_grid_view_column_x (self, x);
+	rect.y = gtk_grid_view_row_y (self, y);
+	rect.width = GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_widths, x)));
+	rect.height = GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_heights, y)));
+	if (x < gtk_grid_view_get_x_span (self) && y < gtk_grid_view_get_y_span (self)) {
+		GtkWidget* _tmp1;
+		GtkWidget* _tmp0;
+		_tmp1 = NULL;
+		_tmp0 = NULL;
+		(*widget) = (_tmp1 = (_tmp0 = GTK_WIDGET (self->priv->cda), (_tmp0 == NULL ? NULL : g_object_ref (_tmp0))), ((*widget) == NULL ? NULL : ((*widget) = (g_object_unref ((*widget)), NULL))), _tmp1);
+		return rect;
+	} else {
+		if (x < gtk_grid_view_get_x_span (self)) {
+			GtkWidget* _tmp4;
+			GtkWidget* _tmp3;
+			_tmp4 = NULL;
+			_tmp3 = NULL;
+			(*widget) = (_tmp4 = (_tmp3 = GTK_WIDGET (self->priv->lda), (_tmp3 == NULL ? NULL : g_object_ref (_tmp3))), ((*widget) == NULL ? NULL : ((*widget) = (g_object_unref ((*widget)), NULL))), _tmp4);
+			rect.y = rect.y - (gtk_grid_view_get_top_height (self));
+		} else {
+			if (y < gtk_grid_view_get_y_span (self)) {
+				GtkWidget* _tmp6;
+				GtkWidget* _tmp5;
+				_tmp6 = NULL;
+				_tmp5 = NULL;
+				(*widget) = (_tmp6 = (_tmp5 = GTK_WIDGET (self->priv->tda), (_tmp5 == NULL ? NULL : g_object_ref (_tmp5))), ((*widget) == NULL ? NULL : ((*widget) = (g_object_unref ((*widget)), NULL))), _tmp6);
+				rect.x = rect.x - (gtk_grid_view_get_left_width (self));
+			} else {
+				GtkWidget* _tmp8;
+				GtkWidget* _tmp7;
+				_tmp8 = NULL;
+				_tmp7 = NULL;
+				(*widget) = (_tmp8 = (_tmp7 = GTK_WIDGET (self->priv->fda), (_tmp7 == NULL ? NULL : g_object_ref (_tmp7))), ((*widget) == NULL ? NULL : ((*widget) = (g_object_unref ((*widget)), NULL))), _tmp8);
+				rect.x = rect.x - (gtk_grid_view_get_left_width (self));
+				rect.y = rect.y - (gtk_grid_view_get_top_height (self));
+			}
+		}
+	}
+	/* stretch the rightmost cell to fill the allocation */
+	if (x == gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)) - 1) {
+		GdkRectangle _tmp9 = {0};
+		rect.width = gdk_rect_right ((_tmp9 = ((GdkRectangle) (GTK_WIDGET (self->priv->fda)->allocation)), &_tmp9)) - rect.x;
+	}
+	return rect;
+}
+
+
+static void gtk_grid_view_invalidate_cell_rect (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col) {
+	GtkWidget* widget;
+	GtkWidget* _tmp2;
+	GdkRectangle _tmp1 = {0};
+	GtkWidget* _tmp0;
+	GdkRectangle rect;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col));
+	widget = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	rect = (_tmp1 = gtk_grid_view_cell_rect (self, path, col, &_tmp0), widget = (_tmp2 = _tmp0, (widget == NULL ? NULL : (widget = (g_object_unref (widget), NULL))), _tmp2), _tmp1);
+	if (widget != NULL && widget->window != NULL) {
+		gdk_window_invalidate_rect (widget->window, &rect, TRUE);
+	}
+	(widget == NULL ? NULL : (widget = (g_object_unref (widget), NULL)));
+}
+
+
+static gint gtk_grid_view_column_x (GtkGridView* self, gint x) {
+	gint ret;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	ret = 0;
+	for ((x = x - 1); x >= 0 && x < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)); x--) {
+		ret = ret + (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_widths, x))));
+	}
+	return ret;
+}
+
+
+static gint gtk_grid_view_row_y (GtkGridView* self, gint y) {
+	gint ret;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	ret = 0;
+	for ((y = y - 1); y >= 0 && y < gee_collection_get_size (GEE_COLLECTION (self->priv->_heights)); y--) {
+		ret = ret + (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_heights, y))));
+	}
+	return ret;
+}
+
+
+static gint gtk_grid_view_drag_x (GtkGridView* self, gint x) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	{
+		gint xc;
+		xc = 1;
+		for (; xc < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)); xc++) {
+			gint distance;
+			distance = x - gtk_grid_view_column_x (self, xc);
+			if (distance > -3 && distance < 3 && (xc != gtk_grid_view_get_x_span (self) || distance < 0)) {
+				return xc - 1;
+			}
+		}
+	}
+	return -1;
+}
+
+
+static void gtk_grid_view_draw_cell (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, GdkRectangle* clip_) {
+	GtkWidget* w;
+	GdkRectangle clip = {0};
+	GtkWidget* _tmp2;
+	GdkRectangle _tmp1 = {0};
+	GtkWidget* _tmp0;
+	GdkRectangle rect;
+	GtkCellRendererState crs;
+	GtkTreeIter i = {0};
+	gboolean header;
+	GtkCellRenderer* _tmp9;
+	GtkCellRenderer* renderer;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	g_return_if_fail (col == NULL || GTK_IS_GRID_VIEW_COLUMN (col));
+	w = NULL;
+	_tmp2 = NULL;
+	_tmp0 = NULL;
+	rect = (_tmp1 = gtk_grid_view_cell_rect (self, path, col, &_tmp0), w = (_tmp2 = _tmp0, (w == NULL ? NULL : (w = (g_object_unref (w), NULL))), _tmp2), _tmp1);
+	/* XXX-VALA: attention: parameter 'clip' is an out parameter!*/
+	if (!gdk_rectangle_intersect (&(*clip_), &rect, &clip)) {
+		(w == NULL ? NULL : (w = (g_object_unref (w), NULL)));
+		return;
+	}
+	crs = 0;
+	if (w != GTK_WIDGET (self->priv->fda)) {
+		GDK_DRAWABLE_GET_CLASS (GDK_DRAWABLE (w->window))->draw_rectangle (GDK_DRAWABLE (w->window), gtk_widget_get_style (w)->mid_gc[w->state], TRUE, rect.x, rect.y, rect.width, rect.height);
+	} else {
+		GtkTreePath* spath;
+		GtkGridViewColumn* scol;
+		GtkGridViewColumn* _tmp8;
+		gboolean _tmp7;
+		GtkGridViewColumn* _tmp6;
+		GtkTreePath* _tmp5;
+		gboolean _tmp4;
+		GtkTreePath* _tmp3;
+		spath = NULL;
+		scol = NULL;
+		_tmp8 = NULL;
+		_tmp6 = NULL;
+		_tmp5 = NULL;
+		_tmp3 = NULL;
+		_tmp7 = (_tmp4 = gtk_grid_selection_get_selected (self->priv->_selection, &_tmp3, &_tmp6), spath = (_tmp5 = _tmp3, (spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL))), _tmp5), _tmp4);
+		scol = (_tmp8 = _tmp6, (scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL))), _tmp8);
+		_tmp7;
+		if (spath != NULL && gtk_tree_path_compare (path, spath) == 0 && col == scol) {
+			crs = GTK_CELL_RENDERER_SELECTED;
+			gtk_paint_flat_box (gtk_widget_get_style (w), w->window, GTK_STATE_SELECTED, GTK_SHADOW_NONE, &clip, GTK_WIDGET (self), "cell_odd", rect.x, rect.y, rect.width, rect.height);
+		}
+		(spath == NULL ? NULL : (spath = (gtk_tree_path_free (spath), NULL)));
+		(scol == NULL ? NULL : (scol = (g_object_unref (scol), NULL)));
+	}
+	gdk_draw_line (GDK_DRAWABLE (w->window), gtk_widget_get_style (w)->bg_gc[w->state], rect.x, gdk_rect_bottom (&rect) - 1, gdk_rect_right (&rect), gdk_rect_bottom (&rect) - 1);
+	gdk_draw_line (GDK_DRAWABLE (w->window), gtk_widget_get_style (w)->bg_gc[w->state], gdk_rect_right (&rect) - 1, rect.y, gdk_rect_right (&rect) - 1, gdk_rect_bottom (&rect));
+	header = gtk_tree_path_get_indices (path)[0] < self->priv->c_span;
+	_tmp9 = NULL;
+	renderer = (_tmp9 = (header && gtk_grid_view_column_get_header_renderer (col) != NULL ? gtk_grid_view_column_get_header_renderer (col) : gtk_grid_view_column_get_field_renderer (col)), (_tmp9 == NULL ? NULL : g_object_ref (_tmp9)));
+	gtk_tree_model_get_iter (self->priv->_model, &i, path);
+	gtk_grid_view_column_cell_set_cell_data (col, self->priv->_model, &i, header);
+	gtk_cell_renderer_render (renderer, w->window, GTK_WIDGET (self), &rect, &rect, &clip, crs);
+	(w == NULL ? NULL : (w = (g_object_unref (w), NULL)));
+	(renderer == NULL ? NULL : (renderer = (g_object_unref (renderer), NULL)));
+}
+
+
+GtkGridView* gtk_grid_view_new (void) {
+	GtkGridView * self;
+	self = g_object_newv (GTK_TYPE_GRID_VIEW, 0, NULL);
+	return self;
+}
+
+
+GtkTreeModel* gtk_grid_view_get_model (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
+	return self->priv->_model;
+}
+
+
+static void _gtk_grid_view_on_model_row_changed_gtk_tree_model_row_changed (GtkTreeModel* _sender, GtkTreePath* path, GtkTreeIter* iter, gpointer self) {
+	gtk_grid_view_on_model_row_changed (self, _sender, path, iter);
+}
+
+
+static void _gtk_grid_view_on_model_row_deleted_gtk_tree_model_row_deleted (GtkTreeModel* _sender, GtkTreePath* path, gpointer self) {
+	gtk_grid_view_on_model_row_deleted (self, _sender, path);
+}
+
+
+static void _gtk_grid_view_on_model_row_inserted_gtk_tree_model_row_inserted (GtkTreeModel* _sender, GtkTreePath* path, GtkTreeIter* iter, gpointer self) {
+	gtk_grid_view_on_model_row_inserted (self, _sender, path);
+}
+
+
+static void _gtk_grid_view_on_model_rows_reordered_gtk_tree_model_rows_reordered (GtkTreeModel* _sender, GtkTreePath* path, GtkTreeIter* iter, void* new_order, gpointer self) {
+	gtk_grid_view_on_model_rows_reordered (self, _sender);
+}
+
+
+void gtk_grid_view_set_model (GtkGridView* self, GtkTreeModel* value) {
+	GtkTreeModel* _tmp2;
+	GtkTreeModel* _tmp1;
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (self->priv->_model == value) {
+		return;
+	}
+	gtk_grid_selection_deselect (self->priv->_selection);
+	_tmp2 = NULL;
+	_tmp1 = NULL;
+	self->priv->_model = (_tmp2 = (_tmp1 = value, (_tmp1 == NULL ? NULL : g_object_ref (_tmp1))), (self->priv->_model == NULL ? NULL : (self->priv->_model = (g_object_unref (self->priv->_model), NULL))), _tmp2);
+	if (self->priv->_model != NULL) {
+		g_signal_connect_object (self->priv->_model, "row-changed", ((GCallback) (_gtk_grid_view_on_model_row_changed_gtk_tree_model_row_changed)), self, 0);
+		g_signal_connect_object (self->priv->_model, "row-deleted", ((GCallback) (_gtk_grid_view_on_model_row_deleted_gtk_tree_model_row_deleted)), self, 0);
+		g_signal_connect_object (self->priv->_model, "row-inserted", ((GCallback) (_gtk_grid_view_on_model_row_inserted_gtk_tree_model_row_inserted)), self, 0);
+		g_signal_connect_object (self->priv->_model, "rows-reordered", ((GCallback) (_gtk_grid_view_on_model_rows_reordered_gtk_tree_model_rows_reordered)), self, 0);
+	}
+	gtk_grid_view_rebuild_dimensions (self);
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->cda));
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->tda));
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->lda));
+	gtk_widget_queue_draw (GTK_WIDGET (self->priv->fda));
+	g_object_notify (((GObject *) (self)), "model");
+}
+
+
+GtkGridViewColumn** gtk_grid_view_get_columns (GtkGridView* self) {
+	GtkGridViewColumn** _tmp1;
+	gint array_length1;
+	gint _tmp0;
+	GtkGridViewColumn** array;
+	GtkGridViewColumn** _tmp3;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
+	/* XXX-VALA: simple array conversion like this would be nice
+	return _columns.to_array (typeof (GridViewColumn));*/
+	_tmp1 = NULL;
+	array = (_tmp1 = g_new0 (GtkGridViewColumn*, (_tmp0 = gee_collection_get_size (GEE_COLLECTION (self->priv->_columns))) + 1), array_length1 = _tmp0, _tmp1);
+	{
+		gint i;
+		i = 0;
+		for (; i < array_length1; i++) {
+			GtkGridViewColumn* _tmp2;
+			_tmp2 = NULL;
+			array[i] = (_tmp2 = ((GtkGridViewColumn*) (gee_list_get (self->priv->_columns, i))), (array[i] == NULL ? NULL : (array[i] = (g_object_unref (array[i]), NULL))), _tmp2);
+		}
+	}
+	_tmp3 = NULL;
+	return (_tmp3 = array, (array = (_vala_array_free (array, array_length1, ((GDestroyNotify) (g_object_unref))), NULL)), _tmp3);
+}
+
+
+GtkPolicyType gtk_grid_view_get_hscrollbar_policy (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->_hbar_policy;
+}
+
+
+void gtk_grid_view_set_hscrollbar_policy (GtkGridView* self, GtkPolicyType value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (self->priv->_hbar_policy == value) {
+		return;
+	}
+	self->priv->_hbar_policy = value;
+	gtk_widget_queue_resize (GTK_WIDGET (self));
+	g_object_notify (((GObject *) (self)), "hscrollbar-policy");
+}
+
+
+GtkPolicyType gtk_grid_view_get_vscrollbar_policy (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->_vbar_policy;
+}
+
+
+void gtk_grid_view_set_vscrollbar_policy (GtkGridView* self, GtkPolicyType value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (self->priv->_vbar_policy == value) {
+		return;
+	}
+	self->priv->_vbar_policy = value;
+	gtk_widget_queue_resize (GTK_WIDGET (self));
+	g_object_notify (((GObject *) (self)), "vscrollbar-policy");
+}
+
+
+GtkGridViewScrollbarSpan gtk_grid_view_get_hscrollbar_span (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->_hbar_span;
+}
+
+
+void gtk_grid_view_set_hscrollbar_span (GtkGridView* self, GtkGridViewScrollbarSpan value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (self->priv->_hbar_span == value) {
+		return;
+	}
+	self->priv->_hbar_span = value;
+	gtk_widget_queue_resize (GTK_WIDGET (self));
+	g_object_notify (((GObject *) (self)), "hscrollbar-span");
+}
+
+
+GtkGridViewScrollbarSpan gtk_grid_view_get_vscrollbar_span (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->_vbar_span;
+}
+
+
+void gtk_grid_view_set_vscrollbar_span (GtkGridView* self, GtkGridViewScrollbarSpan value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (self->priv->_vbar_span == value) {
+		return;
+	}
+	self->priv->_vbar_span = value;
+	gtk_widget_queue_resize (GTK_WIDGET (self));
+	g_object_notify (((GObject *) (self)), "vscrollbar-span");
+}
+
+
+GtkOrientation gtk_grid_view_get_orientation (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->_orientation;
+}
+
+
+void gtk_grid_view_set_orientation (GtkGridView* self, GtkOrientation value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (self->priv->_orientation != value) {
+		self->priv->_orientation = value;
+		gtk_grid_view_rebuild_dimensions (self);
+		g_signal_emit_by_name (G_OBJECT (self), "orientation-changed");
+	}
+	g_object_notify (((GObject *) (self)), "orientation");
+}
+
+
+GtkGridSelection* gtk_grid_view_get_selection (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
+	return self->priv->_selection;
+}
+
+
+gint gtk_grid_view_get_n_row_headers (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->r_span;
+}
+
+
+void gtk_grid_view_set_n_row_headers (GtkGridView* self, gint value) {
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (value >= 0 && value <= gee_collection_get_size (GEE_COLLECTION (self->priv->_columns))) {
+		self->priv->r_span = value;
+		gtk_grid_view_update_drawing_area_size_requests (self);
+	}
+	g_object_notify (((GObject *) (self)), "n-row-headers");
+}
+
+
+gint gtk_grid_view_get_n_col_headers (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return self->priv->c_span;
+}
+
+
+void gtk_grid_view_set_n_col_headers (GtkGridView* self, gint value) {
+	GtkTreeIter i = {0};
+	g_return_if_fail (GTK_IS_GRID_VIEW (self));
+	if (value >= 0 && (value == 0 || gtk_tree_model_iter_nth_child (self->priv->_model, &i, NULL, value - 1))) {
+		self->priv->c_span = value;
+		gtk_grid_view_update_drawing_area_size_requests (self);
+	}
+	g_object_notify (((GObject *) (self)), "n-col-headers");
+}
+
+
+static gint gtk_grid_view_get_x_span (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return (self->priv->_orientation == GTK_ORIENTATION_VERTICAL ? self->priv->r_span : self->priv->c_span);
+}
+
+
+static gint gtk_grid_view_get_y_span (GtkGridView* self) {
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	return (self->priv->_orientation == GTK_ORIENTATION_VERTICAL ? self->priv->c_span : self->priv->r_span);
+}
+
+
+static gint gtk_grid_view_get_left_width (GtkGridView* self) {
+	gint w;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	w = 0;
+	{
+		gint x;
+		x = 0;
+		for (; x < gtk_grid_view_get_x_span (self) && x < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)); x++) {
+			w = w + (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_widths, x))));
+		}
+	}
+	return w;
+}
+
+
+static gint gtk_grid_view_get_top_height (GtkGridView* self) {
+	gint h;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	h = 0;
+	{
+		gint y;
+		y = 0;
+		for (; y < gtk_grid_view_get_y_span (self) && y < gee_collection_get_size (GEE_COLLECTION (self->priv->_heights)); y++) {
+			h = h + (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_heights, y))));
+		}
+	}
+	return h;
+}
+
+
+static gint gtk_grid_view_get_field_width (GtkGridView* self) {
+	gint w;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	w = 0;
+	{
+		gint x;
+		x = gtk_grid_view_get_x_span (self);
+		for (; x < gee_collection_get_size (GEE_COLLECTION (self->priv->_widths)); x++) {
+			w = w + (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_widths, x))));
+		}
+	}
+	return w;
+}
+
+
+static gint gtk_grid_view_get_field_height (GtkGridView* self) {
+	gint h;
+	g_return_val_if_fail (GTK_IS_GRID_VIEW (self), 0);
+	h = 0;
+	{
+		gint y;
+		y = gtk_grid_view_get_y_span (self);
+		for (; y < gee_collection_get_size (GEE_COLLECTION (self->priv->_heights)); y++) {
+			h = h + (GPOINTER_TO_INT (GPOINTER_TO_INT (gee_list_get (self->priv->_heights, y))));
+		}
+	}
+	return h;
+}
+
+
+static void _gtk_grid_view_on_style_set_gtk_widget_style_set (GtkGridView* _sender, GtkStyle* previous_style, gpointer self) {
+	gtk_grid_view_on_style_set (self, _sender, previous_style);
+}
+
+
+static void _gtk_grid_view_on_state_changed_gtk_widget_state_changed (GtkGridView* _sender, GtkStateType previous_state, gpointer self) {
+	gtk_grid_view_on_state_changed (self, _sender, previous_state);
+}
+
+
+static gboolean _gtk_grid_view_on_focus_in_event_gtk_widget_focus_in_event (GtkGridView* _sender, GdkEventFocus* event, gpointer self) {
+	return gtk_grid_view_on_focus_in_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_focus_out_event_gtk_widget_focus_out_event (GtkGridView* _sender, GdkEventFocus* event, gpointer self) {
+	return gtk_grid_view_on_focus_out_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_button_press_event_gtk_widget_button_press_event (GtkGridView* _sender, GdkEventButton* event, gpointer self) {
+	return gtk_grid_view_on_button_press_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_key_press_event_gtk_widget_key_press_event (GtkGridView* _sender, GdkEventKey* event, gpointer self) {
+	return gtk_grid_view_on_key_press_event (self, _sender, event);
+}
+
+
+static void _gtk_grid_view_on_selection_changed_gtk_grid_selection_changed (GtkGridSelection* _sender, gpointer self) {
+	gtk_grid_view_on_selection_changed (self, _sender);
+}
+
+
+static gboolean _gtk_grid_view_on_cda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self) {
+	return gtk_grid_view_on_cda_expose_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_yheader_motion_notify_event_gtk_widget_motion_notify_event (GtkDrawingArea* _sender, GdkEventMotion* event, gpointer self) {
+	return gtk_grid_view_on_yheader_motion_notify_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_yheader_button_press_event_gtk_widget_button_press_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self) {
+	return gtk_grid_view_on_yheader_button_press_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_yheader_button_release_event_gtk_widget_button_release_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self) {
+	return gtk_grid_view_on_yheader_button_release_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_tda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self) {
+	return gtk_grid_view_on_tda_expose_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_lda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self) {
+	return gtk_grid_view_on_lda_expose_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_lda_button_press_event_gtk_widget_button_press_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self) {
+	return gtk_grid_view_on_lda_button_press_event (self, _sender, event);
+}
+
+
+static void _gtk_grid_view_on_fda_style_set_gtk_widget_style_set (GtkDrawingArea* _sender, GtkStyle* previous_style, gpointer self) {
+	gtk_grid_view_on_fda_style_set (self, _sender, previous_style);
+}
+
+
+static void _gtk_grid_view_on_fda_realized_gtk_widget_realize (GtkDrawingArea* _sender, gpointer self) {
+	gtk_grid_view_on_fda_realized (self, _sender);
+}
+
+
+static gboolean _gtk_grid_view_on_fda_expose_event_gtk_widget_expose_event (GtkDrawingArea* _sender, GdkEventExpose* event, gpointer self) {
+	return gtk_grid_view_on_fda_expose_event (self, _sender, event);
+}
+
+
+static gboolean _gtk_grid_view_on_fda_button_press_event_gtk_widget_button_press_event (GtkDrawingArea* _sender, GdkEventButton* event, gpointer self) {
+	return gtk_grid_view_on_fda_button_press_event (self, _sender, event);
+}
+
+
+static GObject * gtk_grid_view_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties) {
+	GObject * obj;
+	GtkGridViewClass * klass;
+	GObjectClass * parent_class;
+	GtkGridView * self;
+	klass = GTK_GRID_VIEW_CLASS (g_type_class_peek (GTK_TYPE_GRID_VIEW));
+	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
+	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
+	self = GTK_GRID_VIEW (obj);
+	{
+		gboolean _tmp0;
+		GtkGridSelection* _tmp1;
+		GtkDrawingArea* _tmp2;
+		GtkDrawingArea* _tmp3;
+		GtkDrawingArea* _tmp4;
+		GtkViewport* _tmp5;
+		GtkDrawingArea* _tmp6;
+		GtkViewport* _tmp7;
+		GtkViewport* _tmp8;
+		GtkScrollbar* _tmp9;
+		GtkGridViewLinkedScrollbar* hbar_linked;
+		GtkScrollbar* _tmp10;
+		GtkGridViewLinkedScrollbar* vbar_linked;
+		g_object_set (GTK_WIDGET (self), "can-focus", TRUE, NULL);
+		GTK_WIDGET_SET_FLAGS (GTK_WIDGET (self), GTK_WIDGET_FLAGS (GTK_WIDGET (self)) | GTK_NO_WINDOW);
+		_tmp1 = NULL;
+		self->priv->_selection = (_tmp1 = gtk_grid_selection_new (self), (self->priv->_selection == NULL ? NULL : (self->priv->_selection = (g_object_unref (self->priv->_selection), NULL))), _tmp1);
+		self->priv->_orientation = GTK_ORIENTATION_VERTICAL;
+		g_signal_connect_object (GTK_WIDGET (self), "style-set", ((GCallback) (_gtk_grid_view_on_style_set_gtk_widget_style_set)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self), "state-changed", ((GCallback) (_gtk_grid_view_on_state_changed_gtk_widget_state_changed)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self), "focus-in-event", ((GCallback) (_gtk_grid_view_on_focus_in_event_gtk_widget_focus_in_event)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self), "focus-out-event", ((GCallback) (_gtk_grid_view_on_focus_out_event_gtk_widget_focus_out_event)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self), "button-press-event", ((GCallback) (_gtk_grid_view_on_button_press_event_gtk_widget_button_press_event)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self), "key-press-event", ((GCallback) (_gtk_grid_view_on_key_press_event_gtk_widget_key_press_event)), self, 0);
+		g_signal_connect_object (self->priv->_selection, "changed", ((GCallback) (_gtk_grid_view_on_selection_changed_gtk_grid_selection_changed)), self, 0);
+		_tmp2 = NULL;
+		self->priv->cda = (_tmp2 = g_object_ref_sink (((GtkDrawingArea*) (gtk_drawing_area_new ()))), (self->priv->cda == NULL ? NULL : (self->priv->cda = (g_object_unref (self->priv->cda), NULL))), _tmp2);
+		g_signal_connect_object (GTK_WIDGET (self->priv->cda), "expose-event", ((GCallback) (_gtk_grid_view_on_cda_expose_event_gtk_widget_expose_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->cda), ((gint) (GDK_POINTER_MOTION_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->cda), "motion-notify-event", ((GCallback) (_gtk_grid_view_on_yheader_motion_notify_event_gtk_widget_motion_notify_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->cda), ((gint) (GDK_BUTTON_PRESS_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->cda), "button-press-event", ((GCallback) (_gtk_grid_view_on_yheader_button_press_event_gtk_widget_button_press_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->cda), ((gint) (GDK_BUTTON_RELEASE_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->cda), "button-release-event", ((GCallback) (_gtk_grid_view_on_yheader_button_release_event_gtk_widget_button_release_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->cda), ((gint) (GDK_SCROLL_MASK)));
+		gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->cda));
+		_tmp3 = NULL;
+		self->priv->tda = (_tmp3 = g_object_ref_sink (((GtkDrawingArea*) (gtk_drawing_area_new ()))), (self->priv->tda == NULL ? NULL : (self->priv->tda = (g_object_unref (self->priv->tda), NULL))), _tmp3);
+		g_signal_connect_object (GTK_WIDGET (self->priv->tda), "expose-event", ((GCallback) (_gtk_grid_view_on_tda_expose_event_gtk_widget_expose_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->tda), ((gint) (GDK_POINTER_MOTION_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->tda), "motion-notify-event", ((GCallback) (_gtk_grid_view_on_yheader_motion_notify_event_gtk_widget_motion_notify_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->tda), ((gint) (GDK_BUTTON_PRESS_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->tda), "button-press-event", ((GCallback) (_gtk_grid_view_on_yheader_button_press_event_gtk_widget_button_press_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->tda), ((gint) (GDK_BUTTON_RELEASE_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->tda), "button-release-event", ((GCallback) (_gtk_grid_view_on_yheader_button_release_event_gtk_widget_button_release_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->tda), ((gint) (GDK_SCROLL_MASK)));
+		_tmp4 = NULL;
+		self->priv->lda = (_tmp4 = g_object_ref_sink (((GtkDrawingArea*) (gtk_drawing_area_new ()))), (self->priv->lda == NULL ? NULL : (self->priv->lda = (g_object_unref (self->priv->lda), NULL))), _tmp4);
+		g_signal_connect_object (GTK_WIDGET (self->priv->lda), "expose-event", ((GCallback) (_gtk_grid_view_on_lda_expose_event_gtk_widget_expose_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->lda), ((gint) (GDK_SCROLL_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->lda), "button-press-event", ((GCallback) (_gtk_grid_view_on_lda_button_press_event_gtk_widget_button_press_event)), self, 0);
+		_tmp5 = NULL;
+		self->priv->fvp = (_tmp5 = g_object_ref_sink (((GtkViewport*) (gtk_viewport_new (NULL, NULL)))), (self->priv->fvp == NULL ? NULL : (self->priv->fvp = (g_object_unref (self->priv->fvp), NULL))), _tmp5);
+		gtk_viewport_set_shadow_type (self->priv->fvp, GTK_SHADOW_NONE);
+		_tmp6 = NULL;
+		self->priv->fda = (_tmp6 = g_object_ref_sink (((GtkDrawingArea*) (gtk_drawing_area_new ()))), (self->priv->fda == NULL ? NULL : (self->priv->fda = (g_object_unref (self->priv->fda), NULL))), _tmp6);
+		g_signal_connect_object (GTK_WIDGET (self->priv->fda), "style-set", ((GCallback) (_gtk_grid_view_on_fda_style_set_gtk_widget_style_set)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self->priv->fda), "realize", ((GCallback) (_gtk_grid_view_on_fda_realized_gtk_widget_realize)), self, 0);
+		g_signal_connect_object (GTK_WIDGET (self->priv->fda), "expose-event", ((GCallback) (_gtk_grid_view_on_fda_expose_event_gtk_widget_expose_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->fda), ((gint) (GDK_BUTTON_PRESS_MASK)));
+		g_signal_connect_object (GTK_WIDGET (self->priv->fda), "button-press-event", ((GCallback) (_gtk_grid_view_on_fda_button_press_event_gtk_widget_button_press_event)), self, 0);
+		gtk_widget_add_events (GTK_WIDGET (self->priv->fda), ((gint) (GDK_SCROLL_MASK)));
+		gtk_container_add (GTK_CONTAINER (self->priv->fvp), GTK_WIDGET (self->priv->fda));
+		gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->fvp));
+		_tmp7 = NULL;
+		self->priv->tvp = (_tmp7 = g_object_ref_sink (((GtkViewport*) (gtk_viewport_new (gtk_viewport_get_hadjustment (self->priv->fvp), NULL)))), (self->priv->tvp == NULL ? NULL : (self->priv->tvp = (g_object_unref (self->priv->tvp), NULL))), _tmp7);
+		gtk_viewport_set_shadow_type (self->priv->tvp, GTK_SHADOW_NONE);
+		gtk_container_add (GTK_CONTAINER (self->priv->tvp), GTK_WIDGET (self->priv->tda));
+		gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->tvp));
+		_tmp8 = NULL;
+		self->priv->lvp = (_tmp8 = g_object_ref_sink (((GtkViewport*) (gtk_viewport_new (NULL, gtk_viewport_get_vadjustment (self->priv->fvp))))), (self->priv->lvp == NULL ? NULL : (self->priv->lvp = (g_object_unref (self->priv->lvp), NULL))), _tmp8);
+		gtk_viewport_set_shadow_type (self->priv->lvp, GTK_SHADOW_NONE);
+		gtk_container_add (GTK_CONTAINER (self->priv->lvp), GTK_WIDGET (self->priv->lda));
+		gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->lvp));
+		_tmp9 = NULL;
+		self->priv->hbar = (_tmp9 = GTK_SCROLLBAR (g_object_ref_sink (((GtkHScrollbar*) (gtk_hscrollbar_new (gtk_viewport_get_hadjustment (self->priv->fvp)))))), (self->priv->hbar == NULL ? NULL : (self->priv->hbar = (g_object_unref (self->priv->hbar), NULL))), _tmp9);
+		hbar_linked = gtk_grid_view_linked_scrollbar_new (self->priv->hbar);
+		gtk_grid_view_linked_scrollbar_link (hbar_linked, GTK_WIDGET (self->priv->tda));
+		gtk_grid_view_linked_scrollbar_link (hbar_linked, GTK_WIDGET (self->priv->fda));
+		gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->hbar));
+		_tmp10 = NULL;
+		self->priv->vbar = (_tmp10 = GTK_SCROLLBAR (g_object_ref_sink (((GtkVScrollbar*) (gtk_vscrollbar_new (gtk_viewport_get_vadjustment (self->priv->fvp)))))), (self->priv->vbar == NULL ? NULL : (self->priv->vbar = (g_object_unref (self->priv->vbar), NULL))), _tmp10);
+		vbar_linked = gtk_grid_view_linked_scrollbar_new (self->priv->vbar);
+		gtk_grid_view_linked_scrollbar_link (vbar_linked, GTK_WIDGET (self->priv->lda));
+		gtk_grid_view_linked_scrollbar_link (vbar_linked, GTK_WIDGET (self->priv->fda));
+		gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->priv->vbar));
+		(hbar_linked == NULL ? NULL : (hbar_linked = (g_object_unref (hbar_linked), NULL)));
+		(vbar_linked == NULL ? NULL : (vbar_linked = (g_object_unref (vbar_linked), NULL)));
+	}
+	return obj;
+}
+
+
+static GtkGridViewLinkedScrollbar* gtk_grid_view_linked_scrollbar_new (GtkScrollbar* sb) {
+	GParameter * __params;
+	GParameter * __params_it;
+	GtkGridViewLinkedScrollbar * self;
+	g_return_val_if_fail (sb == NULL || GTK_IS_SCROLLBAR (sb), NULL);
+	__params = g_new0 (GParameter, 1);
+	__params_it = __params;
+	__params_it->name = "scrollbar";
+	g_value_init (&__params_it->value, GTK_TYPE_SCROLLBAR);
+	g_value_set_object (&__params_it->value, sb);
+	__params_it++;
+	self = g_object_newv (GTK_GRID_VIEW_TYPE_LINKED_SCROLLBAR, __params_it - __params, __params);
+	while (__params_it > __params) {
+		--__params_it;
+		g_value_unset (&__params_it->value);
+	}
+	g_free (__params);
+	return self;
+}
+
+
+static gboolean _gtk_grid_view_linked_scrollbar_on_linked_widget_scroll_event_gtk_widget_scroll_event (GtkWidget* _sender, GdkEventScroll* event, gpointer self) {
+	return gtk_grid_view_linked_scrollbar_on_linked_widget_scroll_event (self, _sender, event);
+}
+
+
+static void gtk_grid_view_linked_scrollbar_link (GtkGridViewLinkedScrollbar* self, GtkWidget* widget) {
+	g_return_if_fail (GTK_GRID_VIEW_IS_LINKED_SCROLLBAR (self));
+	g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
+	g_signal_connect_object (widget, "scroll-event", ((GCallback) (_gtk_grid_view_linked_scrollbar_on_linked_widget_scroll_event_gtk_widget_scroll_event)), self, 0);
+}
+
+
+static void gtk_grid_view_linked_scrollbar_link_all (GtkGridViewLinkedScrollbar* self, GtkWidget** widgets, int widgets_length1) {
+	g_return_if_fail (GTK_GRID_VIEW_IS_LINKED_SCROLLBAR (self));
+	{
+		GtkWidget** w_collection;
+		int w_collection_length1;
+		int w_it;
+		w_collection = widgets;
+		w_collection_length1 = widgets_length1;
+		for (w_it = 0; (widgets_length1 != -1 && w_it < widgets_length1) || (widgets_length1 == -1 && w_collection[w_it] != NULL); w_it = w_it + 1) {
+			GtkWidget* _tmp0;
+			GtkWidget* w;
+			_tmp0 = NULL;
+			w = (_tmp0 = w_collection[w_it], (_tmp0 == NULL ? NULL : g_object_ref (_tmp0)));
+			{
+				gtk_grid_view_linked_scrollbar_link (self, w);
+				(w == NULL ? NULL : (w = (g_object_unref (w), NULL)));
+			}
+		}
+	}
+}
+
+
+/**
+ * the delta calculation is lifted from
+ * _gtk_range_get_wheel_delta (), which is unexposed c api
+ **/
+static gboolean gtk_grid_view_linked_scrollbar_on_linked_widget_scroll_event (GtkGridViewLinkedScrollbar* self, GtkWidget* w, GdkEventScroll* event) {
+	GtkAdjustment* _tmp2;
+	GtkAdjustment* adj;
+	double _tmp3;
+	double delta;
+	gboolean _tmp6;
+	g_return_val_if_fail (GTK_GRID_VIEW_IS_LINKED_SCROLLBAR (self), FALSE);
+	g_return_val_if_fail (w == NULL || GTK_IS_WIDGET (w), FALSE);
+	if (GTK_IS_VSCROLLBAR (self->priv->_scrollbar) && ((*event).direction == GDK_SCROLL_LEFT || (*event).direction == GDK_SCROLL_RIGHT)) {
+		return FALSE;
+	} else {
+		if (GTK_IS_HSCROLLBAR (self->priv->_scrollbar) && ((*event).direction == GDK_SCROLL_UP || (*event).direction == GDK_SCROLL_DOWN)) {
+			return FALSE;
+		}
+	}
+	_tmp2 = NULL;
+	adj = (_tmp2 = gtk_range_get_adjustment (GTK_RANGE (self->priv->_scrollbar)), (_tmp2 == NULL ? NULL : g_object_ref (_tmp2)));
+	delta = pow ((g_object_get (G_OBJECT (adj), "page-size", &_tmp3, NULL), _tmp3), 2.0 / 3.0);
+	if ((*event).direction == GDK_SCROLL_UP || (*event).direction == GDK_SCROLL_LEFT) {
+		gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) - (delta));
+	} else {
+		double _tmp5;
+		double _tmp4;
+		gtk_adjustment_set_value (adj, MIN ((g_object_get (G_OBJECT (adj), "upper", &_tmp4, NULL), _tmp4) - (g_object_get (G_OBJECT (adj), "page-size", &_tmp5, NULL), _tmp5), gtk_adjustment_get_value (adj) + delta));
+	}
+	return (_tmp6 = FALSE, (adj == NULL ? NULL : (adj = (g_object_unref (adj), NULL))), _tmp6);
+}
+
+
+static GtkScrollbar* gtk_grid_view_linked_scrollbar_get_scrollbar (GtkGridViewLinkedScrollbar* self) {
+	g_return_val_if_fail (GTK_GRID_VIEW_IS_LINKED_SCROLLBAR (self), NULL);
+	return self->priv->_scrollbar;
+}
+
+
+static void gtk_grid_view_linked_scrollbar_set_scrollbar (GtkGridViewLinkedScrollbar* self, GtkScrollbar* value) {
+	GtkScrollbar* _tmp2;
+	GtkScrollbar* _tmp1;
+	g_return_if_fail (GTK_GRID_VIEW_IS_LINKED_SCROLLBAR (self));
+	_tmp2 = NULL;
+	_tmp1 = NULL;
+	self->priv->_scrollbar = (_tmp2 = (_tmp1 = value, (_tmp1 == NULL ? NULL : g_object_ref (_tmp1))), (self->priv->_scrollbar == NULL ? NULL : (self->priv->_scrollbar = (g_object_unref (self->priv->_scrollbar), NULL))), _tmp2);
+	g_object_notify (((GObject *) (self)), "scrollbar");
+}
+
+
+static void gtk_grid_view_linked_scrollbar_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
+	GtkGridViewLinkedScrollbar * self;
+	self = GTK_GRID_VIEW_LINKED_SCROLLBAR (object);
+	switch (property_id) {
+		case GTK_GRID_VIEW_LINKED_SCROLLBAR_SCROLLBAR:
+		g_value_set_object (value, gtk_grid_view_linked_scrollbar_get_scrollbar (self));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_view_linked_scrollbar_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) {
+	GtkGridViewLinkedScrollbar * self;
+	self = GTK_GRID_VIEW_LINKED_SCROLLBAR (object);
+	switch (property_id) {
+		case GTK_GRID_VIEW_LINKED_SCROLLBAR_SCROLLBAR:
+		gtk_grid_view_linked_scrollbar_set_scrollbar (self, g_value_get_object (value));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_view_linked_scrollbar_class_init (GtkGridViewLinkedScrollbarClass * klass) {
+	gtk_grid_view_linked_scrollbar_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GtkGridViewLinkedScrollbarPrivate));
+	G_OBJECT_CLASS (klass)->get_property = gtk_grid_view_linked_scrollbar_get_property;
+	G_OBJECT_CLASS (klass)->set_property = gtk_grid_view_linked_scrollbar_set_property;
+	G_OBJECT_CLASS (klass)->dispose = gtk_grid_view_linked_scrollbar_dispose;
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_LINKED_SCROLLBAR_SCROLLBAR, g_param_spec_object ("scrollbar", "scrollbar", "scrollbar", GTK_TYPE_SCROLLBAR, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+static void gtk_grid_view_linked_scrollbar_instance_init (GtkGridViewLinkedScrollbar * self) {
+	self->priv = GTK_GRID_VIEW_LINKED_SCROLLBAR_GET_PRIVATE (self);
+}
+
+
+static void gtk_grid_view_linked_scrollbar_dispose (GObject * obj) {
+	GtkGridViewLinkedScrollbar * self;
+	self = GTK_GRID_VIEW_LINKED_SCROLLBAR (obj);
+	(self->priv->_scrollbar == NULL ? NULL : (self->priv->_scrollbar = (g_object_unref (self->priv->_scrollbar), NULL)));
+	G_OBJECT_CLASS (gtk_grid_view_linked_scrollbar_parent_class)->dispose (obj);
+}
+
+
+static GType gtk_grid_view_linked_scrollbar_get_type (void) {
+	static GType gtk_grid_view_linked_scrollbar_type_id = 0;
+	if (G_UNLIKELY (gtk_grid_view_linked_scrollbar_type_id == 0)) {
+		static const GTypeInfo g_define_type_info = { sizeof (GtkGridViewLinkedScrollbarClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gtk_grid_view_linked_scrollbar_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GtkGridViewLinkedScrollbar), 0, (GInstanceInitFunc) gtk_grid_view_linked_scrollbar_instance_init };
+		gtk_grid_view_linked_scrollbar_type_id = g_type_register_static (G_TYPE_OBJECT, "GtkGridViewLinkedScrollbar", &g_define_type_info, 0);
+	}
+	return gtk_grid_view_linked_scrollbar_type_id;
+}
+
+
+static void gtk_grid_view_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
+	GtkGridView * self;
+	self = GTK_GRID_VIEW (object);
+	switch (property_id) {
+		case GTK_GRID_VIEW_MODEL:
+		g_value_set_object (value, gtk_grid_view_get_model (self));
+		break;
+		case GTK_GRID_VIEW_COLUMNS:
+		g_value_set_pointer (value, gtk_grid_view_get_columns (self));
+		break;
+		case GTK_GRID_VIEW_HSCROLLBAR_POLICY:
+		g_value_set_enum (value, gtk_grid_view_get_hscrollbar_policy (self));
+		break;
+		case GTK_GRID_VIEW_VSCROLLBAR_POLICY:
+		g_value_set_enum (value, gtk_grid_view_get_vscrollbar_policy (self));
+		break;
+		case GTK_GRID_VIEW_HSCROLLBAR_SPAN:
+		g_value_set_enum (value, gtk_grid_view_get_hscrollbar_span (self));
+		break;
+		case GTK_GRID_VIEW_VSCROLLBAR_SPAN:
+		g_value_set_enum (value, gtk_grid_view_get_vscrollbar_span (self));
+		break;
+		case GTK_GRID_VIEW_ORIENTATION:
+		g_value_set_enum (value, gtk_grid_view_get_orientation (self));
+		break;
+		case GTK_GRID_VIEW_SELECTION:
+		g_value_set_object (value, gtk_grid_view_get_selection (self));
+		break;
+		case GTK_GRID_VIEW_N_ROW_HEADERS:
+		g_value_set_int (value, gtk_grid_view_get_n_row_headers (self));
+		break;
+		case GTK_GRID_VIEW_N_COL_HEADERS:
+		g_value_set_int (value, gtk_grid_view_get_n_col_headers (self));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_view_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) {
+	GtkGridView * self;
+	self = GTK_GRID_VIEW (object);
+	switch (property_id) {
+		case GTK_GRID_VIEW_MODEL:
+		gtk_grid_view_set_model (self, g_value_get_object (value));
+		break;
+		case GTK_GRID_VIEW_HSCROLLBAR_POLICY:
+		gtk_grid_view_set_hscrollbar_policy (self, g_value_get_enum (value));
+		break;
+		case GTK_GRID_VIEW_VSCROLLBAR_POLICY:
+		gtk_grid_view_set_vscrollbar_policy (self, g_value_get_enum (value));
+		break;
+		case GTK_GRID_VIEW_HSCROLLBAR_SPAN:
+		gtk_grid_view_set_hscrollbar_span (self, g_value_get_enum (value));
+		break;
+		case GTK_GRID_VIEW_VSCROLLBAR_SPAN:
+		gtk_grid_view_set_vscrollbar_span (self, g_value_get_enum (value));
+		break;
+		case GTK_GRID_VIEW_ORIENTATION:
+		gtk_grid_view_set_orientation (self, g_value_get_enum (value));
+		break;
+		case GTK_GRID_VIEW_N_ROW_HEADERS:
+		gtk_grid_view_set_n_row_headers (self, g_value_get_int (value));
+		break;
+		case GTK_GRID_VIEW_N_COL_HEADERS:
+		gtk_grid_view_set_n_col_headers (self, g_value_get_int (value));
+		break;
+		default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void gtk_grid_view_class_init (GtkGridViewClass * klass) {
+	gtk_grid_view_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GtkGridViewPrivate));
+	G_OBJECT_CLASS (klass)->get_property = gtk_grid_view_get_property;
+	G_OBJECT_CLASS (klass)->set_property = gtk_grid_view_set_property;
+	G_OBJECT_CLASS (klass)->constructor = gtk_grid_view_constructor;
+	G_OBJECT_CLASS (klass)->dispose = gtk_grid_view_dispose;
+	GTK_CONTAINER_CLASS (klass)->add = gtk_grid_view_real_add;
+	GTK_CONTAINER_CLASS (klass)->remove = gtk_grid_view_real_remove;
+	GTK_CONTAINER_CLASS (klass)->forall = gtk_grid_view_real_forall;
+	GTK_WIDGET_CLASS (klass)->size_request = gtk_grid_view_real_size_request;
+	GTK_WIDGET_CLASS (klass)->size_allocate = gtk_grid_view_real_size_allocate;
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_MODEL, g_param_spec_object ("model", "model", "model", GTK_TYPE_TREE_MODEL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_COLUMNS, g_param_spec_pointer ("columns", "columns", "columns", G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_HSCROLLBAR_POLICY, g_param_spec_enum ("hscrollbar-policy", "hscrollbar-policy", "hscrollbar-policy", GTK_TYPE_POLICY_TYPE, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_VSCROLLBAR_POLICY, g_param_spec_enum ("vscrollbar-policy", "vscrollbar-policy", "vscrollbar-policy", GTK_TYPE_POLICY_TYPE, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_HSCROLLBAR_SPAN, g_param_spec_enum ("hscrollbar-span", "hscrollbar-span", "hscrollbar-span", GTK_GRID_VIEW_TYPE_SCROLLBAR_SPAN, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_VSCROLLBAR_SPAN, g_param_spec_enum ("vscrollbar-span", "vscrollbar-span", "vscrollbar-span", GTK_GRID_VIEW_TYPE_SCROLLBAR_SPAN, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_ORIENTATION, g_param_spec_enum ("orientation", "orientation", "orientation", GTK_TYPE_ORIENTATION, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_SELECTION, g_param_spec_object ("selection", "selection", "selection", GTK_TYPE_GRID_SELECTION, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_N_ROW_HEADERS, g_param_spec_int ("n-row-headers", "n-row-headers", "n-row-headers", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (G_OBJECT_CLASS (klass), GTK_GRID_VIEW_N_COL_HEADERS, g_param_spec_int ("n-col-headers", "n-col-headers", "n-col-headers", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_signal_new ("columns_changed", GTK_TYPE_GRID_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+	g_signal_new ("orientation_changed", GTK_TYPE_GRID_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+	gtk_grid_view_DRAG_CURSOR = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+}
+
+
+static void gtk_grid_view_instance_init (GtkGridView * self) {
+	self->priv = GTK_GRID_VIEW_GET_PRIVATE (self);
+	self->priv->_children = GEE_LIST (gee_array_list_new (GTK_TYPE_WIDGET, ((GBoxedCopyFunc) (g_object_ref)), g_object_unref, g_direct_equal));
+	self->priv->_columns = GEE_LIST (gee_array_list_new (GTK_TYPE_GRID_VIEW_COLUMN, ((GBoxedCopyFunc) (g_object_ref)), g_object_unref, g_direct_equal));
+	self->priv->_visible = GEE_LIST (gee_array_list_new (GTK_TYPE_GRID_VIEW_COLUMN, ((GBoxedCopyFunc) (g_object_ref)), g_object_unref, g_direct_equal));
+	self->priv->_widths = GEE_LIST (gee_array_list_new (G_TYPE_INT, NULL, NULL, g_direct_equal));
+	self->priv->_heights = GEE_LIST (gee_array_list_new (G_TYPE_INT, NULL, NULL, g_direct_equal));
+	self->priv->c_span = 1;
+	self->priv->r_span = 1;
+	self->priv->_drag_col = -1;
+	self->priv->_hbar_policy = GTK_POLICY_ALWAYS;
+	self->priv->_vbar_policy = GTK_POLICY_ALWAYS;
+	self->priv->_hbar_span = GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_GAP;
+	self->priv->_vbar_span = GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_GAP;
+}
+
+
+static void gtk_grid_view_dispose (GObject * obj) {
+	GtkGridView * self;
+	self = GTK_GRID_VIEW (obj);
+	(self->priv->_children == NULL ? NULL : (self->priv->_children = (g_object_unref (self->priv->_children), NULL)));
+	(self->priv->_model == NULL ? NULL : (self->priv->_model = (g_object_unref (self->priv->_model), NULL)));
+	(self->priv->_columns == NULL ? NULL : (self->priv->_columns = (g_object_unref (self->priv->_columns), NULL)));
+	(self->priv->_visible == NULL ? NULL : (self->priv->_visible = (g_object_unref (self->priv->_visible), NULL)));
+	(self->priv->_widths == NULL ? NULL : (self->priv->_widths = (g_object_unref (self->priv->_widths), NULL)));
+	(self->priv->_heights == NULL ? NULL : (self->priv->_heights = (g_object_unref (self->priv->_heights), NULL)));
+	(self->priv->tvp == NULL ? NULL : (self->priv->tvp = (g_object_unref (self->priv->tvp), NULL)));
+	(self->priv->lvp == NULL ? NULL : (self->priv->lvp = (g_object_unref (self->priv->lvp), NULL)));
+	(self->priv->fvp == NULL ? NULL : (self->priv->fvp = (g_object_unref (self->priv->fvp), NULL)));
+	(self->priv->cda == NULL ? NULL : (self->priv->cda = (g_object_unref (self->priv->cda), NULL)));
+	(self->priv->tda == NULL ? NULL : (self->priv->tda = (g_object_unref (self->priv->tda), NULL)));
+	(self->priv->lda == NULL ? NULL : (self->priv->lda = (g_object_unref (self->priv->lda), NULL)));
+	(self->priv->fda == NULL ? NULL : (self->priv->fda = (g_object_unref (self->priv->fda), NULL)));
+	(self->priv->hbar == NULL ? NULL : (self->priv->hbar = (g_object_unref (self->priv->hbar), NULL)));
+	(self->priv->vbar == NULL ? NULL : (self->priv->vbar = (g_object_unref (self->priv->vbar), NULL)));
+	(self->priv->_selection == NULL ? NULL : (self->priv->_selection = (g_object_unref (self->priv->_selection), NULL)));
+	(self->priv->_prev_sel_path == NULL ? NULL : (self->priv->_prev_sel_path = (gtk_tree_path_free (self->priv->_prev_sel_path), NULL)));
+	(self->priv->_prev_sel_col == NULL ? NULL : (self->priv->_prev_sel_col = (g_object_unref (self->priv->_prev_sel_col), NULL)));
+	G_OBJECT_CLASS (gtk_grid_view_parent_class)->dispose (obj);
+}
+
+
+GType gtk_grid_view_get_type (void) {
+	static GType gtk_grid_view_type_id = 0;
+	if (G_UNLIKELY (gtk_grid_view_type_id == 0)) {
+		static const GTypeInfo g_define_type_info = { sizeof (GtkGridViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gtk_grid_view_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GtkGridView), 0, (GInstanceInitFunc) gtk_grid_view_instance_init };
+		gtk_grid_view_type_id = g_type_register_static (GTK_TYPE_CONTAINER, "GtkGridView", &g_define_type_info, 0);
+	}
+	return gtk_grid_view_type_id;
+}
+
+
+void gtk_render_attribute_init (GtkRenderAttribute *self, const char* p, gint c) {
+	char* _tmp1;
+	const char* _tmp0;
+	memset (self, 0, sizeof (GtkRenderAttribute));
+	_tmp1 = NULL;
+	_tmp0 = NULL;
+	(*self).property = (_tmp1 = (_tmp0 = p, (_tmp0 == NULL ? NULL : g_strdup (_tmp0))), ((*self).property = (g_free ((*self).property), NULL)), _tmp1);
+	(*self).column = c;
+}
+
+
+gint array_index_of (GObject** array, int array_length1, GObject* item) {
+	g_return_val_if_fail (item == NULL || G_IS_OBJECT (item), 0);
+	{
+		gint i;
+		i = 0;
+		for (; i < array_length1; i++) {
+			if (array[i] == item) {
+				return i;
+			}
+		}
+	}
+	return -1;
+}
+
+
+gint gdk_rect_right (GdkRectangle* rect) {
+	return (*rect).x + (*rect).width;
+}
+
+
+gint gdk_rect_bottom (GdkRectangle* rect) {
+	return (*rect).y + (*rect).height;
+}
+
+
+gint gdk_rect_top (GdkRectangle* rect) {
+	return (*rect).y;
+}
+
+
+gint gdk_rect_left (GdkRectangle* rect) {
+	return (*rect).x;
+}
+
+
+static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) {
+	if (array != NULL && destroy_func != NULL) {
+		int i;
+		if (array_length >= 0)
+		for (i = 0; i < array_length; i = i + 1) {
+			if (((gpointer*) (array))[i] != NULL)
+			destroy_func (((gpointer*) (array))[i]);
+		}
+		else
+		for (i = 0; ((gpointer*) (array))[i] != NULL; i = i + 1) {
+			destroy_func (((gpointer*) (array))[i]);
+		}
+	}
+	g_free (array);
+}
+
+
+
+

Added: trunk/gridview/gridview.h
==============================================================================
--- (empty file)
+++ trunk/gridview/gridview.h	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,170 @@
+/* 
+ * Medsphere.Widgets
+ * Copyright (C) 2007 Medsphere Systems Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GRIDVIEW_H__
+#define __GRIDVIEW_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <float.h>
+#include <math.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <string.h>
+
+G_BEGIN_DECLS
+
+
+#define GTK_TYPE_GRID_SELECTION (gtk_grid_selection_get_type ())
+#define GTK_GRID_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_GRID_SELECTION, GtkGridSelection))
+#define GTK_GRID_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_GRID_SELECTION, GtkGridSelectionClass))
+#define GTK_IS_GRID_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_GRID_SELECTION))
+#define GTK_IS_GRID_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GRID_SELECTION))
+#define GTK_GRID_SELECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GRID_SELECTION, GtkGridSelectionClass))
+
+typedef struct _GtkGridSelection GtkGridSelection;
+typedef struct _GtkGridSelectionClass GtkGridSelectionClass;
+typedef struct _GtkGridSelectionPrivate GtkGridSelectionPrivate;
+
+#define GTK_TYPE_GRID_VIEW_COLUMN (gtk_grid_view_column_get_type ())
+#define GTK_GRID_VIEW_COLUMN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_GRID_VIEW_COLUMN, GtkGridViewColumn))
+#define GTK_GRID_VIEW_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_GRID_VIEW_COLUMN, GtkGridViewColumnClass))
+#define GTK_IS_GRID_VIEW_COLUMN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_GRID_VIEW_COLUMN))
+#define GTK_IS_GRID_VIEW_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GRID_VIEW_COLUMN))
+#define GTK_GRID_VIEW_COLUMN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GRID_VIEW_COLUMN, GtkGridViewColumnClass))
+
+typedef struct _GtkGridViewColumn GtkGridViewColumn;
+typedef struct _GtkGridViewColumnClass GtkGridViewColumnClass;
+typedef struct _GtkGridViewColumnPrivate GtkGridViewColumnPrivate;
+typedef void (*GtkGridCellDataFunc) (GtkGridViewColumn* c, GtkCellRenderer* r, GtkTreeModel* m, GtkTreeIter* i, void* user_data);
+
+#define GTK_TYPE_GRID_VIEW (gtk_grid_view_get_type ())
+#define GTK_GRID_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_GRID_VIEW, GtkGridView))
+#define GTK_GRID_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_GRID_VIEW, GtkGridViewClass))
+#define GTK_IS_GRID_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_GRID_VIEW))
+#define GTK_IS_GRID_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GRID_VIEW))
+#define GTK_GRID_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GRID_VIEW, GtkGridViewClass))
+
+typedef struct _GtkGridView GtkGridView;
+typedef struct _GtkGridViewClass GtkGridViewClass;
+typedef struct _GtkGridViewPrivate GtkGridViewPrivate;
+
+#define GTK_GRID_VIEW_TYPE_SCROLLBAR_SPAN (gtk_grid_view_scrollbar_span_get_type ())
+typedef struct _GtkRenderAttribute GtkRenderAttribute;
+
+struct _GtkGridSelection {
+	GObject parent_instance;
+	GtkGridSelectionPrivate * priv;
+};
+
+struct _GtkGridSelectionClass {
+	GObjectClass parent_class;
+};
+
+struct _GtkGridViewColumn {
+	GObject parent_instance;
+	GtkGridViewColumnPrivate * priv;
+};
+
+struct _GtkGridViewColumnClass {
+	GObjectClass parent_class;
+};
+
+struct _GtkGridView {
+	GtkContainer parent_instance;
+	GtkGridViewPrivate * priv;
+};
+
+struct _GtkGridViewClass {
+	GtkContainerClass parent_class;
+};
+
+typedef enum  {
+	GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_GAP,
+	GTK_GRID_VIEW_SCROLLBAR_SPAN_HEADER_OVERLAP,
+	GTK_GRID_VIEW_SCROLLBAR_SPAN_FULL
+} GtkGridViewScrollbarSpan;
+
+struct _GtkRenderAttribute {
+	char* property;
+	gint column;
+};
+
+
+GtkGridSelection* gtk_grid_selection_new (GtkGridView* g);
+gboolean gtk_grid_selection_select_cell (GtkGridSelection* self, GtkTreePath* path, GtkGridViewColumn* col);
+void gtk_grid_selection_deselect (GtkGridSelection* self);
+gboolean gtk_grid_selection_get_selected (GtkGridSelection* self, GtkTreePath** path, GtkGridViewColumn** col);
+gboolean gtk_grid_selection_get_has_selection (GtkGridSelection* self);
+GType gtk_grid_selection_get_type (void);
+GtkGridViewColumn* gtk_grid_view_column_new (GtkCellRenderer* r);
+void gtk_grid_view_column_set_field_attrs (GtkGridViewColumn* self, GtkRenderAttribute* a, int a_length1);
+void gtk_grid_view_column_set_cell_data_func (GtkGridViewColumn* self, GtkGridCellDataFunc func, void* func_target);
+void gtk_grid_view_column_set_header_cell_data_func (GtkGridViewColumn* self, GtkGridCellDataFunc func, void* func_target);
+void gtk_grid_view_column_set_header_renderer (GtkGridViewColumn* self, GtkCellRenderer* r, GtkRenderAttribute* a, int a_length1);
+void gtk_grid_view_column_cell_set_cell_data (GtkGridViewColumn* self, GtkTreeModel* m, GtkTreeIter* i, gboolean h);
+gboolean gtk_grid_view_column_get_visible (GtkGridViewColumn* self);
+void gtk_grid_view_column_set_visible (GtkGridViewColumn* self, gboolean value);
+GtkCellRenderer* gtk_grid_view_column_get_field_renderer (GtkGridViewColumn* self);
+GtkCellRenderer* gtk_grid_view_column_get_header_renderer (GtkGridViewColumn* self);
+GType gtk_grid_view_column_get_type (void);
+GType gtk_grid_view_scrollbar_span_get_type (void);
+void gtk_grid_view_append_column (GtkGridView* self, GtkGridViewColumn* col);
+GtkGridViewColumn* gtk_grid_view_append_column_with_attributes (GtkGridView* self, GtkCellRenderer* r, GtkRenderAttribute* a, int a_length1);
+GtkGridViewColumn* gtk_grid_view_append_column_with_data_func (GtkGridView* self, GtkCellRenderer* r, GtkGridCellDataFunc f, void* f_target);
+GtkGridViewColumn* gtk_grid_view_append_column_with_header (GtkGridView* self, GtkCellRenderer* r, GtkGridCellDataFunc f, void* f_target, GtkCellRenderer* hr, GtkGridCellDataFunc hf, void* hf_target);
+gint gtk_grid_view_remove_column (GtkGridView* self, GtkGridViewColumn* col);
+gboolean gtk_grid_view_get_selectable (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col);
+void gtk_grid_view_scroll_to_cell (GtkGridView* self, GtkTreePath* path, GtkGridViewColumn* col, gboolean a, float ra, float ca);
+GtkGridView* gtk_grid_view_new (void);
+GtkTreeModel* gtk_grid_view_get_model (GtkGridView* self);
+void gtk_grid_view_set_model (GtkGridView* self, GtkTreeModel* value);
+GtkGridViewColumn** gtk_grid_view_get_columns (GtkGridView* self);
+GtkPolicyType gtk_grid_view_get_hscrollbar_policy (GtkGridView* self);
+void gtk_grid_view_set_hscrollbar_policy (GtkGridView* self, GtkPolicyType value);
+GtkPolicyType gtk_grid_view_get_vscrollbar_policy (GtkGridView* self);
+void gtk_grid_view_set_vscrollbar_policy (GtkGridView* self, GtkPolicyType value);
+GtkGridViewScrollbarSpan gtk_grid_view_get_hscrollbar_span (GtkGridView* self);
+void gtk_grid_view_set_hscrollbar_span (GtkGridView* self, GtkGridViewScrollbarSpan value);
+GtkGridViewScrollbarSpan gtk_grid_view_get_vscrollbar_span (GtkGridView* self);
+void gtk_grid_view_set_vscrollbar_span (GtkGridView* self, GtkGridViewScrollbarSpan value);
+GtkOrientation gtk_grid_view_get_orientation (GtkGridView* self);
+void gtk_grid_view_set_orientation (GtkGridView* self, GtkOrientation value);
+GtkGridSelection* gtk_grid_view_get_selection (GtkGridView* self);
+gint gtk_grid_view_get_n_row_headers (GtkGridView* self);
+void gtk_grid_view_set_n_row_headers (GtkGridView* self, gint value);
+gint gtk_grid_view_get_n_col_headers (GtkGridView* self);
+void gtk_grid_view_set_n_col_headers (GtkGridView* self, gint value);
+GType gtk_grid_view_get_type (void);
+void gtk_render_attribute_init (GtkRenderAttribute *self, const char* p, gint c);
+gint array_index_of (GObject** array, int array_length1, GObject* item);
+#define GDK_KEY_LEFT ((guint) (0xFF51))
+#define GDK_KEY_RIGHT ((guint) (0xFF53))
+#define GDK_KEY_UP ((guint) (0xFF52))
+#define GDK_KEY_DOWN ((guint) (0xFF54))
+gint gdk_rect_right (GdkRectangle* rect);
+gint gdk_rect_bottom (GdkRectangle* rect);
+gint gdk_rect_top (GdkRectangle* rect);
+gint gdk_rect_left (GdkRectangle* rect);
+
+
+G_END_DECLS
+
+#endif

Added: trunk/gridview/gridview.vala
==============================================================================
--- (empty file)
+++ trunk/gridview/gridview.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,1529 @@
+/* 
+ * Medsphere.Widgets
+ * Copyright (C) 2007 Medsphere Systems Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Vala port 2008 by Frederik.
+ *
+ * Remarks specific to this Vala port are tagged with 'XXX-VALA' in order to 
+ * distinguish them from the original remarks.
+ */
+
+using Gee;
+using Gdk;
+using Gtk;
+
+namespace Gtk {
+
+	public class GridSelection : GLib.Object {
+
+		public GridView gv { private get; construct; }
+
+		private TreePath _path = null;
+		private GridViewColumn _col = null;
+
+		public bool has_selection {
+			get { return _path != null && _col != null; }
+		}
+
+		public signal void changed ();
+
+		public GridSelection (GridView g) {
+			this.gv = g;
+		}
+
+		construct {
+			this.gv.columns_changed += on_grid_view_columns_changed;
+		}
+
+		public bool select_cell (TreePath path, GridViewColumn col) {
+			if (!this.gv.get_selectable (path, col)) {
+				return false;
+			}
+
+			if (path != null) {
+				_path = path.copy ();
+			} else {
+				_path = null;
+			}
+			_col = col;
+
+			changed ();
+
+			return true;
+		}
+
+		public void deselect () {
+			_path = null;
+			_col = null;
+
+			changed ();
+		}
+
+		public bool get_selected (out TreePath path, out GridViewColumn col) {
+			if (_path != null) {
+				path = _path.copy ();
+			} else {
+				path = null;
+			}
+			col = _col;
+
+			return this.has_selection;
+		}
+
+		private void on_grid_view_columns_changed () {
+			if (_path == null && _col == null) {
+				return;
+			}
+
+			if (Array.index_of ((GLib.Object[]) this.gv.columns, _col) < 0) {
+				deselect ();
+			}
+		}
+	}
+
+	public class GridViewColumn : GLib.Object {
+
+		public signal void visibility_changed ();
+
+		private bool _visible = true;
+
+		private CellRenderer _header_renderer;
+		private CellRenderer _field_renderer;
+		private Gee.Map<string, int> _header_attrs = new Gee.HashMap<string, int> (str_hash, str_equal);
+		private Gee.Map<string, int> _field_attrs = new Gee.HashMap<string, int> (str_hash, str_equal);
+
+		private GridCellDataFunc _df = null;
+		private GridCellDataFunc _hdf = null;
+
+		public GridViewColumn (CellRenderer r /*, RenderAttribute[]? a */) {
+			this.field_renderer = r;
+		}
+
+		// XXX-VALA: currently arrays can't get passed to construction methods,
+		//           since array properties are not supported yet
+		//           (Vala Bug #536706), so we provide a setter
+		public void set_field_attrs (RenderAttribute[] a) {
+			foreach (RenderAttribute attr in a) {
+				_field_attrs.set (attr.property, attr.column);
+			}
+		}
+
+		public bool visible {
+			get { return _visible; }
+			set {
+				if (_visible == value) {
+					return;
+				}
+
+				_visible = value;
+
+				visibility_changed ();
+			}
+		}
+
+		public CellRenderer field_renderer {
+			get { return _field_renderer; }
+			construct { _field_renderer = value; }
+		}
+
+		public CellRenderer header_renderer {
+			get { return _header_renderer; }
+		}
+
+		// XXX-VALA: no delegate properties yet (Vala Bug #543879)
+//		public GridCellDataFunc cell_data_func {
+//			set { _df = value; }
+//		}
+		public void set_cell_data_func (GridCellDataFunc func) {
+			_df = func;
+		}
+
+		// XXX-VALA: no delegate properties yet (Vala Bug #543879)
+//		public GridCellDataFunc header_cell_data_func {
+//			set { _hdf = value; }
+//		}
+		public void set_header_cell_data_func (GridCellDataFunc func) {
+			_hdf = func;
+		}
+
+		public void set_header_renderer (CellRenderer r,
+		                                 RenderAttribute[]? a = null)
+		{
+			_header_renderer = r;
+
+			foreach (RenderAttribute attr in a) {
+				_header_attrs.set (attr.property, attr.column);
+			}
+		}
+
+		public void cell_set_cell_data (TreeModel m, TreeIter i, bool h) {
+			Gee.Map<string, int> attrs;
+			CellRenderer r;
+			Value v;
+
+			if (h && _header_renderer != null) {
+				r = _header_renderer;
+				attrs = _header_attrs;
+			} else {
+				r = _field_renderer;
+				attrs = _field_attrs;
+			}
+
+			foreach (string prop in attrs.get_keys ()) {
+				// XXX-VALA parameter v should be out instead of ref
+				m.get_value (i, attrs.get (prop), ref v);
+				// XXX-VALA set_property () is missing in glib.vapi
+				r.set_property (prop, v);
+			}
+
+			if (h && _hdf != null) {
+				_hdf (this, r, m, i);
+			} else if (_df != null) {
+				_df (this, r, m, i);
+			}
+		}
+	}
+
+	public delegate void GridCellDataFunc (GridViewColumn c, CellRenderer r,
+	                                       TreeModel m, TreeIter i);
+
+	public class GridView : Container {
+
+		public enum ScrollbarSpan {
+			HEADER_GAP,
+			HEADER_OVERLAP,
+			FULL
+		}
+
+		private class LinkedScrollbar : GLib.Object {
+
+			public Scrollbar scrollbar { private get; construct; }
+
+			public LinkedScrollbar (Scrollbar sb) {
+				this.scrollbar = sb;
+			}
+
+			public void link (Widget widget) {
+				widget.scroll_event += on_linked_widget_scroll_event;
+			}
+
+			public void link_all (Widget[] widgets) {
+				foreach (Widget w in widgets) {
+					link (w);
+				}
+			}
+
+			/**
+			 * the delta calculation is lifted from
+			 * _gtk_range_get_wheel_delta (), which is unexposed c api
+			 **/
+			private bool on_linked_widget_scroll_event (Widget w,
+			                                        Gdk.EventScroll event)
+			{
+				if (this.scrollbar is VScrollbar &&
+				    (event.direction == ScrollDirection.LEFT ||
+				     event.direction == ScrollDirection.RIGHT))
+				{
+					return false;
+				} else if (this.scrollbar is HScrollbar &&
+				           (event.direction == ScrollDirection.UP ||
+				            event.direction == ScrollDirection.DOWN))
+				{
+					return false;
+				}
+
+				Adjustment adj = this.scrollbar.adjustment;
+				double delta = Math.pow (adj.page_size, 2.0 / 3.0);
+
+				if (event.direction == ScrollDirection.UP ||
+				    event.direction == ScrollDirection.LEFT)
+				{
+					adj.value -= delta;
+				} else {
+					adj.value = double.min (adj.upper - adj.page_size,
+					                        adj.value + delta);
+				}
+
+				return false;
+			}
+		}
+
+		private static Cursor DRAG_CURSOR = new Cursor (CursorType.SB_H_DOUBLE_ARROW);
+
+		public signal void columns_changed ();
+		public signal void orientation_changed ();
+
+		private Gee.List<Widget> _children = new Gee.ArrayList<Widget> ();
+
+		private TreeModel _model;
+
+		private Orientation _orientation;
+
+		private Gee.List<GridViewColumn> _columns = new Gee.ArrayList<GridViewColumn> ();
+		private Gee.List<GridViewColumn> _visible = new Gee.ArrayList<GridViewColumn> ();
+
+		private Gee.List<int> _widths = new Gee.ArrayList<int> ();
+		private Gee.List<int> _heights = new Gee.ArrayList<int> ();
+
+		/* column header span, row header span */
+		private int c_span = 1; /* c_span2 = boring; */
+		private int r_span = 1;
+		/* the column currently being resized, or -1 */
+		private int _drag_col = -1;
+
+		/**
+		 * c = top left corner
+		 * t = top
+		 * l = left
+		 * f = field
+		 **/
+		private Viewport tvp;
+		private Viewport lvp;
+		private Viewport fvp;
+		private DrawingArea cda;
+		private DrawingArea tda;
+		private DrawingArea lda;
+		private DrawingArea fda;
+
+		private Scrollbar hbar;
+		private Scrollbar vbar;
+		/* XXX: is this what ScrolledWindow defaults to? */
+		private PolicyType _hbar_policy = PolicyType.ALWAYS;
+		private PolicyType _vbar_policy = PolicyType.ALWAYS;
+		private ScrollbarSpan _hbar_span = ScrollbarSpan.HEADER_GAP;
+		private ScrollbarSpan _vbar_span = ScrollbarSpan.HEADER_GAP;
+
+		private GridSelection _selection;
+		private TreePath _prev_sel_path;
+		private GridViewColumn _prev_sel_col;
+
+		construct {
+			this.can_focus = true;
+			set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+			_selection = new GridSelection (this);
+			_orientation = Orientation.VERTICAL;
+
+			this.style_set += on_style_set;
+			this.state_changed += on_state_changed;
+			this.focus_in_event += on_focus_in_event;
+			this.focus_out_event += on_focus_out_event;
+			this.button_press_event += on_button_press_event;
+			this.key_press_event += on_key_press_event;
+			_selection.changed += on_selection_changed;
+
+			cda = new DrawingArea ();
+			cda.expose_event += on_cda_expose_event;
+			cda.add_events (EventMask.POINTER_MOTION_MASK);
+			cda.motion_notify_event += on_yheader_motion_notify_event;
+			cda.add_events (EventMask.BUTTON_PRESS_MASK);
+			cda.button_press_event += on_yheader_button_press_event;
+			cda.add_events (EventMask.BUTTON_RELEASE_MASK);
+			cda.button_release_event += on_yheader_button_release_event;
+			cda.add_events (EventMask.SCROLL_MASK);
+			add (cda);
+
+			tda = new DrawingArea ();
+			tda.expose_event += on_tda_expose_event;
+			tda.add_events (EventMask.POINTER_MOTION_MASK);
+			tda.motion_notify_event += on_yheader_motion_notify_event;
+			tda.add_events (EventMask.BUTTON_PRESS_MASK);
+			tda.button_press_event += on_yheader_button_press_event;
+			tda.add_events (EventMask.BUTTON_RELEASE_MASK);
+			tda.button_release_event += on_yheader_button_release_event;
+			tda.add_events (EventMask.SCROLL_MASK);
+
+			lda = new DrawingArea ();
+			lda.expose_event += on_lda_expose_event;
+			lda.add_events (EventMask.SCROLL_MASK);
+			lda.button_press_event += on_lda_button_press_event;
+
+			fvp = new Viewport (null, null);
+			fvp.shadow_type = ShadowType.NONE;
+
+			fda = new DrawingArea ();
+			fda.style_set += on_fda_style_set;
+			fda.realize += on_fda_realized;
+			fda.expose_event += on_fda_expose_event;
+			fda.add_events (EventMask.BUTTON_PRESS_MASK);
+			fda.button_press_event += on_fda_button_press_event;
+			fda.add_events (EventMask.SCROLL_MASK);
+			fvp.add (fda);
+			add (fvp);
+
+			tvp = new Viewport (fvp.hadjustment, null);
+			tvp.shadow_type = ShadowType.NONE;
+			tvp.add (tda);
+			add (tvp);
+
+			lvp = new Viewport (null, fvp.vadjustment);
+			lvp.shadow_type = ShadowType.NONE;
+			lvp.add (lda);
+			add (lvp);
+
+			hbar = new HScrollbar (fvp.hadjustment);
+			var hbar_linked = new LinkedScrollbar (hbar);
+			hbar_linked.link (tda);
+			hbar_linked.link (fda);
+			add (hbar);
+
+			vbar = new VScrollbar (fvp.vadjustment);
+			var vbar_linked = new LinkedScrollbar (vbar);
+			vbar_linked.link (lda);
+			vbar_linked.link (fda);
+			add (vbar);
+		}
+
+		public TreeModel model {
+			get { return _model; }
+			set {
+				if (_model == value) {
+					return;
+				}
+
+				_selection.deselect ();
+
+				_model = value;
+
+				if (_model != null) {
+					_model.row_changed += on_model_row_changed;
+					_model.row_deleted += on_model_row_deleted;
+					_model.row_inserted += on_model_row_inserted;
+					_model.rows_reordered += on_model_rows_reordered;
+				}
+
+				rebuild_dimensions ();
+
+				cda.queue_draw ();
+				tda.queue_draw ();
+				lda.queue_draw ();
+				fda.queue_draw ();
+			}
+		}
+
+		public GridViewColumn[] columns {
+			get {
+				// XXX-VALA: simple array conversion like this would be nice
+//				return _columns.to_array (typeof (GridViewColumn));
+				GridViewColumn[] array = new GridViewColumn[_columns.size];
+				for (int i = 0; i < array.length; i++) {
+					array[i] = _columns.get (i);
+				}
+				return array;
+			}
+		}
+
+		public PolicyType hscrollbar_policy {
+			get { return _hbar_policy; }
+			set {
+				if (_hbar_policy == value) {
+					return;
+				}
+
+				_hbar_policy = value;
+
+				queue_resize ();
+			}
+		}
+
+		public PolicyType vscrollbar_policy {
+			get { return _vbar_policy; }
+			set {
+				if (_vbar_policy == value) {
+					return;
+				}
+
+				_vbar_policy = value;
+
+				queue_resize ();
+			}
+		}
+
+		public ScrollbarSpan hscrollbar_span {
+			get { return _hbar_span; }
+			set {
+				if (_hbar_span == value) {
+					return;
+				}
+
+				_hbar_span = value;
+
+				queue_resize ();
+			}
+		}
+
+		public ScrollbarSpan vscrollbar_span {
+			get { return _vbar_span; }
+			set {
+				if (_vbar_span == value) {
+					return;
+				}
+
+				_vbar_span = value;
+
+				queue_resize ();
+			}
+		}
+
+		public Orientation orientation {
+			get { return _orientation; }
+			set {
+				if (_orientation != value) {
+					_orientation = value;
+
+					rebuild_dimensions ();
+
+					orientation_changed ();
+				}
+			}
+		}
+
+		public GridSelection selection {
+			get { return _selection; }
+		}
+
+		public int n_row_headers {
+			get { return r_span; }
+			set {
+				if (value >= 0 && value <= _columns.size) {
+					r_span = value;
+
+					update_drawing_area_size_requests ();
+				}
+			}
+		}
+
+		public int n_col_headers {
+			get { return c_span; }
+			set {
+				TreeIter i;
+				if (value >= 0 &&
+				    (value == 0 || _model.iter_nth_child (out i, null,
+				                                          value - 1)))
+				{
+					c_span = value;
+
+					update_drawing_area_size_requests ();
+				}
+			}
+		}
+
+		public void append_column (GridViewColumn col) {
+			col.visibility_changed += on_column_visibility_changed;
+
+			if (col.visible) {
+				if (_orientation == Orientation.VERTICAL) {
+					_widths.add (0);
+				} else {
+					_heights.add (0);
+				}
+
+				_visible.add (col);
+
+				TreeIter i;
+
+				if (_model != null && _model.get_iter_first (out i)) {
+					do {
+						TreePath path = _model.get_path (i);
+						measure_cell (path, col);
+					} while (_model.iter_next (ref i));
+				}
+
+				if (this.visible) {
+					update_drawing_area_size_requests ();
+				}
+			}
+
+			_columns.add (col);
+
+			columns_changed ();
+		}
+
+		public GridViewColumn append_column_with_attributes (CellRenderer r,
+		                                        RenderAttribute[]? a = null)
+		{
+			var col = new GridViewColumn (r);
+			col.set_field_attrs (a);
+			append_column (col);
+
+			return col;
+		}
+
+		public GridViewColumn append_column_with_data_func (CellRenderer r,
+		                                                    GridCellDataFunc f)
+		{
+			return append_column_with_header (r, f, null, null);
+		}
+
+		public GridViewColumn append_column_with_header (CellRenderer r,
+		                                                 GridCellDataFunc f,
+		                                                 CellRenderer? hr,
+		                                                 GridCellDataFunc? hf)
+		{
+			var col = new GridViewColumn (r);
+			col.set_cell_data_func (f);
+			if (hr != null) {
+				col.set_header_renderer (hr);
+				col.set_header_cell_data_func (hf);
+			}
+			append_column (col);
+
+			return col;
+		}
+
+		public int remove_column (GridViewColumn col) {
+			if (!_columns.contains (col)) {
+				warning ("Trying to remove non-existent column");
+				return _columns.size;
+			}
+
+			if (col.visible) {
+				if (_orientation == Orientation.VERTICAL) {
+					_widths.remove_at (_visible.index_of (col));
+				} else {
+					_heights.remove_at (_visible.index_of (col));
+				}
+
+				_visible.remove (col);
+				update_drawing_area_size_requests ();
+			}
+
+			_columns.remove (col);
+
+			columns_changed ();
+
+			return _columns.size;
+		}
+
+		public bool get_selectable (TreePath path, GridViewColumn col) {
+			TreeIter i;
+
+			return col != null &&
+			       _columns.contains (col) &&
+			       col.visible &&
+			       _visible.index_of (col) >= r_span &&
+			       path != null &&
+			       path.get_indices() [0] >= c_span &&
+			       _model.get_iter (out i, path);
+		}
+
+		public void scroll_to_cell (TreePath path, GridViewColumn col, bool a,
+		                            float ra, float ca)
+		{
+			Adjustment adj;
+			Widget widget;
+			Rectangle rect = cell_rect (path, col, out widget);
+
+			if (widget == tda || widget == fda) {
+				adj = fvp.hadjustment;
+
+				if (a) {
+					adj.value = double.min (adj.upper - adj.page_size,
+					                        (rect.x + rect.width / 2) -
+					                         adj.page_size * ra);
+				} else {
+					if (rect.x < adj.value ||
+						rect.width > fvp.allocation.width)
+					{
+						adj.value -= adj.value - rect.x;
+					} else if (Gdk.Rect.right (rect) >
+					           fvp.allocation.width + adj.value)
+					{
+						adj.value = Gdk.Rect.right (rect)
+						          - fvp.allocation.width;
+					}
+				}
+			}
+
+			if (widget == lda || widget == fda) {
+				adj = fvp.vadjustment;
+
+				if (a) {
+					adj.value = double.min (adj.upper - adj.page_size,
+					                        (rect.y + rect.height / 2) -
+					                        adj.page_size * ca);
+				} else {
+					if (rect.y < adj.value ||
+					    rect.height > fvp.allocation.height)
+					{
+						adj.value -= adj.value - rect.y;
+					} else if (Gdk.Rect.bottom (rect) >
+							   fvp.allocation.height + adj.value)
+					{
+						adj.value = Gdk.Rect.bottom (rect)
+						          - fvp.allocation.height;
+					}
+				}
+			}
+		}
+
+		protected override void add (Widget w) {
+			w.set_parent (this);
+			_children.add (w);
+		}
+
+		protected override void remove (Widget w) {
+			if (w != null) {
+				_children.remove (w);
+				w.unparent ();
+			}
+		}
+
+		protected override void forall (bool i, Gtk.Callback cb) {
+			foreach (Widget widget in _children) {
+				cb (widget);
+			}
+		}
+
+		protected override void size_request (Requisition r) {
+			Requisition bar_req;
+			/**
+			 * XXX: this doesn't change when the visibility of a scrollbar
+			 *      changes.
+			 **/
+			vbar.size_request (bar_req);
+			r.width =
+				this.left_width +
+				(this.x_span < _widths.size ? _widths.get (this.x_span) : 0) +
+				(int) this.border_width + bar_req.width;
+			hbar.size_request (bar_req);
+			r.height =
+				this.top_height +
+				(this.y_span < _heights.size ? _heights.get (this.y_span) : 0) +
+				(int) this.border_width + bar_req.height;
+		}
+
+		/**
+		 * we need to call queue_draw () on each of the drawing areas to avoid
+		 * some nasty unpainted rect artifacts on win32
+		 **/
+		protected override void size_allocate (Rectangle a) {
+			this.allocation = (Allocation) a;
+
+			Requisition hbar_r;
+			hbar.size_request (hbar_r);
+			Requisition vbar_r;
+			vbar.size_request (vbar_r);
+
+			/**
+			 * tmp variables to store the scrollbar visibilities, as flipping
+			 * the .visible property can cause infinite size_allocate () loop
+			 **/
+			bool hbar_v, vbar_v;
+
+			hbar_v = _hbar_policy == PolicyType.ALWAYS ||
+			         (_hbar_policy == PolicyType.AUTOMATIC &&
+			          this.left_width + this.field_width +
+			          this.border_width > a.width);
+
+			vbar_v = _vbar_policy == PolicyType.ALWAYS ||
+			         (_vbar_policy == PolicyType.AUTOMATIC &&
+			          this.top_height + this.field_height + this.border_width +
+			          (hbar_v ? hbar_r.height : 0) > a.height);
+
+			if (!vbar_v) {
+				vbar_r = Requisition ();
+			} else {
+				/**
+				 * the horizontal space used to show the vbar may now
+				 * cause the hbar to be needed
+				 **/
+				hbar_v = _hbar_policy == PolicyType.ALWAYS ||
+				         (_hbar_policy == PolicyType.AUTOMATIC &&
+				          this.left_width + this.field_width +
+				          this.border_width + vbar_r.width > a.width);
+			}
+
+			if (!hbar_v) {
+				hbar_r = Requisition ();
+			}
+
+			hbar.visible = hbar_v;
+			vbar.visible = vbar_v;
+
+			Rectangle wa;
+
+			wa.x = a.x;
+			wa.y = a.y;
+			wa.width = this.left_width;
+			wa.height = this.top_height;
+			cda.size_allocate (wa);
+			cda.queue_draw ();
+
+			wa.x = Gdk.Rect.right ((Rectangle) cda.allocation);
+			wa.y = a.y;
+			wa.width = a.width - this.left_width - (int) this.border_width -
+			                    (_vbar_span != ScrollbarSpan.HEADER_OVERLAP ?
+			                     vbar_r.width : 0);
+			wa.height = this.top_height;
+			tvp.size_allocate (wa);
+			tvp.queue_draw ();
+
+			wa.x = a.x;
+			wa.y = Gdk.Rect.bottom ((Rectangle) cda.allocation);
+			wa.width = this.left_width;
+			wa.height = a.height - this.top_height - (int) this.border_width -
+			                    (_hbar_span != ScrollbarSpan.HEADER_OVERLAP ?
+			                     hbar_r.height : 0);
+			lvp.size_allocate (wa);
+			lvp.queue_draw ();
+
+			wa.x = a.x + this.left_width;
+			wa.y = a.y + this.top_height;
+			wa.width = a.width - this.left_width - (int) this.border_width -
+			           vbar_r.width;
+			wa.height = a.height - this.top_height - (int) this.border_width -
+			           hbar_r.height;
+			fvp.size_allocate (wa);
+			fvp.queue_draw ();
+
+			int gap;
+
+			if (hbar.visible) {
+				gap = _hbar_span == ScrollbarSpan.FULL ? 0 : this.left_width;
+				wa.x = a.x + gap;
+				wa.y = Gdk.Rect.bottom ((Rectangle) a) - hbar_r.height;
+				wa.width = a.width - gap - vbar_r.width;
+				wa.height = hbar_r.height;
+				hbar.size_allocate (wa);
+			}
+
+			if (vbar.visible) {
+				gap = _vbar_span == ScrollbarSpan.FULL ? 0 : this.top_height;
+				wa.x = Gdk.Rect.right ((Rectangle) a) - vbar_r.width;
+				wa.y = a.y + gap;
+				wa.width = vbar_r.width;
+				wa.height = a.height - gap - hbar_r.height;
+				vbar.size_allocate (wa);
+			}
+		}
+
+		private int x_span {
+			get {
+				return _orientation == Orientation.VERTICAL ? r_span : c_span;
+			}
+		}
+
+		private int y_span {
+			get {
+				return _orientation == Orientation.VERTICAL ? c_span : r_span;
+			}
+		}
+
+		private int left_width {
+			get {
+				int w = 0;
+
+				for (int x = 0; x < this.x_span && x < _widths.size; x++) {
+					w += _widths.get (x);
+				}
+
+				return w;
+			}
+		}
+
+		private int top_height {
+			get {
+				int h = 0;
+
+				for (int y = 0; y < this.y_span && y < _heights.size; y++) {
+					h += _heights.get (y);
+				}
+
+				return h;
+			}
+		}
+
+		private int field_width {
+			get {
+				int w = 0;
+
+				for (int x = this.x_span; x < _widths.size; x++) {
+					w += _widths.get (x);
+				}
+
+				return w;
+			}
+		}
+
+		private int field_height {
+			get {
+				int h = 0;
+
+				for (int y = this.y_span; y < _heights.size; y++) {
+					h += _heights.get (y);
+				}
+
+				return h;
+			}
+		}
+
+		private void on_model_row_changed (TreeModel m, TreePath path,
+		                                   TreeIter iter)
+		{
+			foreach (GridViewColumn col in _visible) {
+				// We don't just use the path directly,
+				// as for some bloody reason the path.depth
+				// gets corrupted on win32 randomly resulting 
+				// in depths of 10923461, and things go boom.
+				TreePath p = _model.get_path (iter);
+				measure_cell (p, col);
+				invalidate_cell_rect (p, col);
+			}
+
+			update_drawing_area_size_requests ();
+		}
+
+		private void on_model_row_deleted (TreeModel m, TreePath path) {
+			if (_orientation == Orientation.VERTICAL) {
+				_heights.remove_at (path.get_indices () [0]);
+			} else {
+				_widths.remove_at (path.get_indices () [0]);
+			}
+
+			update_drawing_area_size_requests ();
+		}
+
+		private void on_model_row_inserted (TreeModel m, TreePath path) {
+			if (_orientation == Orientation.VERTICAL) {
+				_heights.insert (path.get_indices () [0], 0);
+			} else {
+				_widths.insert (path.get_indices () [0], 0);
+			}
+		}
+
+		private void on_model_rows_reordered (TreeModel m) {
+			// XXX
+		}
+
+		private void on_style_set (GridView s, Style style) {
+			rebuild_dimensions ();
+		}
+
+		private void on_state_changed (GridView s, StateType previous_state) {
+			Rectangle ir;
+
+			ir.x = 0; ir.y = 0;
+			ir.width = cda.allocation.width; ir.height = cda.allocation.height;
+			cda.window.invalidate_rect (ir, true);
+
+			ir.x = 0; ir.y = 0;
+			ir.width = tda.allocation.width; ir.height = tda.allocation.height;
+			tda.window.invalidate_rect (ir, true);
+
+			ir.x = 0; ir.y = 0;
+			ir.width = lda.allocation.width; ir.height = lda.allocation.height;
+			lda.window.invalidate_rect (ir, true);
+
+			ir.x = 0; ir.y = 0;
+			ir.width = fda.allocation.width; ir.height = fda.allocation.height;
+			fda.window.invalidate_rect (ir, true);
+		}
+
+		private bool on_focus_in_event (GridView s, EventFocus event) {
+			TreePath spath;
+			GridViewColumn scol;
+
+			if (_selection.get_selected (out spath, out scol)) {
+				invalidate_cell_rect (spath, scol);
+			}
+
+			return false;
+		}
+
+		private bool on_focus_out_event (GridView s, EventFocus event) {
+			TreePath spath;
+			GridViewColumn scol;
+
+			if (_selection.get_selected (out spath, out scol)) {
+				invalidate_cell_rect (spath, scol);
+			}
+
+			return false;
+		}
+
+		private bool on_button_press_event (GridView s, EventButton event) {
+			grab_focus ();
+			return false;
+		}
+
+		private bool on_key_press_event (GridView s, EventKey event) {
+			TreePath spath;
+			GridViewColumn scol;
+
+			if (!_selection.get_selected (out spath, out scol)) {
+				return false;
+			}
+
+			int x, y;
+
+			translate_coords (spath, scol, out x, out y);
+
+			switch (event.keyval) {
+				case Gdk.KEY_UP:
+					y -= 1;
+					break;
+				case Gdk.KEY_DOWN:
+					y += 1;
+					break;
+				case Gdk.KEY_LEFT:
+					x -= 1;
+					break;
+				case Gdk.KEY_RIGHT:
+					x += 1;
+					break;
+				default:
+					return false;
+			}
+
+			if (translate_coords_b (x, y, out spath, out scol) &&
+			    _selection.select_cell (spath, scol))
+			{
+				scroll_to_cell (spath, scol, false, 0, 0);
+			}
+
+			return true;
+		}
+
+		private void on_selection_changed (GridSelection s) {
+			if (_model != null && get_selectable (_prev_sel_path,
+			                                      _prev_sel_col))
+			{
+				invalidate_cell_rect (_prev_sel_path, _prev_sel_col);
+			}
+
+			TreePath spath;
+			GridViewColumn scol;
+
+			if (_selection.get_selected (out spath, out scol)) {
+				invalidate_cell_rect (spath, scol);
+			}
+
+			if (spath != null) {
+				_prev_sel_path = spath.copy ();
+			} else {
+				_prev_sel_path = null;
+			}
+			_prev_sel_col = scol;
+		}
+
+		private bool on_cda_expose_event (DrawingArea da, EventExpose event) {
+			if (_model == null) {
+				return false;
+			}
+
+			GridViewColumn col;
+			TreePath path;
+
+			for (int x = 0; x < this.x_span; x++) {
+				for (int y = 0; y < this.y_span; y++) {
+					if (translate_coords_b (x, y, out path, out col)) {
+						draw_cell (path, col, event.area);
+					}
+				}
+			}
+
+			return false;
+		}
+
+		private bool on_tda_expose_event (DrawingArea da, EventExpose event) {
+			if (_model == null) {
+				return false;
+			}
+
+			GridViewColumn col;
+			TreePath path;
+
+			for (int x = this.x_span; x < _widths.size; x++) {
+				for (int y = 0; y < this.y_span; y++) {
+					if (translate_coords_b (x, y, out path, out col)) {
+						draw_cell (path, col, event.area);
+					}
+				}
+			}
+
+			return false;
+		}
+
+		private bool on_lda_expose_event (DrawingArea da, EventExpose event) {
+			if (_model == null) {
+				return false;
+			}
+
+			GridViewColumn col;
+			TreePath path;
+
+			for (int x = 0; x < this.x_span; x++) {
+				for (int y = this.y_span; y < _heights.size; y++) {
+					if (translate_coords_b (x, y, out path, out col)) {
+						draw_cell (path, col, event.area);
+					}
+				}
+			}
+
+			return false;
+		}
+
+		private bool on_fda_expose_event (DrawingArea da, EventExpose event) {
+			if (_model == null) {
+				return false;
+			}
+
+			GridViewColumn col;
+			TreePath path;
+
+			for (int x = this.x_span; x < _widths.size; x++) {
+				for (int y = this.y_span; y < _heights.size; y++) {
+					if (translate_coords_b (x, y, out path, out col)) {
+						draw_cell (path, col, event.area);
+					}
+				}
+			}
+
+			return false;
+		}
+
+		private bool on_yheader_motion_notify_event (DrawingArea da,
+		                                             EventMotion event)
+		{
+			int x = (int) event.x;
+
+			if (da == tda) {
+				x += left_width;
+			}
+
+			da.window.set_cursor (
+				_drag_col >= 0 || drag_x (x) >= 0 ? DRAG_CURSOR : null);
+
+			if (_drag_col >= 0 && x > column_x (_drag_col) + 12) {
+				int prev_width = _widths.get (_drag_col);
+				_widths.set (_drag_col, x - column_x (_drag_col));
+
+				/**
+				 * make sure that we don't cause the grid's size request
+				 * to increase
+				 **/
+				Requisition vbar_req;
+				vbar.size_request (vbar_req);
+				if (_drag_col <= this.x_span &&
+				    column_x (this.x_span) + _widths.get (this.x_span) +
+				    (this.x_span + 1 < _widths.size ?
+				    _widths.get (this.x_span + 1) : 0) +
+				    this.border_width +
+				    (vbar.visible ? vbar_req.width : 0) + 6 >=
+				    allocation.width)
+				{
+					_widths.set (_drag_col, prev_width);
+					return false;
+				}
+
+				update_drawing_area_size_requests ();
+			}
+
+			return false;
+		}
+
+		private bool on_yheader_button_press_event (DrawingArea da,
+		                                            EventButton event)
+		{
+			int x = (int) event.x;
+
+			if (da == tda) {
+				x += this.left_width;
+			}
+
+			_drag_col = drag_x (x);
+			
+			// make the headers eat clicks, so that when you
+			// override button_press in classes using GridView, you
+			// don't get spurious clicks.
+			return true;
+		}
+
+		private bool on_yheader_button_release_event (DrawingArea da,
+		                                              EventButton event)
+		{
+			_drag_col = -1;
+			return false;
+		}
+
+		private void on_fda_style_set (DrawingArea da, Style style) {
+			if ((fda.get_flags () & WidgetFlags.REALIZED) != 0) {
+				fda.window.set_background (fda style  base[(int) fda.state]);
+			}
+		}
+
+		private void on_fda_realized (DrawingArea da) {
+			fda.window.set_background (fda style  base[(int) fda.state]);
+		}
+
+		private bool on_fda_button_press_event (DrawingArea da,
+		                                        EventButton event)
+		{
+			if (event.y > this.field_height) {
+				return false;
+			}
+
+			int x = this.x_span, y = this.y_span;
+
+			while (x < _widths.size &&
+			       (int) event.x > column_x (x) - this.left_width)
+			{
+				x++;
+			}
+			while ((int) event.y > row_y (y) - this.top_height) {
+				y++;
+			}
+
+			GridViewColumn col, scol;
+			TreePath path, spath;
+
+			translate_coords_b (x - 1, y - 1, out path, out col);
+			_selection.get_selected (out spath, out scol);
+
+			if (spath != null && path.compare (spath) == 0 && col == scol &&
+			    (event.state & ModifierType.CONTROL_MASK)
+			                         == ModifierType.CONTROL_MASK)
+			{
+				_selection.deselect ();
+			} else {
+				_selection.select_cell (path, col);
+				scroll_to_cell (path, col, false, 0, 0);
+			}
+
+			return false;
+		}
+
+		// make the headers eat clicks, so that when you override
+		// button_press in classes using GridView, you don't get
+		// spurious clicks.
+		private bool on_lda_button_press_event (DrawingArea da,
+		                                        EventButton event)
+		{
+			return true;
+		}
+
+		private void on_column_visibility_changed (GridViewColumn changed_col) {
+			int vc;
+			Gee.List<int> dimensions = _orientation == Orientation.VERTICAL ?
+			                           _widths : _heights;
+
+			if (changed_col.visible) {
+				_visible.clear ();
+
+				foreach (GridViewColumn col in _columns) {
+					if (col.visible) {
+						_visible.add (col);
+					}
+				}
+
+				vc = _visible.index_of (changed_col);
+				dimensions.insert (vc, 0);
+
+				TreeIter i;
+
+				if (_model != null && _model.get_iter_first (out i)) {
+					do {
+						TreePath path = _model.get_path (i);
+						measure_cell (path, changed_col);
+					} while (_model.iter_next (ref i));
+				}
+			} else {
+				vc = _visible.index_of (changed_col);
+
+				if (dimensions.size > vc) { 
+					dimensions.remove_at (vc);
+				}
+
+				_visible.remove (changed_col);
+			}
+
+			update_drawing_area_size_requests ();
+		}
+
+		private void translate_coords (TreePath path, GridViewColumn col,
+		                               out int x, out int y)
+		{
+			if (_orientation == Orientation.VERTICAL) {
+				x = _visible.index_of (col);
+				y = path.get_indices () [0];
+			} else {
+				x = path.get_indices () [0];
+				y = _visible.index_of (col);
+			}
+		}
+
+		// XXX-VALA: find a better name
+		private bool translate_coords_b (int x, int y,
+		                                 out TreePath path,
+		                                 out GridViewColumn col)
+		{
+			int c = _orientation == Orientation.VERTICAL ? x : y;
+			int r = _orientation == Orientation.VERTICAL ? y : x;
+			TreeIter i;
+
+			if (c >= _visible.size || !_model.iter_nth_child (out i, null, r)) {
+				col = null;
+				path = null;
+
+				return false;
+			} else {
+				col = _visible.get (c);
+				path = new TreePath.from_string (r.to_string ());
+
+				return true;
+			}
+		}
+
+		private void update_drawing_area_size_requests () {
+			cda.set_size_request (this.left_width, this.top_height);
+			tda.set_size_request (this.field_width, this.top_height);
+			lda.set_size_request (this.left_width, this.field_height);
+			fda.set_size_request (this.field_width, this.field_height);
+		}
+
+		private void measure_cell (TreePath path, GridViewColumn col) {
+			int w, h, x, y, x_offset, y_offset;
+			TreeIter i;
+			bool header = path.get_indices () [0] < c_span;
+			Rectangle rect = Rectangle ();
+			CellRenderer renderer = header && col.header_renderer != null ?
+			                        col.header_renderer : col.field_renderer;
+
+			_model.get_iter (out i, path);
+			col.cell_set_cell_data (_model, i, header);
+			// XXX-VALA: vapi change: parameter 'rect' should be ref
+			renderer.get_size (this, rect, out x_offset, out y_offset,
+			                   out w, out h);
+			translate_coords (path, col, out x, out y);
+
+			_widths.set (x, int.max (_widths.get (x), w + 20));
+			_heights.set (y, int.max (_heights.get (y), h + 4));
+		}
+
+		private void rebuild_dimensions () {
+			_widths.clear ();
+			_heights.clear ();
+
+			int x, y;
+			TreeIter i;
+			TreePath path;
+
+			if (_model != null && _model.get_iter_first (out i)) {
+				do {
+					foreach (GridViewColumn col in _visible) {
+						path = _model.get_path (i);
+						translate_coords (path, col, out x, out y);
+
+						if (x == _widths.size) {
+							_widths.add (0);
+						}
+						if (y == _heights.size) {
+							_heights.add (0);
+						}
+
+						measure_cell (path, col);
+					}
+				} while (_model.iter_next (ref i));
+			}
+
+			update_drawing_area_size_requests ();
+		}
+
+		private Rectangle cell_rect (TreePath path, GridViewColumn col,
+		                             out Widget widget)
+		{
+			int x, y;
+			translate_coords (path, col, out x, out y);
+
+			Rectangle rect;
+			rect.x = column_x (x);
+			rect.y = row_y (y);
+			rect.width = _widths.get (x);
+			rect.height = _heights.get (y);
+
+			if (x < this.x_span && y < this.y_span) {
+				widget = cda;
+				return rect;
+			} else if (x < this.x_span) {
+				widget = lda;
+				rect.y -= this.top_height;
+			} else if (y < this.y_span) {
+				widget = tda;
+				rect.x -= this.left_width;
+			} else {
+				widget = fda;
+				rect.x -= this.left_width;
+				rect.y -= this.top_height;
+			}
+
+			/* stretch the rightmost cell to fill the allocation */
+			if (x == _widths.size - 1) {
+				rect.width = Gdk.Rect.right ((Rectangle) fda.allocation) - rect.x;
+			}
+
+			return rect;
+		}
+
+		private void invalidate_cell_rect (TreePath path, GridViewColumn col) {
+			Widget widget;
+			Rectangle rect = cell_rect (path, col, out widget);
+
+			if (widget != null && widget.window != null) {
+				widget.window.invalidate_rect (rect, true);
+			}
+		}
+
+		private int column_x (int x) {
+			int ret = 0;
+			for (--x; x >= 0 && x < _widths.size; x--) {
+				ret += _widths.get (x);
+			}
+
+			return ret;
+		}
+
+		private int row_y (int y) {
+			int ret = 0;
+			for (--y; y >= 0 && y < _heights.size; y--) {
+				ret += _heights.get (y);
+			}
+
+			return ret;
+		}
+
+		private int drag_x (int x) {
+			for (int xc = 1; xc < _widths.size; xc++) {
+				int distance = x - column_x (xc);
+
+				if (distance > -3 && distance < 3 &&
+				    (xc != this.x_span || distance < 0))
+				{
+					return xc - 1;
+				}
+			}
+
+			return -1;
+		}
+
+		private void draw_cell (TreePath path, GridViewColumn col,
+		                        Rectangle clip_)
+		{
+			Widget w;
+			Rectangle clip;
+
+			Rectangle rect = cell_rect (path, col, out w);
+			// XXX-VALA: attention: parameter 'clip' is an out parameter!
+			if (!clip_.intersect (rect, clip)) {
+				return;
+			}
+
+			CellRendererState crs = 0;
+
+			if (w != fda) {
+				w.window.draw_rectangle (w.style.mid_gc [w.state], true,
+				                         rect.x, rect.y,
+				                         rect.width, rect.height);
+			} else {
+				TreePath spath;
+				GridViewColumn scol;
+				_selection.get_selected (out spath, out scol);
+
+				if (spath != null && path.compare (spath) == 0 && col == scol) {
+					crs = CellRendererState.SELECTED;
+					Gtk.paint_flat_box (w.style, w.window,
+					                    StateType.SELECTED, ShadowType.NONE,
+					                    clip, this, "cell_odd", rect.x, rect.y,
+					                    rect.width, rect.height);
+				}
+			}
+
+			Gdk.draw_line (w.window, w.style.bg_gc [w.state],
+			               rect.x, Gdk.Rect.bottom (rect) - 1,
+			               Gdk.Rect.right (rect), Gdk.Rect.bottom (rect) - 1);
+			Gdk.draw_line (w.window, w.style.bg_gc [w.state],
+			               Gdk.Rect.right (rect) - 1, rect.y,
+			               Gdk.Rect.right (rect) - 1, Gdk.Rect.bottom (rect));
+
+			TreeIter i;
+			bool header = path.get_indices () [0] < c_span;
+			CellRenderer renderer = header && col.header_renderer != null ?
+			                        col.header_renderer : col.field_renderer;
+			_model.get_iter (out i, path);
+			col.cell_set_cell_data (_model, i, header);
+			renderer.render (w.window, this, rect, rect, clip, crs);
+		}
+	}
+}
+
+
+// XXX-VALA: these are additional helper definitions for the Vala port
+
+namespace Gtk {
+
+	public struct RenderAttribute {
+
+		public string property;
+		public int column;
+
+		public RenderAttribute (string p, int c) {
+			this.property = p;
+			this.column = c;
+		}
+	}
+}
+
+namespace Array {
+
+	public int index_of (GLib.Object[] array, GLib.Object item) {
+		for (int i = 0; i < array.length; i++) {
+			if (array[i] == item) {
+				return i;
+			}
+		}
+		return -1;
+	}
+}
+
+namespace Gdk {
+	public const uint KEY_LEFT = 0xFF51;
+	public const uint KEY_RIGHT = 0xFF53;
+	public const uint KEY_UP = 0xFF52;
+	public const uint KEY_DOWN = 0xFF54;
+}
+
+namespace Gdk.Rect {
+
+	public static int right (Rectangle rect) {
+		return rect.x + rect.width;
+	}
+
+	public static int bottom (Rectangle rect) {
+		return rect.y + rect.height;
+	}
+
+	public static int top (Rectangle rect) {
+		return rect.y;
+	}
+
+	public static int left (Rectangle rect) {
+		return rect.x;
+	}
+}
+

Added: trunk/ribbon/Makefile
==============================================================================
--- (empty file)
+++ trunk/ribbon/Makefile	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,6 @@
+sample:
+	valac -g --pkg gtk+-2.0 --pkg cairo --pkg pangocairo --pkg gee-1.0 --disable-non-null --Xcc="-std=c99" *.vala -o sample
+
+clean:
+	rm sample
+

Added: trunk/ribbon/README
==============================================================================
--- (empty file)
+++ trunk/ribbon/README	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,62 @@
+This is a Vala port of gtk-sharp-ribbon, just to see what can already be done
+with Vala. The original gtk-sharp-ribbon is a Google Summer of Code project by
+Laurent Debacker.
+
+http://tirania.org/blog/archive/2007/Aug-30-1.html
+http://anonsvn.mono-project.com/viewcvs/trunk/gtk-sharp-ribbon/
+http://debackerl.wordpress.com/
+
+This port is based on SVN revision 107902.
+
+
+Build
+-----
+
+Make sure you have installed the latest Vala version from SVN.
+Vala ribbons depends on GLib, GTK+, Cairo, Pango and libgee, so have them
+installed along with their header files.
+Then manually edit the installed 'gtk+-2.0.vapi' file and change the lines
+
+ public virtual void forall (Gtk.Callback callback, void* callback_data);
+and
+ public weak GLib.List get_children ();
+
+to
+
+ public virtual void forall (bool include_internals, Gtk.Callback callback);
+and
+ public weak GLib.List<Widget> get_children ();
+
+Now type 'make' on the command line and run './sample'.
+
+Some issues
+-----------
+
+Currently you can't switch tabs. This is beacause Vala doesn't support 'real'
+closures yet.
+
+Expand buttons of ribbon groups are not shown because I haven't found out yet
+how to get notified when someone connects to a signal (as the buttons should
+be set to visible/invisible at the moment when someone connects/disconnects).
+
+Due to Vala Bug #538901 it is not possible to call the original base handler
+from an overridden signal default handler. So I had to duplicate the actions of
+the base class as a workaround.
+
+Warning messages on the console: I haven't yet figured out the reason and how
+to get rid of them.
+
+When closing the window the sample application segfaults.
+
+ApplicationMenuItem is not yet ported.
+
+Notes
+-----
+I have done almost no refactoring, so it should be easier to keep the code in
+sync with the original project.
+
+Gee.List is used instead of GLib.List because the latter has no remove_at()
+method.
+
+
+Frederik

Added: trunk/ribbon/application-button.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/application-button.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,135 @@
+using GLib;
+using Cairo;
+using Gtk;
+
+public class ApplicationButton : BaseButton {
+
+	private const double LINE_WIDTH = 1.0;
+
+	/** Fired when the button is clicked. */
+	public signal void clicked ();
+
+	private ApplicationMenu _app_menu;
+	public ApplicationMenu menu {
+		get { return _app_menu; }
+	}
+
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		_app_menu = new ApplicationMenu (this);
+
+		this.height_request = 36;
+		this.width_request = 36;
+
+		_enabled = true;
+	}
+
+	// XXX: workaround
+	private bool has_click_listener () {
+		var signal_id = Signal.lookup ("clicked", typeof (ApplicationButton));
+		return Signal.has_handler_pending (this, signal_id, 0, true);
+	}
+
+	/** Fires the click event. */
+	public void click () {
+		if (_enabled && has_click_listener ()) {
+			clicked ();
+		}
+
+		_app_menu.realize += () => {
+			int x, y;
+			get_parent_window ().get_origin (out x, out y);
+			x += this.allocation.x;
+			y += Gdk.Rect.bottom ((Gdk.Rectangle) this.allocation);
+			_app_menu.window.move (x, y);
+		};
+
+		_app_menu.show ();
+	}
+
+	protected override bool bound_widget_button_press_event (Widget sender,
+													Gdk.EventButton evnt) {
+		event ((Gdk.Event) evnt);
+		return false;
+	}
+
+	protected override bool bound_widget_button_release_event (Widget sender,
+													Gdk.EventButton evnt) {
+		event ((Gdk.Event) evnt);
+		click ();
+		return false;
+	}
+
+	protected override bool expose_event (Gdk.EventExpose event) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (event.area.x, event.area.y,
+						event.area.width, event.area.height);
+		cr.clip ();
+		draw (cr);
+
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return base.expose_event (event);	// FIXME: causes endless loop
+		// *** workaround ***
+		if (this.child != null) {
+			this.child.expose_event (event);
+		}
+		return false;
+		// *** workaround ***
+	}
+
+	protected void draw (Context cr) {
+		_theme.draw_application_button (cr, (Gdk.Rectangle) this.allocation,
+										_state, LINE_WIDTH, this);
+	}
+
+	protected override bool button_press_event (Gdk.EventButton event) {
+//		bool ret = base.button_press_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.PRESSED;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		click ();
+		return ret;
+	}
+
+	protected override bool button_release_event (Gdk.EventButton event) {
+//		bool ret = base.button_release_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.HOVER;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool enter_notify_event (Gdk.EventCrossing event) {
+//		bool ret = base.enter_notify_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.HOVER;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool leave_notify_event (Gdk.EventCrossing event) {
+//		bool ret = base.leave_notify_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.DEFAULT;
+		queue_draw ();
+		return ret;
+	}
+}
+

Added: trunk/ribbon/application-menu-item.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/application-menu-item.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,5 @@
+using Gtk;
+
+public class ApplicationMenuItem : Bin {
+}
+

Added: trunk/ribbon/application-menu.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/application-menu.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,439 @@
+using Gtk;
+using Cairo;
+
+public class ApplicationMenu : Container {
+
+	private const double LINE_WIDTH = 1.0;
+	private const int TOP_PADDING = 24;
+	private const int BORDER_WIDTH = 6;
+	private const int SPACE = 2;
+	private const int VERTICAL_WINDOW_OFFSET = 24 - 2;
+//	private const int VERTICAL_WINDOW_OFFSET = TOP_PADDING - SPACE;	// XXX
+
+	protected Theme _theme = new Theme ();
+
+	private Gee.List<ApplicationMenuItem> _items;
+	private Widget _default_menu;
+	private int _item_height;
+	private Gdk.Size _menu_size;
+
+	private Widget _active_menu;
+
+	private Gdk.Rectangle _items_alloc;
+	private int _menu_items_col_width;
+	private int _buttons_height;
+	private int _exit_button_width;
+	private int _options_button_width;
+	private int _visible_menu_items;
+	private bool _active_menu_visible;
+	private bool _options_button_visible;
+	private bool _exit_button_visible;
+
+	private Window _win;
+
+	public ApplicationButton application_button { get; construct; }
+
+	private Button _options_button;
+	public Button options_button {
+		get { return _options_button; }
+		set {
+			if (_options_button == value) {
+				return;
+			}
+			if (_options_button != null) {
+				_options_button.unparent ();
+			}
+			_options_button = value;
+			if (value != null) {
+				value.draw_background = true;
+				value.opaque_background = true;
+				value.set_parent (this);
+				value.visible = true;
+			}
+		}
+	}
+
+	private Button _exit_button;
+	public Button exit_button {
+		get { return _exit_button; }
+		set {
+			if (_exit_button == value) {
+				return;
+			}
+			if (_exit_button != null) {
+				_exit_button.unparent ();
+			}
+			_exit_button = value;
+			if (value != null) {
+				value.draw_background = true;
+				value.opaque_background = true;
+				value.set_parent (this);
+				value.visible = true;
+			}
+		}
+	}
+
+	public int item_height {
+		get { return _item_height; }
+		set {
+			if (_item_height == value) {
+				return;
+			}
+			_item_height = value;
+			queue_resize ();
+		}
+	}
+
+	public Gdk.Size menu_size {
+		get { return _menu_size; }
+		set {
+//			if (_menu_size == value) {	// XXX
+//				return;
+//			}
+			_menu_size = value;
+			queue_resize ();
+		}
+	}
+
+	public Widget default_menu {
+		get { return _default_menu; }
+		set {
+			if (_default_menu == value) {
+				return;
+			}
+			bool update_active = _default_menu == _active_menu;
+			if (update_active && _default_menu != null) {
+				_default_menu.unparent ();
+			}
+			_default_menu = value;
+			if (update_active) {
+				set_active_menu (value);
+			}
+		}
+	}
+
+	/** Returns the number of children. */
+	public int n_children {
+		get { return _items.size; }
+	}
+
+	/** Constructor. */
+	public ApplicationMenu (ApplicationButton button) {
+		this.application_button = button;
+	}
+
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+
+//		this.children = new Gee.ArrayList<Widget> ();
+
+//		append (new Button ("OK"));
+
+		_items = new Gee.ArrayList<ApplicationMenuItem> ();
+		_item_height = 32;
+		_menu_size = Gdk.Size (240, 320);
+	}
+
+	public void prepend (ApplicationMenuItem item) {
+		insert (item, 0);
+	}
+
+	public void append (ApplicationMenuItem item) {
+		insert (item, -1);
+	}
+
+	public void insert (ApplicationMenuItem item, int index) {
+		item.set_parent (this);
+		item.visible = true;
+
+		if (index == -1) {
+			_items.add (item);
+		} else {
+			_items.insert (index, item);
+		}
+	}
+
+	public void remove (int index) {
+		if (index == -1) {
+			index = _items.size - 1;
+		}
+
+		_items.get (index).unparent ();
+		_items.remove_at (index);
+	}
+
+	public void activate_menu (Widget widget) {
+		if (widget == null) {
+			set_active_menu (_default_menu);
+		} else {
+			set_active_menu (widget);
+		}
+	}
+
+	private void set_active_menu (Widget widget) {
+		if (_active_menu != null) {
+			_active_menu.unparent ();
+		}
+		_active_menu = widget;
+		widget.set_parent (this);
+		widget.visible = true;
+		queue_resize ();
+	}
+
+	public void show_at (int x, int y) {
+//		if (_win != null) {
+//			kill_menu (true);
+//		}
+
+//		foreach (var item in _items) {
+//			item.set_parent (this);
+//		}
+
+		if (_win == null) {
+			_win = new SyntheticWindow (WindowType.POPUP);
+			_win.add (this);
+
+			_win.hide += () => {
+				kill_menu (true);
+			};
+
+			_win.show_all ();
+			_win.window.move (x, y - VERTICAL_WINDOW_OFFSET);
+
+			_win.button_press_event += () => {
+				kill_menu (true);
+			};
+
+			_win.add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+							| Gdk.EventMask.BUTTON_RELEASE_MASK
+							| Gdk.EventMask.POINTER_MOTION_MASK);
+		} else {
+			_win.show_all ();
+			_win.window.move (x, y - VERTICAL_WINDOW_OFFSET);
+		}
+
+		Gtk.grab_add (_win);
+		Gdk.GrabStatus grabbed = Gdk.pointer_grab (_win.window, true,
+									Gdk.EventMask.BUTTON_PRESS_MASK, null, null, 0);
+		if (grabbed != Gdk.GrabStatus.SUCCESS) {
+			kill_menu (false);
+			return;
+		}
+
+		grabbed = Gdk.keyboard_grab (_win.window, true, 0);
+		if (grabbed != Gdk.GrabStatus.SUCCESS) {
+			kill_menu (false);
+			return;
+		}
+	}
+
+	private void kill_menu (bool ungrab) {
+		if (_win == null) {
+			return;
+		}
+
+//		Window win = _win;
+//		_win = null;
+
+//		win.child = null;
+
+		Gtk.grab_remove (_win);
+		if (ungrab) {
+			Gdk.pointer_ungrab (0);
+			Gdk.keyboard_ungrab (0);
+		}
+		_win.hide ();
+//		_win.destroy ();
+	}
+
+	protected override void forall (bool include_internals, Gtk.Callback callback) {
+		foreach (var widget in _items) {
+			if (widget.visible) callback (widget);
+		}
+
+		if (_options_button != null && _options_button.visible) {
+			callback (_options_button);
+		}
+
+		if (_exit_button != null && _exit_button.visible) {
+			callback (_exit_button);
+		}
+
+		if (_active_menu != null && _active_menu.visible) {
+			callback (_active_menu);
+		}
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_requested (requisition);
+
+		_menu_items_col_width = 0;
+		int menu_items_col_height = 0;
+
+		foreach (var mi in _items) {
+			if (mi.visible) {
+				mi.height_request = _item_height;
+				Gtk.Requisition req;
+				mi.size_request (req);
+				if (req.width > _menu_items_col_width) {
+					_menu_items_col_width = req.width;
+				}
+				menu_items_col_height += _item_height;
+			}
+		}
+
+		requisition.height = menu_items_col_height;
+		requisition.width = _menu_items_col_width;
+
+		if (_active_menu != null) {
+//			Gtk.Requisition req = _active_menu.size_request ();
+//			requisition.width += req.width;
+//			if (req.height > requisition.height) {
+//				requisition.height = req.height;
+//			}
+
+			requisition.width += _menu_size.width;
+			if (_menu_size.height > requisition.height) {
+				requisition.height = _menu_size.height;
+			}
+		}
+
+		int buttons_width = 0;
+		_buttons_height = 0;
+
+		if (_options_button != null) {
+			Gtk.Requisition req;
+			_options_button.size_request (req);
+			buttons_width = req.width;
+			_buttons_height = req.height;
+			_options_button_width = req.width;
+		}
+
+		if (_exit_button != null) {
+			Gtk.Requisition req;
+			_exit_button.size_request (req);
+			buttons_width += req.width;
+			if (_options_button != null) {
+				buttons_width += SPACE;
+			}
+			if (req.height > _buttons_height) {
+				_buttons_height = req.height;
+			}
+			_exit_button_width = req.width;
+		}
+
+		if (buttons_width > requisition.width) {
+			requisition.width = buttons_width;
+		}
+
+		if (_buttons_height > 0) {
+			requisition.height += _buttons_height + SPACE;
+		}
+		requisition.width += BORDER_WIDTH << 1;
+		requisition.height += BORDER_WIDTH + TOP_PADDING;
+
+		this._menu_items_col_width = _menu_items_col_width;		// XXX
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocated (allocation);
+		this.allocation = (Allocation) allocation;	// XXX workaround
+
+		_visible_menu_items = 0;
+		_exit_button_visible = _options_button_visible = false;
+
+		allocation.height -= BORDER_WIDTH;
+
+		if (_buttons_height + TOP_PADDING <= allocation.height) {
+			Gdk.Rectangle alloc;
+
+			if (_buttons_height > 0) {
+				alloc.x = Gdk.Rect.right (allocation) - BORDER_WIDTH;
+				alloc.y = Gdk.Rect.bottom (allocation) - _buttons_height;
+				alloc.height = _buttons_height;
+
+				if (_exit_button != null) {
+					alloc.x -= _exit_button_width;
+					alloc.width = _exit_button_width;
+					if (alloc.x >= allocation.x + BORDER_WIDTH) {
+						_exit_button.size_allocate (alloc);
+					}
+				}
+
+				if (_options_button != null) {
+					if (_exit_button != null) {
+						alloc.x -= SPACE;
+					}
+					alloc.x -= _options_button_width;
+					alloc.width = _options_button_width;
+					if (alloc.x >= allocation.x + BORDER_WIDTH) {
+						_options_button.size_allocate (alloc);
+					}
+				}
+
+				allocation.height -= _buttons_height + SPACE;
+			}
+
+			alloc.x = allocation.x + BORDER_WIDTH;
+			alloc.y = allocation.y + TOP_PADDING;
+			_items_alloc.x = alloc.x;
+			_items_alloc.y = alloc.y;
+			alloc.height = _item_height;
+			if (Gdk.Rect.right (allocation) - alloc.x - BORDER_WIDTH < _menu_items_col_width) {
+				_menu_items_col_width = Gdk.Rect.right (allocation) - alloc.x - BORDER_WIDTH;
+			}
+
+			if (_menu_items_col_width > 0) {
+				alloc.width = _menu_items_col_width;
+
+				foreach (var mi in _items) {
+					if (mi.visible) {
+						if (Gdk.Rect.bottom (alloc) <= Gdk.Rect.bottom (allocation)) {
+							mi.size_allocate (alloc);
+							alloc.y += _item_height;
+							_visible_menu_items++;
+						}
+					}
+				}
+			}
+
+			_items_alloc.width = _menu_items_col_width + SPACE;
+			_items_alloc.height = Gdk.Rect.bottom (allocation) - _items_alloc.y - BORDER_WIDTH;
+
+			if (_active_menu != null) {
+				alloc.x = allocation.x + BORDER_WIDTH + _menu_items_col_width + SPACE;
+				alloc.width = Gdk.Rect.right (allocation) - alloc.x - BORDER_WIDTH;
+				alloc.y = allocation.y + TOP_PADDING;
+				alloc.height = Gdk.Rect.bottom (allocation) - alloc.y - BORDER_WIDTH;
+
+				if (alloc.width > 0 && alloc.width > 0) {
+					_active_menu.size_allocate (alloc);
+				}
+			}
+		}
+	}
+
+	protected override bool expose_event (Gdk.EventExpose event) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (event.area.x, event.area.y, event.area.width, event.area.height);
+		cr.clip ();
+		draw (cr);
+
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return base.expose_event (event);	// XXX
+		return false;
+	}
+
+	protected void draw (Context cr) {
+		Gdk.Rectangle rect = (Gdk.Rectangle) this.allocation;	// XXX
+		_theme.draw_application_menu (cr, rect, _items_alloc, LINE_WIDTH, this);
+	}
+}
+

Added: trunk/ribbon/base-button.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/base-button.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,198 @@
+using Gtk;
+
+/**
+ * Foundation of all buttons.
+ */
+public abstract class BaseButton : Bin {
+
+	protected Theme.ButtonState _state = Theme.ButtonState.DEFAULT;
+	protected bool _is_small;
+
+	/** Spacing between the content and the widget. */
+	protected double _padding;
+	public double padding {
+		set {
+			if (_padding == value) {
+				return;
+			}
+			_padding = value;
+			queue_draw ();
+		}
+		get { return _padding; }
+	}
+
+	/** Shape of the widget. */
+	public GroupStyle group_style { get; set; }
+
+	/** <b>true</b> if the widget should paint a background, <b>false</b> otherwise. */
+	protected bool _draw_background;
+	public bool draw_background {
+		set {
+			if (_draw_background == value) {
+				return;
+			}
+			_draw_background = value;
+			queue_draw ();
+		}
+		get { return _draw_background; }
+	}
+
+	protected bool _opaque_background;
+	public bool opaque_background {
+		set {
+			if (_opaque_background == value) {
+				return;
+			}
+			_opaque_background = value;
+			queue_draw ();
+		}
+		get { return _opaque_background; }
+	}
+
+	/** <b>true</b> if the button is enabled, <b>false</b> otherwise. */
+	protected bool _enabled;
+	public bool enabled {
+		set {
+			if (_enabled == value) {
+				return;
+			}
+			_enabled = value;
+			queue_draw ();
+		}
+		get { return _enabled; }
+	}
+
+	/** Image to display. */
+	protected Widget _image;
+	public Widget image {
+		set {
+			if (_image == value) {
+				return;
+			}
+			if (_image != null) {
+				unbind_widget (_image);
+			}
+			_image = value;
+			if (_image != null) {
+				bind_widget (_image);
+			}
+			update_image_label ();
+		}
+		get { return _image; }
+	}
+
+	/** Position of the image relative to the label. */
+	protected PositionType _image_position;
+	public PositionType image_position {
+		set {
+			if (_image_position == value) {
+				return;
+			}
+			_image_position = value;
+			update_image_label ();
+		}
+		get { return _image_position; }
+	}
+
+	/** Label to display. */
+	protected Label _label;
+	public string label {
+		set {
+			if (_label != null) {
+				unbind_widget (_label);
+			}
+			_label = new Label (value);
+			if (_label != null) {
+				bind_widget (_label);
+			}
+			update_image_label ();
+		}
+		get {
+			return _label == null ? null : _label.text;
+		}
+	}
+
+	/** Theme used to draw the widget. */
+	protected Theme _theme = new Theme ();
+	public Theme theme {
+		set {
+			_theme = value;
+			queue_draw ();
+		}
+		get { return _theme; }
+	}
+
+	/** Binds a widget to listen to all button events. */
+	private void bind_widget (Widget w) {
+		w.button_press_event += bound_widget_button_press_event;
+		w.button_release_event += bound_widget_button_release_event;
+	}
+
+	/** Unbinds a widget to no longer listen to button events. */
+	private void unbind_widget (Widget w) {
+		w.button_press_event -= bound_widget_button_press_event;
+		w.button_release_event -= bound_widget_button_release_event;
+	}
+
+	/** Called when a mouse button has been pressed on a binded widget. */
+	protected abstract bool bound_widget_button_press_event (Widget sender,
+													Gdk.EventButton event);
+
+	/** Called when a mouse button has been release on a binded widget. */
+	protected abstract bool bound_widget_button_release_event (Widget sender,
+													Gdk.EventButton event);
+
+	/** Updates the child widget containing the label and/or image. */
+	private void update_image_label () {
+		if (this.child != null) {
+			var con = this.child as Container;
+			if (con != null) {
+				con.remove (_image);
+				con.remove (_label);
+			}
+			remove (this.child);
+		}
+
+		if (_label != null && _image != null) {
+			switch (_image_position) {
+			case PositionType.TOP:
+				{
+					var box = new VBox (false, 0);
+					box.add (_image);
+					box.add (_label);
+					add (box);	// FIXME
+					break;
+				}
+			case PositionType.BOTTOM:
+				{
+					var box = new VBox (false, 0);
+					box.add (_label);
+					box.add (_image);
+					add (box);	// FIXME
+					break;
+				}
+			case PositionType.LEFT:
+				{
+					var box = new HBox (false, 0);
+					box.add (_image);
+					box.add (_label);
+					add (box);	// FIXME
+					break;
+				}
+			case PositionType.RIGHT:
+				{
+					var box = new HBox (false, 0);
+					box.add (_label);
+					box.add (_image);
+					add (box);	// FIXME
+					break;
+				}
+			}
+		}	else if (_label != null) {
+			add (_label);			// FIXME why add instead of this.child = ... ?
+		} else if (_image != null) {
+			add (_image);			// FIXME why add instead of this.child = ... ?
+		}
+	}
+}
+

Added: trunk/ribbon/button.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/button.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,313 @@
+using GLib;
+using Cairo;
+using Gtk;
+
+/** Button to be used in Ribbons. */
+public class Button : BaseButton {
+
+	private double _arrow_size;
+	private Gdk.Rectangle _arrow_allocation;
+
+	protected const double LINE_WIDTH = 1.0;
+	protected const double ARROW_PADDING = 2.0;
+	protected const double SMALL_ARROW_SIZE = 5.0;
+	protected const double BIG_ARROW_SIZE = 8.0;
+
+	/** Fired when the button is clicked. */
+	public signal void clicked ();
+
+	/** Drop down menu displayed when the arrow is pressed. */
+	private Menu _drop_down_menu;
+	public Menu drop_down_menu {
+		set {
+			_drop_down_menu = value;
+			queue_draw ();
+		}
+		get {
+			return _drop_down_menu;
+		}
+	}
+
+	/** Construction method. */
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		this.padding = 2;
+		this.image_position = PositionType.TOP;
+		_is_small = false;
+		_enabled = true;
+	}
+
+	/**
+	 * Constructor given a label to display.
+	 *
+	 * @param label  Label to display.
+	 */
+	public Button.with_label (string label) {
+		this.label = label;
+	}
+
+	/**
+	 * Constructor given an image to display.
+	 *
+	 * @param Image  Image to display
+	 */
+	public Button.with_image (Image image) {
+		this.image = image;
+	}
+
+	/**
+	 * Constructor given a label and an image to display.
+	 *
+	 * @param image  Image to display.
+	 * @param label  label to display.
+	 */
+	public Button (Image image, string label) {
+		this.image = image;
+		this.label = label;
+	}
+
+	/**
+	 * Constructs a Button from a stock.
+	 *
+	 * @param name   Name of the stock.
+	 * @param large  <b>true</b> if the image should be large,
+	 *               <b>false</b> otherwise.
+	 */
+	public static Button from_stock (string name, bool large) {
+		var img = new Image.from_stock (name, large ? IconSize.LARGE_TOOLBAR
+													: IconSize.SMALL_TOOLBAR);
+		var btn = new Button.with_image (img);
+		if (!large) {
+			btn.image_position = PositionType.LEFT;
+		}
+		return btn;
+	}
+
+	/**
+	 * Constructs a Button from a stock.
+	 *
+	 * @param name   Name of the stock.
+	 * @param label  label to display.
+	 * @param large  <b>true</b> if the image should be large,
+	 *               <b>false</b> otherwise.
+	 */
+	public static Button from_stock_with_label (string name, string label, bool large) {
+		var img = new Image.from_stock (name, large ? IconSize.LARGE_TOOLBAR
+													: IconSize.SMALL_TOOLBAR);
+		var btn = new Button (img, label);
+		if (!large) {
+			btn.image_position = PositionType.LEFT;
+		}
+		return btn;
+	}
+
+	/** Fires the clicked event. */
+	private void click () {
+		if (_enabled) {
+			clicked ();
+		}
+	}
+
+	// XXX: workaround
+	private bool has_click_listener () {
+		var signal_id = Signal.lookup ("clicked", typeof (Button));
+		return Signal.has_handler_pending (this, signal_id, 0, true);
+	}
+
+	/** Displays the drop down menu if any. */
+	public void popup () {
+		if (_enabled && _drop_down_menu != null) {
+			_drop_down_menu.popup (null, null, null, 3, Gtk.get_current_event_time ());
+			_drop_down_menu.show_all ();
+		}
+	}
+
+	protected override bool bound_widget_button_press_event (Widget sender,
+													Gdk.EventButton evnt) {
+		event ((Gdk.Event) evnt);
+		return false;
+	}
+
+	protected override bool bound_widget_button_release_event (Widget sender,
+													Gdk.EventButton evnt) {
+		event ((Gdk.Event) evnt);
+		click ();
+		return false;
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_request (requisition);
+		
+		Requisition child_requisition = Requisition ();
+		if (this.child != null && this.child.visible) {
+			 this.child.size_request (child_requisition);
+		}
+
+		if (_drop_down_menu != null) {
+			int arrow_space = (int) ((_is_small ? SMALL_ARROW_SIZE : BIG_ARROW_SIZE)
+									+ 2 * (LINE_WIDTH + ARROW_PADDING));
+
+			if (_image_position == PositionType.TOP
+						|| _image_position == PositionType.BOTTOM) {
+				child_requisition.height += arrow_space;
+			} else {
+				child_requisition.width += arrow_space;
+			}
+		}
+
+//		if (this.height_request == -1) {
+			requisition.height = child_requisition.height
+									+ (int) (LINE_WIDTH * 4 + _padding * 2);
+//		}
+//		if (this.width_request == -1) {
+			requisition.width = child_requisition.width
+									+ (int) (LINE_WIDTH * 4 + _padding * 2);
+//		}
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocate (allocation);
+		this.allocation = (Allocation) allocation;
+
+		if (_drop_down_menu != null) {
+			_arrow_size = _is_small ? SMALL_ARROW_SIZE : BIG_ARROW_SIZE;
+
+			if (_image_position == PositionType.TOP
+						|| _image_position == PositionType.BOTTOM) {
+				if (has_click_listener ()) {
+					_arrow_allocation.height = (int) (_arrow_size + 2 * ARROW_PADDING);
+				} else {
+					_arrow_allocation.height = (int) (allocation.height - 4 * LINE_WIDTH);
+				}
+
+				_arrow_allocation.width = (int) (allocation.width - 4 * LINE_WIDTH);
+			} else {
+				if (has_click_listener ()) {
+					_arrow_allocation.width = (int) (_arrow_size + 2 * ARROW_PADDING);
+				} else {
+					_arrow_allocation.width = (int) (allocation.width - 4 * LINE_WIDTH);
+				}
+
+				_arrow_allocation.height = (int) (allocation.height - 4 * LINE_WIDTH);
+			}
+
+			_arrow_allocation.x = (int) (Gdk.Rect.right (allocation)
+											- _arrow_allocation.width
+											- 2 * LINE_WIDTH);
+			_arrow_allocation.y = (int) (Gdk.Rect.bottom (allocation)
+											- _arrow_allocation.height
+											- 2 * LINE_WIDTH);
+		} else {
+			_arrow_size = 0;
+		}
+
+		allocation.x += (int) (LINE_WIDTH * 2 + _padding);
+		allocation.y += (int) (LINE_WIDTH * 2 + _padding);
+		allocation.height -= (int) (LINE_WIDTH * 4 + _padding * 2);
+		allocation.width -= (int) (LINE_WIDTH * 4 + _padding * 2);
+
+		if (_drop_down_menu != null) {
+			int arrow_space = (int) ((_is_small ? SMALL_ARROW_SIZE : BIG_ARROW_SIZE)
+								+ 2 * (LINE_WIDTH + ARROW_PADDING));
+
+			if (_image_position == PositionType.TOP
+						|| _image_position == PositionType.BOTTOM) {
+				allocation.height -= arrow_space;
+			} else {
+				allocation.width -= arrow_space;
+			}
+		}
+
+		if (allocation.height < 0) {
+			allocation.height = 0;
+		}
+		if (allocation.width < 0) {
+			allocation.width = 0;
+		}
+
+		if (this.child != null && this.child.visible) {
+			this.child.size_allocate (allocation);
+		}
+	}
+
+	protected override bool expose_event (Gdk.EventExpose event) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (event.area.x, event.area.y,
+						event.area.width, event.area.height);
+		cr.clip ();
+		draw (cr);
+
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return base.expose_event (event);	// FIXME: causes endless loop
+		// *** workaround ***
+		if (this.child != null) {
+			this.child.expose_event (event);
+		}
+		return false;
+		// *** workaround ***
+	}
+
+	protected void draw (Context cr) {
+		Gdk.Rectangle rect = (Gdk.Rectangle) this.allocation;
+		double round_size = _is_small ? 2.0 : 3.0;
+		bool draw_separator = (has_click_listener ()) && (_drop_down_menu != null);
+		_theme.draw_button (cr, rect, _state, round_size, LINE_WIDTH,
+					_arrow_size, ARROW_PADDING, draw_separator, this);
+	}
+
+	protected override bool button_press_event (Gdk.EventButton event) {
+//		bool ret = base.button_press_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.PRESSED;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+
+		if (_drop_down_menu != null
+				&& Gdk.Rect.contains (_arrow_allocation, (int) event.x, (int) event.y)) {
+			popup ();
+		}
+
+		return ret;
+	}
+
+	protected override bool button_release_event (Gdk.EventButton event) {
+//		bool ret = base.button_release_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.HOVER;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool enter_notify_event (Gdk.EventCrossing event) {
+//		bool ret = base.enter_notify_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.HOVER;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool leave_notify_event (Gdk.EventCrossing event) {
+//		bool ret = base.leave_notify_event (event);
+		bool ret = false;
+		_state = Theme.ButtonState.DEFAULT;
+		queue_draw ();
+		return ret;
+	}
+}
+

Added: trunk/ribbon/color-scheme.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/color-scheme.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,226 @@
+using GLib;
+
+public class ColorScheme : Object {
+
+	public Color pretty_dark { get; set; }
+	public Color dark { get; set; }
+	public Color light_dark { get; set; }
+	public Color normal { get; set; }
+	public Color light_bright { get; set; }
+	public Color bright { get; set; }
+	public Color pretty_bright { get; set; }
+
+	public ColorScheme () {
+//		this.normal = Color.from_rgb (0.957, 0.957, 0.957);
+		this.normal = Color.from_rgb (0.867, 0.867, 0.867);
+//		this.normal = Color.from_rgb (0.925, 0.914, 0.847);
+//		this.normal = Color.from_rgb (0.937, 0.922, 0.898);
+		// FIXME
+		this.pretty_dark = get_color_relative (this.normal, -0.4);
+		this.dark = get_color_relative (this.normal, -0.1);
+		this.light_dark = get_color_relative (this.normal, -0.05);
+		this.light_bright = get_color_relative (this.normal, 0.05);
+		this.bright = get_color_relative (this.normal, 0.1);
+		this.pretty_bright = get_color_relative (this.normal, 0.15);
+	}
+
+	public ColorScheme.from_color (Color normal) {
+		this.normal = normal;
+		// FIXME
+		this.pretty_dark = get_color_relative (this.normal, -0.4);
+		this.dark = get_color_relative (this.normal, -0.1);
+		this.light_dark = get_color_relative (this.normal, -0.05);
+		this.light_bright = get_color_relative (this.normal, 0.05);
+		this.bright = get_color_relative (this.normal, 0.1);
+		this.pretty_bright = get_color_relative (this.normal, 0.15);
+	}
+
+	construct {
+//		this.pretty_dark = get_color_relative (this.normal, -0.4);
+//		this.dark = get_color_relative (this.normal, -0.1);
+//		this.light_dark = get_color_relative (this.normal, -0.05);
+//		this.light_bright = get_color_relative (this.normal, 0.05);
+//		this.bright = get_color_relative (this.normal, 0.1);
+//		this.pretty_bright = get_color_relative (this.normal, 0.15);
+	}
+
+	public static Color set_alpha_channel (Color c, double alpha) {
+		return Color.from_rgba (c.r, c.g, c.b, alpha);
+	}
+
+	public static Color get_color_absolute (Color c, double luminance) {
+//		double h, s, v;
+//		rgb2hsv (c, out h, out s, out v);
+//		v = v + (1.7 * (luminance - 1));
+//		if (v < 0) {
+//			v = 0;
+//		} else if (v > 1) {
+//			v = 1;
+//		}
+//		return hsv2rgb (h, s, v);
+			
+		double h, s, l;
+		rgb2hsl (c, out h, out s, out l);
+//		double a = (h % 60) / 60;
+//		if (a > 0.5) {
+//			a -= 0.5;
+//		}
+//		l = l + (1.7 * (luminance - 1));
+		l = luminance;
+		if (l < 0) {
+			l = 0;
+		} else if (l > 1) {
+			l = 1;
+		}
+		return hsl2rgb (h, s, l);
+	}
+
+	public static Color get_color_relative (Color c, double luminance) {
+		double h, s, l;
+		rgb2hsl (c, out h, out s, out l);
+//		double a = (h % 60) / 60;
+//		if (a > 0.5) {
+//			a -= 0.5;
+//		}
+		l = l + luminance;
+		if (l < 0) {
+			l = 0;
+		} else if (l > 1) {
+			l = 1;
+		}
+		return hsl2rgb (h, s, l);
+	}
+
+	private static void rgb2hsl (Color c, out double h, out double s, out double l) {
+		double r = c.r;
+		double g = c.g;
+		double b = c.b;
+		double max = Math.fmax (r, Math.fmax (g, b));
+		double min = Math.fmin (r, Math.fmin (g, b));
+		l = 0.5 * (max + min);
+		if (max == min) {
+			h = double.NAN;
+		} else {
+			if (max == r) {
+				if (g >= b) {
+					h = (g - b) / (max - min) * 60;
+				} else {
+					h = (g - b) / (max - min) * 60 + 360;
+				}
+			} else if (max == g) {
+				h = (b - r) / (max - min) * 60 + 120;
+			} else {
+				h = (r - g) / (max - min) * 60 + 240;
+			}
+		}
+		if (0.0000001 <= l && l <= 0.5) {
+			s = (max - min) / (2 * l);
+		} else if (l > 0.5) {
+			s = (max - min) / (2 - 2 * l);
+		} else {
+			s = 0;
+		}
+	}
+
+	private static Color hsl2rgb (double h, double s, double l) {
+		double r = l;
+		double g = l;
+		double b = l;
+		double q;
+		if (l < 0.5) {
+			q = l * (1 + s);
+		} else {
+			q = l + s - l * s;
+		}
+		double p = 2 * l - q;
+		if (q > 0) {
+			double m = l + l - q;
+			h /= 60;
+			int i = (int) h % 6;
+			double vsf = q * (q - m) / q * (h - i);
+			switch (i) {
+			case 0:
+				r = q;
+				g = m + vsf;
+				b = m;
+				break;
+			case 1:
+				r = m - vsf;
+				g = q;
+				b = m;
+				break;
+			case 2:
+				r = m;
+				g = q;
+				b = m + vsf;
+				break;
+			case 3:
+				r = m;
+				g = m - vsf;
+				b = q;
+				break;
+			case 4:
+				r = m + vsf;
+				g = m;
+				b = q;
+				break;
+			case 5:
+				r = q;
+				g = m;
+				b = m - vsf;
+				break;
+			}
+		}
+		return Color.from_rgb (r, g, b);
+	}
+
+	// http://www.daniweb.com/techtalkforums/thread38302.html
+	private static void rgb2hsv (Color c, out double h, out double s, out double v) {
+		double r = c.r;
+		double g = c.g;
+		double b = c.b;
+		double max = Math.fmax (r, Math.fmax (g, b));
+		double min = Math.fmin (r, Math.fmin (g, b));
+		double delta = max - min;
+		v = max;
+		if (Math.fabs (delta) < 0.0000001) {
+			h = s = 0;
+		} else {
+			s = delta / max;
+
+			if (r == max) {
+				h = 60.0 * (g - b) / delta;
+			} else if (g == max) {
+				h = 60.0 * (2 + (b - r) / delta);
+			} else {
+				h = 60.0 * (4 + (r - g) / delta);
+			}
+
+			if (h < 0) {
+				h += 360;
+			} else if (h > 360) {
+				h -= 360;
+			}
+		}
+	}
+
+	// http://en.wikipedia.org/wiki/HSV_color_space
+	private static Color hsv2rgb (double h, double s, double v) {
+		int h_i = (int) (h / 60) % 6;
+		double f = h / 60 - h_i;
+		switch (h_i) {
+		case 0:
+			return Color.from_rgb (v, v * (1 - (1 - f) * s), v * (1 - s));
+		case 1:
+			return Color.from_rgb (v * (1 - f * s), v, v * (1 - s));
+		case 2:
+			return Color.from_rgb (v * (1 - s), v, v * (1 - (1 - f) * s));
+		case 3:
+			return Color.from_rgb (v * (1 - s), v * (1 - f * s), v);
+		case 4:
+			return Color.from_rgb (v * (1 - (1 - f) * s), v * (1 - s), v);
+		}
+		return Color.from_rgb (v, v * (1 - s), v * (1 - f * s));
+	}
+}
+

Added: trunk/ribbon/extra-event-box.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/extra-event-box.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,18 @@
+using Gtk;
+
+/** EventBox extended to transmit all events. */
+public class ExtraEventBox : EventBox {
+
+	protected override bool event (Gdk.Event event) {
+		if (event.any.window == this.window) {
+			if (event.type != Gdk.EventType.EXPOSE) {
+				if (this.child != null) {
+					this.child.event (event);
+				}
+			}
+		}
+//		return base.event (event);
+		return false;
+	}
+}
+

Added: trunk/ribbon/gallery-popup-window.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/gallery-popup-window.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,108 @@
+using GLib;
+using Gee;
+using Gtk;
+
+/** Popup gallery. */
+public class GalleryPopupWindow : Window {
+
+	private const int MAX_HEIGHT = 200;
+	private const int SCROLLBAR_SIZE = 20;
+
+	private Gee.List<Tile> _tiles;
+	private Gee.Map<Tile, Tile> _mapping;
+	private uint _rows;
+	private uint _columns;
+	private Tile _selected_tile;
+
+	private ScrolledWindow _internal_window;
+	private Table _tile_table;
+
+	/** Returns the underlying gallery. */
+	public Gallery underlying_gallery { get; construct; }
+
+	/**
+	 * Default constructor.
+	 *
+	 * @underlying_gallery  The underlying gallery.
+	 */
+	public GalleryPopupWindow (Gallery underlying_gallery) {
+		this.type = WindowType.POPUP;
+		this.underlying_gallery = underlying_gallery;
+	}
+
+	construct {
+		_tiles = new Gee.ArrayList<Tile> ();
+		_mapping = new Gee.HashMap<Tile, Tile> ();
+
+		foreach (var tile in this.underlying_gallery.tiles) {
+			var copy = tile.copy ();
+			copy.show ();
+			_tiles.add (copy);
+
+			if (tile == this.underlying_gallery.selected_tile) {
+				copy.selected = true;
+				_selected_tile = tile;
+			}
+
+			_mapping.set (copy, tile);
+		}
+
+		int width = this.underlying_gallery.allocation.width;
+
+		_columns = (uint) (width / this.underlying_gallery.tile_width);
+		_rows = (uint) Math.ceil ((double) _tiles.size / _columns);
+
+		_tile_table = new Table (_rows, _columns, true);
+		_tile_table.show ();
+		_tile_table.height_request = (int) _rows * this.underlying_gallery.tile_height;
+		_tile_table.width_request = (int) _columns * this.underlying_gallery.tile_width;
+
+		var vp = new Viewport (null, null);
+		vp.show ();
+		vp.add (_tile_table);			// FIXME: add?
+
+		_internal_window = new ScrolledWindow (null, null);
+		_internal_window.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
+		_internal_window.show ();
+		_internal_window.add (vp);
+		_internal_window.height_request = int.min (_tile_table.height_request, MAX_HEIGHT) + SCROLLBAR_SIZE;
+		_internal_window.width_request = _tile_table.width_request + SCROLLBAR_SIZE;
+
+		uint x = 0;
+		uint y = 0;
+		foreach (var tile in _tiles) {
+			var box = new ExtraEventBox ();
+			box.show ();
+			box.add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+							| Gdk.EventMask.BUTTON_RELEASE_MASK
+							| Gdk.EventMask.POINTER_MOTION_MASK);
+			box.add (tile);
+
+			_tile_table.attach_defaults (box, x, x + 1, y, y + 1);
+			tile.clicked += tile_clicked;
+
+			if (++x == _columns) {
+				x = 0;
+				++y;
+			}
+		}
+
+		add (_internal_window);
+		this.child.button_press_event += ()	=> {
+			return true;
+		};
+	}
+
+	private void tile_clicked (Tile sender) {
+		if (_selected_tile != null) {
+			_selected_tile.selected = false;
+		}
+		_selected_tile = sender;
+		_selected_tile.selected = true;
+		
+		this.underlying_gallery.selected_tile = _mapping.get (_selected_tile);
+		
+		hide ();
+	}
+}
+

Added: trunk/ribbon/gallery.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/gallery.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,488 @@
+using GLib;
+using Gee;
+using Gtk;
+using Gdk;
+using Cairo;
+
+/** Gallery of tiles. */
+public class Gallery : Container {
+
+	private Button _up;
+	private Button _down;
+	private ToggleButton _expand;
+	private GalleryPopupWindow _popup;
+
+	private int _first_displayed_tile_index;
+	private int _last_displayed_tile_index;
+	private int _button_width;
+
+	private Requisition _up_req;
+	private Requisition _down_req;
+	private Requisition _expand_req;
+
+	private Gdk.Rectangle _tiles_alloc;
+
+	private const double SPACE = 2.0;
+	private const double LINE_WIDTH = 1.0;
+
+	/** Fired when a Tile has been selected. */
+	public signal void tile_selected (Gallery sender, Tile selected_tile);
+
+	/** Gets or sets the width of tiles. */
+	private int _tile_width;
+	public int tile_width {
+		set {
+			_tile_width = value;
+			queue_draw ();
+		}
+		get { return _tile_width; }	
+	}
+
+	/** Gets or sets the height of tiles. */
+	private int _tile_height;
+	public int tile_height {
+		set {
+			_tile_height = value;
+			queue_draw ();
+		}
+		get { return _tile_height; }
+	}
+
+	/** Gets or sets the spacing between tiles. */
+	private int _tile_spacing;
+	public int tile_spacing {
+		set {
+			_tile_spacing = value;
+			queue_draw ();
+		}
+		get { return _tile_spacing; }
+	}
+
+	/** Gets or sets the default number of tiles per row. */
+	private int _default_tiles_per_row;
+	public int default_tiles_per_row {
+		set {
+			_default_tiles_per_row = value;
+			queue_draw ();
+		}
+		get { return _default_tiles_per_row; }
+	}
+
+	/** Gets or sets the selected Tile. */
+	private Tile _selected_tile;
+	public Tile selected_tile {
+		set {
+			if (_popup != null) {
+				Gtk.grab_remove (_popup);
+				Gdk.pointer_ungrab (0);
+				Gdk.keyboard_ungrab (0);
+
+				_popup.hide ();
+//				_popup.destroy ();
+				_popup = null;
+			}
+
+			if (_selected_tile != null) {
+				_selected_tile.selected = false;
+			}
+			_selected_tile = value;
+			if (_selected_tile != null) {
+				_selected_tile.selected = true;
+
+				int idx = _tiles.index_of (_selected_tile);
+				if (idx != -1) {
+					_first_displayed_tile_index = idx / _default_tiles_per_row
+													 * _default_tiles_per_row;
+					_last_displayed_tile_index = -1;
+					update_tiles_layout ();
+					queue_draw ();
+				}
+			}
+		}
+		get { return _selected_tile; }
+	}
+
+	/** Returns all tiles. */
+	private Gee.List<Tile> _tiles;
+	public Gee.List<Tile> tiles {
+		get {
+			return _tiles;
+		}
+	}
+
+	/** Theme used to draw the widget. */
+	private Theme _theme = new Theme ();
+	public Theme theme {
+		set {
+			_theme = value;
+			queue_draw ();
+		}
+		get { return _theme; }
+	}
+
+	/** Construction method */
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+				| Gdk.EventMask.BUTTON_RELEASE_MASK
+				| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		_tiles = new Gee.ArrayList<Tile> ();
+
+		_default_tiles_per_row = 3;
+		_first_displayed_tile_index = 0;
+		_last_displayed_tile_index = -1;
+
+		_tile_height = 56;
+		_tile_width = 72;
+		_tile_spacing = 0;
+		this.border_width = 2;
+
+		_up = new Button.with_label ("\u25B2");
+		_up.set_parent (this);
+		_up.padding = 0;
+		_up.clicked += up_clicked;
+
+		_down = new Button.with_label ("\u25BC");
+		_down.set_parent (this);
+		_down.padding = 0;
+		_down.clicked += down_clicked;
+		
+		_expand = new ToggleButton.with_label ("\u2193");
+		_expand.set_parent (this);
+		_expand.padding = 0;
+		_expand.value_changed += expand_value_changed;
+	}
+
+	/**
+	 * Adds a tile before all existing _tiles.
+	 *
+	 * @param tile  The tile to add.
+	 */
+	public void prepend_tile (Tile tile) {
+		insert_tile (tile, 0);
+	}
+
+	/**
+	 * Adds a tile after all existing _tiles.
+	 *
+	 * @param tile  The tile to add.
+	 */
+	public void append_tile (Tile tile) {
+		insert_tile (tile, -1);
+	}
+
+	/**
+	 * Inserts a tile at the specified location.
+	 *
+	 * @param tile   The tile to add.
+	 * @param index  The index (starting at 0) at which the tile must be
+	 *               inserted, or -1 to insert the tile after all existing
+	 *               tiles.
+	 */
+	public void insert_tile (Tile tile, int index) {
+		if (index == -1 || index == _tiles.size) {
+			_tiles.add (tile);
+		} else {
+			_tiles.insert (index, tile);
+		}
+
+		if (_tiles.size == 1) {
+			this.selected_tile = tile;
+		}
+
+		// t.set_parent (this);
+		tile.visible = true;
+		tile.clicked += tile_clicked;
+	}
+
+	/**
+	 * Removes the tile at the specified index.
+	 *
+	 * @param index  Index of the tile to remove.
+	 */
+	public void remove_tile (int index) {
+		var tile = _tiles.get (index);
+		tile.clicked -= tile_clicked;
+		tile.unparent ();
+		if (_selected_tile == tile) {
+			_selected_tile = null;
+		}
+
+		_tiles.remove_at (index);
+	}
+
+	private void up_clicked () {
+		move_up ();
+	}
+	
+	private void down_clicked () {
+		move_down ();
+	}
+
+	private void expand_value_changed () {
+		if (_expand.value) {
+			_popup = new GalleryPopupWindow (this);
+			_popup.realize += () => {
+				int x, y;
+				get_parent_window ().get_origin (out x, out y);
+				x += this.allocation.x;
+				y += this.allocation.y;
+				_popup.window.move (x, y);
+			};
+
+			_popup.hide += () => {
+				_expand.value_changed -= expand_value_changed;
+				_expand.value = false;
+				_expand.queue_draw ();
+				_expand.value_changed += expand_value_changed;
+			};
+			_popup.show ();
+
+			_popup.button_release_event += on_button_released;
+			_popup.add_events (Gdk.EventMask.BUTTON_PRESS_MASK);
+			Gtk.grab_add (_popup);
+
+			Gdk.GrabStatus grabbed = Gdk.pointer_grab (_popup.window, true,
+							Gdk.EventMask.BUTTON_RELEASE_MASK, null, null, 0);
+			if (grabbed == Gdk.GrabStatus.SUCCESS) {
+				grabbed = Gdk.keyboard_grab (_popup.window, true, 0);
+
+				if (grabbed != Gdk.GrabStatus.SUCCESS) {
+					Gtk.grab_remove (_popup);
+					_popup.hide ();
+//					_popup.destroy();
+					_popup = null;
+					return;
+				}
+			} else {
+				Gtk.grab_remove (_popup);
+				_popup.hide ();
+//				_popup.destroy ();
+				_popup = null;
+			}
+		} else {
+			if (_popup != null) {
+				Gtk.grab_remove (_popup);
+				_popup.hide ();
+//				_popup.destroy ();
+				_popup = null;
+			}
+		}
+	}
+
+	private void tile_clicked (Tile sender) {
+		if (_selected_tile != null) {
+			_selected_tile.selected = false;
+		}
+		_selected_tile = sender;
+		_selected_tile.selected = true;
+		on_tile_selected (_selected_tile);
+	}
+
+	private void move_up () {
+		if (_first_displayed_tile_index > 0) {
+			_first_displayed_tile_index = -1;
+			_last_displayed_tile_index = _first_displayed_tile_index - 1;
+		}
+		update_tiles_layout ();
+		queue_draw ();
+	}
+
+	private void move_down () {
+		if (_last_displayed_tile_index < _tiles.size - 1) {
+			_first_displayed_tile_index = _last_displayed_tile_index + 1;
+			_last_displayed_tile_index = -1;
+		}
+		update_tiles_layout ();
+		queue_draw ();
+	}
+
+	/**
+	 * Fires the selected_tile event.
+	 *
+	 * @param selected_tile  The Tile that has been selected.
+	 */
+	protected void on_tile_selected (Tile selected_tile) {
+		tile_selected (this, selected_tile);
+	}
+
+	private bool on_button_released (GalleryPopupWindow sender, EventButton event) {
+		if (_popup != null) {
+			Gtk.grab_remove (_popup);
+			Gdk.pointer_ungrab (0);
+			Gdk.keyboard_ungrab (0);
+
+			_popup.hide ();
+			_popup.destroy ();
+			_popup = null;
+		}
+		return false;
+	}
+
+	private void update_tiles_layout () {
+		Gdk.Rectangle tile_alloc;
+		tile_alloc.x = _tiles_alloc.x;
+		tile_alloc.y = _tiles_alloc.y;
+		tile_alloc.height = _tiles_alloc.height;
+		tile_alloc.width = _tile_width;
+
+		int max_tiles = (_tiles_alloc.width + _tile_spacing)
+										/ (_tile_width + _tile_spacing);
+
+		if (_first_displayed_tile_index == -1) {
+			_first_displayed_tile_index = _last_displayed_tile_index - max_tiles + 1;
+			if (_first_displayed_tile_index < 0) {
+				_last_displayed_tile_index -= _first_displayed_tile_index;
+				_first_displayed_tile_index = 0;
+			}
+		} else if (_last_displayed_tile_index == -1) {
+			_last_displayed_tile_index = _first_displayed_tile_index + max_tiles - 1;
+		}
+
+		if (_last_displayed_tile_index >= _tiles.size) {
+			_last_displayed_tile_index = _tiles.size - 1;
+		}
+
+		_up.enabled = _first_displayed_tile_index > 0;
+		_down.enabled = _last_displayed_tile_index < _tiles.size - 1;
+
+		for (int i = 0; i < _first_displayed_tile_index; i++) {
+			if (_tiles.get (i).parent != null) {
+				_tiles.get (i).unparent ();
+			}
+		}
+		for (int i = _last_displayed_tile_index + 1; i < _tiles.size; i++) {
+			if (_tiles.get (i).parent != null) {
+				_tiles.get (i).unparent ();
+			}
+		}
+
+		for (int i = _first_displayed_tile_index; i <= _last_displayed_tile_index; i++) {
+			Tile t = _tiles.get (i);
+			
+			if (t.parent == null) {
+				t.set_parent (this);
+			}
+
+			Requisition req;
+			t.size_request (req);
+
+			t.size_allocate (tile_alloc);
+			tile_alloc.x += tile_alloc.width + _tile_spacing;
+		}
+	}
+
+	protected override void forall (bool include_internals,	Gtk.Callback callback) {
+//		if (include_internals) {
+			callback (_up);
+			callback (_down);
+			callback (_expand);
+//		}
+
+		for (int i = _first_displayed_tile_index; i <= _last_displayed_tile_index; i++) {
+			callback (_tiles.get (i));
+		}
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_requested (requisition);
+
+		_up.size_request (_up_req);
+		_down.size_request (_down_req);
+		_expand.size_request (_expand_req);
+
+		_button_width = int.max (_up_req.width,
+							int.max (_down_req.width, _expand_req.width));
+		int btn_height = _up_req.height + _down_req.height + _expand_req.height;
+
+		int count = int.min (_tiles.size, _default_tiles_per_row);
+		requisition.width = _button_width + (int) SPACE
+							+ 2 * (int) LINE_WIDTH
+							+ count * _tile_width
+							+ (count + 1) * _tile_spacing
+							+ 2 * (int) this.border_width;
+		requisition.height = int.max (_tile_height + 2 * (_tile_spacing + (int) LINE_WIDTH),
+										btn_height) + 2 * (int) this.border_width;
+
+		if (this.width_request != -1) {
+			requisition.width = this.width_request;
+		}
+		if (this.height_request != -1) {
+			requisition.height = this.height_request;
+		}
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocate (allocation);
+		this.allocation = (Allocation) allocation;
+
+		allocation.x += (int) this.border_width;
+		allocation.y += (int) this.border_width;
+		allocation.width -= 2 * (int) this.border_width;
+		allocation.height -= 2 * (int) this.border_width;
+
+		Gdk.Rectangle btn_alloc;
+		btn_alloc.width = _button_width;
+		btn_alloc.x = allocation.x + allocation.width - btn_alloc.width + 1;
+
+		btn_alloc.y = allocation.y;
+		btn_alloc.height = _up_req.height;
+		_up.size_allocate (btn_alloc);
+
+		btn_alloc.y += btn_alloc.height;
+		btn_alloc.height = _down_req.height;
+		_down.size_allocate (btn_alloc);
+
+		btn_alloc.y += btn_alloc.height;
+		btn_alloc.height = _expand_req.height;
+		_expand.size_allocate (btn_alloc);
+
+		_tiles_alloc.x = allocation.x + (int) LINE_WIDTH + _tile_spacing;
+		_tiles_alloc.y = allocation.y + (int) LINE_WIDTH + _tile_spacing;
+		_tiles_alloc.width = btn_alloc.x - _tiles_alloc.x - _tile_spacing
+										- (int) SPACE - 2 * (int) LINE_WIDTH;
+		_tiles_alloc.height = allocation.height - 2 * (_tile_spacing + (int) LINE_WIDTH); 
+
+		update_tiles_layout ();
+	}
+
+	protected override bool expose_event (Gdk.EventExpose evnt) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (evnt.area.x, evnt.area.y,
+						evnt.area.width, evnt.area.height);
+		cr.clip ();
+		draw (cr);
+
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return base.expose_event (evnt);
+		// *** workaround ***
+		((Widget) _up).expose_event (evnt);
+		((Widget) _down).expose_event (evnt);
+		((Widget) _expand).expose_event (evnt);
+		for (int i = _first_displayed_tile_index; i <= _last_displayed_tile_index; i++) {
+			((Widget) _tiles.get (i)).expose_event (evnt);
+		}
+		return false;
+		// *** workaround ***
+	}
+
+	protected void draw (Context cr) {
+		Rectangle alloc;
+		alloc.x = this.allocation.x;
+		alloc.y = this.allocation.y;
+		alloc.width = this.allocation.width;
+		alloc.height = this.allocation.height;
+		Rectangle tiles;
+		tiles.x = _tiles_alloc.x - _tile_spacing;
+		tiles.y = _tiles_alloc.y - _tile_spacing;
+		tiles.width = _tiles_alloc.width + 2 * _tile_spacing;
+		tiles.height = _tiles_alloc.height + 2 * _tile_spacing;
+		_theme.draw_gallery (cr, alloc, tiles, this);
+	}
+}
+

Added: trunk/ribbon/group-style.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/group-style.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,10 @@
+/**
+ * Position of a widget in a group of widget.
+ */
+public enum GroupStyle {
+	ALONE,
+	LEFT,
+	CENTER,
+	RIGHT
+}
+

Added: trunk/ribbon/helpers.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/helpers.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,109 @@
+namespace Gee {
+
+	public void list_remove_range (List list, int index, int count) {
+		for (int i = 0; i < count; i++) {
+			list.remove_at (index);
+		}
+	}
+}
+
+namespace Cairo {
+
+	public static void set_color (Context cr, Color c) {
+		cr.set_source_rgba (c.r, c.g, c.b, c.a);
+	}
+
+	public static void add_stop (Pattern p, double offset, Color c) {
+		p.add_color_stop_rgba (offset, c.r, c.g, c.b, c.a);
+	}
+}
+
+namespace Gdk.Rect {
+
+	public static int right (Gdk.Rectangle rect) {
+		return rect.x + rect.width;
+	}
+
+	public static int bottom (Gdk.Rectangle rect) {
+		return rect.y + rect.height;
+	}
+
+	public static int top (Gdk.Rectangle rect) {
+		return rect.y;
+	}
+
+	public static int left (Gdk.Rectangle rect) {
+		return rect.x;
+	}
+
+	public static bool contains (Gdk.Rectangle rect, int x, int y) {
+		return ((x >= left (rect)) && (x <= right (rect)) && 
+				(y >= top (rect)) && (y <= bottom (rect)));
+	}
+
+	public static void inflate (Rectangle rect, int width, int height) {
+		rect.x -= width;
+		rect.y -= height;
+		rect.width += width * 2;
+		rect.height += height * 2;
+	}
+}
+
+namespace Gdk {
+
+	public Gdk.Color new_color (uint8 r, uint8 g, uint8 b) {
+		Gdk.Color color;
+		color.red = (ushort) (r << 8 | r);
+		color.green = (ushort) (g << 8 | g);
+		color.blue = (ushort) (b << 8 | b);
+		color.pixel = 0;	
+		return color;
+	}
+
+	public struct Size { 
+		public int width;
+		public int height;
+
+		public Size (int width, int height) {
+			this.width = width;
+			this.height = height;
+		}
+	}
+}
+
+namespace Gtk {
+
+	public static ComboBox combo_box_from_entries (string[] entries) {
+		var combo = new ComboBox.with_model (new ListStore (1, typeof (string)));
+		var cell = new CellRendererText ();
+		combo.pack_start (cell, true);
+		combo.set_attributes (cell, "text", 0);
+		foreach (var entry in entries) {
+			combo.append_text (entry);
+		}
+		return combo;
+	}
+}
+
+public struct Color {
+
+	public double r;
+	public double g;
+	public double b;
+	public double a;
+
+	public Color.from_rgb (double r, double g, double b) {
+		this.r = r;
+		this.g = g;
+		this.b = b;
+		this.a = 1.0;
+	}
+
+	public Color.from_rgba (double r, double g, double b, double a) {
+		this.r = r;
+		this.g = g;
+		this.b = b;
+		this.a = a;
+	}
+}
+

Added: trunk/ribbon/quick-access-toolbar.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/quick-access-toolbar.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,127 @@
+using GLib;
+using Gtk;
+using Gee;
+
+public class QuickAccessToolbar : Container {
+
+	private Gee.List<Widget> _widgets;
+	private int[] _widths;
+
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		_widgets = new Gee.ArrayList<Widget> ();
+	}
+
+	/**
+	 * Adds a widget before all existing widgets.
+	 *
+	 * @param widget    The widget to add.
+	 */
+	public void prepend (Widget widget) {
+		insert (widget, 0);
+	}
+
+	/**
+	 * Adds a widget after all existing widgets.
+	 *
+	 * @param widget    The widget to add.
+	 */
+	public void append (Widget widget) {
+		insert (widget, -1);
+	}
+
+	/**
+	 * Inserts a widget at the specified location.</summary>
+	 *
+	 * @param widget   The widget to add.
+	 * @param index    The index (starting at 0) at which the widget must
+	 *                 be inserted, or -1 to insert the widget after all
+	 *                 existing widgets.
+	 */
+	public void insert (Widget widget, int index) {
+		widget.set_parent (this);
+		widget.visible = true;
+
+		if (index == -1) {
+			_widgets.add (widget);
+		} else {
+			_widgets.insert (index, widget);
+		}
+
+		show_all ();
+	}
+
+	/**
+	 * Removes the widget at the specified index.
+	 *
+	 * @param index   Index of the widget to remove.
+	 */
+	public void remove (int index) {
+		if (index == -1) {
+			index = _widgets.size -1;
+		}
+
+		_widgets.get (index).parent = null;
+		_widgets.remove_at (index);
+
+		show_all ();
+	}
+
+	protected override void forall (bool include_internals, Gtk.Callback callback) {
+		foreach (var widget in _widgets) {
+			if (widget.visible) {
+				callback (widget);
+			}
+		}
+	}
+
+	protected override void size_request (Requisition requisition) {
+		base.size_request (requisition);
+
+		if (_widths == null || _widths.length != _widgets.size) {
+			_widths = new int[_widgets.size];
+		}
+
+		requisition.height = 16;
+		requisition.width = 0;
+
+		int i = 0;
+		foreach (var button in _widgets) {
+			button.height_request = requisition.height;
+			Requisition req;
+			button.size_request (req);
+			requisition.width += req.width;
+			_widths[i++] = req.width;
+		}
+		if (this.height_request != -1) {
+			requisition.height = this.height_request;
+		}
+		if (this.width_request != -1) {
+			requisition.width = this.width_request;
+		}
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocate (allocation);
+		this.allocation = (Allocation) allocation;	// XXX workaround
+
+		int i = 0;
+		int x = allocation.x;
+		foreach (var button in _widgets) {
+			Gdk.Rectangle r;
+			r.x = x;
+			r.y = allocation.y;
+			r.width = _widths[i];
+			r.height = allocation.height;
+			button.size_allocate (r);
+			x += r.width;
+			i++;
+		}
+	}
+}
+

Added: trunk/ribbon/ribbon-group.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/ribbon-group.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,282 @@
+using GLib;
+using Cairo;
+using Gtk;
+using Gdk;
+
+/** Ribbon group. */
+public class RibbonGroup : Bin {
+
+	private Pango.Layout _label_layout;
+	private Button _expand_button;
+
+	private double _bar_height;
+	private double _bar_width;
+
+	private const double CHILD_PADDING = 1.0;
+	private const double LINE_WIDTH = 1.0;
+	private const double SPACE = 2.0;
+
+	/** Fired whenever the expand button is clicked. */
+	public signal void expanded (RibbonGroup sender);
+
+	// XXX: is it possible to do something when someone connects/disconnects the signal?
+//	{
+//		add {
+//			_expand_button.visible = has_expand_listener ();
+//		}
+//		remove {
+//			_expand_button.visible = has_expand_listener ();
+//		}
+//	}
+
+	/** Displayed label. */
+	private string _label;
+	public string label {
+		set	{
+			_label = value;
+
+			if (_label == null) {
+				_label_layout = null;
+			} else if (_label_layout == null) {
+				_label_layout = create_pango_layout (_label);
+			} else {
+				// XXX: size () really needed?
+				_label_layout.set_text (_label, (int) _label.size ());
+			}
+			queue_draw ();
+		}
+		get { return _label; }
+	}
+
+	/** Theme used to draw the widget. */
+	private Theme _theme = new Theme ();
+	public Theme theme {
+		set {
+			_theme = value;
+			queue_draw ();
+		}
+		get { return _theme; }
+	}
+
+	/** Position of the label. */
+	private PositionType _label_position = PositionType.BOTTOM;
+	public PositionType label_position {
+		set {
+			_label_position = value;
+			queue_draw ();
+		}
+		get { return _label_position; }
+	}
+
+	/** Construction method. */
+	construct {
+		// This is a NO_WINDOW widget => it does not have its own Gdk Window
+		// => it can be transparent
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+				| Gdk.EventMask.BUTTON_RELEASE_MASK
+				| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		this.label = null;
+		this.height_request = 92;
+
+		_expand_button = new Button.with_label ("\u21F2");
+		_expand_button.padding = 0;
+		_expand_button.visible = false;
+		_expand_button.set_parent (this);
+		_expand_button.clicked += () => {
+			expanded (this);
+		};
+	}
+
+	// XXX: workaround
+	private bool has_expand_listener () {
+		var signal_id = Signal.lookup ("expanded", typeof (RibbonGroup));
+		return Signal.has_handler_pending (this, signal_id, 0, true);
+	}
+
+	protected override void forall (bool include_internals, Gtk.Callback callback) {
+		base.forall (include_internals, callback);
+		if (_expand_button != null && _expand_button.visible) {
+			callback (_expand_button);
+		}
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_request (requisition);
+
+		int lw, lh;
+
+		if (_label_position == PositionType.TOP
+				|| _label_position == PositionType.BOTTOM) {
+			_label_layout.get_pixel_size (out lw, out lh);
+		} else {
+			_label_layout.get_pixel_size (out lh, out lw);
+		}
+
+		double frame_size = 2 * LINE_WIDTH + CHILD_PADDING;
+
+		_bar_height = lh + 2 * SPACE;
+		_bar_width = lw + 2 * SPACE;
+			
+		if (_expand_button != null && _expand_button.visible) {
+			if (_label_position == PositionType.TOP
+					|| _label_position == PositionType.BOTTOM) {
+				_expand_button.set_size_request (lh, lh);
+			} else {
+				_expand_button.set_size_request (lw, lw);
+			}
+
+			Requisition req;		// FIXME
+			_expand_button.size_request (req);
+
+			if (_label_position == PositionType.TOP
+					|| _label_position == PositionType.BOTTOM) {
+				_bar_width += _expand_button.width_request + (int) SPACE;
+			} else {
+				_bar_height += _expand_button.height_request + (int) SPACE;
+			}
+		}
+
+		Requisition child_requisition = Requisition ();
+
+		if (this.child != null && this.child.visible) {
+			if (this.height_request != -1) {
+				int left = this.height_request;
+				if (_label_position == PositionType.TOP
+						|| _label_position == PositionType.BOTTOM) {
+					left -= (int) (2 * frame_size + _bar_height);
+				} else {
+					left -= (int) (2 * frame_size);
+				}
+
+				this.child.height_request = left;
+			}
+			if (this.width_request != -1) {
+				int left = this.width_request;
+				if (_label_position == PositionType.TOP
+						|| _label_position == PositionType.BOTTOM) {
+					left -= (int) (2 * frame_size);
+				} else {
+					left -= (int) (2 * frame_size + _bar_width);
+				}
+				this.child.width_request = left;
+			}
+			this.child.size_request (child_requisition);
+		}
+
+		if (this.width_request == -1) {
+			if (this.child != null && this.child.visible) {
+				requisition.width = child_requisition.width + (int) (2 * frame_size);
+
+				if (_label_position == PositionType.LEFT
+						|| _label_position == PositionType.RIGHT) {
+					requisition.width += (int) _bar_width;
+				}
+			} else {
+				requisition.width = (int) (2 * frame_size + _bar_width);
+			}
+		}
+
+		if (this.height_request == -1) {
+			if (this.child != null && this.child.visible) {
+				requisition.height = child_requisition.height + (int) (2 * frame_size);
+
+				if (_label_position == PositionType.TOP
+						|| _label_position == PositionType.BOTTOM) {
+					requisition.height += (int) _bar_height;
+				}
+			} else {
+				requisition.height = (int) (2 * frame_size + _bar_height);
+			}
+		}
+	}
+
+	protected override void size_allocate (Rectangle allocation) {
+//		base.size_allocate (allocation);
+		this.allocation = (Allocation) allocation;	// workaround
+
+		if (_expand_button != null && _expand_button.visible) {
+			double frame_size = 2 * LINE_WIDTH + SPACE;
+			Rectangle r;
+			r.height = _expand_button.height_request;
+			r.width = _expand_button.width_request;
+
+			if (_label_position == PositionType.LEFT) {
+				r.x = allocation.x + (int) frame_size;
+			} else {
+				r.x = allocation.x + allocation.width - r.width - (int) frame_size;
+			}
+
+			if (_label_position == PositionType.TOP) {
+				r.y = allocation.y + (int) frame_size;
+			} else {
+				r.y = allocation.y + allocation.height - r.height - (int) frame_size;
+			}
+
+			_expand_button.size_allocate (r);
+		}
+
+		if (this.child != null && this.child.visible) {
+			double frame_size = 2 * LINE_WIDTH + CHILD_PADDING;
+			int wi = allocation.width - (int) (2 * frame_size);
+			int he = allocation.height - (int) (2 * frame_size);
+
+			Rectangle r;
+			r.x = allocation.x + (int) frame_size;
+			r.y = allocation.y + (int) frame_size;
+			r.width = wi;
+			r.height = he;
+
+			if (_label_position == PositionType.TOP) {
+				r.y += (int) _bar_height;
+			} else if (_label_position == PositionType.LEFT) {
+				r.x += (int) _bar_width;
+			}
+
+			if (_label_position == PositionType.TOP
+					|| _label_position == PositionType.BOTTOM) {
+				r.height -= (int) _bar_height;
+			} else {
+				r.width -= (int) _bar_width;
+			}
+
+			this.child.size_allocate (r);
+		}
+	}
+
+	private void draw (Context cr) {
+		Rectangle rect;
+		rect.x = this.allocation.x;
+		rect.y = this.allocation.y;
+		rect.width = this.allocation.width;
+		rect.height = this.allocation.height;
+		_theme.draw_group (cr, rect, 4.0, LINE_WIDTH, SPACE, _label_layout,
+							_expand_button, this);
+	}
+
+	protected override bool expose_event (EventExpose event) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (event.area.x, event.area.y,
+						event.area.width, event.area.height);
+		cr.clip ();
+		draw (cr);
+
+		// FIXME: is this necessary?
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return base.expose_event (event);
+		// *** workaround ***
+		if (_expand_button != null && _expand_button.visible) {
+			// FIXME: why is this cast necessary?
+			((Widget) _expand_button).expose_event (event);
+		}
+		this.child.expose_event (event);
+		return false;
+		// *** workaround ***
+	}
+}
+

Added: trunk/ribbon/ribbon.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/ribbon.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,603 @@
+using GLib;
+using Cairo;
+using Gtk;
+using Gdk;
+using Gee;
+
+/** Ribbon widget. */
+public class Ribbon : Container {
+
+	private const double BORDER_WIDTH = 2.0;
+	private const double SPACE = 2.0;
+	private const double PAGE_PADDING = 3.0;
+	private const double TAB_PADDING = 4.0;
+	private const double TABS_MIN_HPOS = 8.0;
+	private const double LINE_WIDTH = 1.0;
+	private const double ROUND_SIZE = 4.0;
+
+	private ColorScheme _color_scheme = new ColorScheme ();
+
+	private Gee.List<RibbonPage> _pages;
+
+	private Rectangle _body_allocation;
+	private Rectangle _page_allocation;
+	private Requisition _app_button_requisition;
+	private Requisition _toolbar_requisition;
+	private Requisition _shortcuts_requisition;
+	private Requisition _page_requisition;
+
+	private double _header_height;
+
+	public signal void page_selected (RibbonPage page);
+	public signal void page_added (RibbonPage page);
+	public signal void page_moved (RibbonPage page);
+	public signal void page_removed (RibbonPage page);
+
+	private ApplicationButton _app_button;
+	public ApplicationButton application_button {
+		set {
+			if (_app_button != null) {
+				_app_button.unparent ();
+			}
+			_app_button = value;
+			if (_app_button != null) {
+				_app_button.visible = true;
+				_app_button.set_parent (this);
+			}
+			show_all ();
+		}
+		get {
+			return _app_button;
+		}
+	}
+
+	private QuickAccessToolbar _toolbar;
+	public QuickAccessToolbar quick_access_toolbar {
+		set {
+			if (_toolbar != null) {
+				_toolbar.unparent ();
+			}
+			_toolbar = value;
+			if (_toolbar != null) {
+				_toolbar.visible = true;
+				_toolbar.set_parent (this);
+			}
+			show_all ();
+		}
+		get {
+			return _toolbar;
+		}
+	}
+
+	/**
+	 * Index of the currently selected page.
+	 *
+	 * Returns -1 if no page is selected.
+	 */
+	private int _current_page_index;
+	public int current_page_index {
+		set {
+			if (_current_page_index != -1) {
+				this.current_page.label.modify_fg (StateType.NORMAL,
+						_theme.get_forecolor_for_ribbon_tabs (false));
+				this.current_page.page.unparent ();
+			}
+			_current_page_index = value;
+			if (_current_page_index != -1) {
+				this.current_page.label.modify_fg (StateType.NORMAL,
+						_theme.get_forecolor_for_ribbon_tabs (true));
+				this.current_page.page.set_parent (this);
+			}
+
+			show_all ();
+			queue_draw ();
+		}
+		get {
+			return _current_page_index;
+		}
+	}
+
+	/** Currently selected page. */
+	public RibbonPage?# current_page {		// FIXME: is this right?
+		get {
+			if (_current_page_index == -1) {
+				return null;
+			}
+			return _pages.get (_current_page_index);
+		}
+	}
+
+	/** Number of pages. */
+	public int n_pages {
+		get {
+			return (int) _pages.size;
+		}
+	}
+
+	/**
+	 * Shortcuts widget.
+	 *
+	 * The shortcuts widget is displayed next to the tabs.
+	 */
+	private Widget _shortcuts;
+	public Widget shortcuts {
+		set {
+			if (_shortcuts != null) {
+				_shortcuts.unparent ();
+			}
+			_shortcuts = value;
+			if (_shortcuts != null) {
+				_shortcuts.visible = true;
+				_shortcuts.set_parent (this);
+			}
+			queue_draw ();
+		}
+		get { return _shortcuts; }
+	}
+
+	/** Theme used to draw the widget. */
+	private Theme _theme = new Theme ();
+	public Theme theme {
+		set {
+			_theme = value;
+			queue_draw ();
+		}
+		get { return _theme; }
+	}
+
+	/** Construction method. */
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (EventMask.BUTTON_PRESS_MASK
+				| EventMask.BUTTON_RELEASE_MASK
+				| EventMask.POINTER_MOTION_MASK);
+
+		_pages = new ArrayList<RibbonPage> ();
+		_current_page_index = -1;
+	}
+
+	/**
+	 * Adds a new page after all existing pages.
+	 *
+	 * @param child   The widget to use as the content of the page.
+	 * @param label   The widget to use as the tab.
+	 */
+	public void append_page (Widget child, Widget label) {
+		insert_page (child, label, -1);
+	}
+
+	/**
+	 * Adds a new page before all existing pages.
+	 *
+	 * @param child   The widget to use as the content of the page.
+	 * @param label   The widget to use as the tab.
+	 */
+	public void prepend_page (Widget child, Widget label) {
+		insert_page (child, label, 0);
+	}
+
+	/**
+	 * Adds a new page at the specified position.
+	 *
+	 * @param child     The widget to use as the content of the page.
+	 * @param label     The widget to use as the tab.
+	 * @param position  The index (starting at 0) at which the page must be
+	 *                  inserted, or -1 to insert the page after all
+	 *                  existing pages.
+	 */
+	public void insert_page (Widget child, Widget label, int position) {
+		var new_page = new RibbonPage (this, child, label);
+
+		if (position == -1) {
+			_pages.add (new_page);
+		} else {
+			_pages.insert (position, new_page);
+				
+			if (_current_page_index != -1) {
+				if (position <= _current_page_index) {
+					_current_page_index++;
+				}
+			}
+		}
+
+		if (_pages.size == 1) {
+			this.current_page_index = 0;
+		} else {
+			label.modify_fg (StateType.NORMAL,
+								_theme.get_forecolor_for_ribbon_tabs (false));
+		}
+
+		label.button_press_event += (sender, event) => {
+			// FIXME: Vala doesn't support real closures yet
+//			select_ribbon_page (new_page);
+		};
+
+		label.enter_notify_event += (sender, event) => {
+			
+		};
+
+		label.leave_notify_event += (sender, event) => {
+			
+		};
+
+		page_added (new_page);
+		for (int i = position + 1; i < _pages.size; i++) {
+			page_selected (_pages.get (i));
+		}
+	}
+
+	/**
+	 * Removes the specified page.
+	 *
+	 * @param page_number   Index of the page to remove.
+	 */
+	public void remove_page (int page_number) {
+		if (_current_page_index != -1) {
+			if (page_number < _current_page_index) {
+				_current_page_index--;
+			} else if (page_number == _current_page_index) {
+				_current_page_index = -1;
+			}
+		}
+
+		var page = _pages.get (page_number);
+		if (_current_page_index == -1) {
+			_pages.remove_at (_pages.size - 1);
+		} else {
+			_pages.remove_at (page_number);
+		}
+
+		page_removed (page);
+	}
+
+	/**
+	 * Returns the index of the specified page given its content widget.
+	 *
+	 * @param child   The content of the page whose index must be returned.
+	 * @return		  The index.
+	 */
+	public int page_num (Widget child) {
+		// Since it is unlikely that the widget will contain more than
+		// a dozen pages, it is just fine to do a linear search.
+		for (int i = 0; i < _pages.size; i++) {
+			if (_pages.get (i).page == child) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Returns the index of the specified page.
+	 *
+	 * @param page   The page whose index must be returned.
+	 * @return       The RibbonPage.
+	 */
+	public int ribbon_page_num (RibbonPage page) {
+		// Since it is unlikely that the widget will containe more than
+		// a dozen pages, it is just fine to do a linear search.
+		for (int i = 0; i < _pages.size; i++) {
+			if (_pages.get (i) == page) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Sets the label widget of the specified page.
+	 *
+	 * @param page    The content of the page whose label must be modified.
+	 * @param label   The new label widget.
+	 */
+	public void set_page_label (Widget child, Widget label) {
+		_pages.get (page_num (child)).label = label;
+	}
+
+	/**
+	 * Gets the label widget of the specified page.
+	 *
+	 * @param child   The content of the page whose label must be returned.
+	 * @return        The label widget.
+	 */
+	public Widget get_page_label (Widget child) {
+		return _pages.get (page_num (child)).label;
+	}
+
+	/**
+	 * Returns the content widget of the n-th page.
+	 *
+	 * @param position   Index of the page whose content has to be returned.
+	 * @return           The n-th page.
+	 */
+	public Widget get_nth_page (int position) {
+		return _pages.get (position).page;
+	}
+
+	/**
+	 * Returns the n-th page.
+	 *
+	 * @param position   Index of the page to return.
+	 */
+	public RibbonPage get_nth_ribbon_page (int position) {
+		return _pages.get (position);
+	}
+
+	/**
+	 * Selects the specified page.
+	 *
+	 * @param page   The page to select.
+	 */
+	public void select_ribbon_page (RibbonPage page) {
+		int index = ribbon_page_num (page);
+		if (index != -1) {
+			this.current_page_index = index;
+		}
+		page_selected (page);
+	}
+
+	/** Selects the previous page. */
+	public void prev_page () {
+		int index = _current_page_index;
+		if (index > 0) {
+			this.current_page_index = index - 1;
+		}
+	}
+
+	/** Selects the next page. */
+	public void next_page () {
+		int index = _current_page_index;
+		if (index < this.n_pages - 1) {
+			this.current_page_index = index + 1;
+		}
+	}
+
+	protected override void forall (bool include_internals, Gtk.Callback callback) {
+		if (is_shown (_toolbar)) {
+			callback (_toolbar);
+		}
+
+		if (is_shown (_app_button)) {
+			callback (_app_button);
+		}
+
+		if (is_shown (_shortcuts)) {
+			callback (_shortcuts);
+		}
+
+		foreach (var page in _pages) {
+			callback (page.label);
+		}
+
+		if (this.current_page != null) {
+			callback (this.current_page.page);
+		}
+	}
+
+	private bool is_shown (Widget? widget) {
+		return (widget != null) && widget.visible;
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_request (requisition);
+
+		double tabs_width = 0;
+		double tabs_height = 0;
+		foreach (var page in _pages) {
+			Requisition req;
+			page.label.size_request (req);
+			tabs_width += req.width;
+			tabs_height = Math.fmax (tabs_height, req.height);
+			page.label_requisition = req;
+		}
+		tabs_width += _pages.size * 2 * TAB_PADDING;
+		tabs_height += 2 * TAB_PADDING;
+
+		double header_width = tabs_width;
+
+		if (is_shown (_shortcuts)) {
+			_shortcuts.size_request (_shortcuts_requisition);
+			double x = _shortcuts_requisition.width + SPACE;
+			header_width += Math.fmax (x, TABS_MIN_HPOS);
+		} else {
+			_shortcuts_requisition = Requisition ();
+			header_width += TABS_MIN_HPOS;
+		}
+
+		_header_height = Math.fmax (tabs_height, _shortcuts_requisition.height);
+
+		if (is_shown (_toolbar)) {
+			_toolbar.size_request (_toolbar_requisition);
+		}
+		if (is_shown (_app_button)) {
+			_app_button.size_request (_app_button_requisition);
+		}
+
+		if (is_shown (_toolbar)) {
+			_header_height += 2 * SPACE + _toolbar_requisition.height;
+		}
+
+		if (is_shown (_app_button)) {
+			_header_height = Math.fmax (_header_height, SPACE + _app_button_requisition.height);
+		}
+
+		double page_width = 0;
+		double page_height = 0;
+		if (this.current_page != null) {
+			this.current_page.page.size_request (_page_requisition);
+			page_width = _page_requisition.width + 2 * PAGE_PADDING;
+			page_height = _page_requisition.height + 2 * PAGE_PADDING;
+		} else {
+			_page_requisition = Requisition ();
+		}
+
+		double width = Math.fmax (header_width, page_width);
+		width = BORDER_WIDTH + width + BORDER_WIDTH;
+		double height = _header_height + page_height + 2 * BORDER_WIDTH;
+
+		requisition.width = (int) Math.ceil (width - double.EPSILON);
+		requisition.height = (int) Math.ceil (height - double.EPSILON);
+	}
+
+	protected override void size_allocate (Rectangle allocation) {
+//		base.size_allocate (allocation);	// FIXME: causes endless loop
+		this.allocation = (Allocation) allocation;	// workaround
+
+		if (allocation.height < _header_height + BORDER_WIDTH) {
+			return;
+		}
+
+		double header_bottom = allocation.y + BORDER_WIDTH + _header_height;
+		double current_x = BORDER_WIDTH;
+
+		if (is_shown (_app_button)) {
+			Rectangle alloc;
+			alloc.x = (int) current_x;
+			alloc.y = (int) (allocation.y + BORDER_WIDTH);
+			alloc.width = int.min (_app_button_requisition.width,
+							(int) (allocation.width - 2 * SPACE));
+			alloc.height = _app_button_requisition.height;
+			_app_button.size_allocate (alloc);
+
+			current_x += alloc.width + SPACE;
+		}
+
+		if (is_shown (_toolbar)) {
+			Rectangle alloc;
+			alloc.x = (int) current_x;
+			alloc.y = (int) (allocation.y + SPACE);
+			alloc.width = int.min (_toolbar_requisition.width,
+						(int) (allocation.width - (alloc.x - allocation.x) - SPACE));
+			alloc.height = _toolbar_requisition.height;
+			_toolbar.size_allocate (alloc);
+		}
+
+		if (is_shown (_shortcuts)) {
+			Rectangle alloc;
+			alloc.x = (int) current_x;
+			alloc.y = (int) (header_bottom - _shortcuts_requisition.height);
+			alloc.width = _shortcuts_requisition.width;
+			alloc.height = _shortcuts_requisition.height;
+			_shortcuts.size_allocate (alloc);
+			current_x += _shortcuts_requisition.width;
+		}
+
+		current_x += SPACE;
+		current_x = Math.fmax (current_x, TABS_MIN_HPOS);
+
+		foreach (var page in _pages) {
+			Rectangle alloc;
+			alloc.x = (int) (current_x + TAB_PADDING);
+			alloc.y = (int) (header_bottom - TAB_PADDING - page.label_requisition.height);
+			alloc.width = page.label_requisition.width;
+			alloc.height = page.label_requisition.height;
+			page.label.size_allocate (alloc);
+
+			alloc.x = (int) current_x;
+			alloc.y = (int) (header_bottom - page.label_requisition.height - 2 * TAB_PADDING);
+			alloc.width = (int) (page.label_requisition.width + 2 * TAB_PADDING);
+			alloc.height = (int) (page.label_requisition.height + 2 * TAB_PADDING);
+			page.label_allocation = alloc;
+
+			current_x += page.label_requisition.width + 2 * TAB_PADDING;
+		}
+
+		_body_allocation.x = allocation.x + (int) BORDER_WIDTH;
+		_body_allocation.y = (int) header_bottom;
+		_body_allocation.width = allocation.width - _body_allocation.x - (int) BORDER_WIDTH;
+		_body_allocation.height = allocation.height - _body_allocation.y - (int) BORDER_WIDTH;
+
+		if (this.current_page != null) {
+			_page_allocation = _body_allocation;
+			int pad = (int) PAGE_PADDING;
+			Rect.inflate (_page_allocation, -pad, -pad);
+			this.current_page.page.size_allocate (_page_allocation);
+		} else {
+			_page_allocation = Rectangle ();
+		}
+	}
+
+	protected override bool expose_event (EventExpose event) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (event.area.x, event.area.y,
+						event.area.width, event.area.height);
+		cr.clip ();
+		draw (cr);
+
+		// FIXME: is this necessary with Vala?
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+		// FIXME: causes endless loop, but necessary to draw the children
+//		return base.expose_event (event);
+		// *** workaround ***
+		if (is_shown (_toolbar)) {
+			_toolbar.expose_event (event);
+		}
+		if (is_shown (_app_button)) {
+			((Widget) _app_button).expose_event (event);	// XXX why cast?
+		}
+		if (is_shown (_shortcuts)) {
+			_shortcuts.expose_event (event);
+		}
+		foreach (var page in _pages) {
+			page.label.expose_event (event);
+		}
+		if (this.current_page != null) {
+			this.current_page.page.expose_event (event);
+		}
+		return false;
+		// *** workaround ***
+	}
+
+	protected void draw (Context cr) {
+		Rectangle menu_bar_allocation;
+		menu_bar_allocation.x = this.allocation.x;
+		menu_bar_allocation.y = this.allocation.y;
+		menu_bar_allocation.width = this.allocation.width;
+		if (is_shown (_toolbar)) {
+			menu_bar_allocation.height = (int) (_toolbar.allocation.height + 2 * SPACE);
+		} else {
+			menu_bar_allocation.height = 0;
+		}  	 
+		_theme.draw_ribbon (cr, menu_bar_allocation, _body_allocation,
+								ROUND_SIZE, LINE_WIDTH, this);
+	}
+}
+
+
+/** Ribbon page. */
+public class RibbonPage : GLib.Object {
+
+	public Ribbon parent { private get; construct; }
+
+	/** Widget used as the content of the page. */
+	public Widget page { get; set; }
+
+	public Requisition label_requisition { get; set; }
+	public Rectangle label_allocation { get; set; }
+
+	/** Label widget of the page. */
+	private Widget _label;
+	public Widget label {
+		set {
+			if (_label != null) {
+				_label.unparent ();
+			}
+			_label = value;
+			if (_label != null) {
+				_label.set_parent (this.parent);
+			}
+		}
+		get { return _label; }
+	}
+
+	public RibbonPage (Ribbon parent, Widget page, Widget label) {
+		this.parent = parent;
+		this.page = page;
+		this.label = label;
+	}
+}
+

Added: trunk/ribbon/sample-tile.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/sample-tile.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,25 @@
+public class SampleTile : Tile {
+
+	public string text { private get; construct; }
+	private Pango.Layout _text_layout;
+
+	public SampleTile (string text) {
+		this.text = text;
+	}
+
+	construct {
+		_text_layout = create_pango_layout (text);
+	}
+
+	public override Tile copy () {
+		return new SampleTile (this.text);
+	}
+
+	public override void draw_content (Cairo.Context context, Gdk.Rectangle area) {
+		context.set_source_rgb (0, 0, 0);
+		Pango.cairo_update_layout (context, _text_layout);
+		context.move_to (area.x, area.y);
+		Pango.cairo_show_layout (context, _text_layout);
+	}
+}
+

Added: trunk/ribbon/sample.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/sample.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,207 @@
+using GLib;
+using Cairo;
+using Gtk;
+
+public class Sample : SyntheticWindow {
+
+	protected bool _compose_available = false;
+
+	private ToolBox _flow_0;
+	private Menu _main_menu;
+
+	construct {
+		this.title = "Ribbons Sample";
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+				| Gdk.EventMask.BUTTON_RELEASE_MASK
+				| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		var master = new VBox (false, 0);
+
+		master.add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+				| Gdk.EventMask.BUTTON_RELEASE_MASK
+				| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		var button_0 = new Button.with_label ("Hello World");
+		var group_0 = new RibbonGroup ();
+		group_0.label = "Summer of Code";
+		group_0.add (button_0);
+		group_0.expanded += on_click;
+
+		var open_menu = new Menu ();
+		var abc_txt = new MenuItem.with_label ("abc.txt");
+		open_menu.append (abc_txt);
+		var foo_txt = new MenuItem.with_label ("foo.txt");
+		open_menu.append (foo_txt);
+
+		var open = Button.from_stock_with_label (STOCK_OPEN, "Open", false);
+		open.drop_down_menu = open_menu;
+		open.clicked += on_click;
+
+		var button_1 = new Button.with_label ("Menu Test");
+		button_1.clicked += on_click;
+		var button_1_menu = new Menu ();
+		var option_1 = new MenuItem.with_label ("Option 1");
+		button_1_menu.append (option_1);
+		button_1.drop_down_menu = button_1_menu;
+
+		var file_tool_pack = new ToolPack ();
+		file_tool_pack.append_button (Button.from_stock_with_label (STOCK_NEW, "New", false));
+		file_tool_pack.append_button (open);
+		file_tool_pack.append_button (Button.from_stock_with_label (STOCK_SAVE, "Save", false));
+
+		var printer_tool_pack = new ToolPack ();
+		printer_tool_pack.append_button (Button.from_stock_with_label (STOCK_PRINT, "Print", false));
+
+		var font_tool_pack = new ToolPack ();
+		font_tool_pack.append_button (ToggleButton.from_stock (STOCK_BOLD, false));
+		font_tool_pack.append_button (ToggleButton.from_stock (STOCK_ITALIC, false));
+		font_tool_pack.append_button (ToggleButton.from_stock (STOCK_UNDERLINE, false));
+
+		var font_combo = Gtk.combo_box_from_entries (new string[] {"Arial", "Verdana"});
+		font_combo.active = 0;
+
+		// var flow_0 = new FlowLayoutContainer ();
+		_flow_0 = new ToolBox ();
+		_flow_0.append (file_tool_pack);
+		_flow_0.append (printer_tool_pack);
+		_flow_0.append (font_tool_pack);
+		_flow_0.append (font_combo);
+
+		var btn_flow_box = new HBox (false, 2);
+		btn_flow_box.add (button_1);
+		btn_flow_box.add (_flow_0);
+
+		// Little hack because Gtk+ is not designed to support size negociations
+		btn_flow_box.size_allocate += (sender, allocation) => {
+			// XXX: flow_0 must be a field, since Vala doesn't support real closures yet.
+			_flow_0.height_request = allocation.height;
+		};
+
+		var group_1 = new RibbonGroup ();
+		group_1.label = "I will be back";
+		group_1.add (btn_flow_box);
+
+		var gallery = new Gallery ();
+		gallery.append_tile (new SampleTile ("1"));
+		gallery.append_tile (new SampleTile ("2"));
+		gallery.append_tile (new SampleTile ("3"));
+		gallery.append_tile (new SampleTile ("4"));
+		gallery.append_tile (new SampleTile ("5"));
+
+		var group_2 = new RibbonGroup ();
+		group_2.label = "Gallery";
+		group_2.add (gallery);
+
+		var page_0 = new HBox (false, 2);
+		page_0.pack_start (group_0, false, false, 0);
+		page_0.pack_start (group_1, false, false, 0);
+		page_0.pack_start (group_2, false, false, 0);
+
+		var page_1 = new HBox (false, 2);
+		var group_1_0 = new RibbonGroup ();
+		group_1_0.label = "Welcome on the second page";
+		page_1.pack_start (group_1_0, false, false, 0);
+
+		var page_2 = new HBox (false, 2);
+
+		var page_label_0 = new Label ("Page 1");
+		var page_label_1 = new Label ("Page 2");
+		var page_label_2 = new Label ("Page 3");
+
+		var shortcuts = new Button.with_label ("Menu");
+		shortcuts.child.modify_fg (StateType.NORMAL, Gdk.new_color (255, 255, 255));
+
+		_main_menu = new Menu ();
+		var main_menu_quit = new MenuItem.with_label ("Quit");
+		main_menu_quit.activate += () => {
+			Gtk.main_quit ();
+		};
+		_main_menu.append (main_menu_quit);
+
+		shortcuts.clicked += () => {
+			// XXX: main_menu must be a field, since Vala doesn't support real closures yet.
+			_main_menu.popup (null, null, null, 3, Gtk.get_current_event_time ());		// FIXME: sane default parameters
+			_main_menu.show_all ();
+		};
+
+		var qat = new QuickAccessToolbar ();
+		qat.append (Button.from_stock (STOCK_NEW, false));
+		qat.append (Button.from_stock (STOCK_SAVE, false));
+
+		var ribbon = new Ribbon ();
+		ribbon.application_button = new ApplicationButton ();
+		ribbon.quick_access_toolbar = qat;
+//		ribbon.shortcuts = shortcuts;
+		ribbon.append_page (page_0, page_label_0);
+		ribbon.append_page (page_1, page_label_1);
+		ribbon.append_page (page_2, page_label_2);
+
+		var txt = new TextView ();
+			
+		master.pack_start (ribbon, false, false, 0);
+		master.pack_start (txt, true, true, 0);
+
+		add (master);
+
+//		this.screen_changed += on_screen_changed;
+//		screen_changed (null);
+//		this.expose_event += on_expose_event;
+		this.destroy += Gtk.main_quit;
+
+		resize (200, 200);
+	}
+
+	private void on_click () {
+		var d = new Dialog.with_buttons ("Test", this, DialogFlags.DESTROY_WITH_PARENT);
+		d.modal = true;
+		d.add_button ("Close", ResponseType.CLOSE);
+		d.run ();
+		d.destroy ();
+	}
+
+//	[ConnectBefore]		// FIXME: does that work?
+//	private bool on_expose_event (Sample sender, Gdk.EventExpose event) {
+//		var cr = Gdk.cairo_create (this.window);
+
+//		if (_compose_available) {
+//			cr.set_source_rgba (0, 0, 0, 0.3);
+//		} else {
+//			cr.set_source_rgb (0.3, 0.3, 0.3);
+//		}
+
+////		cr.set_source_rgb (0.749, 0.859, 1.0);
+
+//		cr.set_operator (Operator.SOURCE);
+//		cr.paint ();
+
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return false;
+//	}
+
+//	private void on_screen_changed (Sample sender, Gdk.Screen? previous_screen) {
+//		weak Gdk.Colormap cm = this.screen.get_rgba_colormap ();
+//		_compose_available = cm != null;	// FIX: Does not seem to detect compose support in all cases 
+
+//		if (!_compose_available) {
+//			cm = this.screen.get_rgb_colormap ();
+//		}
+//		set_colormap (cm);
+
+//		print ("Compose support: %s\n", _compose_available ? "true" : "false");
+//	}
+
+	public static int main (string[] args) {
+		Gtk.init (ref args);
+
+		var sample = new Sample ();
+		sample.show_all ();
+
+		Gtk.main ();
+
+		return 0;
+	}
+}
+

Added: trunk/ribbon/synthetic-window.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/synthetic-window.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,137 @@
+using Gee;
+using Gdk;
+using Gtk;
+
+/** Window generating synthetic events to window-less widgets. */
+public class SyntheticWindow : Gtk.Window {
+
+	private Gee.List<Widget> _last_hovered_widgets;
+
+	construct {
+		_last_hovered_widgets = new Gee.ArrayList<Widget> ();
+	}
+
+	public SyntheticWindow (Gtk.WindowType type) {
+		this.type = type;
+	}
+
+	protected override bool event (Gdk.Event evnt) {
+		// This method is hooked to block the event as soon as possible if required
+
+		if (evnt.any.window == this.window) {
+			switch (evnt.type) {
+			case EventType.BUTTON_PRESS:
+			case EventType.BUTTON_RELEASE:
+			case EventType.3BUTTON_PRESS:
+			case EventType.2BUTTON_PRESS:
+				var eb = evnt.button;
+				return propagate_event_given_coordinate (evnt, eb.x, eb.x_root, eb.y, eb.y_root);
+
+			case EventType.MOTION_NOTIFY:
+				var em = evnt.motion;
+				return propagate_event_given_coordinate (evnt, em.x, em.x_root, em.y, em.y_root);
+
+			case EventType.LEAVE_NOTIFY:
+				foreach (var widget in _last_hovered_widgets) {
+					widget.event (evnt);
+				}
+				_last_hovered_widgets.clear ();
+//				return base.event (evnt);	// FIXME
+				return false;
+			}
+		}
+//		return base.event (evnt);	// FIXME
+		return false;
+	}
+
+	private bool propagate_event_given_coordinate (Gdk.Event evnt, double X, double x_root, double Y, double y_root) {
+		int x = (int) X;
+		int y = (int) Y;
+		Container current = this;	// Current container containing the coordinate
+		Widget match = this;		// Current match for the position
+		int matched_pos = 0;		// Current position in last_hovered_widgets
+
+		while (matched_pos < _last_hovered_widgets.size) {
+			var candidate = _last_hovered_widgets.get (matched_pos);
+			if (candidate.parent == (Widget) current) {	// Is it still a child of the current container ?
+				Gdk.Rectangle alloc = (Gdk.Rectangle) candidate.allocation;
+				if (!Gdk.Rect.contains (alloc, x, y)) {	// Does it contain the coordinate ?
+					break;
+				}
+			}
+			current = candidate as Container;
+			match = candidate;
+			++matched_pos;
+		}
+
+		if (matched_pos < _last_hovered_widgets.size) {	// Not all widgets match
+			// Send a leave notify
+			send_synthetic_event (EventType.LEAVE_NOTIFY, evnt, X, x_root, Y, y_root,
+									_last_hovered_widgets, matched_pos);
+			
+			// Remove them
+			list_remove_range (_last_hovered_widgets, matched_pos,
+						_last_hovered_widgets.size - matched_pos);
+		}
+
+		while (current != null) {
+			Container next = null;
+			foreach (var child in current.get_children ()) {
+				if ((child.get_flags () & WidgetFlags.NO_WINDOW) != 0) {
+					Gdk.Rectangle alloc = (Gdk.Rectangle) child.allocation;
+					if (Gdk.Rect.contains (alloc, x, y)) {
+						_last_hovered_widgets.add (child);
+						match = child;
+						next = child as Container;
+						break;
+					}
+				}
+			}
+			current = next;
+		}
+
+		if (matched_pos < _last_hovered_widgets.size) {	// New widgets have been found
+			// Send an enter notify
+			send_synthetic_event (EventType.ENTER_NOTIFY, evnt, X, x_root, Y, y_root,
+									_last_hovered_widgets, matched_pos);
+		}
+
+		if (match == this) {	// No widget found, the window keeps the event
+//			return base.event (evnt);		// FIXME
+			return false;
+		} else {	// A widget has been found, let's send it the event
+			match.event (evnt);
+			return true;
+		}
+	}
+
+	private void send_synthetic_event (EventType type, Event original_event,
+										double x, double x_root,
+										double y, double y_root,
+										Gee.List<Widget> widgets, int index) {
+		EventCrossing se;
+		se.detail = NotifyType.ANCESTOR;
+		se.focus = false;
+		se.mode = CrossingMode.NORMAL;
+		se.send_event = 0;
+		se.state = 0;
+		se.subwindow = null;
+//		se.Time = DateTime.Now.Ticks / 10000;	// TODO: the real value shoud be the uptime I think
+		se.time = 0;
+		se.type = type;
+		se.window = original_event.any.window;
+		se.x = x;
+		se.x_root = x_root;
+		se.y = y;
+		se.y_root = y_root;
+
+		Event managed_event;
+		managed_event.type = EventType.MOTION_NOTIFY;
+		managed_event.crossing = se;
+
+		for (int i = index; i < widgets.size; i++) {
+			widgets.get (i).event (managed_event);
+		}
+	}
+}
+

Added: trunk/ribbon/theme.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/theme.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,1035 @@
+using GLib;
+using Cairo;
+using Gtk;
+
+/**
+ * Ribbon theme.
+ *
+ * Used to draw ribbon widgets.
+ */
+public class Theme : GLib.Object {
+
+	public enum ButtonState {
+		DEFAULT,
+		HOVER,
+		PRESSED,
+	}
+
+	public enum MenuItemState {
+		DEFAULT,
+		HILIGHT_ACTION,
+		HILIGHT_MENU,
+		HILIGHT,
+	}
+
+	private ColorScheme _color_scheme = new ColorScheme ();
+
+	public void draw_application_menu (Context cr, Gdk.Rectangle r, Gdk.Rectangle items_alloc,
+										double line_width, ApplicationMenu w) {
+		double line_width_05 = line_width / 2;
+		double line_width_15 = line_width * 1.5;
+		Gdk.Rectangle alloc = (Gdk.Rectangle) w.allocation;
+
+		cr.set_source_rgb (0.4, 0.4, 0.4);
+		cr.paint ();
+
+		cr.rectangle (items_alloc.x, items_alloc.y, items_alloc.width, items_alloc.height);
+		cr.set_source_rgb (0.9216, 0.9216, 0.9216);
+		cr.fill ();
+
+		cr.set_line_width (line_width);
+
+		cr.move_to (Gdk.Rect.right (items_alloc) - line_width_05, Gdk.Rect.top (items_alloc));
+		cr.line_to (Gdk.Rect.right (items_alloc) - line_width_05, Gdk.Rect.bottom (items_alloc));
+		cr.set_source_rgba (1, 1, 1, 0.2);
+		cr.stroke ();
+
+		cr.move_to (Gdk.Rect.right (items_alloc) - line_width_15, Gdk.Rect.top (items_alloc));
+		cr.line_to (Gdk.Rect.right (items_alloc) - line_width_15, Gdk.Rect.bottom (items_alloc));
+		cr.set_source_rgba (0, 0, 0, 0.2);
+		cr.stroke ();
+
+		cr.rectangle (alloc.x, alloc.y, alloc.width, items_alloc.y - alloc.y);
+		var lin_grad = new Pattern.linear (0, alloc.y, 0, items_alloc.y - alloc.y);
+		lin_grad.add_color_stop_rgb (0.0, 0.4, 0.4, 0.4);
+		lin_grad.add_color_stop_rgb (0.3, 0.2, 0.2, 0.2);
+		lin_grad.add_color_stop_rgb (0.3, 0, 0, 0);
+		lin_grad.add_color_stop_rgb (1.0, 0.4, 0.4, 0.4);
+		cr.set_source (lin_grad);
+		cr.fill ();
+
+		cr.rectangle (alloc.x, Gdk.Rect.bottom (items_alloc), alloc.width,
+						Gdk.Rect.bottom (alloc) - Gdk.Rect.bottom (items_alloc));
+		lin_grad = new Pattern.linear (0, Gdk.Rect.bottom (items_alloc),
+										0, Gdk.Rect.bottom (alloc));
+		lin_grad.add_color_stop_rgb (0.0, 0.4, 0.4, 0.4);
+		lin_grad.add_color_stop_rgb (0.3, 0.2, 0.2, 0.2);
+		lin_grad.add_color_stop_rgb (0.3, 0, 0, 0);
+		lin_grad.add_color_stop_rgb (1.0, 0.4, 0.4, 0.4);
+		cr.set_source (lin_grad);
+		cr.fill ();
+
+		Gdk.Rectangle app_btn_alloc = (Gdk.Rectangle) w.application_button.allocation;
+		app_btn_alloc.x = alloc.x;
+		app_btn_alloc.y = items_alloc.y - 2 - app_btn_alloc.height;
+		draw_application_button (cr, app_btn_alloc, ButtonState.PRESSED, 1.0,
+									w.application_button);
+	}
+
+	public void draw_application_menu_item (Context cr, Gdk.Rectangle body_allocation,
+										MenuItemState state, double round_size,
+										double line_width, double arrow_size,
+										double arrow_padding, bool draw_separator,
+										ApplicationMenuItem widget) {
+		double line_width_05 = line_width / 2;
+		double line_width_15 = line_width_05 * 3;
+		double separator_x = body_allocation.x + body_allocation.width
+							- 2 * line_width - arrow_size - 2 * arrow_padding;
+
+		cr.set_line_width (line_width);
+
+		if (state != MenuItemState.DEFAULT) {
+			Pattern body_pattern;
+			Pattern inner_border_pattern;
+			Color border_color;
+
+			body_pattern = new Pattern.linear (
+							body_allocation.x, body_allocation.y,
+							body_allocation.x, body_allocation.y + body_allocation.height);
+			body_pattern.add_color_stop_rgb (0.0, 1, 0.996, 0.890);
+			body_pattern.add_color_stop_rgb (0.37, 1, 0.906, 0.592);
+			body_pattern.add_color_stop_rgb (0.43, 1, 0.843, 0.314);
+			body_pattern.add_color_stop_rgb (1.0, 1, 0.906, 0.588);
+
+			inner_border_pattern = new Pattern.linear (
+							body_allocation.x, body_allocation.y,
+							body_allocation.x + body_allocation.width,
+							body_allocation.y + body_allocation.height);
+			inner_border_pattern.add_color_stop_rgba (0.0, 1, 1, 0.969, 1);
+			inner_border_pattern.add_color_stop_rgba (1.0, 1, 1, 0.969, 0);
+
+			border_color = Color.from_rgb (0.824, 0.753, 0.553);
+
+			double x0 = body_allocation.x + line_width_05;
+			double y0 = body_allocation.y + line_width_05;
+			double x1 = body_allocation.x + body_allocation.width - line_width_05;
+			double y1 = body_allocation.y + body_allocation.height - line_width_05;
+
+			cr.move_to (x0 + round_size, y0);
+			cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+			cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+			cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+			cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+
+			cr.set_source (body_pattern);
+			cr.fill ();
+
+			if (state == MenuItemState.HILIGHT_ACTION) {
+				cr.set_source_rgba (1, 1, 1, 0.7);
+				cr.move_to (x0 + round_size, y0);
+				cr.line_to (separator_x, y0);
+				cr.line_to (separator_x, y1);
+				cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+				cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+				cr.fill ();
+			} else if (state == MenuItemState.HILIGHT_MENU) {
+				cr.set_source_rgba (1, 1, 1, 0.7);
+				cr.move_to (separator_x, y0);
+				cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+				cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+				cr.line_to (separator_x, y1);
+				cr.line_to (separator_x, y0);
+				cr.fill ();
+			}
+
+			x0 = body_allocation.x + line_width_15;
+			y0 = body_allocation.y + line_width_15;
+			x1 = body_allocation.x + body_allocation.width - line_width_15;
+			y1 = body_allocation.y + body_allocation.height - line_width_15;
+
+			double round_size_minus_line_width = round_size - line_width;
+
+			x0 -= line_width;
+
+			cr.move_to (x0 + round_size_minus_line_width, y0);
+			cr.arc (x1 - round_size_minus_line_width, y0 + round_size_minus_line_width,
+					round_size_minus_line_width, 1.5 * Math.PI, 0);
+			cr.arc (x1 - round_size_minus_line_width, y1 - round_size_minus_line_width,
+					round_size_minus_line_width, 0, 0.5 * Math.PI);
+			cr.arc (x0 + round_size_minus_line_width, y1 - round_size_minus_line_width,
+					round_size_minus_line_width, 0.5 * Math.PI, Math.PI);
+			cr.arc (x0 + round_size_minus_line_width, y0 + round_size_minus_line_width,
+					round_size_minus_line_width, Math.PI, 1.5 * Math.PI);
+
+			x0 += line_width;
+
+			cr.set_source (inner_border_pattern);
+			cr.stroke ();
+
+			x0 = body_allocation.x + line_width_05;
+			y0 = body_allocation.y + line_width_05;
+			x1 = body_allocation.x + body_allocation.width - line_width_05;
+			y1 = body_allocation.y + body_allocation.height - line_width_05;
+
+			cr.move_to (x0 + round_size, y0);
+			cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+			cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+			cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+
+			Cairo.set_color (cr, border_color);
+			cr.stroke ();
+		}
+
+		if (arrow_size > 0) {
+			double x, y;
+			
+			x = separator_x;
+			y = body_allocation.y + (body_allocation.height - arrow_size) / 2.0;
+			
+			if (draw_separator) {
+				double top = body_allocation.y + 2 * line_width;
+				double bottom = body_allocation.y + body_allocation.height - 2 * line_width;
+				cr.move_to (x - line_width / 2, top);
+				cr.line_to (x - line_width / 2, bottom);
+				cr.set_source_rgba (0, 0, 0, 0.1);
+				cr.stroke ();
+				
+				cr.move_to (x + line_width / 2, top);
+				cr.line_to (x + line_width / 2, bottom);
+				cr.set_source_rgba (1, 1, 1, 0.6);
+				cr.stroke ();
+			}
+			
+			x += arrow_size / 4.0 + line_width / 2.0;
+			
+			cr.move_to (x, y);
+			cr.line_to (x, y + arrow_size);
+			cr.line_to (x + arrow_size / 2.0, y + arrow_size / 2.0);
+			cr.line_to (x, y);
+			cr.set_source_rgb (0, 0, 0);
+			cr.fill ();
+		}
+	}
+
+	/** Draws a group. */
+	public void draw_group (Context cr, Gdk.Rectangle r, double round_size,
+							double line_width, double space, Pango.Layout l,
+							Gtk.Widget expand_button, RibbonGroup w) {
+		double line_width_05 = line_width / 2, line_width_15 = 3 * line_width_05;
+		Pattern lin_grad;
+
+		double x0 = r.x + round_size;
+		double x1 = r.x + r.width - round_size;
+		double y0 = r.y + round_size;
+		double y1 = r.y + r.height - round_size;
+		cr.arc (x1, y1, round_size - line_width_05, 0, Math.PI / 2);
+		cr.arc (x0 + line_width, y1, round_size - line_width_05, Math.PI / 2, Math.PI);
+		cr.arc (x0, y0, round_size - line_width_15, Math.PI, 3 * Math.PI / 2);
+		cr.arc (x1, y0 + line_width, round_size - line_width_05, 3 * Math.PI / 2, 0);
+		cr.line_to (x1 + round_size - line_width_05, y1);
+		cr.set_line_width (line_width);
+		Cairo.set_color (cr, _color_scheme.bright);
+		cr.stroke ();
+
+		if (l != null) {
+			int lbl_width, lbl_height;
+			Pango.cairo_update_layout (cr, l);
+			l.get_pixel_size (out lbl_width, out lbl_height);
+
+			if (w.label_position == PositionType.TOP
+					|| w.label_position == PositionType.BOTTOM) {
+				double label_y;
+				double band_height = lbl_height + 2 * space;
+
+				if (w.label_position == PositionType.TOP) {
+					cr.arc (x0, y0, round_size - line_width_05, Math.PI, 3 * Math.PI / 2);
+					cr.arc (x1, y0, round_size - line_width_05, 3 * Math.PI / 2, 0);
+					double band_y = y0 - round_size + 2 * line_width + band_height;
+					cr.line_to (x1 + round_size - line_width_15, band_y);
+					cr.line_to (x0 - round_size + line_width_05, band_y);
+					lin_grad = new Pattern.linear (0, band_y - band_height, 0, band_y);
+					Cairo.add_stop (lin_grad, 0.0, _color_scheme.dark);
+					Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+					cr.set_source (lin_grad);
+					cr.fill ();
+
+					label_y = band_y - band_height - space;
+				} else {
+					cr.arc (x1, y1, round_size - line_width_15, 0, Math.PI / 2);
+					cr.arc (x0, y1 - line_width, round_size - line_width_05,
+							Math.PI / 2, Math.PI);
+					double band_y = y1 + round_size - 2 * line_width - band_height;
+					cr.line_to (x0 - round_size + line_width_05, band_y);
+					cr.line_to (x1 + round_size - line_width_15, band_y);
+					lin_grad = new Pattern.linear (0, band_y, 0, band_y + band_height);
+					Cairo.add_stop (lin_grad, 0.0, _color_scheme.dark);
+					Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+					cr.set_source (lin_grad);
+					cr.fill ();
+
+					label_y = band_y;
+				}
+
+				double frame_size = 2 * line_width + space;
+				double available_horizontal_space = r.width - 2 * frame_size;
+				if (expand_button.visible) {
+					available_horizontal_space -= expand_button.width_request + space;
+				}
+
+				cr.save ();
+				cr.rectangle (r.x + frame_size, label_y,
+								available_horizontal_space, band_height);
+				cr.clip ();
+					
+				cr.set_source_rgb (1, 1, 1);
+				Pango.cairo_update_layout (cr, l);
+				cr.move_to (r.x + frame_size
+					+ Math.fmax (0, (available_horizontal_space - lbl_width) / 2),
+					label_y + space);
+				Pango.cairo_show_layout (cr, l);
+
+				cr.restore ();
+			} else {	// label at right or left
+				double label_x;
+				double band_width = lbl_height + 2 * space;
+
+				if (w.label_position == PositionType.LEFT) {
+					cr.arc (x0, y1, round_size - line_width_05, Math.PI / 2, Math.PI);
+					cr.arc (x0, y0, round_size - line_width_05, Math.PI, 3 * Math.PI / 2);
+					double band_x = x0 - round_size + 2 * line_width + band_width;
+					cr.line_to (band_x, y0 - round_size + line_width_05);
+					cr.line_to (band_x, y1 + round_size - line_width_15);
+					lin_grad = new Pattern.linear (band_x - band_width, 0, band_x, 0);
+					Cairo.add_stop (lin_grad, 0.0, _color_scheme.dark);
+					Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+					cr.set_source (lin_grad);
+					cr.fill ();
+
+					label_x = band_x - band_width - space;
+				} else {
+					cr.arc (x1, y0 - line_width_05, round_size - line_width_15,
+							3 * Math.PI / 2, 0);
+					cr.arc (x1, y1, round_size - line_width_15, 0, Math.PI / 2);
+					double band_x = x1 + round_size - 2 * line_width - band_width;
+					cr.line_to (band_x, y1 + round_size - line_width_15);
+					cr.line_to (band_x, y0 - round_size + line_width_05);
+					lin_grad = new Pattern.linear (band_x, 0, band_x + band_width, 0);
+					Cairo.add_stop (lin_grad, 0.0, _color_scheme.dark);
+					Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+					cr.set_source (lin_grad);
+					cr.fill ();
+
+					label_x = band_x + space;
+				}
+
+				double frame_size = 2 * line_width + space;
+				double available_vertical_space = r.height - 2 * frame_size;
+				if (expand_button.visible) {
+					available_vertical_space -= expand_button.height_request + space;
+				}
+
+				cr.save ();
+				cr.rectangle (label_x, r.y + frame_size,
+								band_width, available_vertical_space);
+				cr.clip ();
+				cr.rotate (-Math.PI / 2);
+
+				cr.set_source_rgb (1, 1, 1);
+				Pango.cairo_update_layout (cr, l);
+				double shift = Math.fmax (0, (available_vertical_space - lbl_width) / 2);
+				if (expand_button.visible) {
+					shift += expand_button.height_request + space;
+				}
+				cr.move_to (-(r.y + r.height - 2 * space - shift), label_x + space);
+				Pango.cairo_show_layout (cr, l);
+
+				cr.restore ();
+			}
+		}
+
+		cr.move_to (x1 + round_size - line_width_15, y1);
+		cr.arc (x1, y1, round_size - line_width_15, 0, Math.PI / 2);
+		cr.arc (x0, y1 - line_width, round_size - line_width_05, Math.PI / 2, Math.PI);
+		cr.arc (x0, y0, round_size - line_width_05, Math.PI, 3 * Math.PI / 2);
+		cr.arc (x1 - line_width, y0, round_size - line_width_05, 3 * Math.PI / 2, 0);
+		cr.line_to (x1 + round_size - line_width_15, y1);
+		cr.set_line_width (line_width);
+		lin_grad = new Pattern.linear (0, r.y, 0, r.y + r.height - line_width);
+		Cairo.add_stop (lin_grad, 0.0, ColorScheme.get_color_relative (
+											_color_scheme.pretty_dark, 0.1));
+		Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+		cr.set_source (lin_grad);
+		cr.stroke ();
+	}
+
+	public Gdk.Color get_forecolor_for_ribbon_tabs (bool selected) {
+		if (selected) {
+			return Gdk.new_color (0, 0, 0);
+		} else {
+			return Gdk.new_color (255, 255, 255);
+		}
+	}
+
+	/** Draws a ribbon. */
+	public void draw_ribbon (Context cr, Gdk.Rectangle menu_bar_allocation,
+						Gdk.Rectangle body_allocation, double round_size,
+						double line_width, Ribbon widget) {
+		double line_width_05 = line_width / 2;
+		double line_width_15 = 3 * line_width_05;
+		double x0, x1, y0, y1;
+		Pattern lin_grad;
+
+		// XXX: background painting
+		cr.set_source_rgb (0.3, 0.3, 0.3);
+		cr.paint ();
+		// XXX
+
+		if (menu_bar_allocation.height > 0) {
+			cr.rectangle (menu_bar_allocation.x, menu_bar_allocation.y,
+							menu_bar_allocation.width, menu_bar_allocation.height - 1);
+			lin_grad = new Pattern.linear (0, menu_bar_allocation.y, 0,
+							menu_bar_allocation.y + menu_bar_allocation.height - 1);
+			lin_grad.add_color_stop_rgba (0.0, 1, 1, 1, 0.5);
+			lin_grad.add_color_stop_rgba (0.3, 1, 1, 1, 0.2);
+			lin_grad.add_color_stop_rgba (0.3, 1, 1, 1, 0.0);
+			lin_grad.add_color_stop_rgba (1.0, 1, 1, 1, 0.5);
+
+			cr.set_source (lin_grad);
+			cr.fill ();
+
+			cr.move_to (menu_bar_allocation.x, Gdk.Rect.bottom (menu_bar_allocation) + 0.5);
+			cr.line_to (Gdk.Rect.right (menu_bar_allocation), Gdk.Rect.bottom (menu_bar_allocation) + 0.5);
+			cr.set_source_rgba (1, 1, 1, 0.5);
+			cr.set_line_width (1);
+			cr.stroke();
+
+			// Quick Access Toolbar background
+
+			Gdk.Rectangle alloc = (Gdk.Rectangle) widget.quick_access_toolbar.allocation;		// XXX copy?
+			x0 = alloc.x;
+			x1 = Gdk.Rect.right (alloc) - 1;
+			y0 = alloc.y;
+			y1 = Gdk.Rect.bottom (alloc) - 1;
+			double radius = (y1 - y0) / 2;
+
+			cr.set_line_width (1);
+
+			if (widget.application_button != null) {
+				Gdk.Rectangle alloc2 = (Gdk.Rectangle) widget.application_button.allocation;		// XXX
+				double cx = alloc2.x + alloc2.width / 2;
+				double cy = alloc2.y + alloc2.height / 2;
+				double radius2 = x0 - cx;
+				double alpha = Math.asin ((y0 - cy) / radius2);
+				double beta = Math.asin ((y1 - cy) / radius2);
+				double curve_width0 = Math.cos (Math.fabs (alpha)) * radius2;
+				double curve_width1 = Math.cos (Math.fabs (beta)) * radius2;
+				double curve_width = Math.fmin (curve_width0, curve_width1);
+
+				cr.save ();
+				cr.rectangle (cx + curve_width, y0, x1 - cx - curve_width, alloc.height);
+				cr.clip_preserve ();
+				cr.arc_negative (cx, cy, radius2, -alpha, -beta);
+				lin_grad = new Pattern.linear (0, y0, 0, y1);
+				Cairo.add_stop (lin_grad, 0.0, _color_scheme.bright);
+				Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+				cr.set_source (lin_grad);
+//				cr.set_source_rgb (1, 0, 0);
+				cr.fill ();
+				cr.restore ();
+				cr.arc (x1, y0 + radius, radius - 0.5, 1.5 * Math.PI, 0.5 * Math.PI);
+				cr.set_source (lin_grad);
+				cr.fill ();
+
+				cr.arc (cx, cy, radius2, alpha, beta);
+				cr.set_source_rgba (0, 0, 0, 0.6);
+				cr.stroke ();
+				radius2 -= 1;
+				cr.arc (cx, cy, radius2, alpha, beta);
+				cr.set_source_rgba (1, 1, 1, 0.4);
+				cr.stroke ();
+
+				cr.move_to (cx + curve_width0, y0 - 0.5);
+				cr.line_to (x1, y0 - 0.5);
+				cr.set_source_rgba (1, 1, 1, 0.4);
+				cr.stroke ();
+
+				cr.move_to (cx + curve_width0, y0 + 0.5);
+				cr.line_to (x1, y0 + 0.5);
+				cr.set_source_rgba (0, 0, 0, 0.6);
+				cr.stroke ();
+
+				cr.move_to (cx + curve_width1, y1 - 0.5);
+				cr.line_to (x1, y1 - 0.5);
+				cr.set_source_rgba (0, 0, 0, 0.6);
+				cr.stroke ();
+
+				cr.move_to (cx + curve_width1, y1 + 0.5);
+				cr.line_to (x1, y1 + 0.5);
+				cr.set_source_rgba (1, 1, 1, 0.4);
+				cr.stroke ();
+			} else {
+				cr.rectangle (x0, y0, x1 - x0, alloc.height);
+				lin_grad = new Pattern.linear (0, y0, 0, y1);
+				Cairo.add_stop (lin_grad, 0.0, _color_scheme.bright);
+				Cairo.add_stop (lin_grad, 1.0, _color_scheme.pretty_dark);
+				cr.set_source (lin_grad);
+				cr.fill ();
+
+				cr.arc (x1, y0 + radius, radius - 0.5, 1.5 * Math.PI, 0.5 * Math.PI);
+				cr.set_source (lin_grad);
+				cr.fill ();
+
+				cr.move_to (x0 + 0.5, y0);
+				cr.line_to (x0 + 0.5, y1);
+				cr.set_source_rgba (1, 1, 1, 0.4);
+				cr.stroke ();
+
+				cr.move_to (x0 + 1.5, y0);
+				cr.line_to (x0 + 1.5, y1);
+				cr.set_source_rgba (0, 0, 0, 0.6);
+				cr.stroke ();
+			}
+
+			cr.arc (x1, y0 + radius, radius + 0.5, 1.5 * Math.PI, 0.5 * Math.PI);
+			cr.set_source_rgba (1, 1, 1, 0.4);
+			cr.stroke ();
+
+			cr.arc (x1, y0 + radius, radius - 0.5, 1.5 * Math.PI, 0.5 * Math.PI);
+			cr.set_source_rgba (0, 0, 0, 0.6);
+			cr.stroke ();
+		}
+
+		RibbonPage p = widget.current_page;
+		if (p == null) {
+			return;
+		}
+
+//		Color c = _color_scheme.get_color_absoulte (_color_scheme.bright, 0.92);
+		Color c = _color_scheme.normal;
+
+		if (body_allocation.height > 0) {
+			// *** PAGE ***
+
+			x0 = body_allocation.x;
+			x1 = body_allocation.x + body_allocation.width;
+			y0 = body_allocation.y;
+			y1 = body_allocation.y + body_allocation.height;
+
+			cr.arc (x0 + round_size, y1 - round_size,
+					round_size - line_width_05, Math.PI / 2, Math.PI);
+			cr.arc (x0 + round_size, y0 + round_size,
+					round_size - line_width_05, Math.PI, 3 * Math.PI / 2);
+			cr.arc (x1 - round_size, y0 + round_size,
+					round_size - line_width_05, 3 * Math.PI / 2, 0);
+			cr.arc (x1 - round_size, y1 - round_size,
+					round_size - line_width_05, 0, Math.PI/2);
+			cr.line_to (x0 + round_size, y1 - line_width_05);
+
+			// *** BACKGOUND ***
+			Cairo.set_color (cr, c);
+			cr.fill_preserve ();
+
+			// *** DARK BORDER ***
+			cr.set_line_width (line_width);
+			Cairo.set_color (cr, ColorScheme.get_color_absolute (
+											_color_scheme.normal, 0.75));
+			cr.stroke ();
+
+			// *** GLASS EFFECT ***
+			double ymid = Math.round (y0 + (y1 - y0) * 0.25);
+					
+			cr.arc (x0 + round_size, y0 + round_size,
+					round_size - line_width, Math.PI, 3 * Math.PI / 2);
+			cr.arc (x1 - round_size, y0 + round_size,
+					round_size - line_width, 3 * Math.PI / 2, 0);
+			cr.line_to (x1 - line_width, ymid);
+			cr.line_to (x0 + line_width, ymid);
+			cr.line_to (x0 + line_width, y0 + round_size);
+			lin_grad = new Pattern.linear (0, y0, 0, ymid);
+			lin_grad.add_color_stop_rgba (0.0, 0, 0, 0, 0.0);
+			lin_grad.add_color_stop_rgba (1.0, 0, 0, 0, 0.075);
+			cr.set_source (lin_grad);
+			cr.fill ();
+
+			cr.arc (x0 + round_size, y1 - round_size,
+					round_size - line_width, Math.PI / 2, Math.PI);
+			cr.line_to (x0 + line_width, ymid);
+			cr.line_to (x1 - line_width, ymid);
+			cr.arc (x1 - round_size, y1 - round_size,
+					round_size - line_width, 0, Math.PI / 2);
+			cr.line_to (x0 + round_size, y1 - line_width);
+			lin_grad = new Pattern.linear (0, ymid, 0, y1);
+			lin_grad.add_color_stop_rgba (0.0, 0, 0, 0, 0.1);
+			lin_grad.add_color_stop_rgba (0.5, 0, 0, 0, 0.0);
+			cr.set_source (lin_grad);
+			cr.fill ();
+		}
+
+		// *** TAB ***
+
+		Gdk.Rectangle r = p.label_allocation;
+
+		x0 = r.x;
+		x1 = r.x + r.width;
+		y0 = r.y;
+		y1 = r.y + r.height + line_width;
+
+		// *** TAB :: BACKGROUND ***
+
+		cr.move_to (x0 + line_width_05, y1);
+		cr.line_to (x0 + line_width_05, y0 + round_size);
+		cr.arc (x0 + round_size, y0 + round_size,
+				round_size - line_width_05, Math.PI, 3 * Math.PI / 2);
+		cr.arc (x1 - round_size, y0 + round_size,
+				round_size - line_width_05, 3 * Math.PI / 2, 0);
+		cr.line_to (x1 - line_width_05, y1);
+
+		lin_grad = new Pattern.linear (0, y0, 0, y1);
+		Cairo.add_stop (lin_grad, 0.0, _color_scheme.pretty_bright);
+		Cairo.add_stop (lin_grad, 1.0, c);
+		cr.set_source (lin_grad);
+		cr.fill ();
+
+		// *** TAB :: DARK BORDER ***
+
+		cr.move_to (x0 + line_width_05, y1);
+		cr.line_to (x0 + line_width_05, y0 + round_size);
+		cr.arc (x0 + round_size, y0 + round_size,
+				round_size - line_width_05, Math.PI, 3 * Math.PI / 2);
+		cr.arc (x1 - round_size, y0 + round_size,
+				round_size - line_width_05, 3 * Math.PI / 2, 0);
+		cr.line_to (x1 - line_width_05, y1);
+
+		cr.set_line_width (line_width);
+		Cairo.set_color (cr, ColorScheme.get_color_relative (_color_scheme.bright, -0.1));
+		cr.stroke ();
+
+		y1 -= 1.0;
+
+		// *** TAB :: HIGHLIGHT ***
+
+		cr.move_to (x0 + line_width_15, y1);
+		cr.line_to (x0 + line_width_15, y0 + round_size);
+		cr.arc (x0 + round_size, y0 + round_size,
+				round_size - line_width_15, Math.PI, 3 * Math.PI / 2);
+		cr.arc (x1 - round_size, y0 + round_size,
+				round_size - line_width_15, 3 * Math.PI / 2, 0);
+		cr.line_to (x1 - line_width_15, y1);
+
+		cr.set_line_width (line_width);
+		lin_grad = new Pattern.linear (0, y0 + line_width, 0, y1);
+		Cairo.add_stop (lin_grad, 0.0, _color_scheme.pretty_bright);
+		Cairo.add_stop (lin_grad, 1.0, ColorScheme.set_alpha_channel (
+											_color_scheme.bright, 0));
+		cr.set_source (lin_grad);
+		cr.stroke ();
+
+		// *** TAB :: SHADOW ***
+
+		cr.move_to (x0 - line_width_05, y1);
+		cr.line_to (x0 - line_width_05, y0 + round_size);
+		cr.arc (x0 + round_size, y0 + round_size,
+				round_size + line_width_05, Math.PI, 3 * Math.PI / 2);
+		cr.arc (x1 - round_size, y0 + round_size,
+				round_size + line_width_05, 3 * Math.PI / 2, 0);
+		cr.line_to (x1 + line_width_05, y1);
+
+		cr.set_line_width (line_width);
+		cr.set_source_rgba (0, 0, 0, 0.2);
+		cr.stroke ();
+	}
+
+	/** Draws an application button. */
+	public void draw_application_button (Context cr, Gdk.Rectangle body_allocation,
+										ButtonState state, double line_width,
+										BaseButton widget) {
+		double drop_shadow_offset = 1;		// XXX: local consts not yet in Vala
+		double radius = (body_allocation.height - drop_shadow_offset) / 2;
+
+		double x = body_allocation.x + radius + drop_shadow_offset;
+		double y = body_allocation.y + radius + drop_shadow_offset;
+		cr.arc (x, y, radius, 0, 2 * Math.PI);
+		cr.set_source_rgba (0, 0, 0, 0.5);
+		cr.fill ();
+
+		cr.arc (body_allocation.x + radius, body_allocation.y + radius, radius, 0, 2 * Math.PI);
+		switch (state) {
+		case ButtonState.HOVER:
+			cr.set_source_rgb (0.9, 0.815, 0.533);
+			break;
+		case ButtonState.PRESSED:
+			cr.set_source_rgb (0.886, 0.639, 0.356);
+			break;
+		default:
+			cr.set_source_rgb (0.8, 0.8, 0.8);
+			break;
+		}
+		cr.fill ();
+
+		cr.arc (body_allocation.x + radius, body_allocation.y + radius, radius, 0, 2 * Math.PI);
+		var lin_grad = new Pattern.linear (0, body_allocation.y, 0, body_allocation.y + body_allocation.height);
+		lin_grad.add_color_stop_rgba (0.0, 1, 1, 1, 0.9);
+		lin_grad.add_color_stop_rgba (0.5, 1, 1, 1, 0.0);
+		lin_grad.add_color_stop_rgba (1.0, 1, 1, 1, 1.0);
+		cr.set_source (lin_grad);
+		cr.fill ();
+
+		cr.arc (body_allocation.x + radius, body_allocation.y + radius, radius, 0, 2 * Math.PI);
+		lin_grad = new Pattern.linear (0, body_allocation.y, 0, body_allocation.y + body_allocation.height);
+		lin_grad.add_color_stop_rgba (0.0, 0, 0, 0, 0.0);
+		lin_grad.add_color_stop_rgba (0.4, 0, 0, 0, 0.0);
+		lin_grad.add_color_stop_rgba (0.5, 0, 0, 0, 0.1);
+		lin_grad.add_color_stop_rgba (0.75, 0, 0, 0, 0.0);
+		lin_grad.add_color_stop_rgba (1.0, 0, 0, 0, 0.0);
+		cr.set_source (lin_grad);
+		cr.fill ();
+
+		cr.arc (body_allocation.x + radius, body_allocation.y + radius, radius, 0, Math.PI);
+		lin_grad = new Pattern.linear (0, body_allocation.y + radius, 0, body_allocation.y + body_allocation.height);
+		lin_grad.add_color_stop_rgba (0.0, 0, 0, 0, 0.0);
+		lin_grad.add_color_stop_rgba (1.0, 0, 0, 0, 0.5);
+		cr.set_source (lin_grad);
+		cr.set_line_width (1.0);
+		cr.stroke ();
+
+		cr.arc (body_allocation.x + radius, body_allocation.y + radius, radius, Math.PI, 0);
+		lin_grad = new Pattern.linear (0, body_allocation.y, 0, body_allocation.y + radius);
+		lin_grad.add_color_stop_rgba (0.0, 1, 1, 1, 0.5);
+		lin_grad.add_color_stop_rgba (1.0, 1, 1, 1, 0.0);
+		cr.set_line_width (1.0);
+		cr.stroke ();
+
+		cr.arc (body_allocation.x + radius, body_allocation.y + radius, radius, 0, 2 * Math.PI);
+		var rad_grad = new Pattern.radial (
+				body_allocation.x + radius, body_allocation.y + 1.5 * radius, 0,
+				body_allocation.x + radius, body_allocation.y + 1.5 * radius, 0.5 * radius);
+		rad_grad.add_color_stop_rgba (0, 1, 1, 1, 0.4);
+		rad_grad.add_color_stop_rgba (1, 1, 1, 1, 0.0);
+		cr.set_source (rad_grad);
+		cr.fill ();
+	}
+
+	/** Draws a button. */
+	public void draw_button (Context cr, Gdk.Rectangle body_allocation,
+							ButtonState state, double round_size,
+							double line_width, double arrow_size,
+							double arrow_padding, bool draw_separator,
+							BaseButton widget) {
+		double line_width_05 = line_width / 2;
+		double line_width_15 = line_width_05 * 3;
+
+		bool up_left = true;
+		bool up_right = true;
+		bool down_right = true;
+		bool down_left = true;
+		switch (widget.group_style) {
+		case GroupStyle.LEFT:
+			up_right = down_right = false;
+			break;
+		case GroupStyle.CENTER:
+			up_left = down_left = up_right = down_right = false;
+			break;
+		case GroupStyle.RIGHT:
+			up_left = down_left = false;
+			break;
+		}
+
+		cr.set_line_width (line_width);
+
+		if (state == ButtonState.PRESSED || state == ButtonState.HOVER) {
+			Pattern body_pattern;
+			Pattern inner_border_pattern;
+			Color border_color;
+
+			if (state == ButtonState.PRESSED) {
+				body_pattern = new Pattern.linear (
+						body_allocation.x,
+						body_allocation.y,
+						body_allocation.x,
+						body_allocation.y + body_allocation.height);
+				body_pattern.add_color_stop_rgb (0.0, 0.996, 0.847, 0.667);
+				body_pattern.add_color_stop_rgb (0.37, 0.984, 0.710, 0.396);
+				body_pattern.add_color_stop_rgb (0.43, 0.980, 0.616, 0.204);
+				body_pattern.add_color_stop_rgb (1.0, 0.992, 0.933, 0.667);
+
+				inner_border_pattern = new Pattern.linear (
+						body_allocation.x,
+						body_allocation.y,
+						body_allocation.x + body_allocation.width,
+						body_allocation.y + body_allocation.height);
+				inner_border_pattern.add_color_stop_rgba (0.0, 0.876, 0.718, 0.533, 1);
+				inner_border_pattern.add_color_stop_rgba (1.0, 0.876, 0.718, 0.533, 0);
+
+				border_color = Color.from_rgb (0.671, 0.631, 0.549);
+			} else {
+				body_pattern = new Pattern.linear (
+						body_allocation.x,
+						body_allocation.y,
+						body_allocation.x,
+						body_allocation.y + body_allocation.height);
+				body_pattern.add_color_stop_rgb (0.0, 1, 0.996, 0.890);
+				body_pattern.add_color_stop_rgb (0.37, 1, 0.906, 0.592);
+				body_pattern.add_color_stop_rgb (0.43, 1, 0.843, 0.314);
+				body_pattern.add_color_stop_rgb (1.0, 1, 0.906, 0.588);
+
+				inner_border_pattern = new Pattern.linear (
+						body_allocation.x,
+						body_allocation.y,
+						body_allocation.x + body_allocation.width,
+						body_allocation.x + body_allocation.height);
+				inner_border_pattern.add_color_stop_rgba (0.0, 1, 1, 0.969, 1);
+				inner_border_pattern.add_color_stop_rgba (1.0, 1, 1, 0.969, 0);
+
+				border_color = Color.from_rgb (0.824, 0.753, 0.553);
+			}
+
+			double x0 = body_allocation.x + line_width_05;
+			double y0 = body_allocation.y + line_width_05;
+			double x1 = body_allocation.x + body_allocation.width - line_width_05;
+			double y1 = body_allocation.y + body_allocation.height - line_width_05;
+
+			if (up_left) {
+				cr.move_to (x0 + round_size, y0);
+			} else {
+				cr.move_to (x0, y0);
+			}
+			if (up_right) {
+				cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+			} else {
+				cr.line_to (x1, y0);
+			}
+			if (down_right) {
+				cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+			} else {
+				cr.line_to (x1, y1);
+			}
+			if (down_left) {
+				cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+			} else {
+				cr.line_to (x0, y1);
+			}
+			if (up_left) {
+				cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+			} else {
+				cr.line_to (x0, y0);
+			}
+
+			cr.set_source (body_pattern);
+			cr.fill ();
+
+			x0 = body_allocation.x + line_width_15;
+			y0 = body_allocation.y + line_width_15;
+			x1 = body_allocation.x + body_allocation.width - line_width_15;
+			y1 = body_allocation.y + body_allocation.height - line_width_15;
+
+			double round_size_minus_line_width = round_size - line_width;
+
+			if (widget.group_style != GroupStyle.LEFT) {
+				x0 -= line_width;
+			}
+
+			if (up_left) cr.move_to (x0 + round_size_minus_line_width, y0);
+			else cr.move_to (x0, y0);
+			if (up_right) cr.arc (x1 - round_size_minus_line_width, y0 + round_size_minus_line_width, round_size_minus_line_width, 1.5 * Math.PI, 0);
+			else cr.line_to (x1, y0);
+			if (down_right) cr.arc (x1 - round_size_minus_line_width, y1 - round_size_minus_line_width, round_size_minus_line_width, 0, 0.5 * Math.PI);
+			else cr.line_to (x1, y1);
+			if (down_left) cr.arc (x0 + round_size_minus_line_width, y1 - round_size_minus_line_width, round_size_minus_line_width, 0.5 * Math.PI, Math.PI);
+			else cr.line_to (x0, y1);
+			if (up_left) cr.arc (x0 + round_size_minus_line_width, y0 + round_size_minus_line_width, round_size_minus_line_width, Math.PI, 1.5 * Math.PI);
+			else cr.line_to (x0, y0);
+
+			if (widget.group_style != GroupStyle.LEFT) {
+				x0 += line_width;
+			}
+
+			cr.set_source (inner_border_pattern);
+			cr.stroke ();
+
+			x0 = body_allocation.x + line_width_05;
+			y0 = body_allocation.y + line_width_05;
+			x1 = body_allocation.x + body_allocation.width - line_width_05;
+			y1 = body_allocation.y + body_allocation.height - line_width_05;
+
+			if (up_left) cr.move_to (x0 + round_size, y0);
+			else cr.move_to (x0, y0);
+			if (up_right) cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+			else cr.line_to (x1, y0);
+			if (down_right) cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+			else cr.line_to (x1, y1);
+			if (down_left) cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+			else cr.line_to (x0, y1);
+			if (widget.group_style == GroupStyle.LEFT) {
+				if (up_left) cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+				else cr.line_to (x0, y0);
+			}
+
+			Cairo.set_color (cr, border_color);
+			cr.stroke ();
+		} else if (widget.draw_background) {
+			var body_pattern = new Pattern.linear (
+					body_allocation.x,
+					body_allocation.y,
+					body_allocation.x,
+					body_allocation.y + body_allocation.height);
+			body_pattern.add_color_stop_rgba (0.0, 1, 1, 1, 0.7);
+			body_pattern.add_color_stop_rgba (0.37, 1, 1, 1, 0.2);
+			body_pattern.add_color_stop_rgba (0.43, 1, 1, 1, 0.2);
+			body_pattern.add_color_stop_rgba (1.0, 1, 1, 1, 0.7);
+
+			double x0 = body_allocation.x + line_width_05;
+			double y0 = body_allocation.y + line_width_05;
+			double x1 = body_allocation.x + body_allocation.width - line_width_05;
+			double y1 = body_allocation.y + body_allocation.height - line_width_05;
+
+			if (up_left) cr.move_to (x0 + round_size, y0);
+			else cr.move_to (x0, y0);
+			if (up_right) cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+			else cr.line_to (x1, y0);
+			if (down_right) cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+			else cr.line_to (x1, y1);
+			if (down_left) cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+			else cr.line_to (x0, y1);
+			if (up_left) cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+			else cr.line_to (x0, y0);
+
+			cr.set_source (body_pattern);
+			cr.fill ();
+
+			if (widget.group_style != GroupStyle.LEFT) {
+				if (down_left) cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+				else cr.move_to (x0, y1);
+				if (up_left) cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+				else cr.line_to (x0, y0);
+
+				cr.set_source_rgba (1, 1, 1, 0.8);
+				cr.stroke ();
+			}
+
+			if (up_left) cr.arc (x0 + round_size, y0 + round_size, round_size, Math.PI, 1.5 * Math.PI);
+			else cr.move_to (x0, y0);
+			if (up_right) cr.arc (x1 - round_size, y0 + round_size, round_size, 1.5 * Math.PI, 0);
+			else cr.line_to (x1, y0);
+			if (down_right) cr.arc (x1 - round_size, y1 - round_size, round_size, 0, 0.5 * Math.PI);
+			else cr.line_to (x1, y1);
+			if (down_left) cr.arc (x0 + round_size, y1 - round_size, round_size, 0.5 * Math.PI, Math.PI);
+			else cr.line_to (x0, y1);
+			if (widget.group_style == GroupStyle.LEFT) {
+				if (up_left) {
+					cr.line_to (x0, y0 + round_size);
+				} else {
+					cr.line_to (x0, y0);
+				}
+			}
+
+			cr.set_source_rgba (0, 0, 0, 0.2);
+			cr.stroke ();
+		}
+
+		if (arrow_size > 0) {
+			double x, y;
+
+			switch (widget.image_position) {
+			case Gtk.PositionType.BOTTOM:
+			case Gtk.PositionType.TOP:
+				x = body_allocation.x + (body_allocation.width - arrow_size) / 2.0;
+				y = body_allocation.y + body_allocation.height - 2 * line_width
+											- arrow_size - 2 * arrow_padding;
+
+				if (draw_separator) {
+					double left = body_allocation.x + 2 * line_width;
+					double right = body_allocation.x + body_allocation.width - 2 * line_width;
+
+					cr.move_to (left, y - line_width / 2);
+					cr.line_to (right, y - line_width / 2);
+					cr.set_source_rgba (0, 0, 0, 0.1);
+					cr.stroke ();
+
+					cr.move_to (left, y + line_width / 2);
+					cr.line_to (right, y + line_width / 2);
+					cr.set_source_rgba (1, 1, 1, 0.6);
+					cr.stroke ();
+				}
+
+				y += arrow_padding;
+				break;
+			default:
+				x = body_allocation.x + body_allocation.width - 2 * line_width
+											- arrow_size - 2 * arrow_padding;
+				y = body_allocation.y + (body_allocation.height - arrow_size) / 2.0;
+
+				if (draw_separator) {
+					double top = body_allocation.y + 2 * line_width;
+					double bottom = body_allocation.y
+									+ body_allocation.height
+									- 2 * line_width;
+					cr.move_to (x - line_width / 2, top);
+					cr.line_to (x - line_width / 2, bottom);
+					cr.set_source_rgba (0, 0, 0, 0.1);
+					cr.stroke ();
+
+					cr.move_to (x + line_width / 2, top);
+					cr.line_to (x + line_width / 2, bottom);
+					cr.set_source_rgba (1, 1, 1, 0.6);
+					cr.stroke ();
+				}
+
+				x += arrow_padding;
+				break;
+			}
+
+			y += arrow_size / 4.0 + line_width / 2.0;
+			cr.move_to (x, y);
+			cr.line_to (x + arrow_size, y);
+			cr.line_to (x + arrow_size / 2.0, y + arrow_size / 2.0);
+			cr.line_to (x, y);
+			cr.set_source_rgba (0, 0, 0, 1.0);
+			cr.fill ();
+		}
+	}
+
+	/** Draws a gallery. */
+	public void draw_gallery (Context cr, Gdk.Rectangle body_allocation,
+							Gdk.Rectangle tiles_allocation, Gallery widget) {
+		cr.set_source_rgba (0, 0, 0, 0.3);
+		cr.set_line_width (1);
+		cr.rectangle (
+			tiles_allocation.x - 0.5,
+			tiles_allocation.y - 0.5,
+			tiles_allocation.width + 1.0,
+			tiles_allocation.height + 1.0);
+		cr.stroke ();
+	}
+
+	/** Draws a tile. */
+	public void draw_tile (Context cr, Gdk.Rectangle body_allocation,
+							Gdk.Rectangle content_allocation, Tile widget) {
+		if (widget.selected) {
+			var grad = new Pattern.linear (
+				body_allocation.x,
+				body_allocation.y,
+				body_allocation.x,
+				body_allocation.y + body_allocation.height);
+			grad.add_color_stop_rgb (0.00, 0.9922, 0.7373, 0.4353);
+			grad.add_color_stop_rgb (0.27, 0.9961, 0.8039, 0.5569);
+			grad.add_color_stop_rgb (0.33, 0.9961, 0.7255, 0.4078);
+			grad.add_color_stop_rgb (1.00, 0.9843, 0.8980, 0.6313);
+			cr.set_source (grad);
+			cr.rectangle (
+				body_allocation.x,
+				body_allocation.y,
+				body_allocation.width,
+				body_allocation.height);
+			cr.fill ();
+		}
+
+		cr.set_source_rgb (1, 1, 1);
+		cr.rectangle (
+			content_allocation.x,
+			content_allocation.y,
+			content_allocation.width,
+			content_allocation.height);
+		cr.fill ();
+	}
+}
+

Added: trunk/ribbon/tile.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/tile.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,130 @@
+using Gtk;
+
+/**
+ * The Tile widget.
+ */
+public abstract class Tile : Widget {
+
+	/** Gets or sets the width of the border. */
+	private uint _border_width;
+	public uint border_width {
+		set {
+			_border_width = value;
+			queue_draw ();
+		}
+		get { return _border_width; }
+	}
+
+	/** Gets or sets the state of the Tile. */
+	private bool _selected;
+	public bool selected {
+		set {
+			_selected = value;
+			queue_draw ();
+		}
+		get { return _selected; }
+	}
+
+	/** Fired when the Tile has been clicked. */
+	public signal void clicked ();
+
+	/** Theme used to draw the widget. */
+	private Theme _theme = new Theme ();
+	public Theme theme {
+		set {
+			_theme = value;
+			queue_draw ();
+		}
+		get { return _theme; }
+	}
+
+	/** Construction method */
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+		
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+				| Gdk.EventMask.BUTTON_RELEASE_MASK
+				| Gdk.EventMask.POINTER_MOTION_MASK);
+			
+		this.selected = false;
+		this.border_width = 4;
+	}
+
+	/** Creates a carbon copy of the current Tile. */
+	public abstract Tile copy ();
+
+	protected override bool expose_event (Gdk.EventExpose evnt) {
+		var cr = Gdk.cairo_create (this.window);
+
+		Gdk.Rectangle area;
+		area.x = evnt.area.x;
+		area.y = evnt.area.y;
+		area.width = evnt.area.width;
+		area.height = evnt.area.height;
+		Gdk.Rectangle alloc;
+		alloc.x = this.allocation.x;
+		alloc.y = this.allocation.y;
+		alloc.width = this.allocation.width;
+		alloc.height = this.allocation.height;
+		Gdk.Rectangle content_area;
+		content_area.x = alloc.x + (int) this.border_width;
+		content_area.y = alloc.y + (int) this.border_width;
+		content_area.width = alloc.width - 2 * (int) this.border_width;
+		content_area.height = alloc.height - 2 * (int) this.border_width;
+
+		cr.rectangle (area.x, area.y, area.width, area.height);
+		cr.clip ();
+		_theme.draw_tile (cr, alloc, content_area, this);
+		
+		draw_content (cr, content_area);
+		
+//		cr.target.dispose ();
+//		cr.dispose ();
+		
+//		return base.expose_event (evnt);
+		return false;
+	}
+
+	/**
+	 * Draws the content of the tile.
+	 *
+	 * @param context  Cairo context to be used to draw the content.
+	 * @param area     Area that can be painted.
+	 */
+	public abstract void draw_content (Cairo.Context context, Gdk.Rectangle area);
+
+	// TODO
+
+	protected override bool button_press_event (Gdk.EventButton evnt) {
+//		bool ret = base.button_press_event (evnt);
+		bool ret = false;
+		
+		queue_draw ();
+		return ret;
+	}
+	
+	protected override bool button_release_event (Gdk.EventButton evnt) {
+//		bool ret = base.button_release_event (evnt);
+		bool ret = false;
+		clicked ();
+		queue_draw ();
+		return ret;
+	}
+	
+	protected override bool enter_notify_event (Gdk.EventCrossing evnt) {
+//		bool ret = base.enter_notify_event (evnt);
+		bool ret = false;
+		
+		queue_draw ();
+		return ret;
+	}
+	
+	protected override bool leave_notify_event (Gdk.EventCrossing evnt) {
+//		bool ret = base.leave_notify_event (evnt);
+		bool ret = false;
+		
+		queue_draw ();
+		return ret;
+	}
+}
+

Added: trunk/ribbon/toggle-button.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/toggle-button.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,229 @@
+using Cairo;
+using Gtk;
+
+/** Toggle button to be used in Ribbons. */
+public class ToggleButton : BaseButton {
+
+	protected const double LINE_WIDTH = 1.0;
+
+	public signal void value_changed ();
+
+	private bool _value;
+	public bool value {
+		set {
+			if (_value != value) {
+				_value = value;
+				value_changed ();
+			}
+		}
+		get { return _value; }
+	}
+
+	/** Construction method */
+	construct {
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+		
+		this.padding = 2;
+		this.image_position = PositionType.TOP;
+		_is_small = false;
+		_enabled = true;
+		_value = false;
+	}
+
+	/**
+	 * Constructor given a label to display.
+	 *
+	 * @param label  Label to display.
+	 */
+	public ToggleButton.with_label (string label) {
+		this.label = label;
+	}
+
+	/**
+	 * Constructor given an image to display.
+	 *
+	 * @param image  Image to display
+	 */
+	public ToggleButton.with_image (Image image) {
+		this.image = image;
+	}
+
+	/**
+	 * Constructor given a label and an image to display.
+	 *
+	 * @param image  Image to display.
+	 * @param label  Label to display.
+	 */
+	public ToggleButton (Image image, string label) {
+		this.image = image;
+		this.label = label;
+	}
+
+	/**
+	 * Constructs a Button from a stock.
+	 *
+	 * @param name   Name of the stock.
+	 * @param large  <b>true</b> if the image should be large,
+	 *               <b>false</b> otherwise.
+	 */
+	public static ToggleButton from_stock (string name, bool large) {
+		var image = new Image.from_stock (name, large ? IconSize.LARGE_TOOLBAR
+													  : IconSize.SMALL_TOOLBAR);
+		var button = new ToggleButton.with_image (image);
+		if (!large) {
+			button.image_position = PositionType.LEFT;
+		}
+		return button;
+	}
+
+	/**
+	 * Constructs a Button from a stock.
+	 *
+	 * @param name   Name of the stock.
+	 * @param label  Label to display.
+	 * @param large  <b>true</b> if the image should be large,
+	 *               <b>false</b> otherwise.
+	 */
+	public static ToggleButton from_stock_with_label (string name, string label, bool large) {
+		var image = new Image.from_stock (name, large ? IconSize.LARGE_TOOLBAR
+													  : IconSize.SMALL_TOOLBAR);
+		var button = new ToggleButton (image, label);
+		if (!large) {
+			button.image_position = PositionType.LEFT;
+		}
+		return button;
+	}
+
+	protected override bool bound_widget_button_press_event (Widget sender,
+													Gdk.EventButton evnt) {
+		event ((Gdk.Event) evnt);
+		return false;
+	}
+
+	protected override bool bound_widget_button_release_event (Widget sender,
+													Gdk.EventButton evnt) {
+		event ((Gdk.Event) evnt);
+		this.value = !this.value;
+		queue_draw ();
+		return false;
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_request (requisition);
+
+		Requisition child_requisition = Requisition ();
+		if (this.child != null && this.child.visible) {
+			this.child.size_request (child_requisition);
+		}
+
+		if (this.height_request == -1) {
+			requisition.height = child_requisition.height
+									+ (int) (LINE_WIDTH * 4 + _padding * 2);
+		}
+		if (this.width_request == -1) {
+			requisition.width = child_requisition.width
+									+ (int) (LINE_WIDTH * 4 + _padding * 2);
+		}
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocate (allocation);
+		this.allocation = (Allocation) allocation;		// FIXME: workaround
+		
+		allocation.x += (int) (LINE_WIDTH * 2 + _padding);
+		allocation.y += (int) (LINE_WIDTH * 2 + _padding);
+		allocation.height -= (int) (LINE_WIDTH * 4 + _padding * 2);
+		allocation.width -= (int) (LINE_WIDTH * 4 + _padding * 2);
+
+		if (allocation.height < 0) {
+			allocation.height = 0;
+		}
+		if (allocation.width < 0) {
+			allocation.width = 0;
+		}
+
+		if (this.child != null && this.child.visible) {
+			this.child.size_allocate (allocation);
+		}
+	}
+
+	protected override bool expose_event (Gdk.EventExpose evnt) {
+		var cr = Gdk.cairo_create (this.window);
+
+		cr.rectangle (evnt.area.x, evnt.area.y,
+						evnt.area.width, evnt.area.height);
+		cr.clip ();
+		draw (cr);
+
+//		cr.target.dispose ();
+//		cr.dispose ();
+
+//		return base.expose_event (evnt);
+		// *** workaround ***
+		if (this.child != null) {
+			this.child.expose_event (evnt);
+		}
+		return false;
+		// *** workaround ***
+	}
+
+	protected void draw (Context cr) {
+		Gdk.Rectangle rect;
+		rect.x = this.allocation.x;
+		rect.y = this.allocation.y;
+		rect.width = this.allocation.width;
+		rect.height = this.allocation.height;
+		double round_size = _is_small ? 2.0 : 3.0;
+		var s = _state;
+		if (_value == true) {
+			s = Theme.ButtonState.PRESSED;
+		}
+		_theme.draw_button (cr, rect, s, round_size, LINE_WIDTH, 0, 0, false, this);
+	}
+
+	protected override bool button_press_event (Gdk.EventButton evnt) {
+//		bool ret = base.button_press_event (evnt);
+		bool ret = false;
+		_state = Theme.ButtonState.PRESSED;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool button_release_event (Gdk.EventButton evnt) {
+//		bool ret = base.button_release_event (evnt);
+		bool ret = false;
+		_state = Theme.ButtonState.HOVER;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool enter_notify_event (Gdk.EventCrossing evnt) {
+//		bool ret = base.enter_notify_event (evnt);
+		bool ret = false;
+		_state = Theme.ButtonState.HOVER;
+		if (!_enabled) {
+			_state = Theme.ButtonState.DEFAULT;
+		}
+		queue_draw ();
+		return ret;
+	}
+
+	protected override bool leave_notify_event (Gdk.EventCrossing evnt) {
+//		bool ret = base.leave_notify_event (evnt);
+		bool ret = false;
+		_state = Theme.ButtonState.DEFAULT;
+		queue_draw ();
+		return ret;
+	}
+}
+

Added: trunk/ribbon/tool-box.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/tool-box.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,243 @@
+using GLib;
+using Gee;
+using Gtk;
+
+/** ToolBox containing several widgets displayed in rows. */
+public class ToolBox : Container {
+
+	private Gee.List<Widget> _widgets;
+	private Gtk.Requisition[] _requisitions;
+
+	/** Gets or sets the spacing between children. */
+	private int _spacing;
+	public int spacing {
+		set {
+			_spacing = value;
+			queue_draw ();
+		}
+		get { return _spacing; }
+	}
+
+	/** Construction method */
+	construct {
+		_widgets = new Gee.ArrayList<Widget> ();
+
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+
+		_spacing = 2;
+	}
+	
+	/**
+	 * Adds a widget before all existing widgets.
+	 *
+	 * @param widget  The widget to add.
+	 */
+	public void prepend (Widget widget) {
+		insert (widget, 0);
+	}
+	
+	/**
+	 * Adds a widget after all existing widgets.
+	 *
+	 * @param widget  The widget to add.
+	 */
+	public void append (Widget widget) {
+		insert (widget, -1);
+	}
+	
+	/**
+	 * Inserts a widget at the specified location.
+	 *
+	 * @param widget  The widget to add.
+	 * @param index   The index (starting at 0) at which the widget must
+	 *                be inserted, or -1 to insert the widget after all
+	 *                existing widgets.
+	 */
+	public void insert (Widget widget, int index) {
+		widget.set_parent (this);
+		widget.visible = true;
+
+		if (index == -1) {
+			_widgets.add (widget);
+		} else {
+			_widgets.insert (index, widget);
+		}
+
+		show_all ();
+	}
+
+	/**
+	 * Removes the widget at the specified index.
+	 *
+	 * @param index  Index of the widget to remove.
+	 */
+	public void remove (int index) {
+		_widgets.get (index).parent = null;
+
+		if (index == -1) {
+			_widgets.remove_at (_widgets.size - 1);
+		} else {
+			_widgets.remove_at (index);
+		}
+		
+		show_all ();
+	}
+
+	protected override void forall (bool include_internals, Gtk.Callback callback) {
+		foreach (var widget in _widgets) {
+			if (widget.visible) {
+				callback (widget);
+			}
+		}
+	}
+
+	protected override void size_request (Requisition requisition) {
+//		base.size_request (requisition);
+
+		if (_requisitions == null || _requisitions.length != _widgets.size) {
+			_requisitions = new Gtk.Requisition[_widgets.size];
+		}
+
+		int total_width = 0;
+		int row_height = 0;
+		foreach (var widget in _widgets) {
+			if (widget.visible) {
+				Requisition req;
+				widget.size_request (req);
+				row_height = int.max (row_height, req.height);
+			}
+		}
+
+		int i = 0;
+		foreach (var widget in _widgets) {
+			if (widget.visible) {
+				widget.height_request = row_height;
+				// FIXME workaround
+				Requisition req;
+				widget.size_request (req);
+				_requisitions[i] = req;
+				// FIXME workaround
+				total_width += _requisitions[i].width;
+			}
+			++i;
+		}
+
+		if (this.width_request != -1 && this.height_request != -1) {
+			requisition.width = this.width_request;
+			requisition.height = this.height_request;
+		} else if (this.width_request != -1) {
+			int total_height = row_height;
+			int cur_width = 0;
+			int avail_width = this.width_request - 2 * (int) this.border_width;
+
+			i = 0;
+			foreach (var widget in _widgets) {
+				if (widget.visible) {
+					Gtk.Requisition r = _requisitions[i];
+
+					if (cur_width == 0 || cur_width + r.width <= avail_width) {
+						// Continue current line
+						cur_width += r.width;
+						if (cur_width != 0) {
+							cur_width += _spacing;
+						}
+					} else {
+						// Start new line
+						total_height += row_height + _spacing;
+						cur_width = 0;
+					}
+				}
+				++i;
+			}
+
+			requisition.width = this.width_request;
+			requisition.height = total_height + 2 * (int) this.border_width;
+		} else {
+			int rows_left = (int) Math.floor ((double) (this.height_request + _spacing)
+												/ (double) (row_height + _spacing));
+			if (rows_left == 0) {
+				rows_left = 1;
+			}
+			int width_left = total_width;
+			int cur_width = 0;
+			int max_width = 0;
+			int min_width = width_left / rows_left;
+			
+			i = 0;
+			int current_widget_counter = 0;
+			foreach (var widget in _widgets) {
+				if (widget.visible) {
+					Gtk.Requisition r = _requisitions[i];
+
+					width_left -= r.width;
+					cur_width += r.width;
+					++current_widget_counter;
+
+					if (cur_width >= min_width) {
+						// Start new line
+						cur_width += (current_widget_counter - 1) * _spacing;
+						max_width = int.max (max_width, cur_width);
+						cur_width = 0;
+						--rows_left;
+						if (rows_left == 0) {
+							break;
+						}
+						min_width = width_left / rows_left;
+						current_widget_counter = 0;
+					}
+				}
+				++i;
+			}
+
+			requisition.width = max_width + 2 * (int) this.border_width;
+
+			if (this.height_request == -1) {
+				requisition.height = row_height;
+			} else {
+				requisition.height = this.height_request;
+			}
+		}
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocated (allocation);
+		this.allocation = (Allocation) allocation;	// FIXME workaround
+
+		int right = allocation.x + allocation.width - (int) this.border_width;
+		int left = allocation.x + (int) this.border_width;
+		int bottom = allocation.y + allocation.height - (int) this.border_width;
+		int x = left;
+		int row_y = allocation.y + (int) this.border_width;
+		int max_height = 0;
+
+		int i = 0;
+		foreach (var widget in _widgets) {
+			if (widget.visible) {
+				Gdk.Rectangle r;
+				r.width = _requisitions[i].width;
+				r.height = _requisitions[i].height;
+
+				if (x > left && x + r.width > right) {
+					row_y += max_height + _spacing;
+					max_height = 0;
+					x = left;
+				}
+
+				r.x = x;
+				r.y = row_y;
+				r.width = int.min (right, r.x + r.width) - r.x;
+				r.height = int.min (bottom, r.y + r.height) - r.y;
+				widget.size_allocate (r);
+
+				x += r.width + _spacing;
+				max_height = int.max (max_height, r.height);
+			}
+			++i;
+		}
+	}
+}
+

Added: trunk/ribbon/tool-pack.vala
==============================================================================
--- (empty file)
+++ trunk/ribbon/tool-pack.vala	Mon Jul 21 19:46:42 2008
@@ -0,0 +1,163 @@
+using Gee;
+using Cairo;
+using Gtk;
+
+/** Set of ribbon buttons packed together. */
+public class ToolPack : Container {
+
+	private Gee.List<BaseButton> _buttons;
+	private int[] _widths;
+
+	/** Construction method */
+	construct {
+		_buttons = new Gee.ArrayList<BaseButton> ();
+		
+		set_flags (get_flags () | WidgetFlags.NO_WINDOW);
+
+		add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+					| Gdk.EventMask.BUTTON_RELEASE_MASK
+					| Gdk.EventMask.POINTER_MOTION_MASK);
+	}
+
+	/**
+	 * Adds a button before all existing buttons.
+	 *
+	 * @param widget  The button to add.
+	 */
+	public void PrependButton (BaseButton widget) {
+		insert_button (widget, 0);
+	}
+
+	/**
+	 * Adds a button after all existing buttons.
+	 *
+	 * @param widget  The button to add.
+	 */
+	public void append_button (BaseButton widget) {
+		insert_button (widget, -1);
+	}
+
+	/**
+	 * Inserts a button at the specified location.
+	 *
+	 * @param widget        The button to add.
+	 * @param button_index  The index (starting at 0) at which the button must
+	 *                      be inserted, or -1 to insert the button after all
+	 *                      existing buttons.
+	 */
+	public void insert_button (BaseButton widget, int button_index) {
+		widget.set_parent (this);
+		widget.visible = true;
+
+		widget.draw_background = true;
+
+		if (button_index == -1 || button_index == _buttons.size) {
+			if (_buttons.size == 0) {
+				widget.group_style = GroupStyle.ALONE;
+			} else {
+				widget.group_style = GroupStyle.RIGHT;
+
+				if (_buttons.size == 1) {
+					_buttons.get (_buttons.size - 1).group_style = GroupStyle.LEFT;
+				} else if (_buttons.size > 1) {
+					_buttons.get (_buttons.size - 1).group_style = GroupStyle.CENTER;
+				}
+			}
+			_buttons.add (widget);
+		} else {
+			if (button_index == 0) {
+				_buttons.get (_buttons.size - 1).group_style = GroupStyle.LEFT;
+				if (_buttons.size == 1) {
+					_buttons.get (0).group_style = GroupStyle.RIGHT;
+				} else {
+					_buttons.get (0).group_style = GroupStyle.CENTER;
+				}
+			}
+			_buttons.insert (button_index, widget);
+		}
+
+		show_all ();
+	}
+
+	/**
+	 * Removes the button at the specified index.
+	 *
+	 * @param button_index  Index of the button to remove.
+	 */
+	public void remove_button (int button_index) {
+		_buttons.get (button_index).parent = null;
+
+		if (button_index == 0) {
+			if (_buttons.size > 1) {
+				if (_buttons.size > 2) {
+					_buttons.get (0).group_style = GroupStyle.LEFT;
+				} else {
+					_buttons.get (0).group_style = GroupStyle.ALONE;
+				}
+			}
+		} else if (button_index == _buttons.size - 1) {
+			if (_buttons.size > 1) {
+				if (_buttons.size > 2) {
+					_buttons.get (0).group_style = GroupStyle.RIGHT;
+				} else {
+					_buttons.get (0).group_style = GroupStyle.ALONE;
+				}
+			}
+		}
+		_buttons.remove_at (button_index);
+
+		show_all ();
+	}
+
+	protected override void forall (bool include_internals, Gtk.Callback callback) {
+		foreach (var button in _buttons) {
+			if (button.visible) {
+				callback (button);
+			}
+		}
+	}
+	
+	protected override void size_request (Requisition requisition) {
+//		base.size_request (requisition);
+
+		if (_widths == null || _widths.length != _buttons.size) {
+			_widths = new int[_buttons.size];
+		}
+
+		requisition.height = requisition.width = 0;
+		int i = 0;
+		foreach (var button in _buttons) {
+			Gtk.Requisition req;
+			button.size_request (req);
+			if (requisition.height < req.height) {
+				requisition.height = req.height;
+			}
+			requisition.width += req.width;
+			_widths[i++] = req.width;
+		}
+		if (this.height_request != -1) {
+			requisition.height = this.height_request;
+		}
+		if (this.width_request != -1) {
+			requisition.width = this.width_request;
+		}
+	}
+
+	protected override void size_allocate (Gdk.Rectangle allocation) {
+//		base.size_allocate (allocation);
+		this.allocation = (Allocation) allocation;
+
+		int i = 0, x = allocation.x;
+		foreach (var button in _buttons) {
+			Gdk.Rectangle r;
+			r.x = x;
+			r.y = allocation.y;
+			r.width = _widths[i];
+			r.height = allocation.height;
+			button.size_allocate (r);
+			x += r.width;
+			++i;
+		}
+	}
+}
+



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