summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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"));