📄 ui_bookmark.c
字号:
if (!bm->editable) return; switch (info) { case TARGET_URI_LIST: case TARGET_X_URL: list = uri_list_from_text(selection_data->data, FALSE); break; } work = list; while (work) { gchar *path = work->data; gchar *buf; buf = bookmark_string(filename_from_path(path), path, NULL); history_list_add_to_key(bm->key, buf, 0); g_free(buf); work = work->next; } path_list_free(list); bookmark_populate_all(bm->key);}static void bookmark_list_destroy(GtkWidget *widget, gpointer data){ BookMarkData *bm = data; bookmark_widget_list = g_list_remove(bookmark_widget_list, bm); g_free(bm->key); g_free(bm);}GtkWidget *bookmark_list_new(const gchar *key, void (*select_func)(const gchar *path, gpointer data), gpointer select_data){ GtkWidget *scrolled; BookMarkData *bm; if (!key) key = "bookmarks"; bm = g_new0(BookMarkData, 1); bm->key = g_strdup(key); bm->select_func = select_func; bm->select_data = select_data; bm->no_defaults = FALSE; bm->editable = TRUE; scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); bm->box = gtk_vbox_new(FALSE, 0); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), bm->box); gtk_widget_show(bm->box); bookmark_populate(bm); g_signal_connect(G_OBJECT(bm->box), "destroy", G_CALLBACK(bookmark_list_destroy), bm); g_object_set_data(G_OBJECT(bm->box), BOOKMARK_DATA_KEY, bm); g_object_set_data(G_OBJECT(scrolled), BOOKMARK_DATA_KEY, bm); bm->widget = scrolled; gtk_drag_dest_set(scrolled, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, bookmark_drop_types, bookmark_drop_types_n, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); g_signal_connect(G_OBJECT(scrolled), "drag_data_received", G_CALLBACK(bookmark_dnd_get_data), bm); bookmark_widget_list = g_list_append(bookmark_widget_list, bm); return scrolled;}void bookmark_list_set_key(GtkWidget *list, const gchar *key){ BookMarkData *bm; if (!list || !key) return; bm = g_object_get_data(G_OBJECT(list), BOOKMARK_DATA_KEY); if (!bm) return; if (bm->key && strcmp(bm->key, key) == 0) return; g_free(bm->key); bm->key = g_strdup(key); bookmark_populate(bm);}void bookmark_list_set_no_defaults(GtkWidget *list, gint no_defaults){ BookMarkData *bm; bm = g_object_get_data(G_OBJECT(list), BOOKMARK_DATA_KEY); if (!bm) return; bm->no_defaults = no_defaults;}void bookmark_list_set_editable(GtkWidget *list, gint editable){ BookMarkData *bm; bm = g_object_get_data(G_OBJECT(list), BOOKMARK_DATA_KEY); if (!bm) return; bm->editable = editable;}void bookmark_list_add(GtkWidget *list, const gchar *name, const gchar *path){ BookMarkData *bm; gchar *buf; bm = g_object_get_data(G_OBJECT(list), BOOKMARK_DATA_KEY); if (!bm) return; buf = bookmark_string(name, path, NULL); history_list_add_to_key(bm->key, buf, 0); g_free(buf); bookmark_populate_all(bm->key);}void bookmark_add_default(const gchar *name, const gchar *path){ if (!name || !path) return; bookmark_default_list = g_list_append(bookmark_default_list, g_strdup(name)); bookmark_default_list = g_list_append(bookmark_default_list, g_strdup(path));}/* *----------------------------------------------------------------------------- * combo with history key *----------------------------------------------------------------------------- */typedef struct _HistoryComboData HistoryComboData;struct _HistoryComboData{ GtkWidget *combo; GtkWidget *entry; gchar *history_key; gint history_levels;};static void history_combo_destroy(GtkWidget *widget, gpointer data){ HistoryComboData *hc = data; g_free(hc->history_key); g_free(data);}/* if text is NULL, entry is set to the most recent item */GtkWidget *history_combo_new(GtkWidget **entry, const gchar *text, const gchar *history_key, gint max_levels){ HistoryComboData *hc; GList *work; gint n = 0; hc = g_new0(HistoryComboData, 1); 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->entry = GTK_BIN(hc->combo)->child; g_object_set_data(G_OBJECT(hc->combo), "history_combo_data", hc); g_object_set_data(G_OBJECT(hc->entry), "history_combo_data", hc); g_signal_connect(G_OBJECT(hc->combo), "destroy", G_CALLBACK(history_combo_destroy), 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); work = work->next; n++; } if (text) { gtk_entry_set_text(GTK_ENTRY(hc->entry), text); } else if (n > 0) { gtk_combo_box_set_active(GTK_COMBO_BOX(hc->combo), 0); } if (entry) *entry = hc->entry; return hc->combo;}/* if text is NULL, current entry text is used * widget can be the combo or entry widget */void history_combo_append_history(GtkWidget *widget, const gchar *text){ HistoryComboData *hc; gchar *new_text; hc = g_object_get_data(G_OBJECT(widget), "history_combo_data"); if (!hc) { printf("widget is not a history combo\n"); return; } if (text) { new_text = g_strdup(text); } else { new_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(hc->entry))); } if (new_text && strlen(new_text) > 0) { GtkTreeModel *store; GList *work; history_list_add_to_key(hc->history_key, new_text, hc->history_levels); gtk_combo_box_set_active(GTK_COMBO_BOX(hc->combo), -1); store = gtk_combo_box_get_model(GTK_COMBO_BOX(hc->combo)); gtk_list_store_clear(GTK_LIST_STORE(store)); work = history_list_get_by_key(hc->history_key); while (work) { gtk_combo_box_append_text(GTK_COMBO_BOX(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;}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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -