From 4e9cdd282beb1c6dcbcca148745f5665b561c403 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Tue, 22 Dec 2009 19:26:54 +0100 Subject: Initial commit. --- .gitignore | 7 + SConstruct | 38 +++++ db.c | 312 ++++++++++++++++++++++++++++++++++++++ db.h | 29 ++++ main.c | 9 ++ wallpapers.c | 82 ++++++++++ walls.ui | 140 +++++++++++++++++ walls_model.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ walls_model.h | 63 ++++++++ window_main.c | 152 +++++++++++++++++++ window_main.h | 8 + 11 files changed, 1319 insertions(+) create mode 100644 .gitignore create mode 100644 SConstruct create mode 100644 db.c create mode 100644 db.h create mode 100644 main.c create mode 100644 wallpapers.c create mode 100644 walls.ui create mode 100644 walls_model.c create mode 100644 walls_model.h create mode 100644 window_main.c create mode 100644 window_main.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a0a897 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.*.swp +*.o +/.sconf_temp +/.sconsign.dblite +/config.log +/walls_ui.h +/walls diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..4aae244 --- /dev/null +++ b/SConstruct @@ -0,0 +1,38 @@ +env = Environment() + +conf = Configure(env) +for lib, h in (('Imlib2', 'Imlib2.h'), ('glib-2.0', None), ('sqlite3', 'sqlite3.h'), ('gtk-x11-2.0', None)): + if h: + libfound = conf.CheckLibWithHeader(lib, h, 'c') + else: + libfound = conf.CheckLib(lib) + if not libfound: + print 'Can''t find %s' % lib + Exit(1) +env = conf.Finish() + +env.Append(CCFLAGS = ['-std=gnu99', '-g']) +env.Append(LINKFLAGS = ['-Wl,--export-dynamic']) +env.ParseConfig('imlib2-config --cflags --libs') +env.ParseConfig('pkg-config --cflags --libs glib-2.0') +env.ParseConfig('pkg-config --cflags --libs sqlite3') +env.ParseConfig('pkg-config --cflags --libs gtk+-2.0') + +def build_ui(target, source, env): + f = open(str(target[0]), 'w') + f.write('#ifndef _WALLS_UI_H_\n') + f.write('#define _WALLS_UI_H_\n') + f.write('#include \n') + f.write('gchar *ui_string = \n') + for line in open(str(source[0]), 'r'): + f.write('"%s"\n' % line.replace('"', '\\"').strip()) + f.write(';\n') + f.write('#endif\n') + +ui_builder = Builder(action = build_ui) + +env['BUILDERS']['walls_ui'] = ui_builder +env.walls_ui('walls_ui.h', 'walls.ui') +env.Program('walls', Glob('*.c')) + +# vim: syn=python diff --git a/db.c b/db.c new file mode 100644 index 0000000..2fbaed8 --- /dev/null +++ b/db.c @@ -0,0 +1,312 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "db.h" + +sqlite3 *db = NULL; + +void db_close(); + +static int db_create_tables() { + char *errmsg; + int rc; + rc = sqlite3_exec(db, + "create table directory (" + " id integer not null," + " parent integer null," + " name varchar(255)," + " primary key (id)" + ");" + "create table wallpaper (" + " id integer not null," + " dirid integer not null," + " filepath text not null," + " size integer not null," + " width integer not null," + " height integer not null," + " primary key (id)" + ");" + "create table tag (" + " id integer not null," + " name varchar(100) not null," + " primary key (id)" + ");" + "create table walltags (" + " wallid integer not null," + " tagid integer not null," + " primary key (wallid, tagid)" + ");", + NULL, NULL, &errmsg); + if(rc != SQLITE_OK) { + fprintf(stderr, "db_create_tables failed: %s\n", errmsg); + sqlite3_free(errmsg); + return 0; + } + return 1; +} + +int db_open() { + int rc; + int configfound; + char *dbfile; + char *configdir; + + configdir = g_strdup_printf("%s/walls", g_get_user_config_dir()); + if(access(configdir, F_OK) == -1 && g_mkdir_with_parents(configdir, 0700) == -1) { + g_free(configdir); + return 0; + } + g_free(configdir); + + dbfile = g_strdup_printf("%s/walls/db", g_get_user_config_dir()); + printf("db file: %s\n", dbfile); + configfound = access(dbfile, F_OK) == 0; + + rc = sqlite3_open(dbfile, &db); + g_free(dbfile); + + if(rc != SQLITE_OK) { + return 0; + } + + if(!configfound && !db_create_tables()) { + db_close(); + return 0; + } + + return 1; +} + +void db_close() { + if(db) { + sqlite3_close(db); + db = NULL; + } +} + +sqlite_uint64 db_add_directory(const char *path, sqlite_uint64 parent) { + sqlite3_stmt *stmt; + int rc; + + if(parent) { + rc = sqlite3_prepare_v2(db, "INSERT INTO directory (name, parent) VALUES (?, ?)", -1, &stmt, NULL); + } else { + rc = sqlite3_prepare_v2(db, "INSERT INTO directory (name) VALUES (?)", -1, &stmt, NULL); + } + + if(rc != SQLITE_OK) { + return 0; + } + + rc = sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC); + if(rc != SQLITE_OK) { + return 0; + } + + if(parent) { + rc = sqlite3_bind_int(stmt, 2, parent); + if(rc != SQLITE_OK) { + return 0; + } + } + + rc = sqlite3_step(stmt); + + sqlite3_finalize(stmt); + if(rc == SQLITE_DONE) { + return sqlite3_last_insert_rowid(db); + } else { + return 0; + } +} + +sqlite_uint64 db_get_directory(const char *path) { + sqlite3_stmt *stmt; + int rc; + sqlite_uint64 dirid; + + rc = sqlite3_prepare_v2(db, "SELECT id FROM directory WHERE name = ? LIMIT 1", -1, &stmt, NULL); + if(rc != SQLITE_OK) { + return 0; + } + + rc = sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + rc = sqlite3_step(stmt); + if(rc == SQLITE_ROW) { + dirid = sqlite3_column_int64(stmt, 0); + sqlite3_finalize(stmt); + return dirid; + } + + sqlite3_finalize(stmt); + return 0; +} + +int db_get_top_level_directories(GArray **array) { + struct directory_t temp, *temp2; + sqlite3_stmt *stmt; + int rc; + + rc = sqlite3_prepare_v2(db, "SELECT id, name FROM directory WHERE parent ISNULL ORDER BY name", -1, &stmt, NULL); + if(rc != SQLITE_OK) { + return 0; + } + + *array = g_array_new(TRUE, FALSE, sizeof(struct directory_t)); + while((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + temp.name = g_strdup(sqlite3_column_text(stmt, 1)); + temp.dirid = sqlite3_column_int64(stmt, 0); + g_array_append_val(*array, temp); + } + + sqlite3_finalize(stmt); + + if(rc != SQLITE_DONE) { + for(int i = 0; (*array)->len; i++) { + temp2 = &g_array_index(*array, struct directory_t, i); + g_free(temp2->name); + } + g_array_free(*array, TRUE); + return 0; + } + + return 1; +} + +int db_get_directories(sqlite_uint64 parent, GArray **array) { + struct directory_t temp, *temp2; + sqlite3_stmt *stmt; + int rc; + + rc = sqlite3_prepare_v2(db, "SELECT id, name FROM directory WHERE parent = ? ORDER BY name", -1, &stmt, NULL); + if(rc != SQLITE_OK) { + return 0; + } + + rc = sqlite3_bind_int64(stmt, 1, parent); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + *array = g_array_new(TRUE, FALSE, sizeof(struct directory_t)); + while((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + temp.name = g_strdup(sqlite3_column_text(stmt, 1)); + temp.dirid = sqlite3_column_int64(stmt, 0); + g_array_append_val(*array, temp); + } + + sqlite3_finalize(stmt); + + if(rc != SQLITE_DONE) { + for(int i = 0; i < (*array)->len; i++) { + temp2 = &g_array_index(*array, struct directory_t, i); + g_free(temp2->name); + } + g_array_free(*array, TRUE); + return 0; + } + + return 1; +} + +sqlite_uint64 db_add_wallpaper(const char *filepath, sqlite_uint64 dirid, int size, int width, int height) { + sqlite3_stmt *stmt; + int rc; + + rc = sqlite3_prepare_v2(db, "INSERT INTO wallpaper (dirid, filepath, size, width, height) VALUES (?, ?, ?, ?, ?)", -1, &stmt, NULL); + + if(rc != SQLITE_OK) { + return 0; + } + + rc = sqlite3_bind_int64(stmt, 1, dirid); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + rc = sqlite3_bind_text(stmt, 2, filepath, -1, SQLITE_STATIC); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + rc = sqlite3_bind_int(stmt, 3, size); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + rc = sqlite3_bind_int(stmt, 4, width); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + rc = sqlite3_bind_int(stmt, 5, height); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + rc = sqlite3_step(stmt); + + sqlite3_finalize(stmt); + if(rc == SQLITE_DONE) { + return sqlite3_last_insert_rowid(db); + } else { + return 0; + } +} + +int db_get_wallpapers(sqlite_uint64 dirid, GArray **array) { + struct wallpaper_t temp, *temp2; + sqlite3_stmt *stmt; + int rc; + + rc = sqlite3_prepare_v2(db, "SELECT id, filepath, size, width, height FROM wallpaper WHERE dirid = ? ORDER BY filepath", -1, &stmt, NULL); + + if(rc != SQLITE_OK) { + return 0; + } + + rc = sqlite3_bind_int64(stmt, 1, dirid); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + *array = g_array_new(TRUE, FALSE, sizeof(struct wallpaper_t)); + while((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + temp.filepath = g_strdup(sqlite3_column_text(stmt, 1)); + temp.id = sqlite3_column_int64(stmt, 1); + temp.size = sqlite3_column_int(stmt, 2); + temp.width = sqlite3_column_int(stmt, 3); + temp.height = sqlite3_column_int(stmt, 4); + g_array_append_val(*array, temp); + } + + sqlite3_finalize(stmt); + + if(rc != SQLITE_DONE) { + for(int i = 0; i < (*array)->len; i++) { + temp2 = &g_array_index(*array, struct wallpaper_t, i); + g_free(temp2->filepath); + } + return 0; + } + + return 1; +} diff --git a/db.h b/db.h new file mode 100644 index 0000000..3e17d9c --- /dev/null +++ b/db.h @@ -0,0 +1,29 @@ +#ifndef _DB_H_ +#define _DB_H_ + +#include +#include + +struct directory_t { + gchar *name; + sqlite_uint64 dirid; +}; + +struct wallpaper_t { + gchar *filepath; + sqlite_uint64 id; + int size; + int width; + int height; +}; + +int db_open(); +void db_close(); +sqlite_uint64 db_add_directory(const char*, sqlite_uint64); +sqlite_uint64 db_get_directory(const char*); +int db_get_top_level_directories(GArray**); +int db_get_directories(sqlite_uint64, GArray**); +sqlite_uint64 db_add_wallpaper(const char*, sqlite_uint64, int, int, int); +int db_get_wallpapers(sqlite_uint64, GArray**); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..7819dc6 --- /dev/null +++ b/main.c @@ -0,0 +1,9 @@ +#include "window_main.h" + +int main(int argc, char **argv) { + /*printf("%s\n", db_open() ? "db opened" : "failed to open db"); + listdir("/mnt/stuff/wallpapers", 0); + db_close();*/ + + return gui_main(argc, argv); +} diff --git a/wallpapers.c b/wallpapers.c new file mode 100644 index 0000000..525a6c4 --- /dev/null +++ b/wallpapers.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "db.h" + +void listdir(const char *path, sqlite_uint64 parent) { + int pathlen = strlen(path); + //DIR *dir = opendir(path); + //struct dirent *de; + GDir *dir; + const char *filename; + sqlite_uint64 dir_temp; + sqlite_uint64 dirid; + + dirid = db_get_directory(path); + if(dirid == 0) { + dirid = db_add_directory(path, parent); + if(dirid == 0) + return; + } + + dir = g_dir_open(path, 0, NULL); + if(!dir) + return; + + while((filename = g_dir_read_name(dir)) != NULL) { + char *filepath = g_strdup_printf("%s/%s", path, filename); + if(g_access(filepath, R_OK) == -1) { + fprintf(stderr, "Can't read %s: \n", filepath, strerror(errno)); + g_free(filepath); + continue; + } + struct stat st; + if(g_stat(filepath, &st) == -1) { + fprintf(stderr, "Failed to stat file %s\n", filepath); + g_free(filepath); + continue; + } + switch(st.st_mode & S_IFMT) { + case S_IFDIR: + if(strcmp(filepath, ".") == 0 || strcmp(filepath, "..") == 0) { + g_free(filepath); + continue; + } + printf("Directory: %s\n", filepath); + listdir(filepath, dirid); + continue; + case S_IFLNK: + case S_IFREG: + break; + default: + printf("Skipping %s\n", filepath); + g_free(filepath); + continue; + } + Imlib_Image image; + image = imlib_load_image(filepath); + if(image) { + imlib_context_set_image(image); + printf("%s loaded: %dx%d\n", filepath, imlib_image_get_width(), imlib_image_get_height()); + if(db_add_wallpaper(filepath, dirid, st.st_size, imlib_image_get_width(), imlib_image_get_height())) + printf("added\n"); + else + printf("failed to add\n"); + imlib_free_image(); + } else { + fprintf(stderr, "%s failed\n", filepath); + } + g_free(filepath); + } + g_dir_close(dir); +} diff --git a/walls.ui b/walls.ui new file mode 100644 index 0000000..0084e1f --- /dev/null +++ b/walls.ui @@ -0,0 +1,140 @@ + + + + + + + + + True + vertical + + + True + + + True + _File + True + + + True + + + True + + + + + gtk-quit + True + True + True + + + + + + + + + + + True + _View + True + + + + + True + _Help + True + + + True + + + gtk-about + True + True + True + + + + + + + + + False + 0 + + + + + True + + + True + True + + + True + True + automatic + automatic + + + True + True + + + + + + + True + File Hierarchy + + + False + + + + + 0 + + + + + True + 0 + none + + + + + + 1 + + + + + 1 + + + + + True + 2 + + + False + 2 + + + + + + diff --git a/walls_model.c b/walls_model.c new file mode 100644 index 0000000..0cfc4f8 --- /dev/null +++ b/walls_model.c @@ -0,0 +1,479 @@ +#include "walls_model.h" + +static void walls_model_init(WallsModel *walls_model); +static void walls_model_class_init(WallsModelClass *klass); +static void walls_model_tree_model_init(GtkTreeModelIface *iface); +static void walls_model_finalize(GObject *object); +static GtkTreeModelFlags walls_model_get_flags(GtkTreeModel *tree_model); +static gint walls_model_get_n_columns(GtkTreeModel *tree_model); +static GType walls_model_get_column_type(GtkTreeModel *tree_model, gint index); +static gboolean walls_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path); +static GtkTreePath *walls_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter); +static void walls_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value); +static gboolean walls_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter); +static gboolean walls_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent); +static gboolean walls_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter); +static gint walls_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter); +static gboolean walls_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n); +static gboolean walls_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child); + +static GObjectClass *parent_class = NULL; + +GType walls_model_get_type() { + static GType walls_model_type = 0; + if(walls_model_type == 0) { + static const GTypeInfo walls_model_info = { + sizeof(WallsModelClass), + NULL, + NULL, + (GClassInitFunc) walls_model_class_init, + NULL, + NULL, + sizeof(WallsModel), + 0, + (GInstanceInitFunc) walls_model_init + }; + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) walls_model_tree_model_init, + NULL, + NULL + }; + walls_model_type = g_type_register_static(G_TYPE_OBJECT, "WallsModel", &walls_model_info, (GTypeFlags)0); + g_type_add_interface_static(walls_model_type, GTK_TYPE_TREE_MODEL, &tree_model_info); + } + return walls_model_type; +} + +static void walls_model_class_init(WallsModelClass *klass) { + GObjectClass *object_class; + + parent_class = (GObjectClass*)g_type_class_peek_parent(klass); + object_class = (GObjectClass*)klass; + + object_class->finalize = walls_model_finalize; +} + +static void walls_model_tree_model_init(GtkTreeModelIface *iface) { + iface->get_flags = walls_model_get_flags; + iface->get_n_columns = walls_model_get_n_columns; + iface->get_column_type = walls_model_get_column_type; + iface->get_iter = walls_model_get_iter; + iface->get_path = walls_model_get_path; + iface->get_value = walls_model_get_value; + iface->iter_next = walls_model_iter_next; + iface->iter_children = walls_model_iter_children; + iface->iter_has_child = walls_model_iter_has_child; + iface->iter_n_children = walls_model_iter_n_children; + iface->iter_nth_child = walls_model_iter_nth_child; + iface->iter_parent = walls_model_iter_parent; +} + +static void walls_model_init(WallsModel *walls_model) { + WallsModelRecord temp; + GArray *array; + walls_model->n_columns = WALLS_MODEL_N_COLUMNS; + + walls_model->column_types[0] = G_TYPE_STRING; + walls_model->column_types[1] = G_TYPE_UINT64; + walls_model->column_types[2] = G_TYPE_INT; + walls_model->column_types[3] = G_TYPE_INT; + walls_model->column_types[4] = G_TYPE_INT; + + g_assert(WALLS_MODEL_N_COLUMNS == 5); + + walls_model->num_rows = 0; + walls_model->rows = g_array_new(TRUE, FALSE, sizeof(WallsModelRecord)); + walls_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.type = WALLS_MODEL_TYPE_DIR; + 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(walls_model->rows, temp); + walls_model->num_rows++; + } + g_array_free(array, TRUE); + } +} + +static void walls_model_finalize(GObject *object) { + printf("walls_model_finalize\n"); + WallsModel *walls_model; + + g_assert(MODEL_IS_WALLS(object)); + + walls_model = WALLS_MODEL(object); + + for(int i = 0; i < walls_model->rows->len; i++) { + WallsModelRecord *temp; + temp = &g_array_index(walls_model->rows, WallsModelRecord, i); + g_free(temp->dir.name); + } + + g_array_free(walls_model->rows, TRUE); +} + +static GtkTreeModelFlags walls_model_get_flags(GtkTreeModel *tree_model) { + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), (GtkTreeModelFlags)0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + +static gint walls_model_get_n_columns(GtkTreeModel *tree_model) { + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), 0); + + return WALLS_MODEL(tree_model)->n_columns; +} + +static GType walls_model_get_column_type(GtkTreeModel *tree_model, gint index) { + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), G_TYPE_INVALID); + g_return_val_if_fail(index < WALLS_MODEL(tree_model)->n_columns && index >= 0, G_TYPE_INVALID); + + return WALLS_MODEL(tree_model)->column_types[index]; +} + +inline static void fill_dir(WallsModelRecord *record) { + GArray *array; + gint dircount = 0; + + record->children = g_array_new(FALSE, FALSE, sizeof(WallsModelRecord)); + if(db_get_directories(record->dir.dirid, &array)) { + for(int i = 0; i < array->len; i++) { + WallsModelRecord temp; + struct directory_t *dir; + + dir = &g_array_index(array, struct directory_t, i); + temp.type = WALLS_MODEL_TYPE_DIR; + temp.dir.name = g_path_get_basename(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); + } + dircount = array->len; + g_array_free(array, TRUE); + } + + if(db_get_wallpapers(record->dir.dirid, &array)) { + for(int i = 0; i < array->len; i++) { + WallsModelRecord temp; + struct wallpaper_t *wall; + + wall = &g_array_index(array, struct wallpaper_t, i); + temp.type = WALLS_MODEL_TYPE_WALL; + temp.wall.filepath = g_path_get_basename(wall->filepath); + temp.wall.id = wall->id; + temp.wall.size = wall->size; + temp.wall.width = wall->width; + temp.wall.height = wall->height; + + temp.parent = record; + temp.children = NULL; + temp.pos = dircount + i; + + g_array_append_val(record->children, temp); + + g_free(wall->filepath); + } + g_array_free(array, TRUE); + } +} + +#define WALLS_MODEL_ENSURE_CHILDREN(obj) if(!(obj)->children) fill_dir((obj)) + +inline static WallsModelRecord *walls_model_get_record_recursive(WallsModel *walls_model, gint *indices, gint depth) { + WallsModelRecord *temp; + if(depth == 1) { + return &g_array_index(walls_model->rows, WallsModelRecord, indices[depth-1]); + } else { + temp = walls_model_get_record_recursive(walls_model, indices, depth-1); + WALLS_MODEL_ENSURE_CHILDREN(temp); + return &g_array_index(temp->children, WallsModelRecord, indices[depth-1]); + } +} + +static gboolean walls_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { + WallsModel *walls_model; + WallsModelRecord *record; + gint *indices, n, depth; + + g_assert(MODEL_IS_WALLS(tree_model)); + g_assert(path != NULL); + + walls_model = WALLS_MODEL(tree_model); + + indices = gtk_tree_path_get_indices(path); + depth = gtk_tree_path_get_depth(path); + + n = indices[depth-1]; + //if(n >= walls_model->num_rows || n < 0) + // return FALSE; + + //record = &g_array_index(walls_model->rows, WallsModelRecord, n); + record = walls_model_get_record_recursive(walls_model, indices, depth); + + g_assert(record != NULL); + g_assert(record->pos == n); + + iter->stamp = walls_model->stamp; + iter->user_data = record; + iter->user_data2 = NULL; + iter->user_data3 = NULL; + + return TRUE; +} + +static GtkTreePath *walls_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) { + GtkTreePath *path; + WallsModelRecord *record; + WallsModel *walls_model; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), NULL); + g_return_val_if_fail(iter != NULL, NULL); + g_return_val_if_fail(iter->user_data != NULL, NULL); + + walls_model = WALLS_MODEL(tree_model); + + record = (WallsModelRecord*)iter->user_data; + + path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, record->pos); + + return path; +} + +static void walls_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) { + WallsModelRecord *record; + WallsModel *walls_model; + + g_return_if_fail(MODEL_IS_WALLS(walls_model)); + g_return_if_fail(iter != NULL); + g_return_if_fail(column < WALLS_MODEL(walls_model)->n_columns); + + g_value_init(value, WALLS_MODEL(walls_model)->column_types[column]); + + walls_model = WALLS_MODEL(tree_model); + + record = (WallsModelRecord*)iter->user_data; + + g_return_if_fail(record != NULL); + + //if(record->pos >= walls_model->num_rows) + // g_return_if_reached(); + + if(record->type == WALLS_MODEL_TYPE_DIR) { + g_value_set_string(value, record->dir.name); + return; + } + + switch(column) { + case WALLS_MODEL_COL_NAME: + g_value_set_string(value, record->wall.filepath); + break; + case WALLS_MODEL_COL_ID: + g_value_set_uint64(value, record->wall.id); + break; + case WALLS_MODEL_COL_SIZE: + g_value_set_int(value, record->wall.size); + break; + case WALLS_MODEL_COL_WIDTH: + g_value_set_int(value, record->wall.width); + break; + case WALLS_MODEL_COL_HEIGHT: + g_value_set_int(value, record->wall.height); + break; + } +} + +static gboolean walls_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) { + WallsModelRecord *record, *nextrecord; + WallsModel *walls_model; + GArray *array; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); + + if(iter == NULL || iter->user_data == NULL) + return FALSE; + + walls_model = WALLS_MODEL(tree_model); + + record = (WallsModelRecord*)iter->user_data; + + WALLS_MODEL_ENSURE_CHILDREN(record); + + array = (record->parent ? record->parent->children : walls_model->rows); + + if((record->pos + 1) >= array->len) + return FALSE; + + nextrecord = &g_array_index(array, WallsModelRecord, record->pos + 1); + + g_assert(nextrecord != NULL); + g_assert(nextrecord->pos == (record->pos + 1)); + + iter->stamp = walls_model->stamp; + iter->user_data = nextrecord; + + return TRUE; +} + +static gboolean walls_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { + WallsModel *walls_model; + WallsModelRecord *parent_record; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); + + walls_model = WALLS_MODEL(tree_model); + + if(!parent) { + if(walls_model->num_rows == 0) + return FALSE; + iter->stamp = walls_model->stamp; + iter->user_data = &g_array_index(walls_model->rows, WallsModelRecord, 0); + return TRUE; + } + + //g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE); + + parent_record = (WallsModelRecord*)parent->user_data; + + if(parent_record->type == WALLS_MODEL_TYPE_WALL) + return FALSE; + + WALLS_MODEL_ENSURE_CHILDREN(parent_record); + + if(parent_record->children->len == 0) + return FALSE; + + iter->stamp = walls_model->stamp; + iter->user_data = &g_array_index(parent_record->children, WallsModelRecord, 0); + + return TRUE; +} + +static gboolean walls_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) { + WallsModelRecord *record; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); + + record = (WallsModelRecord*)iter->user_data; + + if(record->type == WALLS_MODEL_TYPE_DIR) { + //return (record->children->len > 0 ? TRUE : FALSE); + return TRUE; + } else + return FALSE; +} + +static gint walls_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) { + WallsModel *walls_model; + WallsModelRecord *record; + GArray *array; + int n; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), -1); + g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0); + + walls_model = WALLS_MODEL(tree_model); + + if(!iter) { + return walls_model->num_rows; + } + + record = (WallsModelRecord*)iter->user_data; + + if(record->type == WALLS_MODEL_TYPE_WALL) { + return 0; + } + + //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++); + + WALLS_MODEL_ENSURE_CHILDREN(record); + + return record->children->len; + + return n; +} + +static gboolean walls_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { + WallsModelRecord *record, *parent_record; + WallsModel *walls_model; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); + + walls_model = WALLS_MODEL(tree_model); + + if(!parent) { + if(n >= walls_model->num_rows) + return FALSE; + record = &g_array_index(walls_model->rows, WallsModelRecord, n); + + iter->stamp = walls_model->stamp; + iter->user_data = record; + + return TRUE; + } + + //if(n >= walls_model->num_rows) + // return FALSE; + + parent_record = parent->user_data; + + WALLS_MODEL_ENSURE_CHILDREN(parent_record); + + if(n >= parent_record->children->len) + return FALSE; + + record = &g_array_index(parent_record->children, WallsModelRecord, n); + + g_assert(record != NULL); + g_assert(record->pos == n); + + iter->stamp = walls_model->stamp; + iter->user_data = record; + + return TRUE; +} + +static gboolean walls_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { + WallsModelRecord *record, *childrecord; + WallsModel *walls_model; + + g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); + + walls_model = WALLS_MODEL(tree_model); + + childrecord = (WallsModelRecord*)child->user_data; + + iter->stamp = walls_model->stamp; + iter->user_data = childrecord->parent; + + return TRUE; +} + +WallsModel *walls_model_new() { + WallsModel *new_walls_model; + + new_walls_model = (WallsModel*)g_object_new(MODEL_TYPE_WALLS, NULL); + + g_assert(new_walls_model != NULL); + + return new_walls_model; +} diff --git a/walls_model.h b/walls_model.h new file mode 100644 index 0000000..a5cc779 --- /dev/null +++ b/walls_model.h @@ -0,0 +1,63 @@ +#ifndef _WALLS_MODEL_H_ +#define _WALLS_MODEL_H_ + +#include +#include + +#include "db.h" + +#define MODEL_TYPE_WALLS (walls_model_get_type()) +#define WALLS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MODEL_TYPE_WALLS, WallsModel)) +#define WALLS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), MODEL_TYPE_WALLS, WallsModelClass)) +#define MODEL_IS_WALLS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MODEL_TYPE_WALLS)) +#define MODEL_IS_WALLS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), MODEL_TYPE_WALLS)) +#define WALLS_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MODEL_TYPE_WALLS, WallsModelClass)) + +enum { + WALLS_MODEL_TYPE_DIR = 0, + WALLS_MODEL_TYPE_WALL, +}; + +enum { + WALLS_MODEL_COL_NAME = 0, + WALLS_MODEL_COL_ID, + WALLS_MODEL_COL_SIZE, + WALLS_MODEL_COL_WIDTH, + WALLS_MODEL_COL_HEIGHT, + WALLS_MODEL_N_COLUMNS, +}; + +typedef struct _WallsModelRecord WallsModelRecord; +typedef struct _WallsModel WallsModel; +typedef struct _WallsModelClass WallsModelClass; + +struct _WallsModelRecord { + guint type; + union { + struct directory_t dir; + struct wallpaper_t wall; + }; + WallsModelRecord *parent; + GArray *children; + guint pos; +}; + +struct _WallsModel { + GObject parent; + + guint num_rows; + GArray *rows; + gint n_columns; + GType column_types[WALLS_MODEL_N_COLUMNS]; + gint stamp; +}; + +struct _WallsModelClass { + GObjectClass parent_class; +}; + +GType walls_model_get_type(); +WallsModel *walls_model_new(); +void walls_model_append_record(WallsModel*, void*); + +#endif diff --git a/window_main.c b/window_main.c new file mode 100644 index 0000000..978b88a --- /dev/null +++ b/window_main.c @@ -0,0 +1,152 @@ +#include + +#include "window_main.h" +#include "walls_ui.h" +#include "db.h" +#include "walls_model.h" + +inline static void filetree_create_model(GtkTreeView *filetree) { + GtkTreeModel *tree_model; + GtkTreeIter toplevel, child; + GArray *array; + struct directory_t *dir; + //treestore = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + tree_model = GTK_TREE_MODEL(walls_model_new()); + + /*array = NULL; + if(db_get_top_level_directories(&array)) { + for(int i = 0; ; i++) { + dir = &g_array_index(array, struct directory_t, i); + if(!dir->name) break; + + gtk_tree_store_append(treestore, &toplevel, NULL); + g_printf("%s: %d\n", dir->name, dir->dirid); + gtk_tree_store_set(treestore, &toplevel, 0, dir->name, 1, dir->dirid, -1); + + gtk_tree_store_append(treestore, &child, &toplevel); + gtk_tree_store_set(treestore, &child, 0, "_walls_temp_", -1); + } + for(int i = 0; ; i++) { + dir = &g_array_index(array, struct directory_t, i); + if(!dir->name) break; + g_free(dir->name); + } + g_array_free(array, TRUE); + }*/ + gtk_tree_view_set_model(filetree, GTK_TREE_MODEL(tree_model)); +} + +inline static void filetree_init(GtkTreeView *filetree) { + GtkTreeViewColumn *col1, *col2, *col3, *col4; + GtkCellRenderer *renderer; + + 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); + + 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); + + filetree_create_model(filetree); +} + +G_MODULE_EXPORT gboolean on_filetree_test_expand_row(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { + printf("on_filetree_test_expand_row\n"); + if(gtk_tree_path_get_depth(path) == 0) { + return TRUE; + } + return FALSE; +} + +G_MODULE_EXPORT void on_filetree_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { + printf("expanded\n"); + GtkTreeModel *model; + GtkTreeIter newiter; + GtkTreeIter child; + GArray *array; + gchar **split; + GValue value; + sqlite_uint64 dirid; + gboolean temp_found = FALSE; + + model = gtk_tree_view_get_model(treeview); + if(gtk_tree_model_iter_children(model, &child, iter) == TRUE) { + memset(&value, 0, sizeof(GValue)); + gtk_tree_model_get_value(model, &child, 0, &value); + if(g_strcmp0("_walls_temp_", g_value_get_string(&value)) == 0) + temp_found = TRUE; + else + return; + } + + memset(&value, 0, sizeof(GValue)); + gtk_tree_model_get_value(model, iter, 0, &value); + split = g_strsplit(g_value_get_string(&value), ":", 2); + dirid = g_ascii_strtoull(split[0], NULL, 10); + g_strfreev(split); + + array = NULL; + if(db_get_wallpapers(dirid, &array)) { + for(int i = 0; i < array->len; i++) { + struct wallpaper_t *wp = &g_array_index(array, struct wallpaper_t, i); + gtk_tree_store_append((GtkTreeStore*)model, &newiter, iter); + gtk_tree_store_set((GtkTreeStore*)model, &newiter, 0, wp->filepath, -1); + } + g_array_free(array, TRUE); + if(gtk_tree_model_iter_children(model, &child, iter) == TRUE) { + if(temp_found) + gtk_tree_store_remove((GtkTreeStore*)model, &child); + } + } +} + +int gui_main(int argc, char **argv) { + GtkWidget *window; + GtkWidget *filetree; + GtkBuilder *builder ; + GError *error = NULL; + + if(!db_open()) + return 1; + + gtk_init(&argc, &argv); + + builder = gtk_builder_new(); + //if(!gtk_builder_add_from_file(builder, "walls.ui", &error)) { + if(!gtk_builder_add_from_string(builder, ui_string, -1, &error)) { + g_warning("%s", error->message); + g_free(error); + return 1; + } + + 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)); + + gtk_builder_connect_signals(builder, NULL); + + g_object_unref(G_OBJECT(builder)); + + gtk_widget_show_all(window); + + gtk_main(); + + db_close(); + + return 0; +} diff --git a/window_main.h b/window_main.h new file mode 100644 index 0000000..41b3b38 --- /dev/null +++ b/window_main.h @@ -0,0 +1,8 @@ +#ifndef _WINDOW_MAIN_H_ +#define _WINDOW_MAIN_H_ + +#include + +int gui_main(int, char**); + +#endif -- cgit v1.2.3