summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2009-12-23 17:10:39 +0100
committerJon Bergli Heier <snakebite@jvnv.net>2009-12-23 17:10:39 +0100
commit1f0ef0bc2e7d0b99feb05e57f1c15a5a739c48fa (patch)
treed9000823af75d35d8c0b7a18d51b250c4c674b28
parenta539fdf38688cbed984d9db1f08deaaf34eaf9e0 (diff)
Reworked the main window.
Images are now placed in their own icon view. Folders are selected in the above tree view, while the icon view displays thumbnails of the images in the selected folder. The thumbnails are cached using the thumbnail specification (~/.thumbnails/).
-rw-r--r--browse_model.c443
-rw-r--r--browse_model.h50
-rw-r--r--thumbnails.c138
-rw-r--r--thumbnails.h8
-rw-r--r--walls.ui49
-rw-r--r--window_main.c131
6 files changed, 763 insertions, 56 deletions
diff --git a/browse_model.c b/browse_model.c
new file mode 100644
index 0000000..72aac8a
--- /dev/null
+++ b/browse_model.c
@@ -0,0 +1,443 @@
+#include "browse_model.h"
+
+static void browse_model_init(BrowseModel *browse_model);
+static void browse_model_class_init(BrowseModelClass *klass);
+static void browse_model_tree_model_init(GtkTreeModelIface *iface);
+static void browse_model_finalize(GObject *object);
+static GtkTreeModelFlags browse_model_get_flags(GtkTreeModel *tree_model);
+static gint browse_model_get_n_columns(GtkTreeModel *tree_model);
+static GType browse_model_get_column_type(GtkTreeModel *tree_model, gint index);
+static gboolean browse_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path);
+static GtkTreePath *browse_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static void browse_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value);
+static gboolean browse_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static gboolean browse_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent);
+static gboolean browse_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static gint browse_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static gboolean browse_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n);
+static gboolean browse_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child);
+
+static GObjectClass *parent_class = NULL;
+
+GType browse_model_get_type() {
+ static GType browse_model_type = 0;
+ if(browse_model_type == 0) {
+ static const GTypeInfo browse_model_info = {
+ sizeof(BrowseModelClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) browse_model_class_init,
+ NULL,
+ NULL,
+ sizeof(BrowseModel),
+ 0,
+ (GInstanceInitFunc) browse_model_init
+ };
+ static const GInterfaceInfo tree_model_info = {
+ (GInterfaceInitFunc) browse_model_tree_model_init,
+ NULL,
+ NULL
+ };
+ browse_model_type = g_type_register_static(G_TYPE_OBJECT, "BrowseModel", &browse_model_info, (GTypeFlags)0);
+ g_type_add_interface_static(browse_model_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
+ }
+ return browse_model_type;
+}
+
+static void browse_model_class_init(BrowseModelClass *klass) {
+ GObjectClass *object_class;
+
+ parent_class = (GObjectClass*)g_type_class_peek_parent(klass);
+ object_class = (GObjectClass*)klass;
+
+ object_class->finalize = browse_model_finalize;
+}
+
+static void browse_model_tree_model_init(GtkTreeModelIface *iface) {
+ iface->get_flags = browse_model_get_flags;
+ iface->get_n_columns = browse_model_get_n_columns;
+ iface->get_column_type = browse_model_get_column_type;
+ iface->get_iter = browse_model_get_iter;
+ iface->get_path = browse_model_get_path;
+ iface->get_value = browse_model_get_value;
+ iface->iter_next = browse_model_iter_next;
+ iface->iter_children = browse_model_iter_children;
+ iface->iter_has_child = browse_model_iter_has_child;
+ iface->iter_n_children = browse_model_iter_n_children;
+ iface->iter_nth_child = browse_model_iter_nth_child;
+ iface->iter_parent = browse_model_iter_parent;
+}
+
+static void browse_model_init(BrowseModel *browse_model) {
+ BrowseModelRecord temp;
+ GArray *array;
+ browse_model->n_columns = BROWSE_MODEL_N_COLUMNS;
+
+ browse_model->column_types[0] = G_TYPE_STRING;
+
+ g_assert(BROWSE_MODEL_N_COLUMNS == 1);
+
+ browse_model->num_rows = 0;
+ browse_model->rows = g_array_new(TRUE, FALSE, sizeof(BrowseModelRecord));
+ browse_model->stamp = g_random_int();
+
+ if(db_get_top_level_directories(&array)) {
+ for(int i = 0; i < array->len; i++) {
+ struct directory_t *dir;
+
+ dir = &g_array_index(array, struct directory_t, i);
+
+ temp.dir.name = g_strdup(dir->name);
+ temp.dir.dirid = dir->dirid;
+ temp.parent = NULL;
+ temp.children = NULL;
+ temp.pos = i;
+
+ g_free(dir->name);
+
+ g_array_append_val(browse_model->rows, temp);
+ browse_model->num_rows++;
+ }
+ g_array_free(array, TRUE);
+ }
+}
+
+static void finalize_recursive(BrowseModelRecord *record) {
+ if(!record->children)
+ return;
+
+ for(int i = 0; i < record->children->len; i++) {
+ BrowseModelRecord *temp;
+ temp = &g_array_index(record->children, BrowseModelRecord, i);
+ g_free(temp->dir.name);
+ }
+}
+
+static void browse_model_finalize(GObject *object) {
+ BrowseModel *browse_model;
+
+ g_assert(MODEL_IS_BROWSE(object));
+
+ browse_model = BROWSE_MODEL(object);
+
+ for(int i = 0; i < browse_model->rows->len; i++) {
+ BrowseModelRecord *temp;
+ temp = &g_array_index(browse_model->rows, BrowseModelRecord, i);
+ g_free(temp->dir.name);
+ finalize_recursive(temp);
+ }
+
+ g_array_free(browse_model->rows, TRUE);
+}
+
+static GtkTreeModelFlags browse_model_get_flags(GtkTreeModel *tree_model) {
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), (GtkTreeModelFlags)0);
+
+ return GTK_TREE_MODEL_ITERS_PERSIST;
+}
+
+static gint browse_model_get_n_columns(GtkTreeModel *tree_model) {
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), 0);
+
+ return BROWSE_MODEL(tree_model)->n_columns;
+}
+
+static GType browse_model_get_column_type(GtkTreeModel *tree_model, gint index) {
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail(index < BROWSE_MODEL(tree_model)->n_columns && index >= 0, G_TYPE_INVALID);
+
+ return BROWSE_MODEL(tree_model)->column_types[index];
+}
+
+inline static void fill_dir(BrowseModelRecord *record) {
+ GArray *array;
+
+ record->children = g_array_new(FALSE, FALSE, sizeof(BrowseModelRecord));
+ if(db_get_directories(record->dir.dirid, &array)) {
+ for(int i = 0; i < array->len; i++) {
+ BrowseModelRecord temp;
+ struct directory_t *dir;
+
+ dir = &g_array_index(array, struct directory_t, i);
+ temp.dir.name = g_strdup(dir->name);
+ temp.dir.dirid = dir->dirid;
+ temp.parent = record;
+ temp.children = NULL;
+ temp.pos = i;
+
+ g_array_append_val(record->children, temp);
+
+ g_free(dir->name);
+ }
+ g_array_free(array, TRUE);
+ }
+}
+
+#define BROWSE_MODEL_ENSURE_CHILDREN(obj) if(!(obj)->children) fill_dir((obj))
+
+inline static BrowseModelRecord *browse_model_get_record_recursive(BrowseModel *browse_model, gint *indices, gint depth) {
+ BrowseModelRecord *temp;
+ if(depth == 1) {
+ return &g_array_index(browse_model->rows, BrowseModelRecord, indices[depth-1]);
+ } else {
+ temp = browse_model_get_record_recursive(browse_model, indices, depth-1);
+ BROWSE_MODEL_ENSURE_CHILDREN(temp);
+ return &g_array_index(temp->children, BrowseModelRecord, indices[depth-1]);
+ }
+}
+
+static gboolean browse_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) {
+ BrowseModel *browse_model;
+ BrowseModelRecord *record;
+ gint *indices, n, depth;
+
+ g_assert(MODEL_IS_BROWSE(tree_model));
+ g_assert(path != NULL);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ indices = gtk_tree_path_get_indices(path);
+ depth = gtk_tree_path_get_depth(path);
+
+ n = indices[depth-1];
+ //if(n >= browse_model->num_rows || n < 0)
+ // return FALSE;
+
+ //record = &g_array_index(browse_model->rows, BrowseModelRecord, n);
+ record = browse_model_get_record_recursive(browse_model, indices, depth);
+
+ g_assert(record != NULL);
+ g_assert(record->pos == n);
+
+ iter->stamp = browse_model->stamp;
+ iter->user_data = record;
+ iter->user_data2 = NULL;
+ iter->user_data3 = NULL;
+
+ return TRUE;
+}
+
+static GtkTreePath *browse_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ GtkTreePath *path;
+ BrowseModelRecord *record;
+ BrowseModel *browse_model;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), NULL);
+ g_return_val_if_fail(iter != NULL, NULL);
+ g_return_val_if_fail(iter->user_data != NULL, NULL);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ record = (BrowseModelRecord*)iter->user_data;
+
+ path = gtk_tree_path_new();
+ gtk_tree_path_append_index(path, record->pos);
+
+ return path;
+}
+
+static void browse_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) {
+ BrowseModelRecord *record;
+ BrowseModel *browse_model;
+
+ g_return_if_fail(MODEL_IS_BROWSE(tree_model));
+ g_return_if_fail(iter != NULL);
+ g_return_if_fail(column < BROWSE_MODEL(tree_model)->n_columns);
+
+ g_value_init(value, BROWSE_MODEL(tree_model)->column_types[column]);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ record = (BrowseModelRecord*)iter->user_data;
+
+ g_return_if_fail(record != NULL);
+
+ //if(record->pos >= browse_model->num_rows)
+ // g_return_if_reached();
+
+ switch(column) {
+ case BROWSE_MODEL_COL_NAME:
+ g_value_set_string_take_ownership(value, (record->parent == NULL ? g_strdup(record->dir.name) : g_path_get_basename(record->dir.name)));
+ break;
+ }
+}
+
+static gboolean browse_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ BrowseModelRecord *record, *nextrecord;
+ BrowseModel *browse_model;
+ GArray *array;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE);
+
+ if(iter == NULL || iter->user_data == NULL)
+ return FALSE;
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ record = (BrowseModelRecord*)iter->user_data;
+
+ BROWSE_MODEL_ENSURE_CHILDREN(record);
+
+ array = (record->parent ? record->parent->children : browse_model->rows);
+
+ if((record->pos + 1) >= array->len)
+ return FALSE;
+
+ nextrecord = &g_array_index(array, BrowseModelRecord, record->pos + 1);
+
+ g_assert(nextrecord != NULL);
+ g_assert(nextrecord->pos == (record->pos + 1));
+
+ iter->stamp = browse_model->stamp;
+ iter->user_data = nextrecord;
+
+ return TRUE;
+}
+
+static gboolean browse_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) {
+ BrowseModel *browse_model;
+ BrowseModelRecord *parent_record;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ if(!parent) {
+ if(browse_model->num_rows == 0)
+ return FALSE;
+ iter->stamp = browse_model->stamp;
+ iter->user_data = &g_array_index(browse_model->rows, BrowseModelRecord, 0);
+ return TRUE;
+ }
+
+ //g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE);
+
+ parent_record = (BrowseModelRecord*)parent->user_data;
+
+ BROWSE_MODEL_ENSURE_CHILDREN(parent_record);
+
+ if(parent_record->children->len == 0)
+ return FALSE;
+
+ iter->stamp = browse_model->stamp;
+ iter->user_data = &g_array_index(parent_record->children, BrowseModelRecord, 0);
+
+ return TRUE;
+}
+
+static gboolean browse_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ BrowseModelRecord *record;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE);
+
+ record = (BrowseModelRecord*)iter->user_data;
+ BROWSE_MODEL_ENSURE_CHILDREN(record);
+
+ return (record->parent == NULL && BROWSE_MODEL(tree_model)->num_rows == 0 ? FALSE : (record->children->len > 0 ? TRUE : FALSE));
+}
+
+static gint browse_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ BrowseModel *browse_model;
+ BrowseModelRecord *record;
+ GArray *array;
+ int n;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), -1);
+ g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ if(!iter) {
+ return browse_model->num_rows;
+ }
+
+ record = (BrowseModelRecord*)iter->user_data;
+
+ //array = NULL;
+ //g_return_val_if_fail(db_get_wallpapers(record->dir.dirid, &array), -1);
+ //for(n = 0; (&g_array_index(array, struct wallpaper_t, n))->filepath; n++);
+
+ BROWSE_MODEL_ENSURE_CHILDREN(record);
+
+ return record->children->len;
+
+ return n;
+}
+
+static gboolean browse_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) {
+ BrowseModelRecord *record, *parent_record;
+ BrowseModel *browse_model;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ if(!parent) {
+ if(n >= browse_model->num_rows)
+ return FALSE;
+ record = &g_array_index(browse_model->rows, BrowseModelRecord, n);
+
+ iter->stamp = browse_model->stamp;
+ iter->user_data = record;
+
+ return TRUE;
+ }
+
+ //if(n >= browse_model->num_rows)
+ // return FALSE;
+
+ parent_record = parent->user_data;
+
+ BROWSE_MODEL_ENSURE_CHILDREN(parent_record);
+
+ if(n >= parent_record->children->len)
+ return FALSE;
+
+ record = &g_array_index(parent_record->children, BrowseModelRecord, n);
+
+ g_assert(record != NULL);
+ g_assert(record->pos == n);
+
+ iter->stamp = browse_model->stamp;
+ iter->user_data = record;
+
+ return TRUE;
+}
+
+static gboolean browse_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) {
+ BrowseModelRecord *record, *childrecord;
+ BrowseModel *browse_model;
+
+ g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE);
+
+ browse_model = BROWSE_MODEL(tree_model);
+
+ childrecord = (BrowseModelRecord*)child->user_data;
+
+ iter->stamp = browse_model->stamp;
+ iter->user_data = childrecord->parent;
+
+ return TRUE;
+}
+
+BrowseModel *browse_model_new() {
+ BrowseModel *new_browse_model;
+
+ new_browse_model = (BrowseModel*)g_object_new(MODEL_TYPE_BROWSE, NULL);
+
+ g_assert(new_browse_model != NULL);
+
+ return new_browse_model;
+}
+
+void browse_model_get_dir_record(GtkTreeModel *tree_model, GtkTreeIter *iter, struct directory_t **dir) {
+ BrowseModel *browse_model;
+ BrowseModelRecord *record;
+
+ g_assert(MODEL_IS_BROWSE(tree_model));
+ g_assert(iter != NULL);
+
+ browse_model = BROWSE_MODEL(tree_model);
+ record = (BrowseModelRecord*)iter->user_data;
+ *dir = &record->dir;
+}
diff --git a/browse_model.h b/browse_model.h
new file mode 100644
index 0000000..1070d74
--- /dev/null
+++ b/browse_model.h
@@ -0,0 +1,50 @@
+#ifndef _BROWSE_MODEL_H_
+#define _BROWSE_MODEL_H_
+
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#include "db.h"
+
+#define MODEL_TYPE_BROWSE (browse_model_get_type())
+#define BROWSE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MODEL_TYPE_BROWSE, BrowseModel))
+#define BROWSE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), MODEL_TYPE_BROWSE, BrowseModelClass))
+#define MODEL_IS_BROWSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MODEL_TYPE_BROWSE))
+#define MODEL_IS_BROWSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), MODEL_TYPE_BROWSE))
+#define BROWSE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MODEL_TYPE_BROWSE, BrowseModelClass))
+
+enum {
+ BROWSE_MODEL_COL_NAME = 0,
+ BROWSE_MODEL_N_COLUMNS,
+};
+
+typedef struct _BrowseModelRecord BrowseModelRecord;
+typedef struct _BrowseModel BrowseModel;
+typedef struct _BrowseModelClass BrowseModelClass;
+
+struct _BrowseModelRecord {
+ struct directory_t dir;
+ BrowseModelRecord *parent;
+ GArray *children;
+ guint pos;
+};
+
+struct _BrowseModel {
+ GObject parent;
+
+ guint num_rows;
+ GArray *rows;
+ gint n_columns;
+ GType column_types[BROWSE_MODEL_N_COLUMNS];
+ gint stamp;
+};
+
+struct _BrowseModelClass {
+ GObjectClass parent_class;
+};
+
+GType browse_model_get_type();
+BrowseModel *browse_model_new();
+void browse_model_get_dir_record(GtkTreeModel*, GtkTreeIter*, struct directory_t**);
+
+#endif
diff --git a/thumbnails.c b/thumbnails.c
new file mode 100644
index 0000000..18e2d9f
--- /dev/null
+++ b/thumbnails.c
@@ -0,0 +1,138 @@
+#include <unistd.h>
+#include <utime.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include "db.h"
+#include "thumbnails.h"
+
+inline static gchar *get_wall_thumb_name(const gchar *filepath) {
+ GChecksum *ck;
+ gchar *s;
+ gchar *cksum;
+
+ ck = g_checksum_new(G_CHECKSUM_MD5);
+ s = g_strdup_printf("file://%s", filepath);
+ g_checksum_update(ck, s, -1);
+ g_free(s);
+ cksum = g_strdup_printf("%s/.thumbnails/normal/%s.png", g_get_home_dir(), g_checksum_get_string(ck));
+ g_checksum_free(ck);
+ return cksum;
+}
+
+inline static time_t get_mtime(const gchar *filepath) {
+ struct utimbuf times;
+
+ if(g_utime(filepath, &times) == 0) {
+ return times.modtime;
+ } else {
+ return 0;
+ }
+}
+
+GdkPixbuf *get_thumbnail(const gchar *filepath) {
+ GdkPixbuf *pb, *pb2;
+ gint win_width, win_height, img_width, img_height, width, height;
+ gdouble scalex, scaley, width_ratio, height_ratio, max_ratio;
+ GError *error = NULL;
+ gchar *thumbname;
+
+ thumbname = get_wall_thumb_name(filepath);
+
+ if(g_access(thumbname, F_OK) == 0) {
+ pb = gdk_pixbuf_new_from_file(thumbname, &error);
+ g_free(thumbname);
+ return pb;
+ } else {
+ pb = gdk_pixbuf_new_from_file(filepath, &error);
+ }
+
+ if(!pb) {
+ g_warning("%s", error->message);
+ g_free(error);
+ return NULL;
+ }
+
+ img_width = gdk_pixbuf_get_width(pb);
+ img_height = gdk_pixbuf_get_height(pb);
+ win_width = win_height = 128;
+
+ width_ratio = (gdouble)img_width / (gdouble)win_width;
+ height_ratio = (gdouble)img_height / (gdouble)win_height;
+ if(width_ratio > height_ratio) {
+ width = win_width;
+ height = (gint)(1.0 / width_ratio * img_height);
+ } else {
+ height = win_height;
+ width = (gint)(1.0 / height_ratio * img_width);
+ }
+ scalex = (gdouble)width / (gdouble)img_width;
+ scaley = (gdouble)height / (gdouble)img_height;
+
+ pb2 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+ gdk_pixbuf_scale(pb, pb2, 0, 0, width, height, 0, 0, scalex, scaley, GDK_INTERP_BILINEAR);
+ g_object_unref(pb);
+
+ error = NULL;
+ if(!gdk_pixbuf_save(pb2, thumbname, "png", &error,
+ "tEXt::Thumb::URI", filepath,
+ "tEXt::Thumb::MTime", get_mtime(filepath),
+ "tEXt::Software", "walls",
+ NULL)) {
+ g_warning("%s", error->message);
+ g_free(error);
+ }
+
+ g_free(thumbname);
+
+ return pb2;
+}
+
+static void fill_wall_list(GtkListStore *liststore, GArray *array) {
+ GtkTreeIter iter;
+
+ for(int i = 0; i < array->len; i++) {
+ struct wallpaper_t *wall;
+ wall = &g_array_index(array, struct wallpaper_t, i);
+
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter, 0, NULL, 1, wall->filepath, -1);
+ g_free(wall->filepath);
+ }
+ g_array_free(array, TRUE);
+}
+
+gpointer add_thumbs_thread(gpointer data) {
+ GtkListStore *liststore;
+ GtkTreeIter iter;
+ int n;
+ GValue value;
+ GdkPixbuf *pb = NULL;
+ const gchar *filepath;
+
+ liststore = GTK_LIST_STORE(data);
+
+ if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter)) {
+ return NULL;
+ }
+
+ n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore), NULL);
+
+ memset(&value, 0, sizeof(GValue));
+
+ for(int i = 0; i < n; i++) {
+ gtk_tree_model_get_value(GTK_TREE_MODEL(liststore), &iter, 1, &value);
+ printf("file: %s\n", g_value_get_string(&value));
+ filepath = g_value_get_string(&value);
+ pb = get_thumbnail(filepath);
+ g_value_unset(&value);
+ if(pb) {
+ gtk_list_store_set(liststore, &iter, 0, pb, -1);
+
+ g_object_unref(pb);
+ }
+ gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter);
+ }
+}
diff --git a/thumbnails.h b/thumbnails.h
new file mode 100644
index 0000000..d4ab69f
--- /dev/null
+++ b/thumbnails.h
@@ -0,0 +1,8 @@
+#ifndef _THUMBNAILS_H_
+#define _THUMBNAILS_H_
+
+#include <glib.h>
+
+gpointer add_thumbs_thread(gpointer data);
+
+#endif
diff --git a/walls.ui b/walls.ui
index bbc024b..67b227e 100644
--- a/walls.ui
+++ b/walls.ui
@@ -86,30 +86,61 @@
<object class="GtkHPaned" id="window_hpane">
<property name="visible">True</property>
<child>
- <object class="GtkNotebook" id="left_pages">
+ <object class="GtkVPaned" id="vpaned1">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkScrolledWindow" id="filtree_scroller">
+ <object class="GtkNotebook" id="left_pages">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkTreeView" id="filetree">
+ <object class="GtkScrolledWindow" id="filtree_scroller">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="foldtree">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">File Hierarchy</property>
</object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
</child>
</object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
</child>
- <child type="tab">
- <object class="GtkLabel" id="label1">
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
- <property name="label" translatable="yes">File Hierarchy</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkIconView" id="thumbview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="orientation">horizontal</property>
+ <signal name="selection_changed" handler="on_thumbview_selection_changed"/>
+ </object>
+ </child>
</object>
<packing>
- <property name="tab_fill">False</property>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
</packing>
</child>
</object>
diff --git a/window_main.c b/window_main.c
index cfc24c6..e84144f 100644
--- a/window_main.c
+++ b/window_main.c
@@ -1,12 +1,16 @@
+//#include <unistd.h>
#include <string.h>
+#include <glib/gstdio.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "window_main.h"
#include "walls_ui.h"
#include "db.h"
+#include "browse_model.h"
#include "walls_model.h"
#include "wallpapers.h"
+#include "thumbnails.h"
GdkPixbuf *orig_pixbuf = NULL;
gint last_width = 0,
@@ -16,59 +20,37 @@ gint last_width = 0,
GtkImage *image = NULL;
GtkWidget *layout = NULL;
GtkStatusbar *statusbar;
+GtkIconView *thumbview;
-GThread *add_thread = NULL;
+GThread *add_thread = NULL,
+ *thumb_thread = NULL;
-void on_filetree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data);
+void on_foldtree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data);
-inline static void filetree_create_model(GtkTreeView *filetree) {
+inline static void foldtree_create_model(GtkTreeView *foldtree) {
GtkTreeModel *tree_model;
- tree_model = GTK_TREE_MODEL(walls_model_new());
- gtk_tree_view_set_model(filetree, GTK_TREE_MODEL(tree_model));
+ tree_model = GTK_TREE_MODEL(browse_model_new());
+ gtk_tree_view_set_model(foldtree, GTK_TREE_MODEL(tree_model));
}
-inline static void filetree_init(GtkTreeView *filetree) {
- GtkTreeViewColumn *col1, *col2, *col3, *col4;
+inline static void foldtree_init(GtkTreeView *foldtree) {
+ GtkTreeViewColumn *col1;
GtkCellRenderer *renderer;
GtkTreeSelection *selection;
col1 = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(col1, "Name");
- gtk_tree_view_append_column(filetree, col1);
-
- col2 = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(col2, "Size");
- gtk_tree_view_append_column(filetree, col2);
-
- col3 = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(col3, "Width");
- gtk_tree_view_append_column(filetree, col3);
-
- col4 = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(col4, "Height");
- gtk_tree_view_append_column(filetree, col4);
+ gtk_tree_view_append_column(foldtree, col1);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(col1, renderer, TRUE);
gtk_tree_view_column_add_attribute(col1, renderer, "text", 0);
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_column_pack_start(col2, renderer, TRUE);
- gtk_tree_view_column_add_attribute(col2, renderer, "text", 1);
-
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_column_pack_start(col3, renderer, TRUE);
- gtk_tree_view_column_add_attribute(col3, renderer, "text", 2);
-
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_column_pack_start(col4, renderer, TRUE);
- gtk_tree_view_column_add_attribute(col4, renderer, "text", 3);
-
- filetree_create_model(filetree);
+ foldtree_create_model(foldtree);
- selection = gtk_tree_view_get_selection(filetree);
- g_signal_connect(selection, "changed", G_CALLBACK(on_filetree_selection_changed), filetree);
+ selection = gtk_tree_view_get_selection(foldtree);
+ g_signal_connect(selection, "changed", G_CALLBACK(on_foldtree_selection_changed), foldtree);
}
static void resize_pixbuf() {
@@ -131,16 +113,14 @@ void on_window_hpane_resized(GObject *gobject, GParamSpec *pspec, gpointer user_
}
}
-static void load_pixbuf(struct wallpaper_t *wall) {
+static void load_pixbuf(const gchar *filepath) {
GdkPixbuf *pb;
GError *error = NULL;
GdkWindow *window;
- gint win_width, win_height, img_width, img_height, width, height;
- gdouble scalex, scaley, width_ratio, height_ratio, max_ratio;
if(orig_pixbuf)
g_object_unref(orig_pixbuf);
- orig_pixbuf = gdk_pixbuf_new_from_file(wall->filepath, &error);
+ orig_pixbuf = gdk_pixbuf_new_from_file(filepath, &error);
if(!orig_pixbuf) {
g_warning("%s", error->message);
g_free(error);
@@ -150,16 +130,70 @@ static void load_pixbuf(struct wallpaper_t *wall) {
resize_pixbuf();
}
-void on_filetree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) {
+static void fill_wall_list(GtkListStore *liststore, GArray *array) {
+ GtkTreeIter iter;
+
+ for(int i = 0; i < array->len; i++) {
+ struct wallpaper_t *wall;
+ wall = &g_array_index(array, struct wallpaper_t, i);
+
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter, 0, NULL, 1, wall->filepath, -1);
+ g_free(wall->filepath);
+ }
+ g_array_free(array, TRUE);
+}
+
+void on_foldtree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) {
GtkTreeModel *model;
GtkTreeIter iter;
- struct wallpaper_t *wall;
+ struct directory_t *dir;
+ GArray *array;
+ GtkListStore *liststore;
+ GError *error = NULL;
if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
- if(walls_model_get_record_type(model, &iter) == WALLS_MODEL_TYPE_WALL) {
- walls_model_get_wall_record(model, &iter, &wall);
- load_pixbuf(wall);
+ browse_model_get_dir_record(model, &iter, &dir);
+
+ if(!db_get_wallpapers(dir->dirid, &array))
+ return;
+
+ liststore = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+ fill_wall_list(liststore, array);
+ gtk_icon_view_set_model(thumbview, GTK_TREE_MODEL(liststore));
+
+ thumb_thread = g_thread_create(add_thumbs_thread, liststore, FALSE, &error);
+
+ if(!thumb_thread) {
+ g_warning("%s", error->message);
+ g_free(error);
+ }
+ }
+}
+
+void on_thumbview_selection_changed(GtkIconView *iconview, gpointer user_data) {
+ GList *list;
+ GValue value;
+ const gchar *filename;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ list = gtk_icon_view_get_selected_items(iconview);
+ if(list) {
+ if(g_list_length(list) == 1) {
+ path = g_list_nth_data(list, 0);
+ model = gtk_icon_view_get_model(iconview);
+ gtk_tree_model_get_iter(model, &iter, path);
+ memset(&value, 0, sizeof(GValue));
+ gtk_tree_model_get_value(model, &iter, 1, &value);
+ filename = g_value_get_string(&value);
+ load_pixbuf(filename);
+ g_value_unset(&value);
}
+
+ g_list_foreach(list, gtk_tree_path_free, NULL);
+ g_list_free(list);
}
}
@@ -198,7 +232,7 @@ void on_add_dir_action_activate(GtkAction *action, gpointer user_data) {
int gui_main(int argc, char **argv) {
GtkWidget *window;
- GtkWidget *filetree;
+ GtkWidget *foldtree;
GtkWidget *window_hpane;
GtkBuilder *builder ;
GError *error = NULL;
@@ -222,8 +256,11 @@ int gui_main(int argc, char **argv) {
window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
gtk_window_set_title(GTK_WINDOW(window), "walls");
- filetree = GTK_WIDGET(gtk_builder_get_object(builder, "filetree"));
- filetree_init(GTK_TREE_VIEW(filetree));
+ foldtree = GTK_WIDGET(gtk_builder_get_object(builder, "foldtree"));
+ foldtree_init(GTK_TREE_VIEW(foldtree));
+
+ thumbview = GTK_ICON_VIEW(gtk_builder_get_object(builder, "thumbview"));
+ gtk_icon_view_set_pixbuf_column(thumbview, 0);
image = GTK_IMAGE(gtk_builder_get_object(builder, "image"));
layout = GTK_WIDGET(gtk_builder_get_object(builder, "layout"));