summaryrefslogtreecommitdiff
path: root/preload.c
diff options
context:
space:
mode:
Diffstat (limited to 'preload.c')
-rw-r--r--preload.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/preload.c b/preload.c
new file mode 100644
index 0000000..281bdf6
--- /dev/null
+++ b/preload.c
@@ -0,0 +1,281 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "preload.h"
+#include "wallpapers.h"
+
+guint preload_max = 6;
+
+static gboolean preload_thread_exit = FALSE;
+static GHashTable *hashtable = NULL;
+static GMutex *preload_hashtable_mutex = NULL, *preload_thread_mutex = NULL;
+static GThread *preload_thread = NULL;
+
+static gpointer preload_thread_func(gpointer);
+
+struct preload_thread_data_t {
+ GArray *array;
+ gint win_width, win_height;
+};
+
+static void preload_hash_table_free(gpointer data) {
+ struct preload_hash_table_value_t *pt;
+
+ pt = data;
+
+ g_object_unref(pt->pb);
+
+ g_free(data);
+}
+
+void preload_init() {
+ preload_hashtable_mutex = g_mutex_new();
+ preload_thread_mutex = g_mutex_new();
+
+ hashtable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, preload_hash_table_free);
+}
+
+void preload_free() {
+ if(preload_thread) {
+ preload_thread_exit = TRUE;
+ g_thread_join(preload_thread);
+ }
+
+ g_mutex_free(preload_hashtable_mutex);
+ g_mutex_free(preload_thread_mutex);
+
+ g_hash_table_destroy(hashtable);
+ preload_hashtable_mutex = NULL;
+}
+
+#define preload_index(i) (((i) / 2) + 1) * (((i) % 2 * (-2) + 1))
+
+static GArray *preload_prepare_data(GtkWidget *thumbview) {
+ GList *list;
+ GArray *array;
+ GtkTreePath *sel_path, *path;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GValue value = {0};
+ gchar *filename;
+ guint list_len;
+ gint selected_index, *indices, index;
+ gboolean b;
+
+ array = g_array_new(FALSE, FALSE, sizeof(gchar*));
+
+ list = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(thumbview));
+
+ list_len = g_list_length(list);
+
+ if(list_len != 1) {
+ g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(list);
+
+ return array;
+ }
+
+ sel_path = g_list_nth_data(list, 0);
+
+ indices = gtk_tree_path_get_indices(sel_path);
+ if(!indices) {
+ g_warning("preload_thread: Failed to get indices");
+
+ g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(list);
+
+ return array;
+ }
+
+ selected_index = indices[0];
+
+ model = gtk_icon_view_get_model(GTK_ICON_VIEW(thumbview));
+
+ /* Make sure the selected pixbuf is also preloaded. */
+ if(gtk_tree_model_get_iter(model, &iter, sel_path)) {
+ gtk_tree_model_get_value(model, &iter, 1, &value);
+ filename = g_value_dup_string(&value);
+ g_value_unset(&value);
+
+ g_array_append_val(array, filename);
+ }
+
+ for(gint i = 0; i < preload_max; i++) {
+ /* Make sure the selected pixbuf is also preloaded. */
+ if(array->len == 0 && gtk_tree_model_get_iter(model, &iter, sel_path)) {
+ gtk_tree_model_get_value(model, &iter, 1, &value);
+ filename = g_value_dup_string(&value);
+ g_value_unset(&value);
+
+ g_array_append_val(array, filename);
+ }
+
+ index = selected_index + preload_index(i);
+ if(index < 0) {
+ continue;
+ }
+
+ path = gtk_tree_path_new_from_indices(index, -1);
+
+ if(gtk_tree_path_get_depth(path) != 1) {
+ /* Assume we're out of bounds. */
+ gtk_tree_path_free(path);
+ continue;
+ }
+
+ b = gtk_tree_model_get_iter(model, &iter, path);
+
+ gtk_tree_path_free(path);
+
+ if(b == FALSE)
+ continue;
+
+ gtk_tree_model_get_value(model, &iter, 1, &value);
+ filename = g_value_dup_string(&value);
+ g_value_unset(&value);
+
+ g_array_append_val(array, filename);
+ }
+
+ g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(list);
+
+ return array;
+}
+
+void preload_start_thread(GtkWidget *thumbview, gint win_width, gint win_height) {
+ struct preload_thread_data_t *data;
+ GError *error = NULL;
+
+ if(preload_thread) {
+ preload_thread_exit = TRUE;
+ g_thread_join(preload_thread);
+ }
+
+ data = g_malloc(sizeof(struct preload_thread_data_t));
+
+ data->array = preload_prepare_data(thumbview);
+ data->win_width = win_width;
+ data->win_height = win_height;
+
+ preload_thread_exit = FALSE;
+ preload_thread = g_thread_create(preload_thread_func, data, TRUE, &error);
+
+ if(!preload_thread) {
+ g_error("%s", error->message);
+ g_error_free(error);
+ }
+}
+
+void preload_clear() {
+ g_hash_table_remove_all(hashtable);
+}
+
+static void preload_add(const gchar *filename, gpointer data) {
+ g_mutex_lock(preload_hashtable_mutex);
+
+ g_hash_table_replace(hashtable, g_strdup(filename), data);
+
+ g_mutex_unlock(preload_hashtable_mutex);
+}
+
+gpointer preload_get(const gchar *filename) {
+ gpointer data;
+
+ g_mutex_lock(preload_hashtable_mutex);
+
+ data = g_hash_table_lookup(hashtable, filename);
+
+ g_mutex_unlock(preload_hashtable_mutex);
+
+ return data;
+}
+
+inline static void add_pixbuf(const gchar *filename, gpointer _data) {
+ struct preload_thread_data_t *data;
+ struct preload_hash_table_value_t *value;
+ GdkPixbuf *orig, *pb;
+ GError *error = NULL;
+ gint width, height;
+ gdouble ratio;
+
+ /* Check if we already loaded this filename. */
+ if(preload_get(filename))
+ return;
+
+ orig = gdk_pixbuf_new_from_file(filename, &error);
+
+ if(!orig) {
+ g_warning("%s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ data = _data;
+
+ pb = resize_pixbuf(orig, data->win_width, data->win_height, &width, &height, &ratio);
+
+ value = g_malloc(sizeof(struct preload_hash_table_value_t));
+
+ if(pb) {
+ value->pb = pb;
+ value->width = width;
+ value->height = height;
+ value->ratio = ratio;
+
+ g_object_unref(orig);
+ } else {
+ value->pb = orig;
+ value->width = 0;
+ value->height = 0;
+ value->ratio = 0;
+ }
+
+ preload_add(filename, value);
+}
+
+static gpointer preload_thread_func(gpointer _data) {
+ struct preload_thread_data_t *data;
+ GArray *array;
+ GList *keys;
+ gchar *added_name;
+ const gchar *key_name;
+ gboolean found;
+
+ data = _data;
+ array = data->array;
+
+ g_mutex_lock(preload_hashtable_mutex);
+ keys = g_hash_table_get_keys(hashtable);
+ g_mutex_unlock(preload_hashtable_mutex);
+
+ for(int i = 0; i < g_list_length(keys) && preload_thread_exit == FALSE; i++) {
+ found = FALSE;
+ key_name = g_list_nth_data(keys, i);
+ for(int j = 0; j < array->len && preload_thread_exit == FALSE; j++) {
+ added_name = g_array_index(array, gchar*, j);
+ if(g_strcmp0(key_name, added_name) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+ if(found == FALSE) {
+ g_mutex_lock(preload_hashtable_mutex);
+ g_hash_table_remove(hashtable, key_name);
+ g_mutex_unlock(preload_hashtable_mutex);
+ }
+ }
+
+ for(int i = 0; i < array->len && preload_thread_exit == FALSE; i++) {
+ added_name = g_array_index(array, gchar*, i);
+ add_pixbuf(added_name, data);
+ }
+
+ g_list_free(keys);
+ g_array_free(array, TRUE);
+
+ g_free(data);
+ preload_thread = NULL;
+ return NULL;
+}