📄 cache_maint.c
字号:
/* * GQview * (C) 2004 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#include "gqview.h"#include "cache_maint.h"#include "cache.h"#include "filelist.h"#include "thumb.h"#include "thumb_standard.h"#include "ui_fileops.h"#include "ui_misc.h"#include "ui_spinner.h"#include "ui_tabcomp.h"#include "ui_utildlg.h"typedef struct _CMData CMData;struct _CMData{ GList *list; GList *done_list; gint idle_id; GenericDialog *gd; GtkWidget *entry; GtkWidget *spinner; GtkWidget *button_stop; GtkWidget *button_close; gint clear; gint metadata;};#define PURGE_DIALOG_WIDTH 400/* *------------------------------------------------------------------- * cache maintenance *------------------------------------------------------------------- */static gint extension_truncate(gchar *path, const gchar *ext){ gint l; gint el; if (!path || !ext) return FALSE; l = strlen(path); el = strlen(ext); if (l < el || strcmp(path + (l - el), ext) != 0) return FALSE; path[l - el] = '\0'; return TRUE;}static gchar *extension_find_dot(gchar *path){ gchar *ptr; if (!path || *path == '\0') return NULL; ptr = path; while (*ptr != '\0') ptr++; while (ptr > path && *ptr != '.') ptr--; if (ptr == path) return NULL; return ptr;}static gint isempty(const gchar *path){ DIR *dp; struct dirent *dir; gchar *pathl; pathl = path_from_utf8(path); dp = opendir(pathl); g_free(pathl); if (!dp) return FALSE; while ((dir = readdir(dp)) != NULL) { gchar *name = dir->d_name; if (dir->d_ino > 0 && !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) ) { closedir(dp); return FALSE; } } closedir(dp); return TRUE;}static void cache_maintain_home_close(CMData *cm){ if (cm->idle_id != -1) g_source_remove(cm->idle_id); if (cm->gd) generic_dialog_close(cm->gd); path_list_free(cm->list); g_list_free(cm->done_list); g_free(cm);}static void cache_maintain_home_stop(CMData *cm){ if (cm->idle_id != -1) { g_source_remove(cm->idle_id); cm->idle_id = -1; } gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done")); spinner_set_interval(cm->spinner, -1); gtk_widget_set_sensitive(cm->button_stop, FALSE); gtk_widget_set_sensitive(cm->button_close, TRUE);}static gint cache_maintain_home_cb(gpointer data){ CMData *cm = data; GList *dlist = NULL; GList *list = NULL; gchar *path; gint just_done = FALSE; gint still_have_a_file = TRUE; gint base_length; const gchar *cache_folder; if (cm->metadata) { cache_folder = GQVIEW_CACHE_RC_METADATA; } else { cache_folder = GQVIEW_CACHE_RC_THUMB; } base_length = strlen(homedir()) + strlen("/") + strlen(cache_folder); if (!cm->list) { if (debug) printf("purge chk done.\n"); cm->idle_id = -1; cache_maintain_home_stop(cm); return FALSE; } path = cm->list->data; if (debug) printf("purge chk (%d) \"%s\"\n", (cm->clear && !cm->metadata), path); if (g_list_find(cm->done_list, path) == NULL) { cm->done_list = g_list_prepend(cm->done_list, path); if (path_list(path, &list, &dlist)) { GList *work; just_done = TRUE; still_have_a_file = FALSE; work = list; while (work) { gchar *path_buf = work->data; gchar *dot; dot = extension_find_dot(path_buf); if (dot) *dot = '\0'; if ((!cm->metadata && cm->clear) || (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) ) { if (dot) *dot = '.'; if (!unlink_file(path_buf)) printf("failed to delete:%s\n", path_buf); } else { still_have_a_file = TRUE; } work = work->next; } } } path_list_free(list); cm->list = g_list_concat(dlist, cm->list); if (cm->list && g_list_find(cm->done_list, cm->list->data) != NULL) { /* check if the dir is empty */ if (cm->list->data == path && just_done) { if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(path)) { printf("Unable to delete dir: %s\n", path); } } else { /* must re-check for an empty dir */ if (isempty(path) && cm->list->next && !rmdir_utf8(path)) { printf("Unable to delete dir: %s\n", path); } } path = cm->list->data; cm->done_list = g_list_remove(cm->done_list, path); cm->list = g_list_remove(cm->list, path); g_free(path); } if (cm->list) { const gchar *buf; path = cm->list->data; if (strlen(path) > base_length) { buf = path + base_length; } else { buf = "..."; } gtk_entry_set_text(GTK_ENTRY(cm->entry), buf); } return TRUE;}static void cache_maintain_home_close_cb(GenericDialog *gd, gpointer data){ CMData *cm = data; if (!GTK_WIDGET_SENSITIVE(cm->button_close)) return; cache_maintain_home_close(cm);}static void cache_maintain_home_stop_cb(GenericDialog *gd, gpointer data){ CMData *cm = data; cache_maintain_home_stop(cm);}/* sorry for complexity (cm->done_list), but need it to remove empty dirs */void cache_maintain_home(gint metadata, gint clear, GtkWidget *parent){ CMData *cm; GList *dlist = NULL; gchar *base; const gchar *msg; const gchar *cache_folder; GtkWidget *hbox; if (metadata) { cache_folder = GQVIEW_CACHE_RC_METADATA; } else { cache_folder = GQVIEW_CACHE_RC_THUMB; } base = g_strconcat(homedir(), "/", cache_folder, NULL); if (!path_list(base, NULL, &dlist)) { g_free(base); return; } dlist = g_list_append(dlist, base); cm = g_new0(CMData, 1); cm->list = dlist; cm->done_list = NULL; cm->clear = clear; cm->metadata = metadata; if (metadata) { msg = _("Removing old metadata..."); } else if (clear) { msg = _("Clearing cached thumbnails..."); } else { msg = _("Removing old thumbnails..."); } cm->gd = generic_dialog_new(_("Maintenance"), "GQview", "gqview_maintenance", parent, FALSE, NULL, cm); cm->gd->cancel_cb = cache_maintain_home_close_cb; cm->button_close = generic_dialog_add_button(cm->gd, GTK_STOCK_CLOSE, NULL, cache_maintain_home_close_cb, FALSE); gtk_widget_set_sensitive(cm->button_close, FALSE); cm->button_stop = generic_dialog_add_button(cm->gd, GTK_STOCK_STOP, NULL, cache_maintain_home_stop_cb, FALSE); generic_dialog_add_message(cm->gd, NULL, msg, NULL); gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5); gtk_widget_show(hbox); cm->entry = gtk_entry_new(); GTK_WIDGET_UNSET_FLAGS(cm->entry, GTK_CAN_FOCUS); gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE); gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0); gtk_widget_show(cm->entry); cm->spinner = spinner_new(NULL, SPINNER_SPEED); gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0); gtk_widget_show(cm->spinner); gtk_widget_show(cm->gd->dialog); cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);}/* This checks all files in ~/.gqview/thumbnails and * removes them if thay have no source counterpart. * (this assumes all cache files have an extension of 4 chars including '.') */gint cache_maintain_home_dir(const gchar *dir, gint recursive, gint clear){ gchar *base; gint base_length; GList *dlist = NULL; GList *flist = NULL; gint still_have_a_file = FALSE; if (debug) printf("maintainance check: %s\n", dir); base_length = strlen(homedir()) + strlen("/") + strlen(GQVIEW_CACHE_RC_THUMB); base = g_strconcat(homedir(), "/", GQVIEW_CACHE_RC_THUMB, dir, NULL); if (path_list(base, &flist, &dlist)) { GList *work; work = dlist; while(work) { gchar *path = work->data; if (recursive && strlen(path) > base_length && !cache_maintain_home_dir(path + base_length, recursive, clear)) { if (debug) printf("Deleting thumb dir: %s\n", path); if (!rmdir_utf8(path)) { printf("Unable to delete dir: %s\n", path); } } else { still_have_a_file = TRUE; } work = work->next; } work = flist; while (work) { gchar *path = work->data; gchar *dot; dot = extension_find_dot(path); if (dot) *dot = '\0'; if (clear || (strlen(path) > base_length && !isfile(path + base_length)) ) { if (dot) *dot = '.'; if (!unlink_file(path)) printf("failed to delete:%s\n", path); } else { still_have_a_file = TRUE; } work = work->next; } } path_list_free(dlist); path_list_free(flist); g_free(base); return still_have_a_file;}/* This checks relative caches in dir/.thumbnails and * removes them if they have no source counterpart. */gint cache_maintain_dir(const gchar *dir, gint recursive, gint clear){ GList *list = NULL; gchar *cachedir; gint still_have_a_file = FALSE; GList *work; cachedir = g_strconcat(dir, "/", GQVIEW_CACHE_LOCAL_THUMB, NULL); path_list(cachedir, &list, NULL); work = list; while (work) { const gchar *path; gchar *source; path = work->data; work = work->next; source = g_strconcat(dir, "/", filename_from_path(path), NULL); if (clear || extension_truncate(source, GQVIEW_CACHE_EXT_THUMB) || extension_truncate(source, GQVIEW_CACHE_EXT_SIM)) { if (!clear && isfile(source)) { still_have_a_file = TRUE; } else { if (!unlink_file(path)) { if (debug) printf("Failed to remove cache file %s\n", path); still_have_a_file = TRUE; } } } else { still_have_a_file = TRUE; } g_free(source); } path_list_free(list); g_free(cachedir); if (recursive) { list = NULL; path_list(dir, NULL, &list); work = list; while (work) { const gchar *path = work->data; work = work->next; still_have_a_file |= cache_maintain_dir(path, recursive, clear); } path_list_free(list); } return still_have_a_file;}static void cache_file_move(const gchar *src, const gchar *dest){ if (!dest || !src || !isfile(src)) return; if (!move_file(src, dest)) { if (debug) printf("Failed to move cache file %s\nto %s\n", src, dest); /* we remove it anyway - it's stale */ unlink_file(src); }}void cache_maint_moved(const gchar *src, const gchar *dest){ gchar *base; mode_t mode = 0755; if (!src || !dest) return; base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode); if (cache_ensure_dir_exists(base, mode)) { gchar *buf; gchar *d; buf = cache_find_location(CACHE_TYPE_THUMB, src); d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, NULL); cache_file_move(buf, d); g_free(d); g_free(buf); buf = cache_find_location(CACHE_TYPE_SIM, src); d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, NULL); cache_file_move(buf, d); g_free(d); g_free(buf); } else { printf("Failed to create cache dir for move %s\n", base); } g_free(base); base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode); if (cache_ensure_dir_exists(base, mode)) { gchar *buf; gchar *d; buf = cache_find_location(CACHE_TYPE_METADATA, src); d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, NULL); cache_file_move(buf, d); g_free(d); g_free(buf); } g_free(base); if (enable_thumb_caching && thumbnail_spec_standard) thumb_std_maint_moved(src, dest);}static void cache_file_remove(const gchar *path){ if (path && isfile(path) && !unlink_file(path)) { if (debug) printf("Failed to remove cache file %s\n", path); }}void cache_maint_removed(const gchar *source){ gchar *buf; buf = cache_find_location(CACHE_TYPE_THUMB, source); cache_file_remove(buf); g_free(buf); buf = cache_find_location(CACHE_TYPE_SIM, source); cache_file_remove(buf); g_free(buf); buf = cache_find_location(CACHE_TYPE_METADATA, source); cache_file_remove(buf); g_free(buf); if (enable_thumb_caching && thumbnail_spec_standard) thumb_std_maint_removed(source);}void cache_maint_copied(const gchar *src, const gchar *dest){ gchar *dest_base; gchar *src_cache; mode_t mode = 0755; src_cache = cache_find_location(CACHE_TYPE_METADATA, src); if (!src_cache) return; dest_base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode); if (cache_ensure_dir_exists(dest_base, mode)) { gchar *path; path = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, NULL); if (!copy_file(src_cache, path)) { if (debug) printf("failed to copy metadata %s to %s\n", src_cache, path); } g_free(path); } g_free(dest_base); g_free(src_cache);}/* *------------------------------------------------------------------- * new cache maintenance utilities *------------------------------------------------------------------- */typedef struct _CacheManager CacheManager;struct _CacheManager{ GenericDialog *dialog; GtkWidget *folder_entry; GtkWidget *progress; GList *list_todo; gint count_total; gint count_done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -