From 9a2a4c5ee028085dc0a8bc6113e501c09409153c Mon Sep 17 00:00:00 2001
From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com>
Date: Fri, 5 Aug 2005 06:32:53 +0000
Subject: [PATCH] Added MooPaned and MooFileView from junk
---
moo.kdevelop | 32 +-
moo/mooedit/mooedit-private.h | 10 +-
moo/mooedit/mooeditprefs.c | 2 +-
moo/mooutils/Makefile.am | 5 +
moo/mooutils/moofileview-icons.c | 319 ++++++
moo/mooutils/moofileview.c | 1179 ++++++++++++++++++++
moo/mooutils/moofileview.h | 88 ++
moo/mooutils/moomarshals.list | 1 +
moo/mooutils/moopaned.c | 1719 ++++++++++++++++++++++++++++++
moo/mooutils/moopaned.h | 78 ++
tests/Makefile.am | 21 +-
tests/testfileview.c | 25 +
tests/testpaned.c | 116 ++
13 files changed, 3570 insertions(+), 25 deletions(-)
create mode 100644 moo/mooutils/moofileview-icons.c
create mode 100644 moo/mooutils/moofileview.c
create mode 100644 moo/mooutils/moofileview.h
create mode 100644 moo/mooutils/moopaned.c
create mode 100644 moo/mooutils/moopaned.h
create mode 100644 tests/testfileview.c
create mode 100644 tests/testpaned.c
diff --git a/moo.kdevelop b/moo.kdevelop
index cbd3376c..b785f992 100644
--- a/moo.kdevelop
+++ b/moo.kdevelop
@@ -24,7 +24,7 @@
.
false
-
+
C
@@ -36,17 +36,17 @@
debug
- tests/editor
+ tests/testfileview
executable
/
-
+
false
false
- --enable-debug=full --enable-all-gcc-warnings=fatal --enable-developer-mode --disable-moo-module
+ --enable-debug=full --enable-all-gcc-warnings=fatal --enable-developer-mode --disable-moo-module --without-mooui --without-mooapp --without-mooterm --without-mooedit --without-python
build/debug
kdevgccoptions
kdevgppoptions
@@ -54,13 +54,13 @@
-O0 -g3 -pg
-O0 -g3 -pg
-
-
-
-
-
-
-
+
+
+
+
+
+
+
--enable-all-gcc-warnings=fatal --enable-developer-mode
@@ -166,10 +166,10 @@
libtool
--g-fatal-warnings --sync
-
-
-
-
+
+
+
+
true
false
true
@@ -270,7 +270,7 @@
-
+
set
m_,_
theValue
diff --git a/moo/mooedit/mooedit-private.h b/moo/mooedit/mooedit-private.h
index 35bd8652..907f7e0d 100644
--- a/moo/mooedit/mooedit-private.h
+++ b/moo/mooedit/mooedit-private.h
@@ -56,11 +56,11 @@ int _moo_edit_extend_selection (MooEdit *edit,
/* Preferences
/*/
void _moo_edit_set_default_settings (void);
-void _moo_edit_apply_settings (MooEdit *edit);
-void _moo_edit_apply_style_settings (MooEdit *edit);
-void _moo_edit_settings_changed (const char *key,
- const char *newval,
- MooEdit *edit);
+void _moo_edit_apply_settings (MooEdit *edit);
+void _moo_edit_apply_style_settings (MooEdit *edit);
+void _moo_edit_settings_changed (const char *key,
+ const GValue *newval,
+ MooEdit *edit);
/***********************************************************************/
/* File operations
diff --git a/moo/mooedit/mooeditprefs.c b/moo/mooedit/mooeditprefs.c
index 45f49277..20a46adc 100644
--- a/moo/mooedit/mooeditprefs.c
+++ b/moo/mooedit/mooeditprefs.c
@@ -162,7 +162,7 @@ void _moo_edit_apply_style_settings (MooEdit *edit)
void _moo_edit_settings_changed (const char *key,
- G_GNUC_UNUSED const char *newval,
+ G_GNUC_UNUSED const GValue *newval,
MooEdit *edit)
{
GtkSourceBuffer *buffer = edit->priv->source_buffer;
diff --git a/moo/mooutils/Makefile.am b/moo/mooutils/Makefile.am
index 8bcb3168..3ab3252c 100644
--- a/moo/mooutils/Makefile.am
+++ b/moo/mooutils/Makefile.am
@@ -48,12 +48,17 @@ libmooutils_la_SOURCES = \
moodialogs.h \
moofileutils.c \
moofileutils.h \
+ moofileview.c \
+ moofileview.h \
+ moofileview-icons.c \
moolog.c \
moolog.h \
moomarkup.c \
moomarkup.h \
mooobjectfactory.c \
mooobjectfactory.h \
+ moopaned.c \
+ moopaned.h \
mooparam.c \
mooparam.h \
mooprefs.c \
diff --git a/moo/mooutils/moofileview-icons.c b/moo/mooutils/moofileview-icons.c
new file mode 100644
index 00000000..20b033cb
--- /dev/null
+++ b/moo/mooutils/moofileview-icons.c
@@ -0,0 +1,319 @@
+/*
+ * mooutils/moofileview-icons.c
+ *
+ * Copyright (C) 2004-2005 by Yevgen Muntyan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See COPYING file that comes with this distribution.
+ */
+
+#include "mooutils/moofileview.h"
+#include
+#include
+#include
+
+
+/* Icon type, supplemented by MIME type
+ */
+typedef enum {
+ ICON_NOENT,
+ ICON_NONE, /* "Could not compute the icon type" */
+ ICON_REGULAR, /* Use mime type for icon */
+ ICON_BLOCK_DEVICE,
+ ICON_BROKEN_SYMBOLIC_LINK,
+ ICON_CHARACTER_DEVICE,
+ ICON_DIRECTORY,
+ ICON_EXECUTABLE,
+ ICON_FIFO,
+ ICON_SOCKET
+} IconType;
+
+
+typedef struct {
+ gint size;
+ GdkPixbuf *pixbuf;
+} IconCacheElement;
+
+static void icon_cache_element_free (IconCacheElement *element)
+{
+ if (element->pixbuf)
+ g_object_unref (element->pixbuf);
+ g_free (element);
+}
+
+static void icon_theme_changed (GtkIconTheme *icon_theme)
+{
+ GHashTable *cache;
+
+ /* Difference from the initial creation is that we don't
+ * reconnect the signal */
+ cache = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)icon_cache_element_free);
+ g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
+ cache, (GDestroyNotify)g_hash_table_destroy);
+}
+
+
+static IconType get_icon_type_from_stat (const struct stat *statp)
+{
+ if (S_ISBLK (statp->st_mode))
+ return ICON_BLOCK_DEVICE;
+ else if (S_ISLNK (statp->st_mode))
+ return ICON_BROKEN_SYMBOLIC_LINK; /* See get_icon_type */
+ else if (S_ISCHR (statp->st_mode))
+ return ICON_CHARACTER_DEVICE;
+ else if (S_ISDIR (statp->st_mode))
+ return ICON_DIRECTORY;
+#ifdef S_ISFIFO
+ else if (S_ISFIFO (statp->st_mode))
+ return ICON_FIFO;
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK (statp->st_mode))
+ return ICON_SOCKET;
+#endif
+ else
+ return ICON_REGULAR;
+}
+
+
+static IconType get_icon_type (MooFileViewFile *file)
+{
+ const struct stat *statp = moo_file_view_file_get_stat (file);
+ if (statp)
+ return get_icon_type_from_stat (statp);
+ else
+ return ICON_NOENT;
+}
+
+
+static GdkPixbuf *get_cached_icon (GtkWidget *widget,
+ const gchar *name,
+ gint pixel_size)
+{
+ GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
+ GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
+ IconCacheElement *element;
+
+ if (!cache)
+ {
+ cache = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)icon_cache_element_free);
+
+ g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
+ cache, (GDestroyNotify)g_hash_table_destroy);
+ g_signal_connect (icon_theme, "changed",
+ G_CALLBACK (icon_theme_changed), NULL);
+ }
+
+ element = g_hash_table_lookup (cache, name);
+ if (!element)
+ {
+ element = g_new0 (IconCacheElement, 1);
+ g_hash_table_insert (cache, g_strdup (name), element);
+ }
+
+ if (element->size != pixel_size)
+ {
+ if (element->pixbuf)
+ g_object_unref (element->pixbuf);
+ element->size = pixel_size;
+ element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
+ pixel_size, 0, NULL);
+ }
+
+ return element->pixbuf;
+}
+
+
+static GdkPixbuf *get_icon_for_mime_type (GtkWidget *widget,
+ const char *mime_type,
+ gint pixel_size)
+{
+ const char *separator;
+ GString *icon_name;
+ GdkPixbuf *pixbuf;
+
+ separator = strchr (mime_type, '/');
+ if (!separator)
+ return NULL; /* maybe we should return a GError with "invalid MIME-type" */
+
+ icon_name = g_string_new ("gnome-mime-");
+ g_string_append_len (icon_name, mime_type, separator - mime_type);
+ g_string_append_c (icon_name, '-');
+ g_string_append (icon_name, separator + 1);
+ pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
+ g_string_free (icon_name, TRUE);
+ if (pixbuf)
+ return pixbuf;
+
+ icon_name = g_string_new ("gnome-mime-");
+ g_string_append_len (icon_name, mime_type, separator - mime_type);
+ pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
+ g_string_free (icon_name, TRUE);
+
+ return pixbuf;
+}
+
+
+/* Returns the name of the icon to be used for a path which is known to be a
+ * directory. This can vary for Home, Desktop, etc.
+ */
+static const char *get_icon_name_for_directory (const char *path)
+{
+ static char *desktop_path = NULL;
+
+ if (!g_get_home_dir ())
+ return "gnome-fs-directory";
+
+ if (!desktop_path)
+ desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
+
+ if (strcmp (g_get_home_dir (), path) == 0)
+ return "gnome-fs-home";
+ else if (strcmp (desktop_path, path) == 0)
+ return "gnome-fs-desktop";
+ else
+ return "gnome-fs-directory";
+}
+
+
+/* Renders an icon for a non-ICON_REGULAR file */
+static GdkPixbuf *get_special_icon (IconType icon_type,
+ MooFileViewFile *file,
+ GtkWidget *widget,
+ gint pixel_size)
+{
+ const char *name;
+
+ g_assert (icon_type != ICON_REGULAR);
+
+ switch (icon_type)
+ {
+ case ICON_BLOCK_DEVICE:
+ name = "gnome-fs-blockdev";
+ break;
+ case ICON_BROKEN_SYMBOLIC_LINK:
+ name = "gnome-fs-symlink";
+ break;
+ case ICON_CHARACTER_DEVICE:
+ name = "gnome-fs-chardev";
+ break;
+ case ICON_DIRECTORY:
+ name = get_icon_name_for_directory
+ (moo_file_view_file_path (file));
+ break;
+ case ICON_EXECUTABLE:
+ name ="gnome-fs-executable";
+ break;
+ case ICON_FIFO:
+ name = "gnome-fs-fifo";
+ break;
+ case ICON_SOCKET:
+ name = "gnome-fs-socket";
+ break;
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ return get_cached_icon (widget, name, pixel_size);
+}
+
+
+/* Renders a fallback icon from the stock system */
+static GdkPixbuf *get_fallback_icon (GtkWidget *widget,
+ IconType icon_type,
+ GtkIconSize size)
+{
+ const char *stock_name;
+ GdkPixbuf *pixbuf;
+
+ switch (icon_type)
+ {
+ case ICON_BLOCK_DEVICE:
+ stock_name = GTK_STOCK_HARDDISK;
+ break;
+
+ case ICON_DIRECTORY:
+ stock_name = GTK_STOCK_DIRECTORY;
+ break;
+
+ case ICON_EXECUTABLE:
+ stock_name = GTK_STOCK_EXECUTE;
+ break;
+
+ case ICON_NOENT:
+ stock_name = GTK_STOCK_MISSING_IMAGE;
+ break;
+
+ default:
+ stock_name = GTK_STOCK_FILE;
+ break;
+ }
+
+ pixbuf = gtk_widget_render_icon (widget, stock_name, size, NULL);
+
+ if (!pixbuf)
+ {
+ g_warning ("%s: could not get a stock icon for %s",
+ G_STRLOC, stock_name);
+ }
+
+ return pixbuf;
+}
+
+
+GdkPixbuf *moo_get_icon_for_file (GtkWidget *widget,
+ MooFileViewFile *file,
+ GtkIconSize size)
+{
+ IconType icon_type;
+ GdkPixbuf *pixbuf;
+ int pixel_size;
+
+ icon_type = get_icon_type (file);
+
+ if (icon_type == ICON_REGULAR && !moo_file_view_file_mime_type (file))
+ icon_type = ICON_NONE;
+
+ if (!gtk_icon_size_lookup (size, &pixel_size, NULL))
+ if (!gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &pixel_size, NULL))
+ pixel_size = 16;
+
+ switch (icon_type)
+ {
+ case ICON_NONE:
+ goto fallback;
+
+ case ICON_NOENT:
+ pixbuf = get_fallback_icon (widget, icon_type, size);
+ break;
+
+ case ICON_REGULAR:
+ pixbuf = get_icon_for_mime_type (widget,
+ moo_file_view_file_mime_type (file),
+ pixel_size);
+ break;
+
+ default:
+ pixbuf = get_special_icon (icon_type, file, widget, pixel_size);
+ }
+
+ if (pixbuf)
+ goto out;
+
+fallback:
+ pixbuf = get_cached_icon (widget, "gnome-fs-regular", pixel_size);
+ if (!pixbuf)
+ pixbuf = get_fallback_icon (widget, icon_type, size);
+
+out:
+ return pixbuf;
+}
diff --git a/moo/mooutils/moofileview.c b/moo/mooutils/moofileview.c
new file mode 100644
index 00000000..19440b71
--- /dev/null
+++ b/moo/mooutils/moofileview.c
@@ -0,0 +1,1179 @@
+/*
+ * mooutils/moofileview.c
+ *
+ * Copyright (C) 2004-2005 by Yevgen Muntyan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See COPYING file that comes with this distribution.
+ */
+
+#include "mooutils/moofileview.h"
+#include "mooutils/moomarshals.h"
+#include
+#include
+#include
+#include
+#include
+
+
+#define TREEVIEW_UPDATE_TIMEOUT 0.5
+
+enum {
+ TREEVIEW_PAGE = 0,
+ ICONVIEW_PAGE = 1
+};
+
+
+typedef struct _History History;
+
+struct _MooFileViewFile {
+ char *basename;
+ char *fullname;
+ char *uri;
+ char *display_name;
+ char *mime_type;
+ GdkPixbuf *pixbuf;
+ gboolean is_dir;
+ struct stat statbuf;
+ gboolean exists;
+ gpointer time; /* struct tm* */
+ gpointer date_string;
+ guint size;
+ guint ref_count;
+};
+
+struct _MooFileViewPrivate {
+ GtkListStore *store;
+ GtkTreeModel *filter_model;
+ MooFileViewType view_type;
+ GtkWidget *treeview;
+ GtkWidget *iconview;
+ char *current_dir;
+ gboolean show_hidden_files;
+ History *history;
+ guint populate_idle;
+ GDir *populate_dir;
+};
+
+
+static MooFileViewFile *file_new (MooFileView *fileview,
+ const char *basename,
+ const char *fullname);
+static MooFileViewFile *file_ref (MooFileViewFile *file);
+static void file_unref (MooFileViewFile *file);
+
+
+static void moo_file_view_finalize (GObject *object);
+
+static gboolean moo_file_view_chdir_real(MooFileView *fileview,
+ const char *dir,
+ GError **error);
+static void moo_file_view_go_up (MooFileView *fileview);
+static void moo_file_view_go_home (MooFileView *fileview);
+static void moo_file_view_go_back (MooFileView *fileview);
+static void moo_file_view_go_forward(MooFileView *fileview);
+
+static void history_init (MooFileView *fileview);
+static void history_free (MooFileView *fileview);
+static void history_goto (MooFileView *fileview,
+ const char *dirname);
+static const char *history_go (MooFileView *fileview,
+ GtkDirectionType where);
+static void history_revert_go (MooFileView *fileview);
+
+static gboolean populate_tree (MooFileView *fileview,
+ GError **error);
+static gboolean filter_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ MooFileView *fileview);
+static int tree_compare_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b);
+
+static void init_gui (MooFileView *fileview);
+static GtkWidget *create_toolbar (MooFileView *fileview);
+static void toolbar_button_clicked (GtkToolButton *button,
+ MooFileView *fileview);
+static GtkWidget *create_notebook (MooFileView *fileview);
+static GtkWidget *create_filter_combo (MooFileView *fileview);
+
+static GtkWidget *create_treeview (MooFileView *fileview);
+static void tree_row_activated (GtkTreeView *treeview,
+ GtkTreePath *treepath,
+ GtkTreeViewColumn *column,
+ MooFileView *fileview);
+
+static GtkWidget *create_iconview (MooFileView *fileview);
+static void icon_item_activated (GtkIconView *iconview,
+ GtkTreePath *treepath,
+ MooFileView *fileview);
+
+static void get_icon (MooFileView *fileview,
+ MooFileViewFile*file);
+
+
+/* MOO_TYPE_FILE_VIEW */
+G_DEFINE_TYPE (MooFileView, moo_file_view, GTK_TYPE_VBOX)
+
+enum {
+ PROP_0,
+ PROP_DIRECTORY
+};
+
+enum {
+ COLUMN_FILE = 0,
+ COLUMN_PIXBUF = 1,
+ COLUMN_DISPLAY_NAME = 2,
+ COLUMN_SIZE = 3,
+ COLUMN_DATE = 4
+};
+
+enum {
+ CHDIR,
+ ACTIVATE,
+ GO_UP,
+ GO_BACK,
+ GO_FORWARD,
+ GO_HOME,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void moo_file_view_class_init (MooFileViewClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkBindingSet *binding_set;
+
+ gobject_class->finalize = moo_file_view_finalize;
+
+ klass->chdir = moo_file_view_chdir_real;
+ klass->go_up = moo_file_view_go_up;
+ klass->go_home = moo_file_view_go_home;
+ klass->go_back = moo_file_view_go_back;
+ klass->go_forward = moo_file_view_go_forward;
+
+ signals[CHDIR] = g_signal_new ("chdir",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (MooFileViewClass, chdir),
+ NULL, NULL,
+ _moo_marshal_BOOLEAN__STRING_POINTER,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_POINTER);
+
+ signals[ACTIVATE] = g_signal_new ("activate",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (MooFileViewClass, activate),
+ NULL, NULL,
+ _moo_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ MOO_TYPE_FILE_VIEW_FILE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ signals[GO_UP] = g_signal_new ("go-up",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (MooFileViewClass, go_up),
+ NULL, NULL,
+ _moo_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[GO_FORWARD] = g_signal_new ("go-forward",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (MooFileViewClass, go_forward),
+ NULL, NULL,
+ _moo_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[GO_BACK] = g_signal_new ("go-back",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (MooFileViewClass, go_back),
+ NULL, NULL,
+ _moo_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[GO_HOME] = g_signal_new ("go-home",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (MooFileViewClass, go_home),
+ NULL, NULL,
+ _moo_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ binding_set = gtk_binding_set_by_class (klass);
+
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_Up, GDK_MOD1_MASK,
+ "go-up",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Up, GDK_MOD1_MASK,
+ "go-up",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_Left, GDK_MOD1_MASK,
+ "go-back",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Left, GDK_MOD1_MASK,
+ "go-back",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_Right, GDK_MOD1_MASK,
+ "go-forward",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Right, GDK_MOD1_MASK,
+ "go-forward",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_Home, GDK_MOD1_MASK,
+ "home-folder",
+ 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Home, GDK_MOD1_MASK,
+ "home-folder",
+ 0);
+}
+
+
+static void moo_file_view_init (MooFileView *fileview)
+{
+ fileview->priv = g_new0 (MooFileViewPrivate, 1);
+
+ fileview->priv->current_dir = NULL;
+ fileview->priv->show_hidden_files = FALSE;
+
+ fileview->priv->view_type = MOO_FILE_VIEW_LIST;
+
+ history_init (fileview);
+
+ fileview->priv->store =
+ gtk_list_store_new (5,
+ MOO_TYPE_FILE_VIEW_FILE,
+ GDK_TYPE_PIXBUF,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (fileview->priv->store),
+ COLUMN_FILE,
+ (GtkTreeIterCompareFunc) tree_compare_func,
+ fileview, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (fileview->priv->store),
+ COLUMN_FILE, GTK_SORT_ASCENDING);
+
+ fileview->priv->filter_model =
+ gtk_tree_model_filter_new (GTK_TREE_MODEL (fileview->priv->store),
+ NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (fileview->priv->filter_model),
+ (GtkTreeModelFilterVisibleFunc) filter_visible_func,
+ fileview, NULL);
+
+ init_gui (fileview);
+}
+
+
+static void moo_file_view_finalize (GObject *object)
+{
+ MooFileView *fileview = MOO_FILE_VIEW (object);
+
+ g_object_unref (fileview->priv->filter_model);
+ g_object_unref (fileview->priv->store);
+
+ history_free (fileview);
+
+ g_free (fileview->priv->current_dir);
+
+ g_free (fileview->priv);
+
+ G_OBJECT_CLASS (moo_file_view_parent_class)->finalize (object);
+}
+
+
+GtkWidget *moo_file_view_new (void)
+{
+ return GTK_WIDGET (g_object_new (MOO_TYPE_FILE_VIEW, NULL));
+}
+
+
+static gboolean moo_file_view_chdir_real(MooFileView *fileview,
+ const char *new_dir,
+ GError **error)
+{
+ char *real_new_dir;
+
+ g_return_val_if_fail (MOO_IS_FILE_VIEW (fileview), FALSE);
+ g_return_val_if_fail (new_dir != NULL, FALSE);
+
+ if (fileview->priv->current_dir && !strcmp (fileview->priv->current_dir, new_dir))
+ return TRUE;
+
+ if (g_path_is_absolute (new_dir))
+ {
+ real_new_dir = g_strdup (new_dir);
+ }
+ else
+ {
+ char *current_dir = g_get_current_dir ();
+ real_new_dir = g_build_filename (current_dir, new_dir);
+ }
+
+ if (!g_file_test (real_new_dir, G_FILE_TEST_IS_DIR))
+ {
+ g_set_error (error,
+ G_FILE_ERROR,
+ G_FILE_ERROR_NOTDIR,
+ "'%s' is not a directory",
+ real_new_dir);
+ g_free (real_new_dir);
+ return FALSE;
+ }
+
+ g_free (fileview->priv->current_dir);
+ fileview->priv->current_dir = real_new_dir;
+
+ history_goto (fileview, real_new_dir);
+
+ gtk_list_store_clear (fileview->priv->store);
+ return populate_tree (fileview, error);
+}
+
+
+static void init_gui (MooFileView *fileview)
+{
+ GtkBox *box;
+ GtkWidget *toolbar, *notebook, *filter_combo;
+
+ box = GTK_BOX (fileview);
+
+ toolbar = create_toolbar (fileview);
+ gtk_widget_show (toolbar);
+ gtk_box_pack_start (box, toolbar, FALSE, FALSE, 0);
+
+ notebook = create_notebook (fileview);
+ gtk_widget_show (notebook);
+ gtk_box_pack_start (box, notebook, TRUE, TRUE, 0);
+
+ filter_combo = create_filter_combo (fileview);
+ gtk_widget_show (filter_combo);
+ gtk_box_pack_start (box, filter_combo, FALSE, FALSE, 0);
+
+ if (fileview->priv->view_type == MOO_FILE_VIEW_ICON)
+ {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook),
+ ICONVIEW_PAGE);
+ gtk_widget_grab_focus (fileview->priv->iconview);
+ }
+ else
+ {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook),
+ TREEVIEW_PAGE);
+ gtk_widget_grab_focus (fileview->priv->treeview);
+ }
+}
+
+
+static GtkWidget *create_toolbar (MooFileView *fileview)
+{
+ GtkWidget *toolbar, *icon;
+ GtkToolItem *item;
+ GtkTooltips *tooltips;
+
+ tooltips = gtk_tooltips_new ();
+
+ /*********************************************************/
+ /* Navigation toolbar */
+
+ toolbar = gtk_toolbar_new ();
+ gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE);
+ gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar),
+ GTK_ICON_SIZE_MENU);
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_ICONS);
+
+ /* Up */
+ icon = gtk_image_new_from_stock (GTK_STOCK_GO_UP,
+ GTK_ICON_SIZE_MENU);
+ item = gtk_tool_button_new (icon, NULL);
+ gtk_tool_item_set_tooltip (item, tooltips, "Up", "Up");
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ g_object_set_data (G_OBJECT (item), "moo-file-view-signal",
+ (gpointer) "go-up");
+ g_signal_connect (item, "clicked",
+ G_CALLBACK (toolbar_button_clicked),
+ fileview);
+
+ /* Back */
+ icon = gtk_image_new_from_stock (GTK_STOCK_GO_BACK,
+ GTK_ICON_SIZE_MENU);
+ item = gtk_tool_button_new (icon, NULL);
+ gtk_tool_item_set_tooltip (item, tooltips, "Back", "Back");
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ g_object_set_data (G_OBJECT (item), "moo-file-view-signal",
+ (gpointer) "go-back");
+ g_signal_connect (item, "clicked",
+ G_CALLBACK (toolbar_button_clicked),
+ fileview);
+
+ /* Forward */
+ icon = gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,
+ GTK_ICON_SIZE_MENU);
+ item = gtk_tool_button_new (icon, NULL);
+ gtk_tool_item_set_tooltip (item, tooltips, "Forward", "Forward");
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ g_object_set_data (G_OBJECT (item), "moo-file-view-signal",
+ (gpointer) "go-forward");
+ g_signal_connect (item, "clicked",
+ G_CALLBACK (toolbar_button_clicked),
+ fileview);
+
+ /* Home */
+ icon = gtk_image_new_from_stock (GTK_STOCK_HOME,
+ GTK_ICON_SIZE_MENU);
+ item = gtk_tool_button_new (icon, NULL);
+ gtk_tool_item_set_tooltip (item, tooltips, "Home", "Home");
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ g_object_set_data (G_OBJECT (item), "moo-file-view-signal",
+ (gpointer) "go-home");
+ g_signal_connect (item, "clicked",
+ G_CALLBACK (toolbar_button_clicked),
+ fileview);
+
+ return toolbar;
+}
+
+
+static void toolbar_button_clicked (GtkToolButton *button,
+ MooFileView *fileview)
+{
+ const char *signal = g_object_get_data (G_OBJECT (button),
+ "moo-file-view-signal");
+ g_return_if_fail (signal != NULL);
+ g_signal_emit_by_name (fileview, signal);
+}
+
+
+static GtkWidget *create_notebook (MooFileView *fileview)
+{
+ GtkWidget *notebook, *swin, *treeview, *iconview;
+
+ notebook = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
+
+ swin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (swin);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swin, NULL);
+ fileview->priv->treeview = treeview = create_treeview (fileview);
+ gtk_widget_show (treeview);
+ gtk_container_add (GTK_CONTAINER (swin), treeview);
+
+ swin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (swin);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swin, NULL);
+ fileview->priv->iconview = iconview = create_iconview (fileview);
+ gtk_widget_show (iconview);
+ gtk_container_add (GTK_CONTAINER (swin), iconview);
+
+ return notebook;
+}
+
+
+static GtkWidget *create_filter_combo (G_GNUC_UNUSED MooFileView *fileview)
+{
+ GtkWidget *hbox, *button, *combo;
+
+ hbox = gtk_hbox_new (FALSE, 0);
+
+ button = gtk_toggle_button_new_with_label ("Filter");
+ gtk_widget_show (button);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ combo = gtk_combo_box_entry_new ();
+ gtk_widget_show (combo);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
+
+ return hbox;
+}
+
+
+static GtkWidget *create_treeview (MooFileView *fileview)
+{
+ GtkWidget *treeview;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+
+ treeview = gtk_tree_view_new_with_model (fileview->priv->filter_model);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), COLUMN_DISPLAY_NAME);
+
+ g_signal_connect (treeview, "row-activated",
+ G_CALLBACK (tree_row_activated), fileview);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, "Name");
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "pixbuf", COLUMN_PIXBUF,
+ NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "text", COLUMN_DISPLAY_NAME,
+ NULL);
+
+#if 0
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, "Size");
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "text", COLUMN_SIZE,
+ NULL);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, "Date");
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "text", COLUMN_DATE,
+ NULL);
+#endif
+
+ return treeview;
+}
+
+
+static void get_icon (MooFileView *fileview,
+ MooFileViewFile*file)
+{
+ GdkPixbuf *pixbuf = NULL;
+
+ g_return_if_fail (file != NULL);
+
+ pixbuf = moo_get_icon_for_file (GTK_WIDGET (fileview), file,
+ GTK_ICON_SIZE_MENU);
+
+ if (file->pixbuf)
+ g_object_unref (file->pixbuf);
+
+ if (pixbuf)
+ file->pixbuf = g_object_ref (pixbuf);
+ else
+ file->pixbuf = NULL;
+}
+
+
+#define MAX_DATE_LEN 1024
+static gboolean populate_a_bit (MooFileView *fileview)
+{
+ const char *path;
+ const char *name;
+ GDir *dir;
+ GtkTreeIter iter;
+ GTimer *timer;
+ gboolean done = FALSE;
+
+ dir = fileview->priv->populate_dir;
+ path = fileview->priv->current_dir;
+
+ if (!dir || !path)
+ {
+ fileview->priv->populate_idle = 0;
+ g_dir_close (fileview->priv->populate_dir);
+ fileview->priv->populate_dir = NULL;
+ g_return_val_if_reached (FALSE);
+ }
+
+ timer = g_timer_new ();
+
+ while (TRUE)
+ {
+ char *fullname;
+ char *size = NULL;
+ MooFileViewFile *file;
+
+ name = g_dir_read_name (dir);
+
+ if (!name)
+ {
+ done = TRUE;
+ break;
+ }
+
+ fullname = g_build_filename (path, name, NULL);
+
+ file = file_new (fileview, name, fullname);
+ size = g_strdup_printf ("%d", file->size);
+
+ gtk_list_store_append (fileview->priv->store, &iter);
+ gtk_list_store_set (fileview->priv->store, &iter,
+ COLUMN_FILE, file,
+ COLUMN_DISPLAY_NAME, file->display_name,
+ COLUMN_PIXBUF, file->pixbuf,
+ COLUMN_SIZE, size,
+ COLUMN_DATE, file->date_string,
+ -1);
+
+ file_unref (file);
+ g_free (fullname);
+ g_free (size);
+
+ if (g_timer_elapsed (timer, NULL) > TREEVIEW_UPDATE_TIMEOUT)
+ break;
+ }
+
+ g_timer_destroy (timer);
+
+ if (done)
+ {
+ fileview->priv->populate_idle = 0;
+ g_dir_close (fileview->priv->populate_dir);
+ fileview->priv->populate_dir = NULL;
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+#undef MAX_DATE_LEN
+
+
+static gboolean populate_tree (MooFileView *fileview,
+ GError **error)
+{
+ const char *path = fileview->priv->current_dir;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ if (fileview->priv->populate_idle)
+ {
+ g_source_remove (fileview->priv->populate_idle);
+ fileview->priv->populate_idle = 0;
+ g_dir_close (fileview->priv->populate_dir);
+ }
+
+ fileview->priv->populate_dir = g_dir_open (path, 0, error);
+ if (!fileview->priv->populate_dir) return FALSE;
+
+ if (populate_a_bit (fileview))
+ fileview->priv->populate_idle =
+ g_idle_add ((GSourceFunc) populate_a_bit, fileview);
+
+ if (gtk_tree_model_get_iter_first (fileview->priv->filter_model, &iter))
+ {
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fileview->priv->treeview));
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+
+ return TRUE;
+}
+
+
+static gboolean filter_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ MooFileView *fileview)
+{
+ MooFileViewFile *file;
+ gboolean visible = TRUE;
+
+ gtk_tree_model_get (model, iter, COLUMN_FILE, &file, -1);
+
+ if (!file)
+ {
+ visible = FALSE;
+ goto out;
+ }
+
+ if (!fileview->priv->show_hidden_files && file->basename[0] == '.')
+ {
+ visible = FALSE;
+ goto out;
+ }
+
+out:
+ file_unref (file);
+ return visible;
+}
+
+
+static int tree_compare_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b)
+{
+ MooFileViewFile *f1, *f2;
+ gboolean result = 0;
+
+ gtk_tree_model_get (model, a, COLUMN_FILE, &f1, -1);
+ gtk_tree_model_get (model, b, COLUMN_FILE, &f2, -1);
+
+ if (!f1 || !f2)
+ {
+ if (f1 < f2)
+ result = -1;
+ else if (f1 == f2)
+ result = 0;
+ else
+ result = 1;
+ goto out;
+ }
+
+ if (f1->is_dir != f2->is_dir)
+ {
+ if (f1->is_dir && !f2->is_dir)
+ result = -1;
+ else
+ result = 1;
+ goto out;
+ }
+
+ result = strcmp (f1->basename, f2->basename);
+
+out:
+ file_unref (f1);
+ file_unref (f2);
+ return result;
+}
+
+
+static MooFileViewFile *file_new (MooFileView *fileview,
+ const char *basename,
+ const char *fullname)
+{
+ MooFileViewFile *file;
+
+ g_return_val_if_fail (basename != NULL, NULL);
+ g_return_val_if_fail (fullname != NULL, NULL);
+
+ file = g_new (MooFileViewFile, 1);
+ file->ref_count = 1;
+
+ file->basename = g_strdup (basename);
+ file->fullname = g_strdup (fullname);
+ file->uri = g_strdup_printf ("file://%s", fullname);
+ file->display_name = g_filename_display_basename (basename);
+ file->mime_type = NULL;
+
+ file->time = NULL; /* struct tm* */
+ file->date_string = NULL;
+ file->size = 0;
+
+ file->is_dir = FALSE;
+ file->exists = TRUE;
+
+ if (g_stat (fullname, &file->statbuf) != 0)
+ {
+ if (errno == ENOENT)
+ {
+ gchar *display_name = g_filename_display_name (fullname);
+ g_warning ("%s: file '%s' doesn't exist",
+ G_STRLOC, display_name);
+ g_free (display_name);
+ file->exists = FALSE;
+ }
+ else if (g_lstat (fullname, &file->statbuf) != 0)
+ {
+ int save_errno = errno;
+ gchar *display_name = g_filename_display_name (fullname);
+ g_warning ("%s: error getting information for '%s': %s",
+ G_STRLOC, display_name,
+ g_strerror (save_errno));
+ g_free (display_name);
+ file->exists = FALSE;
+ }
+ }
+
+ if (file->exists)
+ {
+ if (S_ISDIR (file->statbuf.st_mode))
+ file->is_dir = TRUE;
+ }
+
+ file->pixbuf = NULL;
+ get_icon (fileview, file);
+
+ return file;
+}
+
+
+static MooFileViewFile *file_ref (MooFileViewFile *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+ file->ref_count++;
+ return file;
+}
+
+
+static void file_unref (MooFileViewFile *file)
+{
+ if (file && !--file->ref_count)
+ {
+ g_free (file->basename);
+ g_free (file->fullname);
+ g_free (file->uri);
+ g_free (file->display_name);
+ g_free (file->mime_type);
+ if (file->pixbuf) g_object_unref (file->pixbuf);
+ g_free (file->time); /* struct tm* */
+ g_free (file->date_string);
+ g_free (file);
+ }
+}
+
+
+GType moo_file_view_file_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ type = g_boxed_type_register_static ("MooFileViewFile",
+ (GBoxedCopyFunc) file_ref,
+ (GBoxedFreeFunc) file_unref);
+ }
+
+ return type;
+}
+
+
+gboolean moo_file_view_chdir (MooFileView *fileview,
+ const char *dir,
+ GError **error)
+{
+ gboolean result;
+
+ g_return_val_if_fail (MOO_IS_FILE_VIEW (fileview), FALSE);
+ g_return_val_if_fail (dir != NULL, FALSE);
+
+ g_signal_emit (fileview, signals[CHDIR], 0, dir, error, &result);
+
+ return result;
+}
+
+
+static void moo_file_view_go_up (MooFileView *fileview)
+{
+ char *dirname;
+ GError *error = NULL;
+
+ dirname = g_path_get_dirname (fileview->priv->current_dir);
+
+ if (!moo_file_view_chdir (fileview, dirname, &error))
+ {
+ g_warning ("%s: could not go up", G_STRLOC);
+
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ }
+ }
+
+ g_free (dirname);
+}
+
+
+static void moo_file_view_go_home (MooFileView *fileview)
+{
+ const char *dir;
+ GError *error = NULL;
+
+ dir = g_get_home_dir ();
+
+ if (!moo_file_view_chdir (fileview, dir, &error))
+ {
+ g_warning ("%s: could not go up", G_STRLOC);
+
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ }
+ }
+}
+
+
+static void tree_path_activated (MooFileView *fileview,
+ GtkTreePath *filter_treepath)
+{
+ GtkTreePath *treepath = NULL;
+ MooFileViewFile *file = NULL;
+ GtkTreeIter iter;
+
+ treepath = gtk_tree_model_filter_convert_path_to_child_path (
+ GTK_TREE_MODEL_FILTER (fileview->priv->filter_model), filter_treepath);
+ g_return_if_fail (treepath != NULL);
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (fileview->priv->store),
+ &iter, treepath))
+ {
+ gtk_tree_path_free (treepath);
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (fileview->priv->store),
+ &iter, COLUMN_FILE, &file, -1);
+ if (!file)
+ {
+ gtk_tree_path_free (treepath);
+ g_return_if_reached ();
+ }
+
+ if (file->is_dir)
+ {
+ GError *error = NULL;
+
+ if (!moo_file_view_chdir (fileview, file->fullname, &error))
+ {
+ g_warning ("%s: could not go into '%s'",
+ G_STRLOC, file->fullname);
+
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ }
+ }
+ }
+ else
+ {
+ g_signal_emit (fileview, signals[ACTIVATE], 0, file);
+ }
+
+ gtk_tree_path_free (treepath);
+ file_unref (file);
+}
+
+
+static void tree_row_activated (G_GNUC_UNUSED GtkTreeView *treeview,
+ GtkTreePath *filter_treepath,
+ G_GNUC_UNUSED GtkTreeViewColumn *column,
+ MooFileView *fileview)
+{
+ tree_path_activated (fileview, filter_treepath);
+}
+
+
+static void icon_item_activated (G_GNUC_UNUSED GtkIconView *iconview,
+ GtkTreePath *filter_treepath,
+ MooFileView *fileview)
+{
+ tree_path_activated (fileview, filter_treepath);
+}
+
+
+static void moo_file_view_go (MooFileView *fileview,
+ GtkDirectionType where)
+{
+ const char *dir;
+ GError *error = NULL;
+
+ dir = history_go (fileview, where);
+
+ if (dir)
+ {
+ if (!moo_file_view_chdir (fileview, dir, &error))
+ {
+ g_warning ("%s: could not go into '%s'",
+ G_STRLOC, dir);
+
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ }
+
+ history_revert_go (fileview);
+ }
+ }
+}
+
+
+static void moo_file_view_go_back (MooFileView *fileview)
+{
+ moo_file_view_go (fileview, GTK_DIR_LEFT);
+}
+
+
+static void moo_file_view_go_forward(MooFileView *fileview)
+{
+ moo_file_view_go (fileview, GTK_DIR_RIGHT);
+}
+
+
+struct _History {
+ gboolean done;
+ GtkDirectionType direction;
+
+ GList *list;
+ GList *current;
+};
+
+
+static void history_init (MooFileView *fileview)
+{
+ History *hist;
+
+ fileview->priv->history = hist = g_new0 (History, 1);
+}
+
+
+static void history_free (MooFileView *fileview)
+{
+ g_list_foreach (fileview->priv->history->list, (GFunc) g_free, NULL);
+ g_list_free (fileview->priv->history->list);
+ g_free (fileview->priv->history);
+ fileview->priv->history = NULL;
+}
+
+
+static const char *history_go (MooFileView *fileview,
+ GtkDirectionType where)
+{
+ History *hist = fileview->priv->history;
+ const char *dir;
+
+ g_assert (where == GTK_DIR_LEFT || where == GTK_DIR_RIGHT);
+
+ if (!hist->current)
+ return NULL;
+
+ if (where == GTK_DIR_RIGHT)
+ {
+ if (!hist->current->next)
+ return NULL;
+
+ dir = hist->current->next->data;
+ hist->current = hist->current->next;
+ }
+ else
+ {
+ if (!hist->current->prev)
+ return NULL;
+ dir = hist->current->prev->data;
+ hist->current = hist->current->prev;
+ }
+
+ hist->done = TRUE;
+ hist->direction = where;
+ return dir;
+}
+
+
+static void history_revert_go (MooFileView *fileview)
+{
+ History *hist = fileview->priv->history;
+
+ g_assert (hist->done);
+
+ if (hist->direction == GTK_DIR_LEFT)
+ {
+ g_assert (hist->current && hist->current->next);
+ hist->current = hist->current->next;
+ }
+ else
+ {
+ g_assert (hist->current && hist->current->prev);
+ hist->current = hist->current->prev;
+ }
+
+ hist->done = FALSE;
+}
+
+
+static void history_goto (MooFileView *fileview,
+ const char *dirname)
+{
+ History *hist = fileview->priv->history;
+
+ g_return_if_fail (dirname != NULL);
+
+ if (hist->done)
+ {
+ hist->done = FALSE;
+ return;
+ }
+
+ if (hist->current && hist->current->next)
+ {
+ GList *l;
+ for (l = hist->current->next; l != NULL; l = l->next)
+ g_free (l->data);
+ l = hist->current->next;
+ hist->current->next = NULL;
+ g_list_free (l);
+ }
+
+ if (!hist->current || strcmp (dirname, (char*) hist->current))
+ {
+ hist->list = g_list_append (hist->list, g_strdup (dirname));
+ hist->current = g_list_last (hist->list);
+ }
+}
+
+
+static GtkWidget *create_iconview (MooFileView *fileview)
+{
+ GtkWidget *iconview;
+
+ iconview = gtk_icon_view_new_with_model (fileview->priv->filter_model);
+ gtk_icon_view_set_text_column (GTK_ICON_VIEW (iconview),
+ COLUMN_DISPLAY_NAME);
+ gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (iconview),
+ COLUMN_PIXBUF);
+ gtk_icon_view_set_orientation (GTK_ICON_VIEW (iconview),
+ GTK_ORIENTATION_HORIZONTAL);
+
+ g_signal_connect (iconview, "item-activated",
+ G_CALLBACK (icon_item_activated), fileview);
+
+ return iconview;
+}
+
+
+gconstpointer moo_file_view_file_get_stat (MooFileViewFile *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+ if (file->exists)
+ return &file->statbuf;
+ else
+ return NULL;
+}
+
+
+const char *moo_file_view_file_path (MooFileViewFile *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+ return file->fullname;
+}
+
+
+const char *moo_file_view_file_mime_type (MooFileViewFile *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+ return file->mime_type;
+}
diff --git a/moo/mooutils/moofileview.h b/moo/mooutils/moofileview.h
new file mode 100644
index 00000000..4e7c3bca
--- /dev/null
+++ b/moo/mooutils/moofileview.h
@@ -0,0 +1,88 @@
+/*
+ * mooutils/moofileview.h
+ *
+ * Copyright (C) 2004-2005 by Yevgen Muntyan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See COPYING file that comes with this distribution.
+ */
+
+#ifndef MOOUTILS_MOOFILEVIEW_H
+#define MOOUTILS_MOOFILEVIEW_H
+
+#include
+
+G_BEGIN_DECLS
+
+
+#define MOO_TYPE_FILE_VIEW_FILE (moo_file_view_file_get_type ())
+#define MOO_TYPE_FILE_VIEW_TYPE (moo_file_view_type_get_type ())
+#define MOO_TYPE_FILE_VIEW (moo_file_view_get_type ())
+#define MOO_FILE_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_FILE_VIEW, MooFileView))
+#define MOO_FILE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_FILE_VIEW, MooFileViewClass))
+#define MOO_IS_FILE_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_FILE_VIEW))
+#define MOO_IS_FILE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_FILE_VIEW))
+#define MOO_FILE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_FILE_VIEW, MooFileViewClass))
+
+
+typedef enum {
+ MOO_FILE_VIEW_LIST,
+ MOO_FILE_VIEW_ICON
+} MooFileViewType;
+
+typedef struct _MooFileView MooFileView;
+typedef struct _MooFileViewFile MooFileViewFile;
+typedef struct _MooFileViewPrivate MooFileViewPrivate;
+typedef struct _MooFileViewClass MooFileViewClass;
+
+struct _MooFileView
+{
+ GtkVBox vbox;
+ MooFileViewPrivate *priv;
+};
+
+struct _MooFileViewClass
+{
+ GtkVBoxClass vbox_class;
+
+ gboolean (*chdir) (MooFileView *fileview,
+ const char *dir,
+ GError **error);
+ void (*activate) (MooFileView *fileview,
+ MooFileViewFile *file);
+ void (*go_back) (MooFileView *fileview);
+ void (*go_forward) (MooFileView *fileview);
+ void (*go_home) (MooFileView *fileview);
+ void (*go_up) (MooFileView *fileview);
+};
+
+
+GType moo_file_view_get_type (void) G_GNUC_CONST;
+GType moo_file_view_file_get_type (void) G_GNUC_CONST;
+GType moo_file_view_type_get_type (void) G_GNUC_CONST;
+
+GtkWidget *moo_file_view_new (void);
+
+gboolean moo_file_view_chdir (MooFileView *fileview,
+ const char *dir,
+ GError **error);
+
+void moo_file_view_set_view_type (MooFileView *fileview,
+ MooFileViewType type);
+
+gconstpointer moo_file_view_file_get_stat (MooFileViewFile *file);
+const char *moo_file_view_file_path (MooFileViewFile *file);
+const char *moo_file_view_file_mime_type (MooFileViewFile *file);
+
+GdkPixbuf *moo_get_icon_for_file (GtkWidget *widget,
+ MooFileViewFile *file,
+ GtkIconSize size);
+
+
+G_END_DECLS
+
+#endif /* MOOUTILS_MOOFILEVIEW_H */
diff --git a/moo/mooutils/moomarshals.list b/moo/mooutils/moomarshals.list
index 994a486f..776fae71 100644
--- a/moo/mooutils/moomarshals.list
+++ b/moo/mooutils/moomarshals.list
@@ -1,6 +1,7 @@
BOOL:VOID
BOOL:POINTER
BOOL:STRING
+BOOL:STRING,POINTER
BOOL:STRING,STRING
BOOL:STRING,STRING,POINTER
INT:VOID
diff --git a/moo/mooutils/moopaned.c b/moo/mooutils/moopaned.c
new file mode 100644
index 00000000..ba805926
--- /dev/null
+++ b/moo/mooutils/moopaned.c
@@ -0,0 +1,1719 @@
+/*
+ * mooutils/moopaned.c
+ *
+ * Copyright (C) 2004-2005 by Yevgen Muntyan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See COPYING file that comes with this distribution.
+ */
+
+#include "mooutils/moopaned.h"
+
+
+static int MIN_PANE_SIZE = 10;
+static int SPACING_IN_BUTTON = 4;
+
+
+typedef struct {
+ GtkWidget *widget;
+ GtkWidget *button;
+} Pane;
+
+
+struct _MooPanedPrivate {
+ GtkPositionType pane_position;
+
+ GdkWindow *handle_window;
+ GdkWindow *pane_window;
+
+ Pane *current_pane;
+ GSList *panes;
+
+ gboolean close_on_child_focus;
+
+ int position;
+
+ gboolean button_box_visible;
+ int button_box_size;
+ gboolean handle_visible;
+ int handle_size;
+ gboolean pane_widget_visible;
+ int pane_widget_size;
+ gboolean sticky;
+
+ gboolean handle_prelit;
+ gboolean in_drag;
+ int drag_start;
+};
+
+
+static void moo_paned_finalize (GObject *object);
+static void moo_paned_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void moo_paned_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static GObject *moo_paned_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties);
+
+static void moo_paned_realize (GtkWidget *widget);
+static void moo_paned_unrealize (GtkWidget *widget);
+static void moo_paned_map (GtkWidget *widget);
+
+static void moo_paned_set_focus_child (GtkContainer *container,
+ GtkWidget *widget);
+
+static void moo_paned_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void moo_paned_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+static gboolean moo_paned_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static gboolean moo_paned_motion (GtkWidget *widget,
+ GdkEventMotion *event);
+static gboolean moo_paned_enter (GtkWidget *widget,
+ GdkEventCrossing *event);
+static gboolean moo_paned_leave (GtkWidget *widget,
+ GdkEventCrossing *event);
+static gboolean moo_paned_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean moo_paned_button_release(GtkWidget *widget,
+ GdkEventButton *event);
+
+static void moo_paned_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data);
+static void moo_paned_remove (GtkContainer *container,
+ GtkWidget *widget);
+static void moo_paned_remove_pane (MooPaned *paned,
+ GtkWidget *pane_widget);
+
+static void realize_handle (MooPaned *paned);
+static void realize_pane (MooPaned *paned);
+static void draw_handle (MooPaned *paned);
+static void button_toggled (GtkToggleButton *button,
+ MooPaned *paned);
+static void button_box_visible_notify (MooPaned *paned);
+
+
+/* MOO_TYPE_PANED */
+G_DEFINE_TYPE (MooPaned, moo_paned, GTK_TYPE_BIN)
+
+enum {
+ PROP_0,
+ PROP_PANE_POSITION,
+ PROP_CLOSE_PANE_ON_CHILD_FOCUS,
+ PROP_STICKY_PANE
+};
+
+
+static void moo_paned_class_init (MooPanedClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ gobject_class->finalize = moo_paned_finalize;
+ gobject_class->set_property = moo_paned_set_property;
+ gobject_class->get_property = moo_paned_get_property;
+ gobject_class->constructor = moo_paned_constructor;
+
+ widget_class->realize = moo_paned_realize;
+ widget_class->unrealize = moo_paned_unrealize;
+ widget_class->map = moo_paned_map;
+ widget_class->expose_event = moo_paned_expose;
+ widget_class->size_request = moo_paned_size_request;
+ widget_class->size_allocate = moo_paned_size_allocate;
+ widget_class->motion_notify_event = moo_paned_motion;
+ widget_class->enter_notify_event = moo_paned_enter;
+ widget_class->leave_notify_event = moo_paned_leave;
+ widget_class->button_press_event = moo_paned_button_press;
+ widget_class->button_release_event = moo_paned_button_release;
+
+ container_class->forall = moo_paned_forall;
+ container_class->set_focus_child = moo_paned_set_focus_child;
+ container_class->remove = moo_paned_remove;
+
+ g_object_class_install_property (gobject_class,
+ PROP_PANE_POSITION,
+ g_param_spec_enum ("pane-position",
+ "pane-position",
+ "pane-position",
+ GTK_TYPE_POSITION_TYPE,
+ GTK_POS_LEFT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class,
+ PROP_CLOSE_PANE_ON_CHILD_FOCUS,
+ g_param_spec_boolean ("close-pane-on-child-focus",
+ "close-pane-on-child-focus",
+ "close-pane-on-child-focus",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_STICKY_PANE,
+ g_param_spec_boolean ("sticky-pane",
+ "sticky-pane",
+ "sticky-pane",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("handle-size",
+ "handle-size",
+ "handle-size",
+ 0,
+ G_MAXINT,
+ 5,
+ G_PARAM_READABLE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("button-spacing",
+ "button-spacing",
+ "button-spacing",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE));
+}
+
+
+static void moo_paned_init (MooPaned *paned)
+{
+ paned->priv = g_new0 (MooPanedPrivate, 1);
+
+ paned->button_box = NULL;
+
+ paned->priv->pane_position = -1;
+ paned->priv->handle_window = NULL;
+ paned->priv->pane_window = NULL;
+ paned->priv->current_pane = NULL;
+ paned->priv->panes = NULL;
+ paned->priv->button_box_visible = FALSE;
+ paned->priv->button_box_size = 0;
+ paned->priv->handle_visible = FALSE;
+ paned->priv->handle_size = 0;
+ paned->priv->pane_widget_visible = FALSE;
+ paned->priv->pane_widget_size = 0;
+ paned->priv->sticky = FALSE;
+ paned->priv->position = -1;
+ paned->priv->handle_prelit = FALSE;
+ paned->priv->in_drag = FALSE;
+ paned->priv->drag_start = -1;
+}
+
+
+static GObject *moo_paned_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ MooPaned *paned;
+ int button_spacing;
+
+ object = G_OBJECT_CLASS(moo_paned_parent_class)->constructor (type,
+ n_construct_properties, construct_properties);
+ paned = MOO_PANED (object);
+
+ gtk_widget_style_get (GTK_WIDGET (paned),
+ "button-spacing", &button_spacing, NULL);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ paned->button_box = gtk_vbox_new (FALSE, button_spacing);
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ paned->button_box = gtk_hbox_new (FALSE, button_spacing);
+ break;
+ default:
+ g_warning ("%s: invalid 'pane-position' property value '%d',"
+ "falling back to GTK_POS_LEFT", G_STRLOC,
+ paned->priv->pane_position);
+ paned->priv->pane_position = GTK_POS_LEFT;
+ paned->button_box = gtk_vbox_new (FALSE, button_spacing);
+ break;
+ }
+
+ gtk_object_sink (gtk_object_ref (GTK_OBJECT (paned->button_box)));
+ gtk_widget_set_parent (paned->button_box, GTK_WIDGET (paned));
+ gtk_widget_show (paned->button_box);
+ g_signal_connect_swapped (paned->button_box, "notify::visible",
+ G_CALLBACK (button_box_visible_notify),
+ paned);
+
+ return object;
+}
+
+
+static void moo_paned_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MooPaned *paned = MOO_PANED (object);
+
+ switch (prop_id)
+ {
+ case PROP_PANE_POSITION:
+ paned->priv->pane_position = g_value_get_enum (value);
+ break;
+
+ case PROP_CLOSE_PANE_ON_CHILD_FOCUS:
+ paned->priv->close_on_child_focus =
+ g_value_get_boolean (value);
+ g_object_notify (object, "close-pane-on-child-focus");
+ break;
+
+ case PROP_STICKY_PANE:
+ moo_paned_set_sticky_pane (paned,
+ g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+
+static void moo_paned_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MooPaned *paned = MOO_PANED (object);
+
+ switch (prop_id)
+ {
+ case PROP_PANE_POSITION:
+ g_value_set_enum (value, paned->priv->pane_position);
+ break;
+
+ case PROP_CLOSE_PANE_ON_CHILD_FOCUS:
+ g_value_set_boolean (value, paned->priv->close_on_child_focus);
+ break;
+
+ case PROP_STICKY_PANE:
+ g_value_set_boolean (value, paned->priv->sticky);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+
+static void moo_paned_finalize (GObject *object)
+{
+ MooPaned *paned = MOO_PANED (object);
+ g_free (paned->priv);
+ G_OBJECT_CLASS (moo_paned_parent_class)->finalize (object);
+}
+
+
+GtkWidget *moo_paned_new (GtkPositionType pane_position)
+{
+ return GTK_WIDGET (g_object_new (MOO_TYPE_PANED,
+ "pane-position", pane_position,
+ NULL));
+}
+
+
+static void moo_paned_realize (GtkWidget *widget)
+{
+ static GdkWindowAttr attributes;
+ gint attributes_mask;
+ MooPaned *paned;
+
+ paned = MOO_PANED (widget);
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (widget)
+ | GDK_EXPOSURE_MASK;
+
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.wclass = GDK_INPUT_OUTPUT;
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (widget->window, widget);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+
+ realize_pane (paned);
+}
+
+
+static void realize_handle (MooPaned *paned)
+{
+ static GdkWindowAttr attributes;
+ gint attributes_mask;
+ GtkWidget *widget = GTK_WIDGET (paned);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ attributes.y = 0;
+ attributes.width = paned->priv->handle_size;
+ attributes.height = widget->allocation.height;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ attributes.x = 0;
+ attributes.width = widget->allocation.width;
+ attributes.height = paned->priv->handle_size;
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ attributes.x = paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_RIGHT:
+ attributes.x = 0;
+ break;
+ case GTK_POS_TOP:
+ attributes.y = paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_BOTTOM:
+ attributes.y = 0;
+ break;
+ }
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (widget)
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_EXPOSURE_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK;
+
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.wclass = GDK_INPUT_OUTPUT;
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ attributes.cursor = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
+ break;
+ }
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
+ GDK_WA_COLORMAP | GDK_WA_CURSOR;
+
+ paned->priv->handle_window = gdk_window_new (paned->priv->pane_window,
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (paned->priv->handle_window, widget);
+
+ gtk_style_set_background (widget->style,
+ paned->priv->handle_window,
+ GTK_STATE_NORMAL);
+
+ gdk_cursor_unref (attributes.cursor);
+}
+
+
+static void realize_pane (MooPaned *paned)
+{
+ static GdkWindowAttr attributes;
+ gint attributes_mask;
+ GtkWidget *widget = GTK_WIDGET (paned);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ attributes.y = 0;
+ attributes.height = widget->allocation.height;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ attributes.x = 0;
+ attributes.width = widget->allocation.width;
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ attributes.x = paned->priv->button_box_size;
+ attributes.width = paned->priv->pane_widget_size +
+ paned->priv->handle_size;
+ break;
+ case GTK_POS_RIGHT:
+ attributes.width = paned->priv->pane_widget_size +
+ paned->priv->handle_size;
+ attributes.x = widget->allocation.width -
+ paned->priv->button_box_size -
+ attributes.width;
+ break;
+ case GTK_POS_TOP:
+ attributes.y = paned->priv->button_box_size;
+ attributes.height = paned->priv->pane_widget_size +
+ paned->priv->handle_size;
+ break;
+ case GTK_POS_BOTTOM:
+ attributes.height = paned->priv->pane_widget_size +
+ paned->priv->handle_size;
+ attributes.y = widget->allocation.height -
+ paned->priv->button_box_size -
+ attributes.height;
+ break;
+ }
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (widget)
+ | GDK_EXPOSURE_MASK;
+
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
+ GDK_WA_COLORMAP;
+
+ paned->priv->pane_window =
+ gdk_window_new (widget->window, &attributes, attributes_mask);
+ gdk_window_set_user_data (paned->priv->pane_window, widget);
+
+ gtk_style_set_background (widget->style,
+ paned->priv->pane_window,
+ GTK_STATE_NORMAL);
+
+ realize_handle (paned);
+}
+
+
+static void moo_paned_unrealize (GtkWidget *widget)
+{
+ MooPaned *paned = MOO_PANED (widget);
+
+ if (GTK_WIDGET_CLASS (moo_paned_parent_class)->unrealize)
+ GTK_WIDGET_CLASS (moo_paned_parent_class)->unrealize (widget);
+
+ if (paned->priv->handle_window)
+ {
+ gdk_window_set_user_data (paned->priv->handle_window, NULL);
+ gdk_window_destroy (paned->priv->handle_window);
+ paned->priv->handle_window = NULL;
+ paned->priv->handle_visible = FALSE;
+ paned->priv->handle_size = 0;
+ }
+
+ if (paned->priv->pane_window)
+ {
+ gdk_window_set_user_data (paned->priv->pane_window, NULL);
+ gdk_window_destroy (paned->priv->pane_window);
+ paned->priv->pane_window = NULL;
+ paned->priv->pane_widget_visible = FALSE;
+ paned->priv->pane_widget_size = 0;
+ }
+}
+
+
+static void add_button_box_requisition (MooPaned *paned,
+ GtkRequisition *requisition,
+ GtkRequisition *child_requisition)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ requisition->width += child_requisition->width;
+ requisition->height = MAX (child_requisition->height, requisition->height);
+ paned->priv->button_box_size = child_requisition->width;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ requisition->height += child_requisition->height;
+ requisition->width = MAX (child_requisition->width, requisition->width);
+ paned->priv->button_box_size = child_requisition->height;
+ break;
+ }
+}
+
+
+static void add_handle_requisition (MooPaned *paned,
+ GtkRequisition *requisition)
+{
+ gtk_widget_style_get (GTK_WIDGET (paned),
+ "handle_size", &paned->priv->handle_size,
+ NULL);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ requisition->width += paned->priv->handle_size;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ requisition->height += paned->priv->handle_size;
+ break;
+ }
+}
+
+
+static void add_pane_widget_requisition (MooPaned *paned,
+ GtkRequisition *requisition,
+ GtkRequisition *child_requisition)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ requisition->height = MAX (child_requisition->height, requisition->height);
+
+ if (paned->priv->sticky)
+ {
+ requisition->width += child_requisition->width;
+ }
+ else
+ {
+ requisition->width = MAX (child_requisition->width +
+ paned->priv->button_box_size +
+ paned->priv->handle_size, requisition->width);
+ }
+
+ break;
+
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ requisition->width = MAX (child_requisition->width, requisition->width);
+
+ if (paned->priv->sticky)
+ {
+ requisition->height += child_requisition->height;
+ }
+ else
+ {
+ requisition->height = MAX (child_requisition->height +
+ paned->priv->button_box_size +
+ paned->priv->handle_size, requisition->height);
+ }
+
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ paned->priv->pane_widget_size = MAX (paned->priv->position,
+ child_requisition->width);
+ paned->priv->position = paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ paned->priv->pane_widget_size = MAX (paned->priv->position,
+ child_requisition->height);
+ paned->priv->position = paned->priv->pane_widget_size;
+ break;
+ }
+}
+
+
+static void moo_paned_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkBin *bin = GTK_BIN (widget);
+ MooPaned *paned = MOO_PANED (widget);
+ GtkRequisition child_requisition;
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+ {
+ gtk_widget_size_request (bin->child, &child_requisition);
+ requisition->width += child_requisition.width;
+ requisition->height += child_requisition.height;
+ }
+
+ if (paned->priv->button_box_visible)
+ {
+ gtk_widget_size_request (paned->button_box, &child_requisition);
+ add_button_box_requisition (paned, requisition, &child_requisition);
+ }
+ else
+ {
+ paned->priv->button_box_size = 0;
+ }
+
+ if (paned->priv->handle_visible)
+ add_handle_requisition (paned, requisition);
+ else
+ paned->priv->handle_size = 0;
+
+ if (paned->priv->pane_widget_visible)
+ {
+ gtk_widget_size_request (paned->priv->current_pane->widget, &child_requisition);
+ add_pane_widget_requisition (paned, requisition, &child_requisition);
+ }
+ else
+ {
+ paned->priv->pane_widget_size = 0;
+ }
+}
+
+
+static void get_pane_widget_allocation (MooPaned *paned,
+ GtkAllocation *allocation)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ allocation->x = 0;
+ allocation->y = 0;
+ allocation->width = paned->priv->pane_widget_size;
+ allocation->height = GTK_WIDGET(paned)->allocation.height;
+ break;
+ case GTK_POS_RIGHT:
+ allocation->x = paned->priv->handle_size;
+ allocation->y = 0;
+ allocation->width = paned->priv->pane_widget_size;
+ allocation->height = GTK_WIDGET(paned)->allocation.height;
+ break;
+ case GTK_POS_TOP:
+ allocation->x = 0;
+ allocation->y = 0;
+ allocation->width = GTK_WIDGET(paned)->allocation.width;
+ allocation->height = paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_BOTTOM:
+ allocation->x = 0;
+ allocation->y = paned->priv->handle_size;
+ allocation->width = GTK_WIDGET(paned)->allocation.width;
+ allocation->height = paned->priv->pane_widget_size;
+ break;
+ }
+}
+
+
+static void get_button_box_allocation (MooPaned *paned,
+ GtkAllocation *allocation)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ allocation->y = 0;
+ allocation->height = GTK_WIDGET(paned)->allocation.height;
+ allocation->width = paned->priv->button_box_size;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ allocation->x = 0;
+ allocation->width = GTK_WIDGET(paned)->allocation.width;
+ allocation->height = paned->priv->button_box_size;
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ allocation->x = 0;
+ break;
+ case GTK_POS_RIGHT:
+ allocation->x = GTK_WIDGET(paned)->allocation.width -
+ allocation->width;
+ break;
+ case GTK_POS_TOP:
+ allocation->y = 0;
+ break;
+ case GTK_POS_BOTTOM:
+ allocation->y = GTK_WIDGET(paned)->allocation.height -
+ allocation->height;
+ break;
+ }
+}
+
+
+static void get_bin_child_allocation (MooPaned *paned,
+ GtkAllocation *allocation)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ allocation->y = 0;
+ allocation->height = GTK_WIDGET(paned)->allocation.height;
+ allocation->width = GTK_WIDGET(paned)->allocation.width -
+ paned->priv->button_box_size -
+ paned->priv->handle_size;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ allocation->x = 0;
+ allocation->width = GTK_WIDGET(paned)->allocation.width;
+ allocation->height = GTK_WIDGET(paned)->allocation.height -
+ paned->priv->button_box_size -
+ paned->priv->handle_size;
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ allocation->x = paned->priv->button_box_size +
+ paned->priv->handle_size;
+ break;
+ case GTK_POS_RIGHT:
+ allocation->x = 0;
+ break;
+ case GTK_POS_TOP:
+ allocation->y = paned->priv->button_box_size +
+ paned->priv->handle_size;
+ break;
+ case GTK_POS_BOTTOM:
+ allocation->y = 0;
+ break;
+ }
+
+ if (paned->priv->sticky)
+ {
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ allocation->x += paned->priv->pane_widget_size;
+ allocation->width -= paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_RIGHT:
+ allocation->width -= paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_TOP:
+ allocation->y += paned->priv->pane_widget_size;
+ allocation->height -= paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_BOTTOM:
+ allocation->height -= paned->priv->pane_widget_size;
+ break;
+ }
+ }
+}
+
+
+static void clamp_handle_size (MooPaned *paned)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ paned->priv->handle_size = CLAMP (paned->priv->handle_size, 0,
+ GTK_WIDGET(paned)->allocation.width);
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ paned->priv->handle_size = CLAMP (paned->priv->handle_size, 0,
+ GTK_WIDGET(paned)->allocation.height);
+ break;
+ }
+}
+
+
+static void clamp_button_box_size (MooPaned *paned)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ paned->priv->button_box_size = CLAMP (paned->priv->button_box_size, 0,
+ GTK_WIDGET(paned)->allocation.width -
+ paned->priv->handle_size);
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ paned->priv->button_box_size = CLAMP (paned->priv->button_box_size, 0,
+ GTK_WIDGET(paned)->allocation.height -
+ paned->priv->handle_size);
+ break;
+ }
+}
+
+
+static void clamp_child_requisition (MooPaned *paned,
+ GtkRequisition *requisition)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ requisition->width = CLAMP (requisition->width, 0,
+ GTK_WIDGET(paned)->allocation.width -
+ paned->priv->handle_size -
+ paned->priv->button_box_size);
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ requisition->height = CLAMP (requisition->height, 0,
+ GTK_WIDGET(paned)->allocation.height -
+ paned->priv->handle_size -
+ paned->priv->button_box_size);
+ break;
+ }
+}
+
+
+static void clamp_pane_widget_size (MooPaned *paned,
+ GtkRequisition *child_requisition)
+{
+ int min_size, max_size;
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ max_size = GTK_WIDGET(paned)->allocation.width -
+ paned->priv->handle_size -
+ paned->priv->button_box_size;
+ if (paned->priv->sticky)
+ max_size -= child_requisition->width;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ max_size = GTK_WIDGET(paned)->allocation.height -
+ paned->priv->handle_size -
+ paned->priv->button_box_size;
+ if (paned->priv->sticky)
+ max_size -= child_requisition->height;
+ break;
+ }
+
+ min_size = CLAMP (MIN_PANE_SIZE, 0, max_size);
+
+ paned->priv->pane_widget_size =
+ CLAMP (paned->priv->pane_widget_size, min_size, max_size);
+}
+
+
+static void get_pane_window_rect (MooPaned *paned,
+ GdkRectangle *rect)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ rect->width = paned->priv->pane_widget_size + paned->priv->handle_size;
+ rect->height = GTK_WIDGET(paned)->allocation.height;
+ rect->y = 0;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ rect->height = paned->priv->pane_widget_size + paned->priv->handle_size;
+ rect->width = GTK_WIDGET(paned)->allocation.width;
+ rect->x = 0;
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ rect->x = paned->priv->button_box_size;
+ break;
+ case GTK_POS_RIGHT:
+ rect->x = GTK_WIDGET(paned)->allocation.width -
+ rect->width -
+ paned->priv->button_box_size;
+ break;
+ case GTK_POS_TOP:
+ rect->y = paned->priv->button_box_size;
+ break;
+ case GTK_POS_BOTTOM:
+ rect->y = GTK_WIDGET(paned)->allocation.height -
+ rect->height -
+ paned->priv->button_box_size;
+ break;
+ }
+}
+
+
+static void get_handle_window_rect (MooPaned *paned,
+ GdkRectangle *rect)
+{
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ rect->y = 0;
+ rect->width = paned->priv->handle_size;
+ rect->height = GTK_WIDGET(paned)->allocation.height;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ rect->x = 0;
+ rect->height = paned->priv->handle_size;
+ rect->width = GTK_WIDGET(paned)->allocation.width;
+ break;
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ rect->x = paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_RIGHT:
+ rect->x = 0;
+ break;
+ case GTK_POS_TOP:
+ rect->y = paned->priv->pane_widget_size;
+ break;
+ case GTK_POS_BOTTOM:
+ rect->y = 0;
+ break;
+ }
+}
+
+
+static void moo_paned_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkBin *bin;
+ MooPaned *paned;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition = {0, 0};
+
+ widget->allocation = *allocation;
+ bin = GTK_BIN (widget);
+ paned = MOO_PANED (widget);
+
+ if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+ gtk_widget_get_child_requisition (bin->child, &child_requisition);
+
+ if (paned->priv->handle_visible)
+ clamp_handle_size (paned);
+
+ if (paned->priv->button_box_visible)
+ clamp_button_box_size (paned);
+
+ clamp_child_requisition (paned, &child_requisition);
+
+ if (paned->priv->pane_widget_visible)
+ {
+ clamp_pane_widget_size (paned, &child_requisition);
+ paned->priv->position = paned->priv->pane_widget_size;
+ }
+
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ GdkRectangle rect;
+
+ gdk_window_move_resize (widget->window,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+
+ if (paned->priv->pane_window)
+ {
+ get_pane_window_rect (paned, &rect);
+ gdk_window_move_resize (paned->priv->pane_window,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ if (paned->priv->handle_visible)
+ {
+ get_handle_window_rect (paned, &rect);
+ gdk_window_move_resize (paned->priv->handle_window,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+ }
+
+ if (paned->priv->button_box_visible)
+ {
+ get_button_box_allocation (paned, &child_allocation);
+ gtk_widget_size_allocate (paned->button_box, &child_allocation);
+ }
+
+ if (bin->child)
+ {
+ get_bin_child_allocation (paned, &child_allocation);
+ gtk_widget_size_allocate (bin->child, &child_allocation);
+ }
+
+ if (paned->priv->pane_widget_visible)
+ {
+ get_pane_widget_allocation (paned, &child_allocation);
+ gtk_widget_size_allocate (paned->priv->current_pane->widget,
+ &child_allocation);
+ }
+}
+
+
+static void moo_paned_map (GtkWidget *widget)
+{
+ MooPaned *paned = MOO_PANED (widget);
+
+ gdk_window_show (widget->window);
+
+ (* GTK_WIDGET_CLASS (moo_paned_parent_class)->map) (widget);
+
+ if (paned->priv->handle_visible)
+ {
+ gdk_window_show (paned->priv->pane_window);
+ gdk_window_show (paned->priv->handle_window);
+ gdk_window_raise (paned->priv->pane_window);
+ }
+}
+
+
+static void moo_paned_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ MooPaned *paned = MOO_PANED (container);
+ GtkBin *bin = GTK_BIN (container);
+ GSList *l;
+
+ if (bin->child)
+ callback (bin->child, callback_data);
+
+ if (include_internals)
+ {
+ callback (paned->button_box, callback_data);
+
+ for (l = paned->priv->panes; l != NULL; l = l->next)
+ callback (((Pane*)l->data)->widget, callback_data);
+ }
+}
+
+
+static gboolean moo_paned_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ MooPaned *paned = MOO_PANED (widget);
+
+ if (paned->priv->button_box_visible)
+ gtk_container_propagate_expose (GTK_CONTAINER (paned),
+ paned->button_box, event);
+
+ if (GTK_WIDGET_DRAWABLE (GTK_BIN(paned)->child))
+ gtk_container_propagate_expose (GTK_CONTAINER (paned),
+ GTK_BIN(paned)->child, event);
+
+ if (paned->priv->pane_widget_visible)
+ gtk_container_propagate_expose (GTK_CONTAINER (paned),
+ paned->priv->current_pane->widget,
+ event);
+
+ if (paned->priv->handle_visible)
+ draw_handle (paned);
+
+ return FALSE;
+}
+
+
+static void draw_handle (MooPaned *paned)
+{
+ GtkWidget *widget = GTK_WIDGET (paned);
+ GtkStateType state;
+
+ GdkRectangle area;
+
+ area.x = 0;
+ area.y = 0;
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ area.width = paned->priv->handle_size;
+ area.height = widget->allocation.height;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ area.width = widget->allocation.width;
+ area.height = paned->priv->handle_size;
+ break;
+ }
+
+ if (gtk_widget_is_focus (widget))
+ state = GTK_STATE_SELECTED;
+ else if (paned->priv->handle_prelit)
+ state = GTK_STATE_PRELIGHT;
+ else
+ state = GTK_WIDGET_STATE (widget);
+
+ gtk_paint_handle (widget->style,
+ paned->priv->handle_window,
+ state,
+ GTK_SHADOW_NONE,
+ &area,
+ widget,
+ "paned",
+ area.x, area.y, area.width, area.height,
+ GTK_ORIENTATION_VERTICAL);
+}
+
+
+static void button_toggled (GtkToggleButton *button,
+ MooPaned *paned)
+{
+ Pane *pane;
+
+ if (!gtk_toggle_button_get_active (button))
+ {
+ if (paned->priv->current_pane &&
+ paned->priv->current_pane->button == GTK_WIDGET (button))
+ {
+ gtk_widget_hide (paned->priv->current_pane->widget);
+ paned->priv->current_pane = NULL;
+ paned->priv->pane_widget_visible = FALSE;
+ paned->priv->pane_widget_size = 0;
+ gtk_widget_queue_resize (GTK_WIDGET (paned));
+ }
+
+ return;
+ }
+
+ if (paned->priv->current_pane)
+ {
+ Pane *old_pane = paned->priv->current_pane;
+ paned->priv->current_pane = NULL;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (old_pane->button), FALSE);
+ gtk_widget_hide (old_pane->widget);
+ }
+
+ pane = g_object_get_data (G_OBJECT (button), "moo-pane");
+ g_return_if_fail (pane != NULL);
+
+ if (GTK_WIDGET_REALIZED (paned))
+ {
+ gtk_widget_set_parent_window (pane->widget,
+ paned->priv->pane_window);
+ gtk_widget_queue_resize (GTK_WIDGET (paned));
+ }
+
+ paned->priv->current_pane = pane;
+ gtk_widget_show (pane->widget);
+
+ paned->priv->handle_visible = TRUE;
+ gtk_widget_style_get (GTK_WIDGET (paned),
+ "handle_size", &paned->priv->handle_size,
+ NULL);
+ paned->priv->pane_widget_visible = TRUE;
+ if (paned->priv->position > 0)
+ paned->priv->pane_widget_size = paned->priv->position;
+}
+
+
+void moo_paned_set_sticky_pane (MooPaned *paned,
+ gboolean sticky)
+{
+ g_return_if_fail (MOO_IS_PANED (paned));
+ if (paned->priv->sticky != sticky && GTK_WIDGET_REALIZED (paned))
+ gtk_widget_queue_resize (GTK_WIDGET (paned));
+ paned->priv->sticky = sticky;
+ g_object_notify (G_OBJECT (paned), "sticky-pane");
+}
+
+
+void moo_paned_hide_pane (MooPaned *paned)
+{
+ GtkToggleButton *btn;
+ g_return_if_fail (MOO_IS_PANED (paned));
+ if (paned->priv->current_pane)
+ {
+ btn = GTK_TOGGLE_BUTTON (paned->priv->current_pane->button);
+ gtk_toggle_button_set_active (btn, FALSE);
+ }
+}
+
+
+void moo_paned_open_pane (MooPaned *paned,
+ guint index)
+{
+ Pane *pane;
+ g_return_if_fail (MOO_IS_PANED (paned));
+ pane = g_slist_nth_data (paned->priv->panes, index);
+ g_return_if_fail (pane != NULL);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pane->button),
+ TRUE);
+}
+
+
+GtkWidget *moo_paned_get_nth_pane (MooPaned *paned,
+ guint n)
+{
+ Pane *pane;
+ g_return_val_if_fail (MOO_IS_PANED (paned), NULL);
+ pane = g_slist_nth_data (paned->priv->panes, n);
+ g_return_val_if_fail (pane != NULL, NULL);
+ return pane->widget;
+}
+
+
+static gboolean moo_paned_motion (GtkWidget *widget,
+ G_GNUC_UNUSED GdkEventMotion *event)
+{
+ MooPaned *paned = MOO_PANED (widget);
+
+ if (paned->priv->in_drag)
+ {
+ int size;
+ GtkRequisition requisition;
+
+ gtk_widget_get_child_requisition (paned->priv->current_pane->widget,
+ &requisition);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ gtk_widget_get_pointer (widget, &size, NULL);
+ size -= (paned->priv->drag_start + paned->priv->button_box_size);
+ size = CLAMP (size, requisition.width,
+ widget->allocation.width - paned->priv->button_box_size -
+ paned->priv->handle_size);
+ break;
+ case GTK_POS_RIGHT:
+ gtk_widget_get_pointer (widget, &size, NULL);
+ size = widget->allocation.width - size;
+ size -= (paned->priv->drag_start + paned->priv->button_box_size);
+ size = CLAMP (size, requisition.width,
+ widget->allocation.width - paned->priv->button_box_size -
+ paned->priv->handle_size);
+ break;
+ case GTK_POS_TOP:
+ gtk_widget_get_pointer (widget, NULL, &size);
+ size -= (paned->priv->drag_start + paned->priv->button_box_size);
+ size = CLAMP (size, requisition.height,
+ widget->allocation.height - paned->priv->button_box_size -
+ paned->priv->handle_size);
+ break;
+ case GTK_POS_BOTTOM:
+ gtk_widget_get_pointer (widget, NULL, &size);
+ size = widget->allocation.height - size;
+ size -= (paned->priv->drag_start + paned->priv->button_box_size);
+ size = CLAMP (size, requisition.height,
+ widget->allocation.height - paned->priv->button_box_size -
+ paned->priv->handle_size);
+ break;
+ }
+
+ if (size != paned->priv->pane_widget_size)
+ moo_paned_set_pane_size (paned, size);
+ }
+
+ return FALSE;
+}
+
+
+static void get_handle_rect (MooPaned *paned,
+ GdkRectangle *rect)
+{
+ rect->x = rect->y = 0;
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ rect->width = paned->priv->handle_size;
+ rect->height = GTK_WIDGET(paned)->allocation.height;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ rect->height = paned->priv->handle_size;
+ rect->width = GTK_WIDGET(paned)->allocation.width;
+ break;
+ }
+}
+
+
+static gboolean moo_paned_enter (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ MooPaned *paned = MOO_PANED (widget);
+ GdkRectangle rect;
+
+ if (event->window == paned->priv->handle_window &&
+ !paned->priv->in_drag)
+ {
+ paned->priv->handle_prelit = TRUE;
+ get_handle_rect (paned, &rect);
+ gdk_window_invalidate_rect (paned->priv->handle_window,
+ &rect, FALSE);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean moo_paned_leave (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ MooPaned *paned = MOO_PANED (widget);
+ GdkRectangle rect;
+
+ if (event->window == paned->priv->handle_window &&
+ !paned->priv->in_drag)
+ {
+ paned->priv->handle_prelit = FALSE;
+ get_handle_rect (paned, &rect);
+ gdk_window_invalidate_rect (paned->priv->handle_window,
+ &rect, FALSE);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean moo_paned_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ MooPaned *paned = MOO_PANED (widget);
+
+ if (!paned->priv->in_drag &&
+ (event->window == paned->priv->handle_window) &&
+ (event->button == 1) &&
+ paned->priv->pane_widget_visible)
+ {
+ paned->priv->in_drag = TRUE;
+
+ /* This is copied from gtkpaned.c */
+ gdk_pointer_grab (paned->priv->handle_window, FALSE,
+ GDK_POINTER_MOTION_HINT_MASK
+ | GDK_BUTTON1_MOTION_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK,
+ NULL, NULL,
+ event->time);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ paned->priv->drag_start = event->x;
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ paned->priv->drag_start = event->y;
+ break;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean moo_paned_button_release(GtkWidget *widget,
+ GdkEventButton *event)
+{
+ MooPaned *paned = MOO_PANED (widget);
+
+ if (paned->priv->in_drag && (event->button == 1))
+ {
+ paned->priv->in_drag = FALSE;
+ paned->priv->drag_start = -1;
+ gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
+ event->time);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void moo_paned_set_pane_size (MooPaned *paned,
+ int size)
+{
+ g_return_if_fail (MOO_IS_PANED (paned));
+
+ if (GTK_WIDGET_REALIZED (paned))
+ {
+ GtkWidget *widget = GTK_WIDGET (paned);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ size = CLAMP (size, 0,
+ widget->allocation.width - paned->priv->button_box_size -
+ paned->priv->handle_size);
+ break;
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ size = CLAMP (size, 0,
+ widget->allocation.height - paned->priv->button_box_size -
+ paned->priv->handle_size);
+ break;
+ }
+
+ if (size != paned->priv->position)
+ {
+ paned->priv->position = size;
+ if (paned->priv->pane_widget_visible)
+ gtk_widget_queue_resize (widget);
+ }
+ }
+ else
+ {
+ paned->priv->position = size;
+ }
+}
+
+
+static void button_box_visible_notify (MooPaned *paned)
+{
+ gboolean visible = GTK_WIDGET_VISIBLE (paned->button_box);
+
+ if (paned->priv->button_box_visible == visible)
+ return;
+
+ if (paned->priv->panes)
+ paned->priv->button_box_visible = visible;
+
+ if (GTK_WIDGET_REALIZED (paned))
+ gtk_widget_queue_resize (GTK_WIDGET (paned));
+}
+
+
+void moo_paned_add_pane (MooPaned *paned,
+ GtkWidget *pane_widget,
+ const char *button_label,
+ const char *button_stock_id)
+{
+ GtkWidget *box;
+ GtkWidget *label = NULL;
+ GtkWidget *icon = NULL;
+
+ g_return_if_fail (MOO_IS_PANED (paned));
+ g_return_if_fail (GTK_IS_WIDGET (pane_widget));
+ g_return_if_fail (pane_widget->parent == NULL);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ box = gtk_vbox_new (FALSE, SPACING_IN_BUTTON);
+ break;
+ default:
+ box = gtk_hbox_new (FALSE, SPACING_IN_BUTTON);
+ break;
+ }
+
+ gtk_widget_show (box);
+
+ if (button_label)
+ {
+ label = gtk_label_new (button_label);
+ gtk_widget_show (label);
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ gtk_label_set_angle (GTK_LABEL (label), 90);
+ break;
+ case GTK_POS_RIGHT:
+ gtk_label_set_angle (GTK_LABEL (label), 270);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (button_stock_id)
+ {
+ icon = gtk_image_new_from_stock (button_stock_id,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (icon);
+ }
+
+ switch (paned->priv->pane_position)
+ {
+ case GTK_POS_LEFT:
+ if (label)
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+ if (icon)
+ gtk_box_pack_start (GTK_BOX (box), icon, FALSE, FALSE, 0);
+ break;
+ default:
+ if (icon)
+ gtk_box_pack_start (GTK_BOX (box), icon, FALSE, FALSE, 0);
+ if (label)
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+ break;
+ }
+
+ moo_paned_insert_pane (paned, pane_widget, box, -1);
+}
+
+
+void moo_paned_insert_pane (MooPaned *paned,
+ GtkWidget *pane_widget,
+ GtkWidget *button_widget,
+ int position)
+{
+ GtkWidget *button;
+ Pane *pane;
+
+ g_return_if_fail (MOO_IS_PANED (paned));
+ g_return_if_fail (GTK_IS_WIDGET (pane_widget));
+ g_return_if_fail (GTK_IS_WIDGET (button_widget));
+ g_return_if_fail (pane_widget->parent == NULL);
+ g_return_if_fail (button_widget->parent == NULL);
+
+ button = gtk_toggle_button_new ();
+ gtk_widget_show (button);
+ gtk_container_add (GTK_CONTAINER (button), button_widget);
+ gtk_widget_show (button_widget);
+
+ if (position < 0 || position > (int) moo_paned_n_panes (paned))
+ position = moo_paned_n_panes (paned);
+
+ gtk_container_add_with_properties (GTK_CONTAINER (paned->button_box),
+ button,
+ "expand", FALSE,
+ "fill", FALSE,
+ "pack-type", GTK_PACK_START,
+ "position", position,
+ NULL);
+
+ gtk_widget_set_parent (pane_widget, GTK_WIDGET (paned));
+ gtk_object_sink (gtk_object_ref (GTK_OBJECT (pane_widget)));
+
+ pane = g_new (Pane, 1);
+ pane->widget = pane_widget;
+ pane->button = button;
+ paned->priv->panes = g_slist_insert (paned->priv->panes,
+ pane, position);
+
+ g_object_set_data (G_OBJECT (button), "moo-pane", pane);
+ g_object_set_data (G_OBJECT (pane_widget), "moo-pane", pane);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (button_toggled), paned);
+
+ if (GTK_WIDGET_VISIBLE (paned->button_box))
+ paned->priv->button_box_visible = TRUE;
+
+ paned->priv->handle_visible = TRUE;
+ gtk_widget_style_get (GTK_WIDGET (paned),
+ "handle_size", &paned->priv->handle_size,
+ NULL);
+
+ if (GTK_WIDGET_VISIBLE (paned))
+ gtk_widget_queue_resize (GTK_WIDGET (paned));
+
+ if (GTK_WIDGET_REALIZED (paned))
+ gtk_widget_set_parent_window (pane_widget,
+ paned->priv->pane_window);
+}
+
+
+static void moo_paned_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ MooPaned *paned = MOO_PANED (container);
+
+ if (widget == GTK_BIN(paned)->child)
+ GTK_CONTAINER_CLASS(moo_paned_parent_class)->remove (container, widget);
+ else
+ moo_paned_remove_pane (paned, widget);
+}
+
+
+static void moo_paned_remove_pane (MooPaned *paned,
+ GtkWidget *pane_widget)
+{
+ Pane *pane;
+
+ g_return_if_fail (MOO_IS_PANED (paned));
+ g_return_if_fail (GTK_IS_WIDGET (pane_widget));
+
+ pane = g_object_get_data (G_OBJECT (pane_widget), "moo-pane");
+ g_return_if_fail (pane != NULL);
+ g_return_if_fail (pane->widget == pane_widget);
+
+ if (paned->priv->current_pane &&
+ paned->priv->current_pane->widget == pane_widget)
+ {
+ moo_paned_hide_pane (paned);
+ }
+
+ g_object_set_data (G_OBJECT (pane->button), "moo-pane", NULL);
+ g_object_set_data (G_OBJECT (pane_widget), "moo-pane", NULL);
+ g_signal_handlers_disconnect_by_func (pane->button,
+ (gpointer) button_toggled,
+ paned);
+
+ gtk_container_remove (GTK_CONTAINER (paned->button_box), pane->button);
+ paned->priv->panes = g_slist_remove (paned->priv->panes, pane);
+
+ gtk_widget_unparent (pane_widget);
+
+ if (!moo_paned_n_panes (paned))
+ {
+ paned->priv->handle_visible = FALSE;
+ paned->priv->handle_size = 0;
+ if (paned->priv->pane_window)
+ gdk_window_hide (paned->priv->pane_window);
+ gtk_widget_hide (paned->button_box);
+ }
+
+ if (GTK_WIDGET_VISIBLE (paned))
+ gtk_widget_queue_resize (GTK_WIDGET (paned));
+}
+
+
+guint moo_paned_n_panes (MooPaned *paned)
+{
+ g_return_val_if_fail (MOO_IS_PANED (paned), 0);
+ return g_slist_length (paned->priv->panes);
+}
+
+
+static void moo_paned_set_focus_child (GtkContainer *container,
+ GtkWidget *widget)
+{
+ MooPaned *paned = MOO_PANED (container);
+
+ GTK_CONTAINER_CLASS(moo_paned_parent_class)->set_focus_child (container, widget);
+
+ if (widget == GTK_BIN(paned)->child &&
+ paned->priv->close_on_child_focus &&
+ !paned->priv->sticky)
+ {
+ moo_paned_hide_pane (paned);
+ }
+}
diff --git a/moo/mooutils/moopaned.h b/moo/mooutils/moopaned.h
new file mode 100644
index 00000000..3727a51e
--- /dev/null
+++ b/moo/mooutils/moopaned.h
@@ -0,0 +1,78 @@
+/*
+ * mooutils/moopaned.h
+ *
+ * Copyright (C) 2004-2005 by Yevgen Muntyan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See COPYING file that comes with this distribution.
+ */
+
+#ifndef MOOUTILS_MOOPANED_H
+#define MOOUTILS_MOOPANED_H
+
+#include
+
+G_BEGIN_DECLS
+
+
+#define MOO_TYPE_PANED (moo_paned_get_type ())
+#define MOO_PANED(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_PANED, MooPaned))
+#define MOO_PANED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_PANED, MooPanedClass))
+#define MOO_IS_PANED(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_PANED))
+#define MOO_IS_PANED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_PANED))
+#define MOO_PANED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_PANED, MooPanedClass))
+
+
+typedef struct _MooPaned MooPaned;
+typedef struct _MooPanedPrivate MooPanedPrivate;
+typedef struct _MooPanedClass MooPanedClass;
+
+struct _MooPaned
+{
+ GtkBin bin;
+ GtkWidget *button_box;
+ MooPanedPrivate *priv;
+};
+
+struct _MooPanedClass
+{
+ GtkBinClass bin_class;
+};
+
+
+GType moo_paned_get_type (void) G_GNUC_CONST;
+
+GtkWidget *moo_paned_new (GtkPositionType pane_position);
+
+void moo_paned_add_pane (MooPaned *paned,
+ GtkWidget *pane_widget,
+ const char *button_label,
+ const char *button_stock_id);
+void moo_paned_insert_pane (MooPaned *paned,
+ GtkWidget *pane_widget,
+ GtkWidget *button_widget,
+ int position);
+
+guint moo_paned_n_panes (MooPaned *paned);
+
+GtkWidget *moo_paned_get_nth_pane (MooPaned *paned,
+ guint n);
+
+void moo_paned_set_sticky_pane (MooPaned *paned,
+ gboolean sticky);
+
+void moo_paned_set_pane_size (MooPaned *paned,
+ int size);
+
+void moo_paned_open_pane (MooPaned *paned,
+ guint index);
+void moo_paned_hide_pane (MooPaned *paned);
+
+
+G_END_DECLS
+
+#endif /* MOOUTILS_MOOPANED_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 06eac13a..9c3c01a3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,14 +3,14 @@
#
EXTRA_PROGRAMS = medit mterm markup editor termbuffer
-bin_PROGRAMS =
+bin_PROGRAMS =
noinst_PROGRAMS =
EXTRA_DIST = \
pyapp.py.in \
meditui.xml \
editor-ui.xml
-
+
BUILT_SOURCES = editor-ui.h
editor-ui.h: editor-ui.xml
sh $(srcdir)/../moo/mooutils/xml2h.sh MEDIT_UI $(srcdir)/editor-ui.xml > editor-ui.h
@@ -27,7 +27,7 @@ if BUILD_MOOTERM
noinst_PROGRAMS += mterm termbuffer
endif
if BUILD_MOOUTILS
-noinst_PROGRAMS += markup
+noinst_PROGRAMS += markup testpaned testfileview
endif
@@ -104,3 +104,18 @@ markup_LDFLAGS += -mwindows
endif MINGW_BUILD
markup_SOURCES = markup.c
+
+
+testpaned_LDFLAGS =
+testpaned_LDADD = $(MOO_LIBS) ../moo/libmoo.la
+if MINGW_BUILD
+testpaned_LDFLAGS += -mwindows
+endif MINGW_BUILD
+testpaned_SOURCES = testpaned.c
+
+testfileview_LDFLAGS =
+testfileview_LDADD = $(MOO_LIBS) ../moo/libmoo.la
+if MINGW_BUILD
+testfileview_LDFLAGS += -mwindows
+endif MINGW_BUILD
+testfileview_SOURCES = testfileview.c
diff --git a/tests/testfileview.c b/tests/testfileview.c
new file mode 100644
index 00000000..d4849287
--- /dev/null
+++ b/tests/testfileview.c
@@ -0,0 +1,25 @@
+#include "mooutils/moofileview.h"
+
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *window, *tree;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+ gtk_window_set_default_size (GTK_WINDOW (window), -1, 500);
+
+ tree = moo_file_view_new ();
+ gtk_container_add (GTK_CONTAINER (window), tree);
+
+ moo_file_view_chdir (MOO_FILE_VIEW (tree),
+ g_get_home_dir (), NULL);;
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+ return 0;
+}
diff --git a/tests/testpaned.c b/tests/testpaned.c
new file mode 100644
index 00000000..275b0c72
--- /dev/null
+++ b/tests/testpaned.c
@@ -0,0 +1,116 @@
+#include "mooutils/moopaned.h"
+
+
+static int WINDOWS = 0;
+
+static void window_destroyed (void)
+{
+ if (!--WINDOWS) gtk_main_quit ();
+}
+
+
+static void sticky_button_toggled (GtkToggleButton *button,
+ MooPaned *paned)
+{
+ gboolean active = gtk_toggle_button_get_active (button);
+ moo_paned_set_sticky_pane (paned, active);
+}
+
+
+static void create_window_with_paned (GtkPositionType pane_position)
+{
+ GtkWidget *window, *paned, *textview, *button, *label, *swin;
+ GtkTextBuffer *buffer;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (window_destroyed), NULL);
+ WINDOWS++;
+
+ paned = moo_paned_new (pane_position);
+ gtk_widget_show (paned);
+ gtk_container_add (GTK_CONTAINER (window), paned);
+
+ textview = gtk_text_view_new ();
+ gtk_widget_show (textview);
+ swin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_show (swin);
+ gtk_container_add (GTK_CONTAINER (paned), swin);
+ gtk_container_add (GTK_CONTAINER (swin), textview);
+
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview), GTK_WRAP_WORD);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+ gtk_text_buffer_insert_at_cursor (buffer, "Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. "
+ "Click a button. Click a button. Click a button. Click a button. ",
+ -1);
+
+ textview = gtk_text_view_new ();
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview), GTK_WRAP_WORD);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+ gtk_text_buffer_insert_at_cursor (buffer, "Hi there. Hi there. "
+ "Hi there. Hi there. Hi there. Hi there. Hi there. ", -1);
+ moo_paned_add_pane (MOO_PANED (paned),
+ textview,
+ "TextView",
+ GTK_STOCK_OK);
+ moo_paned_add_pane (MOO_PANED (paned),
+ gtk_label_new ("This is a label"),
+ "Label",
+ GTK_STOCK_CANCEL);
+
+ button = gtk_toggle_button_new ();
+ gtk_widget_show (button);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (sticky_button_toggled),
+ paned);
+ gtk_box_pack_end (GTK_BOX (MOO_PANED(paned)->button_box),
+ button, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("Sticky");
+ switch (pane_position)
+ {
+ case GTK_POS_LEFT:
+ gtk_label_set_angle (GTK_LABEL (label), 90);
+ break;
+ case GTK_POS_RIGHT:
+ gtk_label_set_angle (GTK_LABEL (label), 270);
+ break;
+ default:
+ break;
+ }
+
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (button), label);
+
+ gtk_widget_show_all (window);
+}
+
+
+int main (int argc, char *argv[])
+{
+ gtk_init (&argc, &argv);
+
+// gdk_window_set_debug_updates (TRUE);
+
+ create_window_with_paned (GTK_POS_RIGHT);
+ create_window_with_paned (GTK_POS_LEFT);
+ create_window_with_paned (GTK_POS_TOP);
+ create_window_with_paned (GTK_POS_BOTTOM);
+
+ gtk_main ();
+ return 0;
+}