From: iev Date: Wed, 24 Aug 2011 15:43:42 +0000 (+0400) Subject: history + hotkeys(partly) X-Git-Url: http://git.osdn.net/view?p=eb123%2Feb123.git;a=commitdiff_plain;h=6b93f53c541590adf8e6f41fe7a8378fe3d5ac02 history + hotkeys(partly) --- diff --git a/src/eb123.c b/src/eb123.c index 1b11cb8..e1f706a 100644 --- a/src/eb123.c +++ b/src/eb123.c @@ -48,7 +48,6 @@ int main(int argc, char *argv[]) hooksets_init(); - //history_load_words(); //hotkeys_load(); mainwnd_prepare(mainwnd); diff --git a/src/eb123.glade b/src/eb123.glade index 08f829d..d9c4f27 100644 --- a/src/eb123.glade +++ b/src/eb123.glade @@ -638,7 +638,10 @@ True False + mainwnd_search_store + 0 True + 0 True @@ -674,7 +677,7 @@ 100 True False - mainwnd_search_store + mainwnd_search_method_store False @@ -683,12 +686,13 @@ - + True True True False none + True @@ -1073,12 +1077,18 @@ - + + + + + + + False popup @@ -1718,7 +1728,7 @@ True False - mainwnd_search_store + mainwnd_search_method_store 1 @@ -1982,7 +1992,64 @@ False 12 - + + True + False + + + True + False + + + True + True + never + + + True + False + + + True + False + 10 + + + + + + + + + + True + True + 0 + + + + + Ignore locks + True + True + False + False + True + + + False + False + 1 + + + + + True + True + 0 + + + diff --git a/src/history.c b/src/history.c index 5bd04aa..df31e80 100644 --- a/src/history.c +++ b/src/history.c @@ -8,12 +8,45 @@ extern Builder *_builder; extern Prefs *_prefs; -void history_prev() +G_DEFINE_TYPE(History, history, G_TYPE_OBJECT); + +static gint history_selection_depth = -1; + +static void history_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) +{ + History *history = HISTORY(object); + switch(param_id) + { + case 1: + history->builder = BUILDER(g_value_get_pointer(value)); + break; + case 2: + history->prefs = PREFS(g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); + break; + } +} + +static void history_class_init(HistoryClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + gobject_class->set_property = history_set_property; + g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("builder", _("Builder"), _("Builder"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + g_object_class_install_property(gobject_class, 2, g_param_spec_pointer("prefs", _("Prefs"), _("Prefs"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); +} + +static void history_init(History *self) +{ +} + +void history_prev(History *self) { GList *hist, *hist1; RESULT *res; - hist = g_list_last(history.list); + hist = g_list_last(self->list); if(!hist) return; @@ -22,27 +55,27 @@ void history_prev() return; result_free((RESULT *)hist->data); - history.list = g_list_delete_link(history.list, hist); + self->list = g_list_delete_link(self->list, hist); res = (RESULT *)(hist1->data); - //mainwnd_open(res); + mainwnd_open(MAINWND(mainwnd_get_wnd()), res); } -void history_next(RESULT *res) +void history_insert_res(History *self, RESULT *res) { - GList *hist = g_list_last(history.list); + GList *hist = g_list_last(self->list); if(hist) { RESULT *res1 = (RESULT*)hist->data; if((res1->binfo == res->binfo) && (res1->pos.page == res->pos.page) && (res1->pos.offset == res->pos.offset)) return; } - history.list = g_list_append(history.list, result_duplicate(res)); + self->list = g_list_append(self->list, result_duplicate(res)); } -RESULT *history_last_result() +RESULT *history_last_result(History *self) { - GList *hist = g_list_last(history.list); + GList *hist = g_list_last(self->list); if(hist) return (RESULT*)hist->data; return NULL; @@ -61,7 +94,7 @@ gboolean history_remove_word(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter return FALSE; } -void history_insert_word(const gchar *word) +void history_insert_word(History *self, const gchar *word) { gboolean b; GtkTreeIter iter; @@ -71,17 +104,20 @@ void history_insert_word(const gchar *word) gtk_tree_model_foreach(model, history_remove_word, (gpointer)word); gtk_tree_model_foreach(model, history_remove_word, (gpointer)word); -#if 0 - while(gtk_tree_model_iter_n_children(model, NULL) > dictbar.word_hist) + gint n = prefs_get_int(self->prefs, "dictbar.word_hist"); +#if 1 + while(gtk_tree_model_iter_n_children(model, NULL) > n) { - path = gtk_tree_path_new_from_indices(dictbar.word_hist - 1, -1); + path = gtk_tree_path_new_from_indices(n - 1, -1); b = gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); if(!b) break; gtk_list_store_remove(GTK_LIST_STORE(model), &iter); } - gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(mainwnd_search), word); - gtk_combo_box_set_active(mainwnd_search, 0); + gtk_list_store_prepend(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, word, -1); + //gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(mainwnd_search), word); + //gtk_combo_box_set_active(mainwnd_search, 0); #endif return; } @@ -96,10 +132,10 @@ gboolean history_save_word(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter * return FALSE; } -void history_save_words() +void history_save_words(History *self) { gchar filename[PATH_MAX]; - GtkComboBox *mainwnd_search = GTK_COMBO_BOX(gtk_builder_get_object(GTK_BUILDER(_builder), "mainwnd_search")); + GtkComboBox *mainwnd_search = GTK_COMBO_BOX(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search")); GtkTreeModel *model = gtk_combo_box_get_model(mainwnd_search); xmlDocPtr doc = xmlNewDoc((xmlChar*)"1.0"); doc->children = xmlNewDocRawNode(doc, NULL, (xmlChar*)"History", NULL); @@ -112,11 +148,20 @@ void history_save_words() void history_load_word(void *ctx, const xmlChar *name, const xmlChar **atts) { + xmlParserCtxt *ctxt = (xmlParserCtxt*)ctx; + xmlSAXHandler *cb = ctxt->sax; + History *self = HISTORY(cb->_private); if(!g_strcmp0((gchar*)name, "word")) - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mainwnd_search), (gchar*)atts[1]); + { + GtkComboBox *mainwnd_search = GTK_COMBO_BOX(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search")); + GtkTreeModel *model = gtk_combo_box_get_model(mainwnd_search); + GtkTreeIter iter; + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, (gchar*)atts[1], -1); + } } -void history_load_words() +void history_load_words(History *self) { gchar filename[PATH_MAX]; xmlSAXHandler cb; @@ -126,7 +171,8 @@ void history_load_words() return; memset(&cb, 0, sizeof(xmlSAXHandler)); cb.startElement = &history_load_word; - xmlDocPtr doc = xmlSAXParseFile(&cb, filename, 0); + cb._private = self; + xmlDocPtr doc = xmlSAXParseFile(&cb, filename, NULL); xmlFreeDoc(doc); } diff --git a/src/history.h b/src/history.h index 7745822..e530ab8 100644 --- a/src/history.h +++ b/src/history.h @@ -2,13 +2,45 @@ #ifndef __HISTORY_H_ #define __HISTORY_H_ -void history_prev(); -void history_next(RESULT *res); +#include "builder.h" +#include "prefs.h" + +G_BEGIN_DECLS + +#define TYPE_HISTORY (history_get_type ()) +#define HISTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_HISTORY, History)) +#define HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_HISTORY, HistoryClass)) +#define IS_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_HISTORY)) +#define IS_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_HISTORY)) +#define HISTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_HISTORY, HistoryClass)) + +typedef struct _History History; +typedef struct _HistoryClass HistoryClass; + +struct _History { + GObject parent_instance; + GList *list; + Builder *builder; + Prefs *prefs; +}; + +struct _HistoryClass { + GObjectClass parent_class; +}; + +void history_insert_word(History *self, const gchar *word); +void history_insert_res(History *self, RESULT *res); +void history_prev(History *self); + +void history_save_words(History *self); +void history_load_words(History *self); + +GType history_get_type (void); + +G_END_DECLS + RESULT* history_last_result(); void history_free_data(RESULT *res); -void history_insert_word(const gchar *word); -void history_save_words(); -void history_load_words(); RESULT* result_new(BOOK_INFO *binfo, EB_Position *pos); RESULT* result_duplicate(RESULT *res); @@ -17,9 +49,4 @@ void result_free(gpointer data); void result_clear_all(); gboolean result_compare(RESULT *res1, RESULT *res2); -struct _history -{ - GList *list; -} history; - #endif /* __HISTORY_H_ */ diff --git a/src/hotkeys.c b/src/hotkeys.c index dec624e..4dcd130 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -7,47 +7,92 @@ #include "mainwnd.h" #include "prefs.h" +typedef struct +{ + gchar *name; + void (* func)(); + gboolean global; +} HOTKEY_COMMAND; + +typedef struct +{ + guint32 mask, keyval; + gboolean enabled; +} HOTKEY_EVENT; + const HOTKEY_COMMAND hotkeys_list[] = { { _("Search"), mainwnd_search_, FALSE}, { _("Go back"), history_prev, FALSE}, -// { _("Clear search field"), mainwnd_clear_combo, FALSE}, + { _("Clear search field"), mainwnd_clear_combo, FALSE}, // { _("Next hit"), headword_next, FALSE}, // { _("Previous hit"), headword_prev, FALSE}, // { _("Select all dictionaries"), dictbar_all_select, FALSE}, // { _("Unselect all dictionaries"), dictbar_all_unselect, FALSE}, // { _("Select next group"), dictbar_group_next, FALSE}, // { _("Select previous group"), dictbar_group_prev, FALSE}, - { _("Quit program"), mainwnd_exit, FALSE}, - { _("Iconify/restore main window"), mainwnd_iconify_restore, TRUE}, // { _("Search in main window"), selection_search_in_mainwnd, TRUE}, // { _("Search in popup window"), selection_search_in_popupwnd, TRUE}, - {NULL, NULL, FALSE} + { _("Iconify/restore main window"), mainwnd_iconify_restore, TRUE}, + { _("Quit program"), mainwnd_exit, FALSE} }; -void hotkeys_list_init() +G_DEFINE_TYPE(Hotkeys, hotkeys, G_TYPE_OBJECT); + +static Hotkeys *_hotkeys = NULL; + +#if 0 +static void hotkeys_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) +{ + Hotkeys *hotkeys = HOTKEYS(object); + switch(param_id) + { + case 1: + hotkeys->builder = BUILDER(g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); + break; + } +} +#endif + +static void hotkeys_class_init(HotkeysClass *klass) +{ + //GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + //gobject_class->set_property = hotkeys_set_property; + //g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("builder", _("Builder"), _("Builder"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); +} + +static void hotkeys_init(Hotkeys *self) { + if(!_hotkeys) + _hotkeys = self; + else + g_assert(1); gint i; HOTKEY_EVENT *events = g_try_new0(HOTKEY_EVENT, sizeof(hotkeys_list)); if(!events) return; - hotkeys.list = NULL; - for(i = 0; hotkeys_list[i].name; i++) - hotkeys.list = g_list_append(hotkeys.list, (gpointer)&(events[i])); + self->list = NULL; + g_printf("hotkeys list size = %d\n", SZ(hotkeys_list)); + for(i = 0; i < SZ(hotkeys_list); i++) + self->list = g_list_append(self->list, (gpointer)&(events[i])); } -static gboolean hotkeys_local_activated_cb(GtkAccelGroup *accelgroup, GObject *arg1, guint arg2, GdkModifierType arg3, gpointer user_data) +static gboolean hotkeys_local_activated_cb(GtkAccelGroup *accelgroup, GObject *arg1, guint arg2, GdkModifierType arg3, gpointer data) { gint i; guint cmp; HOTKEY_EVENT *evt; + Hotkeys *self = HOTKEYS(data); - gulong keyval = (gulong)user_data; + gulong keyval = (gulong)arg2; gulong mask = arg3; - for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++) + for(i = 0; (evt = g_list_nth_data(self->list, i)); i++) { if(!keyval) continue; if(evt->keyval != keyval) continue; cmp = (evt->mask ^ mask); - if(hotkeys.ignore_locks) + if(self->ignore_locks) cmp = cmp & !(GDK_MOD2_MASK | GDK_LOCK_MASK); if(!cmp) { @@ -58,7 +103,7 @@ static gboolean hotkeys_local_activated_cb(GtkAccelGroup *accelgroup, GObject *a return FALSE; } -void hotkeys_local_install() +void hotkeys_local_install(Hotkeys *self) { static GtkAccelGroup *accel_group = NULL; GClosure *closure; @@ -71,9 +116,9 @@ void hotkeys_local_install() } accel_group = gtk_accel_group_new(); gtk_window_add_accel_group(mainwnd_get_wnd(), accel_group); - g_signal_connect(G_OBJECT(accel_group), "accel-activate", G_CALLBACK(hotkeys_local_activated_cb), NULL); + g_signal_connect(G_OBJECT(accel_group), "accel-activate", G_CALLBACK(hotkeys_local_activated_cb), self); - for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++) + for(i = 0; (evt = g_list_nth_data(self->list, i)); i++) { gulong keyval = evt->keyval; if(!evt->enabled || hotkeys_list[i].global) continue; @@ -90,16 +135,17 @@ static GdkFilterReturn hotkeys_global_cb(GdkXEvent *gdk_xevent, GdkEvent *event, const guint mods = LockMask | Mod2Mask; guint i; HOTKEY_EVENT *evt; + Hotkeys *self = HOTKEYS(self); switch(xevent->type) { case KeyPress: { - for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++) + for(i = 0; (evt = g_list_nth_data(self->list, i)); i++) { if(!hotkeys_list[i].global) continue; gboolean mask_cmp; - if(hotkeys.ignore_locks) + if(self->ignore_locks) mask_cmp = ((xevent->xkey.state | mods) == (evt->mask | mods)); else mask_cmp = (xevent->xkey.state == evt->mask); @@ -118,7 +164,7 @@ static GdkFilterReturn hotkeys_global_cb(GdkXEvent *gdk_xevent, GdkEvent *event, return GDK_FILTER_CONTINUE; } -void hotkeys_global_install() +void hotkeys_global_install(Hotkeys *self) { static gboolean cb_added = FALSE; GdkWindow *rootwin = gdk_get_default_root_window(); @@ -128,7 +174,7 @@ void hotkeys_global_install() if(!cb_added) { - gdk_window_add_filter(rootwin, hotkeys_global_cb, NULL); + gdk_window_add_filter(rootwin, hotkeys_global_cb, self); cb_added = TRUE; } const guint mod_masks [] = { @@ -138,17 +184,17 @@ void hotkeys_global_install() LockMask | Mod2Mask }; // remove all hotkeys - for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++) + for(i = 0; (evt = g_list_nth_data(self->list, i)); i++) { if(!hotkeys_list[i].global) continue; for(j = 0; j < G_N_ELEMENTS(mod_masks); j++) XUngrabKey(d, XKeysymToKeycode(d, evt->keyval), evt->mask | mod_masks[j], DefaultRootWindow(d)); } // install currently assigned hotkeys - for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++) + for(i = 0; (evt = g_list_nth_data(self->list, i)); i++) { if(!hotkeys_list[i].global) continue; - if(hotkeys.ignore_locks) + if(self->ignore_locks) { for(j = 0; j < G_N_ELEMENTS(mod_masks); j++) XGrabKey(d, XKeysymToKeycode(d, evt->keyval), evt->mask | mod_masks[j], DefaultRootWindow(d), True, GrabModeAsync, GrabModeAsync); @@ -158,18 +204,18 @@ void hotkeys_global_install() } } -HOTKEY_EVENT* hotkeys_find(const gchar *name) +HOTKEY_EVENT* hotkeys_find(Hotkeys *self, const gchar *name) { gint i; - for(i = 0; hotkeys_list[i].name; i++) + for(i = 0; i < SZ(hotkeys_list); i++) { if(!g_strcmp0(hotkeys_list[i].name, name)) - return (HOTKEY_EVENT*)g_list_nth_data(hotkeys.list, i); + return (HOTKEY_EVENT*)g_list_nth_data(self->list, i); } return NULL; } -void hotkeys_save() +void hotkeys_save(Hotkeys *self) { gchar filename[PATH_MAX], buff[16]; gint i; @@ -178,7 +224,7 @@ void hotkeys_save() doc->children = xmlNewDocRawNode(doc, NULL, (xmlChar*)"hotkeys", NULL); gchar *userdir = prefs_get_userdir(); sprintf(filename, "%s%s%s", userdir, G_DIR_SEPARATOR_S, FILENAME_HOTKEYS); - for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++) + for(i = 0; (evt = g_list_nth_data(self->list, i)); i++) { if(!evt->enabled) continue; xmlNodePtr node1 = xmlAddChild((xmlNodePtr)doc->children, xmlNewNode(NULL, (xmlChar*)"hotkeys")); @@ -195,22 +241,27 @@ void hotkeys_save() void hotkeys_load_item(void *ctx, const xmlChar *name, const xmlChar **atts) { if(!atts) return; - HOTKEY_EVENT *evt = hotkeys_find((gchar*)atts[1]); + + xmlParserCtxt *ctxt = (xmlParserCtxt*)ctx; + xmlSAXHandler *cb = ctxt->sax; + Hotkeys *self = HOTKEYS(cb->_private); + HOTKEY_EVENT *evt = hotkeys_find(self, (gchar*)atts[1]); if(!evt) return; + evt->mask = strtol((gchar*)atts[3], NULL, 16); evt->keyval = strtol((gchar*)atts[5], NULL, 16); evt->enabled = (evt->keyval != 0); } /* Add local some default hotkeys */ -void hotkeys_add_defaults() +void hotkeys_add_defaults(Hotkeys *self) { gint i; for(i = 0; hotkeys_list[i].name; i++) { if(hotkeys_list[i].func == mainwnd_exit) { - HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(hotkeys.list, i); + HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(self->list, i); evt->mask = 0x4; evt->keyval = 0x71; evt->enabled = TRUE; @@ -240,7 +291,7 @@ void hotkeys_add_defaults() #endif else if(hotkeys_list[i].func == mainwnd_iconify_restore) { - HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(hotkeys.list, i); + HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(self->list, i); evt->mask = 0x4; evt->keyval = 0x69; evt->enabled = TRUE; @@ -248,7 +299,7 @@ void hotkeys_add_defaults() } } -void hotkeys_load() +void hotkeys_load(Hotkeys *self) { gchar filename[PATH_MAX]; xmlSAXHandler cb; @@ -256,11 +307,12 @@ void hotkeys_load() sprintf(filename, "%s%s%s", userdir, G_DIR_SEPARATOR_S, FILENAME_HOTKEYS); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - hotkeys_add_defaults(); + hotkeys_add_defaults(self); return; } memset(&cb, 0, sizeof(xmlSAXHandler)); cb.startElement = &hotkeys_load_item; + cb._private = self; xmlDocPtr doc = xmlSAXParseFile(&cb, filename, 0); xmlFreeDoc(doc); } @@ -314,3 +366,93 @@ void hotkey_to_string(guint mask, guint keyval, gchar *key) strcat(key, gdk_keyval_name(keyval)); } +GtkEntry* hotkeys_hbox_get_entry(GtkHBox *hbox) +{ + GList *list = gtk_container_get_children(GTK_CONTAINER(hbox)); + return GTK_ENTRY(list->next->data); +} + +static gboolean hotkeys_grab_key_cb(GtkDialog *dlg, GdkEventKey *evt, GtkHBox *hbox) +{ + gchar key[256]; + + switch (evt->keyval){ + case GDK_Shift_L: + case GDK_Shift_R: + case GDK_Control_L: + case GDK_Control_R: + case GDK_Meta_L: + case GDK_Meta_R: + case GDK_Alt_L: + case GDK_Alt_R: + case GDK_Caps_Lock: + case GDK_Shift_Lock: + case GDK_Scroll_Lock: + case GDK_Num_Lock: + case GDK_Kana_Lock: + return(FALSE); + break; + } + + if(evt->keyval == GDK_Escape) + { + gtk_dialog_response(dlg, GTK_RESPONSE_NO); + return TRUE; + } + + if(_hotkeys->ignore_locks) + evt->state = evt->state & (~GDK_LOCK_MASK) & (~GDK_MOD2_MASK); + hotkey_to_string(evt->state, evt->keyval, key); + + gtk_entry_set_text(hotkeys_hbox_get_entry(hbox), key); + gtk_dialog_response(dlg, GTK_RESPONSE_OK); + + return TRUE; +} + +static void hotkeys_edit_cb(GtkWidget *widget, GtkHBox *hbox) +{ + GtkWidget* dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, + _("Press a key (or a key combination) to setup hotkey,\n" + "\"Clear\" button or \"Esc\" key to remove current hotkey,\n" + "\"Cancel\" to close this message.")); + gtk_dialog_add_buttons(GTK_DIALOG(dlg), GTK_STOCK_CLEAR, GTK_RESPONSE_NO, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + + gtk_window_set_title(GTK_WINDOW(dlg), _("Grabbing a key.")); + g_signal_connect(G_OBJECT(dlg), "key-press-event", G_CALLBACK(hotkeys_grab_key_cb), hbox); + + if(gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_NO) + gtk_entry_set_text(hotkeys_hbox_get_entry(hbox), ""); + gtk_widget_destroy(dlg); +} + +GtkWidget* hotkeys_edit_nth(Hotkeys *self, gint n) +{ + if(n >= SZ(hotkeys_list)) + return NULL; + + GtkWidget *hbox = gtk_hbox_new(FALSE, 5); + if(hotkeys_list[n].global) + gtk_widget_set_tooltip_text(hbox, _("Global hotkey")); + + GtkWidget *label = gtk_label_new(hotkeys_list[n].name); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + GtkWidget *btn = gtk_button_new_with_label(_("Edit...")); + gtk_box_pack_end(GTK_BOX(hbox), btn, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(hotkeys_edit_cb), hbox); + + GtkWidget *entry = gtk_entry_new(); + gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); + gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0); + + HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(self->list, n); + gchar keystr[64]; + if(evt ? evt->enabled : FALSE) + { + hotkey_to_string(evt->mask, evt->keyval, keystr); + gtk_entry_set_text(GTK_ENTRY(entry), keystr); + } + return hbox; +} + diff --git a/src/hotkeys.h b/src/hotkeys.h index 94c70d8..d61771e 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -2,31 +2,40 @@ #ifndef __HOTKEYS_H__ #define __HOTKEYS_H__ -struct _hotkeys -{ - gboolean ignore_locks; - GList *list; -} hotkeys; - -typedef struct -{ - gchar *name; - void (* func)(); - gboolean global; -} HOTKEY_COMMAND; - -typedef struct -{ - guint32 mask, keyval; - gboolean enabled; -} HOTKEY_EVENT; - -void hotkeys_list_init(); +#include "builder.h" + +G_BEGIN_DECLS + +#define TYPE_HOTKEYS (hotkeys_get_type ()) +#define HOTKEYS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_HOTKEYS, Hotkeys)) +#define HOTKEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_HOTKEYS, HotkeysClass)) +#define IS_HOTKEYS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_HOTKEYS)) +#define IS_HOTKEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_HOTKEYS)) +#define HOTKEYS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_HOTKEYS, HotkeysClass)) + +typedef struct _Hotkeys Hotkeys; +typedef struct _HotkeysClass HotkeysClass; + +struct _Hotkeys { + GObject parent_instance; + GList *list; + gboolean ignore_locks; +}; + +struct _HotkeysClass { + GObjectClass parent_class; +}; + +void hotkeys_load(Hotkeys *self); +void hotkeys_save(Hotkeys *self); +GtkWidget* hotkeys_edit_nth(Hotkeys *self, gint n); + +GType hotkeys_get_type (void); + +G_END_DECLS + void hotkeys_local_install(); void hotkeys_global_install(); -HOTKEY_EVENT* hotkeys_find(const gchar *name); -void hotkeys_save(); -void hotkeys_load(); void hotkey_to_string(guint mask, guint keyval, gchar *key); #endif /* __HOTKEYS_H__ */ diff --git a/src/mainwnd.c b/src/mainwnd.c index 370090a..3f58a73 100644 --- a/src/mainwnd.c +++ b/src/mainwnd.c @@ -30,12 +30,14 @@ static void mainwnd_init(Mainwnd *self) self->builder = g_object_new(TYPE_BUILDER, NULL); self->prefs = g_object_new(TYPE_PREFS, "builder", self->builder, NULL); self->dicts = g_object_new(TYPE_DICTS, "builder", self->builder, NULL); + self->history = g_object_new(TYPE_HISTORY, "builder", self->builder, "prefs", self->prefs, NULL); + self->hotkeys = g_object_new(TYPE_HOTKEYS, NULL); self->results = g_sequence_new(result_free); gtk_builder_connect_signals(GTK_BUILDER(self->builder), self); GtkWidget *vbox = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(self->builder), "vbox1")); gtk_widget_reparent(vbox, GTK_WIDGET(self)); GtkContainer *scroll = GTK_CONTAINER(gtk_builder_get_object(GTK_BUILDER(self->builder), "scrolledwindow2")); - self->text = g_object_new(TYPE_TEXTVIEW, "prefs", self->prefs, NULL); + self->text = g_object_new(TYPE_TEXTVIEW, "prefs", self->prefs, "history", self->history, NULL); gtk_container_add(scroll, GTK_WIDGET(self->text)); self->popupwnd = g_object_new(TYPE_POPUPWND, "mainwnd", self, "type", GTK_WINDOW_POPUP, NULL); self->word = NULL; @@ -105,7 +107,7 @@ void mainwnd_exit() w = gtk_paned_get_position(p); prefs_set_int(prefs, "paned.tree_width", w); - //history_save_words(); + history_save_words(mw->history); prefs_save(prefs); dicts_save(mw->dicts); //hotkeys_save(); @@ -144,7 +146,7 @@ void mainwnd_search(Mainwnd *self, const gchar *word, gint method) if(method == -1) method = builder_get_int(self->builder, "mainwnd_search_method"); - //history_insert_word(word); + history_insert_word(self->history, word); gint maxhits = prefs_get_int(self->prefs, "headword.maxhits"); ebook_search(word, method, self->results, maxhits, False); mainwnd_update_results(self); @@ -177,11 +179,14 @@ static void mainwnd_prev(GtkWidget *widget, gpointer data) history_prev(); } +#endif + void mainwnd_clear_combo() { + //GtkWidget *combo = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(_mainwnd->builder), "mainwnd_search")); + //GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo))); builder_set_str(_mainwnd->builder, "mainwnd_search", ""); } -#endif gboolean mainwnd_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { @@ -227,6 +232,7 @@ static void mainwnd_scan_start_stop(Mainwnd *self, gboolean scan) void mainwnd_scan_toggled_cb(GtkToggleButton *btn, gpointer data) { Mainwnd *mw = MAINWND(data); + if(!gtk_widget_get_visible(GTK_WIDGET(mw))) return; gint scan = gtk_toggle_button_get_active(btn); mainwnd_scan_start_stop(mw, scan); } @@ -373,19 +379,20 @@ void mainwnd_dict_buttons_update(Mainwnd *self) void mainwnd_prepare(Mainwnd *self) { -#if 0 - hotkeys_local_install(); - hotkeys_global_install(); -#endif GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)icon_xpm); gtk_window_set_default_icon(pixbuf); g_object_unref(pixbuf); gtk_widget_hide_on_delete(GTK_WIDGET(self)); prefs_load(self->prefs); + history_load_words(self->history); + hotkeys_load(self->hotkeys); + hotkeys_local_install(self->hotkeys); + hotkeys_global_install(self->hotkeys); builder_install_text_cellrenderer(self->builder, "mainwnd_search_method"); builder_install_text_cellrenderer(self->builder, "mainwnd_dict_group"); + builder_install_text_cellrenderer(self->builder, "mainwnd_search"); GtkTreeView *tree = GTK_TREE_VIEW(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_results")); GtkTreeSelection *select = gtk_tree_view_get_selection(tree); @@ -407,12 +414,9 @@ void mainwnd_prepare(Mainwnd *self) builder_set_int(self->builder, "mainwnd_dict_group", active); builder_set_int(self->builder, "mainwnd_search", 0); - gboolean b = prefs_get_int(self->prefs, "selection.lookup_started"); - builder_set_int(self->builder, "mainwnd_scan", b); - gint i; GtkTreeIter iter; - GtkListStore *store = GTK_LIST_STORE(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search_store")); + GtkListStore *store = GTK_LIST_STORE(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search_method_store")); for(i = 0; i < 4; i++) { const gchar *name = ebook_index_to_method_name(i); @@ -434,6 +438,8 @@ void mainwnd_prepare(Mainwnd *self) gtk_window_move(GTK_WINDOW(self), x, y); } mainwnd_reset_font(self); + gboolean b = prefs_get_int(self->prefs, "selection.lookup_started"); + builder_set_int(self->builder, "mainwnd_scan", b); builder_grab_focus(self->builder, "mainwnd_search"); } @@ -501,3 +507,9 @@ void mainwnd_dict_group_changed_cb(GtkComboBox *widget, gpointer data) mainwnd_dict_buttons_update(mw); } +void mainwnd_prev_clicked_cb(GtkWidget *widget, gpointer data) +{ + Mainwnd *mw = MAINWND(data); + history_prev(mw->history); +} + diff --git a/src/mainwnd.h b/src/mainwnd.h index 30b4818..e3bcee5 100644 --- a/src/mainwnd.h +++ b/src/mainwnd.h @@ -5,6 +5,8 @@ #include "builder.h" #include "dicts.h" #include "prefs.h" +#include "history.h" +#include "hotkeys.h" #include "textview.h" #include "popupwnd.h" @@ -25,6 +27,8 @@ struct _Mainwnd { Builder *builder; Dicts *dicts; Prefs *prefs; + History *history; + Hotkeys *hotkeys; GSequence *results; TextView *text; Popupwnd *popupwnd; @@ -52,9 +56,9 @@ GType mainwnd_get_type (void); G_END_DECLS +void mainwnd_clear_combo(); void mainwnd_iconify_restore(); void mainwnd_search_(); -void mainwnd_clear_combo(); GtkWidget* mainwnd_search_method_combo(); #endif /* __MAINWND_H__ */ diff --git a/src/prefs.c b/src/prefs.c index 07a665c..6179b63 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -92,8 +92,6 @@ static void prefs_init(Prefs *self) g_datalist_init(&(self->data)); - hotkeys_list_init(); - gchar *home_dir = getenv("HOME"); gchar *userdir = g_strdup_printf("%s%s.%s", home_dir, G_DIR_SEPARATOR_S, PACKAGE_NAME); prefs_set_str(self, "userdir", userdir); @@ -255,6 +253,13 @@ void prefs_btn_clicked_cb(GtkWidget *widget, gpointer data) } GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(mw->builder), "mainwnd.font")); gtk_widget_set_sensitive(w, prefs_get_int(mw->prefs, "mainwnd.custom_font")); + + Hotkeys *hotkeys = mw->hotkeys; + GtkBox *vbox = GTK_BOX(gtk_builder_get_object(GTK_BUILDER(mw->builder), "hotkeys_vbox")); + for(i = 0; w = hotkeys_edit_nth(hotkeys, i); i++) + { + gtk_box_pack_start(vbox, w, FALSE, FALSE, 0); + } preparewnd = False; } if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_store), &iter1)) @@ -290,7 +295,8 @@ void prefs_save(Prefs *self) break; case G_TYPE_STRING: str = prefs_get_str(self, p->name); - sprintf(buff, "%s", str); + if(str) + sprintf(buff, "%s", str); break; } xmlNodePtr node = xmlAddChild(doc->children, xmlNewNode(NULL, (xmlChar*)prefs_list[i].name)); diff --git a/src/textview.c b/src/textview.c index 8ff52c9..64ede98 100644 --- a/src/textview.c +++ b/src/textview.c @@ -149,9 +149,8 @@ void textview_open(TextView *self, RESULT *res, gboolean clear, const gchar *wor render_content(res->binfo, self, text, self->prefs); g_free(text); - TextViewClass *klass = TEXTVIEW_GET_CLASS(self); - if(klass->history_next) - klass->history_next(res); + if(self->history) + history_insert_res(self->history, res); if(word && prefs_get_int(self->prefs, "highlight_all_keywords")) textview_highlight_word(self, word); } @@ -166,6 +165,9 @@ static void textview_set_property(GObject *object, guint param_id, const GValue text->prefs = PREFS(g_value_get_pointer(value)); g_signal_connect(G_OBJECT(text), "populate_popup", G_CALLBACK(textview_populate_popup_cb), text); break; + case 2: + text->history = HISTORY(g_value_get_pointer(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; @@ -174,10 +176,10 @@ static void textview_set_property(GObject *object, guint param_id, const GValue static void textview_class_init(TextViewClass *klass) { - klass->history_next = NULL; GObjectClass *gobject_class = G_OBJECT_CLASS(klass); gobject_class->set_property = textview_set_property; g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("prefs", _("Prefs"), _("Prefs"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + g_object_class_install_property(gobject_class, 2, g_param_spec_pointer("history", _("History"), _("History"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); } static void textview_init(TextView *self) @@ -192,6 +194,7 @@ static void textview_init(TextView *self) gtk_text_view_set_right_margin(GTK_TEXT_VIEW(self), 10); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(self), GTK_WRAP_WORD); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(self), FALSE); + self->history = NULL; } void textview_clear_textbuf(TextView *self) diff --git a/src/textview.h b/src/textview.h index 23f83e2..e917299 100644 --- a/src/textview.h +++ b/src/textview.h @@ -20,11 +20,11 @@ struct _TextView { GtkTextView parent_instance; GtkTextTag *tag; Prefs *prefs; + History *history; }; struct _TextViewClass { GtkTextViewClass parent_class; - void (*history_next)(RESULT *res); }; void textview_open(TextView *self, RESULT *res, gboolean clear, const gchar *word);