diff options
-rw-r--r-- | browse_model.c | 443 | ||||
-rw-r--r-- | browse_model.h | 50 | ||||
-rw-r--r-- | thumbnails.c | 138 | ||||
-rw-r--r-- | thumbnails.h | 8 | ||||
-rw-r--r-- | walls.ui | 49 | ||||
-rw-r--r-- | window_main.c | 131 |
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, ×) == 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 @@ -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")); |