/*
* (SLIK) SimpLIstic sKin functions
* (C) 2004 John Ellis
- * Copyright (C) 2008 The Geeqie Team
+ * Copyright (C) 2008 - 2012 The Geeqie Team
*
* Author: John Ellis
*
#include <gdk/gdkkeysyms.h> /* for key values */
#include "main.h"
-#include "filelist.h"
-#include "secure_save.h"
+#include "filedata.h"
+#include "history_list.h"
+
#include "ui_bookmark.h"
#include "ui_fileops.h"
#include "ui_menu.h"
#include "ui_misc.h"
#include "ui_utildlg.h"
#include "ui_tabcomp.h"
+#include "uri_utils.h"
-/*
- *-----------------------------------------------------------------------------
- * history lists
- *-----------------------------------------------------------------------------
- */
-
-#define HISTORY_DEFAULT_KEY_COUNT 16
-
-
-typedef struct _HistoryData HistoryData;
-struct _HistoryData
-{
- gchar *key;
- GList *list;
-};
-
-static GList *history_list = NULL;
-
-
-static gchar *quoted_from_text(const gchar *text)
-{
- const gchar *ptr;
- gint c = 0;
- gint l = strlen(text);
-
- if (l == 0) return NULL;
-
- while (c < l && text[c] !='"') c++;
- if (text[c] == '"')
- {
- gint e;
- c++;
- ptr = text + c;
- e = c;
- while (e < l && text[e] !='"') e++;
- if (text[e] == '"')
- {
- if (e - c > 0)
- {
- return g_strndup(ptr, e - c);
- }
- }
- }
- return NULL;
-}
-
-gint history_list_load(const gchar *path)
-{
- FILE *f;
- gchar *key = NULL;
- gchar s_buf[1024];
- gchar *pathl;
-
- pathl = path_from_utf8(path);
- f = fopen(pathl, "r");
- g_free(pathl);
- if (!f) return FALSE;
-
- /* first line must start with History comment */
- if (!fgets(s_buf,1024,f) ||
- strncmp(s_buf, "#History", 8) != 0)
- {
- fclose(f);
- return FALSE;
- }
-
- while (fgets(s_buf,1024,f))
- {
- if (s_buf[0]=='#') continue;
- if (s_buf[0]=='[')
- {
- gint c;
- gchar *ptr;
-
- ptr = s_buf + 1;
- c = 0;
- while(ptr[c] != ']' && ptr[c] != '\n' && ptr[c] != '\0') c++;
-
- g_free(key);
- key = g_strndup(ptr, c);
- }
- else
- {
- gchar *value;
-
- value = quoted_from_text(s_buf);
- if (value && key)
- {
- history_list_add_to_key(key, value, 0);
- }
- g_free(value);
- }
- }
-
- fclose(f);
-
- g_free(key);
-
- return TRUE;
-}
-
-gint history_list_save(const gchar *path)
-{
- SecureSaveInfo *ssi;
- GList *list;
- gchar *pathl;
-
- pathl = path_from_utf8(path);
- ssi = secure_open(pathl);
- g_free(pathl);
- if (!ssi)
- {
- printf_term(_("Unable to write history lists to: %s\n"), path);
- return FALSE;
- }
-
- secure_fprintf(ssi, "#History lists\n");
- secure_fprintf(ssi, "\n");
-
- list = g_list_last(history_list);
- while(list && secsave_errno == SS_ERR_NONE)
- {
- HistoryData *hd;
- GList *work;
-
- hd = list->data;
- list = list->prev;
-
- secure_fprintf(ssi, "[%s]\n", hd->key);
-
- /* save them inverted (oldest to newest)
- * so that when reading they are added correctly
- */
- work = g_list_last(hd->list);
- while(work && secsave_errno == SS_ERR_NONE)
- {
- secure_fprintf(ssi, "\"%s\"\n", (gchar *)work->data);
- work = work->prev;
- }
- secure_fputc(ssi, '\n');
- }
-
- secure_fprintf(ssi, "#end\n");
-
- return (secure_close(ssi) == 0);
-}
-
-static void history_list_free(HistoryData *hd)
-{
- GList *work;
-
- if (!hd) return;
-
- work = hd->list;
- while(work)
- {
- g_free(work->data);
- work = work->next;
- }
-
- g_free(hd->key);
- g_free(hd);
-}
-
-static HistoryData *history_list_find_by_key(const gchar* key)
-{
- GList *work = history_list;
-
- if (!key) return NULL;
-
- while (work)
- {
- HistoryData *hd = work->data;
- if (strcmp(hd->key, key) == 0) return hd;
- work = work->next;
- }
- return NULL;
-}
-
-const gchar *history_list_find_last_path_by_key(const gchar* key)
-{
- HistoryData *hd;
-
- hd = history_list_find_by_key(key);
- if (!hd || !hd->list) return NULL;
-
- return hd->list->data;
-}
-
-void history_list_free_key(const gchar *key)
-{
- HistoryData *hd;
- hd = history_list_find_by_key(key);
- if (!hd) return;
-
- history_list = g_list_remove(history_list, hd);
- history_list_free(hd);
-}
-
-void history_list_add_to_key(const gchar *key, const gchar *path, gint max)
-{
- HistoryData *hd;
- GList *work;
-
- if (!key || !path) return;
-
- hd = history_list_find_by_key(key);
- if (!hd)
- {
- hd = g_new(HistoryData, 1);
- hd->key = g_strdup(key);
- hd->list = NULL;
- history_list = g_list_prepend(history_list, hd);
- }
-
- /* if already in the list, simply move it to the top */
- work = hd->list;
- while(work)
- {
- gchar *buf = work->data;
- work = work->next;
- if (strcmp(buf, path) == 0)
- {
- hd->list = g_list_remove(hd->list, buf);
- hd->list = g_list_prepend(hd->list, buf);
- return;
- }
- }
-
- hd->list = g_list_prepend(hd->list, g_strdup(path));
-
- if (max == -1) max = HISTORY_DEFAULT_KEY_COUNT;
- if (max > 0)
- {
- while(hd->list && g_list_length(hd->list) > max)
- {
- GList *work = g_list_last(hd->list);
- gchar *buf = work->data;
- hd->list = g_list_remove(hd->list, buf);
- g_free(buf);
- }
- }
-}
-
-void history_list_item_change(const gchar *key, const gchar *oldpath, const gchar *newpath)
-{
- HistoryData *hd;
- GList *work;
-
- if (!oldpath) return;
- hd = history_list_find_by_key(key);
- if (!hd) return;
-
- work = hd->list;
- while(work)
- {
- gchar *buf = work->data;
- if (strcmp(buf, oldpath) == 0)
- {
- if (newpath)
- {
- work->data = g_strdup(newpath);
- }
- else
- {
- hd->list = g_list_remove(hd->list, buf);
- }
- g_free(buf);
- return;
- }
- work = work->next;
- }
-}
-
-void history_list_item_move(const gchar *key, const gchar *path, gint direction)
-{
- HistoryData *hd;
- GList *work;
- gint p = 0;
-
- if (!path) return;
- hd = history_list_find_by_key(key);
- if (!hd) return;
-
- work = hd->list;
- while (work)
- {
- gchar *buf = work->data;
- if (strcmp(buf, path) == 0)
- {
- p += direction;
- if (p < 0) return;
- hd->list = g_list_remove(hd->list, buf);
- hd->list = g_list_insert(hd->list, buf, p);
- return;
- }
- work = work->next;
- p++;
- }
-}
-
-void history_list_item_remove(const gchar *key, const gchar *path)
-{
- history_list_item_change(key, path, NULL);
-}
-
-GList *history_list_get_by_key(const gchar *key)
-{
- HistoryData *hd;
-
- hd = history_list_find_by_key(key);
- if (!hd) return NULL;
-
- return hd->list;
-}
/*
*-----------------------------------------------------------------------------
void (*select_func)(const gchar *path, gpointer data);
gpointer select_data;
- gint no_defaults;
- gint editable;
+ gboolean no_defaults;
+ gboolean editable;
+ gboolean only_directories;
BookButtonData *active_button;
};
if (path_ptr && icon_ptr && icon_ptr < path_ptr)
{
- printf("warning, bookmark icon must be after path\n");
+ log_printf("warning, bookmark icon must be after path\n");
return NULL;
}
static gchar *bookmark_string(const gchar *name, const gchar *path, const gchar *icon)
{
if (!name) name = _("New Bookmark");
- if (icon && strncmp(icon, "/", 1) != 0) icon = NULL;
+ if (icon && strncmp(icon, G_DIR_SEPARATOR_S, 1) != 0) icon = NULL;
if (icon)
{
p->bb = bookmark_from_string(text);
p->bb->parent = g_strdup(key);
- gd = generic_dialog_new(_("Edit Bookmark"), GQ_WMCLASS, "bookmark_edit",
+ gd = generic_dialog_new(_("Edit Bookmark"), "bookmark_edit",
parent, TRUE,
bookmark_edit_cancel_cb, p);
g_signal_connect(G_OBJECT(gd->dialog), "destroy",
static void bookmark_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gint *pushed_in, gpointer data)
{
GtkWidget *button = data;
+ GtkAllocation allocation;
- gdk_window_get_origin(button->window, x, y);
- *y += button->allocation.y + button->allocation.height;
+ gtk_widget_set_allocation(button, &allocation);
+ gdk_window_get_origin(gtk_widget_get_window(button), x, y);
+ *y += allocation.y + allocation.height;
}
static void bookmark_menu_popup(BookMarkData *bm, GtkWidget *button,
- gint button_n, guint32 time, gint local)
+ gint button_n, guint32 time, gboolean local)
{
GtkWidget *menu;
BookButtonData *b;
}
}
-static gint bookmark_press_cb(GtkWidget *button, GdkEventButton *event, gpointer data)
+static gboolean bookmark_press_cb(GtkWidget *button, GdkEventButton *event, gpointer data)
{
BookMarkData *bm = data;
return TRUE;
}
-static gint bookmark_keypress_cb(GtkWidget *button, GdkEventKey *event, gpointer data)
+static gboolean bookmark_keypress_cb(GtkWidget *button, GdkEventKey *event, gpointer data)
{
BookMarkData *bm = data;
switch (event->keyval)
{
- case GDK_F10:
+ case GDK_KEY_F10:
if (!(event->state & GDK_CONTROL_MASK)) return FALSE;
- case GDK_Menu:
+ case GDK_KEY_Menu:
bookmark_menu_popup(bm, button, 0, event->time, TRUE);
return TRUE;
break;
- case GDK_Up:
+ case GDK_KEY_Up:
if (event->state & GDK_SHIFT_MASK)
{
bookmark_move(bm, button, -1);
return TRUE;
}
break;
- case GDK_Down:
+ case GDK_KEY_Down:
if (event->state & GDK_SHIFT_MASK)
{
bookmark_move(bm, button, 1);
{
BookMarkData *bm = data;
BookButtonData *b;
- gchar *uri_text = NULL;
- gint length = 0;
GList *list = NULL;
+#if GTK_CHECK_VERSION(3,0,0)
+ if (gdk_drag_context_get_dest_window(context) == gtk_widget_get_window(bm->widget)) return;
+#else
if (context->dest_window == bm->widget->window) return;
+#endif
b = g_object_get_data(G_OBJECT(button), "bookbuttondata");
if (!b) return;
list = g_list_append(list, b->path);
- switch (info)
+ gchar **uris = uris_from_filelist(list);
+ gboolean ret = gtk_selection_data_set_uris(selection_data, uris);
+ if (!ret)
{
- case TARGET_URI_LIST:
- uri_text = uri_text_from_list(list, &length, FALSE);
- break;
- case TARGET_TEXT_PLAIN:
- uri_text = uri_text_from_list(list, &length, TRUE);
- break;
+ char *str = g_strjoinv("\r\n", uris);
+ ret = gtk_selection_data_set_text(selection_data, str, -1);
+ g_free(str);
}
+ g_strfreev(uris);
g_list_free(list);
-
- if (!uri_text) return;
-
- gtk_selection_data_set(selection_data, selection_data->target,
- 8, (guchar *)uri_text, length);
- g_free(uri_text);
}
static void bookmark_drag_begin(GtkWidget *button, GdkDragContext *context, gpointer data)
GdkPixbuf *pixbuf;
GdkModifierType mask;
gint x, y;
-
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation(button, &allocation);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ pixbuf = gdk_pixbuf_get_from_window(gtk_widget_get_window(button),
+ allocation.x, allocation.y,
+ allocation.width, allocation.height);
+#else
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
- button->allocation.width, button->allocation.height);
- gdk_pixbuf_get_from_drawable(pixbuf, button->window, NULL,
- button->allocation.x, button->allocation.y,
- 0, 0, button->allocation.width, button->allocation.height);
-
- gdk_window_get_pointer(button->window, &x, &y, &mask);
+ allocation.width, allocation.height);
+ gdk_pixbuf_get_from_drawable(pixbuf, gtk_widget_get_window(button), NULL,
+ allocation.x, allocation.y,
+ 0, 0, allocation.width, allocation.height);
+#endif
+ gdk_window_get_pointer(gtk_widget_get_window(button), &x, &y, &mask);
gtk_drag_set_icon_pixbuf(context, pixbuf,
- x - button->allocation.x, y - button->allocation.y);
+ x - allocation.x, y - allocation.y);
g_object_unref(pixbuf);
}
history_list_add_to_key(bm->key, buf, 0);
g_free(buf);
- path = concat_dir_and_file(homedir(), "Desktop");
+ path = g_build_filename(homedir(), "Desktop", NULL);
if (isname(path))
{
buf = bookmark_string(_("Desktop"), path, NULL);
BookMarkData *bm = data;
GList *list = NULL;
GList *work;
+ gchar **uris;
if (!bm->editable) return;
- switch (info)
- {
- case TARGET_URI_LIST:
- case TARGET_X_URL:
- list = uri_list_from_text((gchar *)selection_data->data, FALSE);
- break;
- }
+ uris = gtk_selection_data_get_uris(selection_data);
+ list = uri_filelist_from_uris(uris);
+ g_strfreev(uris);
work = list;
while (work)
gchar *path = work->data;
gchar *buf;
+ work = work->next;
+
+ if (bm->only_directories && !isdir(path)) continue;
buf = bookmark_string(filename_from_path(path), path, NULL);
history_list_add_to_key(bm->key, buf, 0);
g_free(buf);
-
- work = work->next;
}
string_list_free(list);
bm->no_defaults = FALSE;
bm->editable = TRUE;
+ bm->only_directories = FALSE;
scrolled = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
bookmark_populate(bm);
}
-void bookmark_list_set_no_defaults(GtkWidget *list, gint no_defaults)
+void bookmark_list_set_no_defaults(GtkWidget *list, gboolean no_defaults)
{
BookMarkData *bm;
bm->no_defaults = no_defaults;
}
-void bookmark_list_set_editable(GtkWidget *list, gint editable)
+void bookmark_list_set_editable(GtkWidget *list, gboolean editable)
{
BookMarkData *bm;
bm->editable = editable;
}
+void bookmark_list_set_only_directories(GtkWidget *list, gboolean only_directories)
+{
+ BookMarkData *bm;
+
+ bm = g_object_get_data(G_OBJECT(list), BOOKMARK_DATA_KEY);
+ if (!bm) return;
+
+ bm->only_directories = only_directories;
+}
+
void bookmark_list_add(GtkWidget *list, const gchar *name, const gchar *path)
{
BookMarkData *bm;
hc->history_key = g_strdup(history_key);
hc->history_levels = max_levels;
- hc->combo = gtk_combo_box_entry_new_text();
-#if 0
- gtk_combo_set_case_sensitive(GTK_COMBO(hc->combo), TRUE);
- gtk_combo_set_use_arrows(GTK_COMBO(hc->combo), FALSE);
-#endif
+ hc->combo = gtk_combo_box_text_new_with_entry();
- hc->entry = GTK_BIN(hc->combo)->child;
+ hc->entry = gtk_bin_get_child(GTK_BIN(hc->combo));
g_object_set_data(G_OBJECT(hc->combo), "history_combo_data", hc);
g_object_set_data(G_OBJECT(hc->entry), "history_combo_data", hc);
work = history_list_get_by_key(hc->history_key);
while (work)
{
- gtk_combo_box_append_text(GTK_COMBO_BOX(hc->combo), (gchar *)work->data);
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(hc->combo), (gchar *)work->data);
work = work->next;
n++;
}
hc = g_object_get_data(G_OBJECT(widget), "history_combo_data");
if (!hc)
{
- printf("widget is not a history combo\n");
+ log_printf("widget is not a history combo\n");
return;
}
work = history_list_get_by_key(hc->history_key);
while (work)
{
- gtk_combo_box_append_text(GTK_COMBO_BOX(hc->combo), (gchar *)work->data);
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(hc->combo), (gchar *)work->data);
work = work->next;
}
}
g_free(new_text);
}
-
-/*
- *-----------------------------------------------------------------------------
- * drag and drop uri utils
- *-----------------------------------------------------------------------------
- */
-
-/* the following characters are allowed to be unencoded for pathnames:
- * $ & + , / : = @
- */
-static gint escape_char_list[] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 */
-/* spc ! " # $ % & ' */
- 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, /* 30 */
-/* ( ) * + , - . / 0 1 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
-/* 2 3 4 5 6 7 8 9 : ; */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 50 */
-/* < = > ? @ A B C D E */
- 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, /* 60 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
-/* Z [ \ ] ^ _ ` a b c */
- 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, /* 90 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 100 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 110 */
-/* x y z { | } ~ del */
- 0, 0, 0, 1, 1, 1, 0, 0 /* 120, 127 is end */
-};
-
-static gchar *hex_char = "0123456789ABCDEF";
-
-static gint escape_test(guchar c)
-{
- if (c < 32 || c > 127) return TRUE;
- return (escape_char_list[c] != 0);
-}
-
-static const gchar *escape_code(guchar c)
-{
- static gchar text[4];
-
- text[0] = '%';
- text[1] = hex_char[c>>4];
- text[2] = hex_char[c%16];
- text[3] = '\0';
-
- return text;
-}
-
-gchar *uri_text_escape(const gchar *text)
-{
- GString *string;
- gchar *result;
- const gchar *p;
-
- if (!text) return NULL;
-
- string = g_string_new("");
-
- p = text;
- while (*p != '\0')
- {
- if (escape_test(*p))
- {
- g_string_append(string, escape_code(*p));
- }
- else
- {
- g_string_append_c(string, *p);
- }
- p++;
- }
-
- result = string->str;
- g_string_free(string, FALSE);
-
- /* dropped filenames are expected to be utf-8 compatible */
- if (!g_utf8_validate(result, -1, NULL))
- {
- gchar *tmp;
-
- tmp = g_locale_to_utf8(result, -1, NULL, NULL, NULL);
- if (tmp)
- {
- g_free(result);
- result = tmp;
- }
- }
-
- return result;
-}
-
-/* this operates on the passed string, decoding escaped characters */
-void uri_text_decode(gchar *text)
-{
- if (strchr(text, '%'))
- {
- gchar *w;
- gchar *r;
-
- w = r = text;
-
- while(*r != '\0')
- {
- if (*r == '%' && *(r + 1) != '\0' && *(r + 2) != '\0')
- {
- gchar t[3];
- gint n;
-
- r++;
- t[0] = *r;
- r++;
- t[1] = *r;
- t[2] = '\0';
- n = (gint)strtol(t, NULL, 16);
- if (n > 0 && n < 256)
- {
- *w = (gchar)n;
- }
- else
- {
- /* invalid number, rewind and ignore this escape */
- r -= 2;
- *w = *r;
- }
- }
- else if (w != r)
- {
- *w = *r;
- }
- r++;
- w++;
- }
- if (*w != '\0') *w = '\0';
- }
-}
-
-static void uri_list_parse_encoded_chars(GList *list)
-{
- GList *work = list;
-
- while (work)
- {
- gchar *text = work->data;
-
- uri_text_decode(text);
-
- work = work->next;
- }
-}
-
-GList *uri_list_from_text(gchar *data, gint files_only)
-{
- GList *list = NULL;
- gint b, e;
-
- b = e = 0;
-
- while (data[b] != '\0')
- {
- while (data[e] != '\r' && data[e] != '\n' && data[e] != '\0') e++;
- if (strncmp(data + b, "file:", 5) == 0)
- {
- gchar *path;
- b += 5;
- while (data[b] == '/' && data[b+1] == '/') b++;
- path = g_strndup(data + b, e - b);
- list = g_list_append(list, path_to_utf8(path));
- g_free(path);
- }
- else if (!files_only && strncmp(data + b, "http:", 5) == 0)
- {
- list = g_list_append(list, g_strndup(data + b, e - b));
- }
- else if (!files_only && strncmp(data + b, "ftp:", 3) == 0)
- {
- list = g_list_append(list, g_strndup(data + b, e - b));
- }
- while (data[e] == '\r' || data[e] == '\n') e++;
- b = e;
- }
-
- uri_list_parse_encoded_chars(list);
-
- return list;
-}
-
-GList *uri_filelist_from_text(gchar *data, gint files_only)
-{
- GList *path_list = uri_list_from_text(data, files_only);
- GList *filelist = filelist_from_path_list(path_list);
- string_list_free(path_list);
- return filelist;
-}
-
-gchar *uri_text_from_list(GList *list, gint *len, gint plain_text)
-{
- gchar *uri_text = NULL;
- GString *string;
- GList *work;
-
- if (!list)
- {
- if (len) *len = 0;
- return NULL;
- }
-
- string = g_string_new("");
-
- work = list;
- while (work)
- {
- const gchar *name8; /* dnd filenames are in utf-8 */
-
- name8 = work->data;
-
- if (!plain_text)
- {
- gchar *escaped;
-
- escaped = uri_text_escape(name8);
- g_string_append(string, "file:");
- g_string_append(string, escaped);
- g_free(escaped);
-
- g_string_append(string, "\r\n");
- }
- else
- {
- g_string_append(string, name8);
- if (work->next) g_string_append(string, "\n");
- }
-
- work = work->next;
- }
-
- uri_text = string->str;
- if (len) *len = string->len;
- g_string_free(string, FALSE);
-
- return uri_text;
-}
-
-gchar *uri_text_from_filelist(GList *list, gint *len, gint plain_text)
-{
- GList *path_list = filelist_to_path_list(list);
- gchar *ret = uri_text_from_list(path_list, len, plain_text);
- string_list_free(path_list);
- return ret;
-}
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */