From 9a4ddc65abb573eee1329552e65160205f0a3f8f Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Mon, 4 Mar 2013 22:45:20 +0100 Subject: [PATCH] Use some logic together for all windows. --- config.mk | 1 + src/command.c | 223 ++++++++-------- src/command.h | 46 ++-- src/completion.c | 154 +++++------ src/completion.h | 4 +- src/dom.c | 22 +- src/dom.h | 2 +- src/hints.c | 124 +++++---- src/hints.h | 8 +- src/history.c | 30 +-- src/history.h | 4 +- src/keybind.c | 32 ++- src/keybind.h | 1 + src/main.c | 634 ++++++++++++++++++++++++---------------------- src/main.h | 65 ++--- src/setting.c | 367 +++++++++++++++------------ src/setting.h | 10 +- src/url_history.c | 1 + 18 files changed, 902 insertions(+), 826 deletions(-) diff --git a/config.mk b/config.mk index cbc8c6b..f26da6f 100644 --- a/config.mk +++ b/config.mk @@ -41,6 +41,7 @@ CPPFLAGS += -DFEATURE_COOKIE CPPFLAGS += -DFEATURE_SEARCH_HIGHLIGHT CPPFLAGS += -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=500 +CPPFLAGS += -DPROJECT=\"${PROJECT}\" ifeq ($(USEGTK3), 1) CPPFLAGS += -DHAS_GTK3 endif diff --git a/src/command.c b/src/command.c index dc62778..562150f 100644 --- a/src/command.c +++ b/src/command.c @@ -94,7 +94,7 @@ static CommandInfo cmd_list[] = { {"command-hist-prev", command_history, {VP_SEARCH_BACKWARD}}, }; -static void command_write_input(const char* str); +static void command_write_input(Client* c, const char* str); void command_init(void) @@ -119,34 +119,36 @@ gboolean command_exists(const char* name) return g_hash_table_contains(core.behave.commands, name); } -gboolean command_run(const char* name, const char* param) +gboolean command_run(Client* c, const char* name, const char* param) { - CommandInfo* c = NULL; + CommandInfo* command = NULL; gboolean result; Arg a; - c = g_hash_table_lookup(core.behave.commands, name); - if (!c) { - vp_echo(VP_MSG_ERROR, TRUE, "Command '%s' not found", name); - vp_set_mode(VP_MODE_NORMAL, FALSE); + command = g_hash_table_lookup(core.behave.commands, name); + if (!command) { + if (c) { + vp_echo(c, VP_MSG_ERROR, TRUE, "Command '%s' not found", name); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); + } return FALSE; } - a.i = c->arg.i; - a.s = g_strdup(param ? param : c->arg.s); - result = c->function(&a); + a.i = command->arg.i; + a.s = g_strdup(param ? param : command->arg.s); + result = command->function(c, &a); g_free(a.s); return result; } -gboolean command_open(const Arg* arg) +gboolean command_open(Client* c, const Arg* arg) { char* uri = NULL; gboolean result; if (!arg->s || arg->s[0] == '\0') { Arg a = {arg->i, core.config.home_page}; - return vp_load_uri(&a); + return vp_load_uri(c, &a); } /* check for searchengine handles */ /* split into handle and searchterms */ @@ -156,11 +158,11 @@ gboolean command_open(const Arg* arg) ) { char* term = soup_uri_encode(string[1], "&"); Arg a = {arg->i, g_strdup_printf(uri, term)}; - result = vp_load_uri(&a); + result = vp_load_uri(c, &a); g_free(term); g_free(a.s); } else { - result = vp_load_uri(arg); + result = vp_load_uri(c, arg); } g_strfreev(string); @@ -170,88 +172,87 @@ gboolean command_open(const Arg* arg) /** * Reopens the last closed page. */ -gboolean command_open_closed(const Arg* arg) +gboolean command_open_closed(Client* c, const Arg* arg) { gboolean result; Arg a = {arg->i}; a.s = util_get_file_contents(core.files[FILES_CLOSED], NULL); - result = vp_load_uri(&a); + result = vp_load_uri(c, &a); g_free(a.s); return result; } -gboolean command_input(const Arg* arg) +gboolean command_input(Client* c, const Arg* arg) { const char* url; /* add current url if requested */ if (VP_INPUT_CURRENT_URI == arg->i - && (url = CURRENT_URL()) + && (url = webkit_web_view_get_uri(c->gui.webview)) ) { /* append the current url to the input message */ char* input = g_strconcat(arg->s, url, NULL); - command_write_input(input); + command_write_input(c, input); g_free(input); } else { - command_write_input(arg->s); + command_write_input(c, arg->s); } - vp_set_mode(VP_MODE_COMMAND, FALSE); + vp_set_mode(c, VP_MODE_COMMAND, FALSE); return TRUE; } -gboolean command_close(const Arg* arg) +gboolean command_close(Client* c, const Arg* arg) { - gtk_main_quit(); - vp_clean_up(); + gtk_widget_destroy(GTK_WIDGET(c->gui.window)); return TRUE; } -gboolean command_view_source(const Arg* arg) +gboolean command_view_source(Client* c, const Arg* arg) { - gboolean mode = webkit_web_view_get_view_source_mode(vp.gui.webview); - webkit_web_view_set_view_source_mode(vp.gui.webview, !mode); - webkit_web_view_reload(vp.gui.webview); + gboolean mode = webkit_web_view_get_view_source_mode(c->gui.webview); + webkit_web_view_set_view_source_mode(c->gui.webview, !mode); + webkit_web_view_reload(c->gui.webview); - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return TRUE; } -gboolean command_navigate(const Arg* arg) +gboolean command_navigate(Client* c, const Arg* arg) { if (arg->i <= VP_NAVIG_FORWARD) { - int count = vp.state.count ? vp.state.count : 1; + int count = c->state.count ? c->state.count : 1; webkit_web_view_go_back_or_forward( - vp.gui.webview, (arg->i == VP_NAVIG_BACK ? -count : count) + c->gui.webview, (arg->i == VP_NAVIG_BACK ? -count : count) ); } else if (arg->i == VP_NAVIG_RELOAD) { - webkit_web_view_reload(vp.gui.webview); + webkit_web_view_reload(c->gui.webview); } else if (arg->i == VP_NAVIG_RELOAD_FORCE) { - webkit_web_view_reload_bypass_cache(vp.gui.webview); + webkit_web_view_reload_bypass_cache(c->gui.webview); } else { - webkit_web_view_stop_loading(vp.gui.webview); + webkit_web_view_stop_loading(c->gui.webview); } - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return TRUE; } -gboolean command_scroll(const Arg* arg) +gboolean command_scroll(Client* c, const Arg* arg) { - GtkAdjustment *adjust = (arg->i & VP_SCROLL_AXIS_H) ? vp.gui.adjust_h : vp.gui.adjust_v; + GtkAdjustment *adjust = (arg->i & VP_SCROLL_AXIS_H) ? c->gui.adjust_h : c->gui.adjust_v; int direction = (arg->i & (1 << 2)) ? 1 : -1; /* type scroll */ if (arg->i & VP_SCROLL_TYPE_SCROLL) { gdouble value; - int count = vp.state.count ? vp.state.count : 1; + int count = c->state.count ? c->state.count : 1; if (arg->i & VP_SCROLL_UNIT_LINE) { value = core.config.scrollstep; } else if (arg->i & VP_SCROLL_UNIT_HALFPAGE) { @@ -260,10 +261,10 @@ gboolean command_scroll(const Arg* arg) value = gtk_adjustment_get_page_size(adjust); } gtk_adjustment_set_value(adjust, gtk_adjustment_get_value(adjust) + direction * value * count); - } else if (vp.state.count) { + } else if (c->state.count) { /* jump - if count is set to count% of page */ gdouble max = gtk_adjustment_get_upper(adjust) - gtk_adjustment_get_page_size(adjust); - gtk_adjustment_set_value(adjust, max * vp.state.count / 100); + gtk_adjustment_set_value(adjust, max * c->state.count / 100); } else if (direction == 1) { /* jump to top */ gtk_adjustment_set_value(adjust, gtk_adjustment_get_upper(adjust)); @@ -272,15 +273,15 @@ gboolean command_scroll(const Arg* arg) gtk_adjustment_set_value(adjust, gtk_adjustment_get_lower(adjust)); } - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return TRUE; } -gboolean command_map(const Arg* arg) +gboolean command_map(Client* c, const Arg* arg) { gboolean result; - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); char **string = g_strsplit(arg->s, "=", 2); if (g_strv_length(string) != 2) { @@ -292,14 +293,14 @@ gboolean command_map(const Arg* arg) return result; } -gboolean command_unmap(const Arg* arg) +gboolean command_unmap(Client* c, const Arg* arg) { - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return keybind_remove_from_string(arg->s, arg->i); } -gboolean command_set(const Arg* arg) +gboolean command_set(Client* c, const Arg* arg) { gboolean success; char* line = NULL; @@ -316,81 +317,81 @@ gboolean command_set(const Arg* arg) token = g_strsplit(line, "=", 2); g_free(line); - success = setting_run(token[0], token[1] ? token[1] : NULL); + success = setting_run(c, token[0], token[1] ? token[1] : NULL); g_strfreev(token); - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return success; } -gboolean command_complete(const Arg* arg) +gboolean command_complete(Client* c, const Arg* arg) { - completion_complete(arg->i ? TRUE : FALSE); + completion_complete(c, arg->i ? TRUE : FALSE); - vp_set_mode(VP_MODE_COMMAND | VP_MODE_COMPLETE, FALSE); + vp_set_mode(c, VP_MODE_COMMAND | VP_MODE_COMPLETE, FALSE); return TRUE; } -gboolean command_inspect(const Arg* arg) +gboolean command_inspect(Client* c, const Arg* arg) { gboolean enabled; WebKitWebSettings* settings = NULL; - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); - settings = webkit_web_view_get_settings(vp.gui.webview); + settings = webkit_web_view_get_settings(c->gui.webview); g_object_get(G_OBJECT(settings), "enable-developer-extras", &enabled, NULL); if (enabled) { - if (vp.state.is_inspecting) { - webkit_web_inspector_close(vp.gui.inspector); + if (c->state.is_inspecting) { + webkit_web_inspector_close(c->gui.inspector); } else { - webkit_web_inspector_show(vp.gui.inspector); + webkit_web_inspector_show(c->gui.inspector); } return TRUE; } - vp_echo(VP_MSG_ERROR, TRUE, "enable-developer-extras not enabled"); + vp_echo(c, VP_MSG_ERROR, TRUE, "enable-developer-extras not enabled"); return FALSE; } -gboolean command_hints(const Arg* arg) +gboolean command_hints(Client* c, const Arg* arg) { - command_write_input(arg->s); - hints_create(NULL, arg->i, (arg->s ? strlen(arg->s) : 0)); + command_write_input(c, arg->s); + hints_create(c, NULL, arg->i, (arg->s ? strlen(arg->s) : 0)); - vp_set_mode(VP_MODE_HINTING, FALSE); + vp_set_mode(c, VP_MODE_HINTING, FALSE); return TRUE; } -gboolean command_hints_focus(const Arg* arg) +gboolean command_hints_focus(Client* c, const Arg* arg) { - hints_focus_next(arg->i ? TRUE : FALSE); + hints_focus_next(c, arg->i ? TRUE : FALSE); - vp_set_mode(VP_MODE_HINTING, FALSE); + vp_set_mode(c, VP_MODE_HINTING, FALSE); return TRUE; } -gboolean command_yank(const Arg* arg) +gboolean command_yank(Client* c, const Arg* arg) { - vp_set_mode(VP_MODE_NORMAL, TRUE); + vp_set_mode(c, VP_MODE_NORMAL, TRUE); if (arg->i & COMMAND_YANK_SELECTION) { char* text = NULL; /* copy current selection to clipboard */ - webkit_web_view_copy_clipboard(vp.gui.webview); + webkit_web_view_copy_clipboard(c->gui.webview); text = gtk_clipboard_wait_for_text(PRIMARY_CLIPBOARD()); if (!text) { text = gtk_clipboard_wait_for_text(SECONDARY_CLIPBOARD()); } if (text) { /* TODO is this the rigth place to switch the focus */ - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); - vp_echo(VP_MSG_NORMAL, FALSE, "Yanked: %s", text); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); + vp_echo(c, VP_MSG_NORMAL, FALSE, "Yanked: %s", text); g_free(text); return TRUE; @@ -402,15 +403,15 @@ gboolean command_yank(const Arg* arg) Arg a = {arg->i}; if (arg->i & COMMAND_YANK_URI) { /* yank current url */ - a.s = g_strdup(CURRENT_URL()); + a.s = g_strdup(webkit_web_view_get_uri(c->gui.webview)); } else { a.s = arg->s ? g_strdup(arg->s) : NULL; } if (a.s) { vp_set_clipboard(&a); /* TODO is this the rigth place to switch the focus */ - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); - vp_echo(VP_MSG_NORMAL, FALSE, "Yanked: %s", a.s); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); + vp_echo(c, VP_MSG_NORMAL, FALSE, "Yanked: %s", a.s); g_free(a.s); return TRUE; @@ -419,7 +420,7 @@ gboolean command_yank(const Arg* arg) return FALSE; } -gboolean command_paste(const Arg* arg) +gboolean command_paste(Client* c, const Arg* arg) { Arg a = {.i = arg->i & VP_TARGET_NEW}; if (arg->i & VP_CLIPBOARD_PRIMARY) { @@ -430,7 +431,7 @@ gboolean command_paste(const Arg* arg) } if (a.s) { - vp_load_uri(&a); + vp_load_uri(c, &a); g_free(a.s); return TRUE; @@ -438,15 +439,14 @@ gboolean command_paste(const Arg* arg) return FALSE; } -gboolean command_search(const Arg* arg) +gboolean command_search(Client* c, const Arg* arg) { - State* state = &vp.state; - gboolean forward = !(arg->i ^ state->search_dir); + gboolean forward = !(arg->i ^ c->state.search_dir); - if (arg->i == VP_SEARCH_OFF && state->search_query) { - OVERWRITE_STRING(state->search_query, NULL); + if (arg->i == VP_SEARCH_OFF && c->state.search_query) { + OVERWRITE_STRING(c->state.search_query, NULL); #ifdef FEATURE_SEARCH_HIGHLIGHT - webkit_web_view_unmark_text_matches(vp.gui.webview); + webkit_web_view_unmark_text_matches(c->gui.webview); #endif return TRUE; @@ -454,29 +454,29 @@ gboolean command_search(const Arg* arg) /* copy search query for later use */ if (arg->s) { - OVERWRITE_STRING(state->search_query, arg->s); + OVERWRITE_STRING(c->state.search_query, arg->s); /* set dearch dir only when the searching is started */ - vp.state.search_dir = arg->i; + c->state.search_dir = arg->i; } - if (state->search_query) { + if (c->state.search_query) { #ifdef FEATURE_SEARCH_HIGHLIGHT - webkit_web_view_mark_text_matches(vp.gui.webview, state->search_query, FALSE, 0); - webkit_web_view_set_highlight_text_matches(vp.gui.webview, TRUE); + webkit_web_view_mark_text_matches(c->gui.webview, c->state.search_query, FALSE, 0); + webkit_web_view_set_highlight_text_matches(c->gui.webview, TRUE); #endif /* make sure we have a count greater than 0 */ - vp.state.count = vp.state.count ? vp.state.count : 1; + c->state.count = c->state.count ? c->state.count : 1; do { - webkit_web_view_search_text(vp.gui.webview, state->search_query, FALSE, forward, TRUE); - } while (--vp.state.count); + webkit_web_view_search_text(c->gui.webview, c->state.search_query, FALSE, forward, TRUE); + } while (--c->state.count); } - vp_set_mode(VP_MODE_SEARCH, FALSE); + vp_set_mode(c, VP_MODE_SEARCH, FALSE); return TRUE; } -gboolean command_searchengine(const Arg* arg) +gboolean command_searchengine(Client* c, const Arg* arg) { gboolean result; if (arg->i) { @@ -492,73 +492,74 @@ gboolean command_searchengine(const Arg* arg) result = searchengine_remove(arg->s); } - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return result; } -gboolean command_zoom(const Arg* arg) +gboolean command_zoom(Client* c, const Arg* arg) { float step, level; int count; if (arg->i & COMMAND_ZOOM_RESET) { - webkit_web_view_set_zoom_level(vp.gui.webview, 1.0); - vp_set_mode(VP_MODE_NORMAL, FALSE); + webkit_web_view_set_zoom_level(c->gui.webview, 1.0); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return TRUE; } - count = vp.state.count ? vp.state.count : 1; - level = webkit_web_view_get_zoom_level(vp.gui.webview); + count = c->state.count ? c->state.count : 1; + level = webkit_web_view_get_zoom_level(c->gui.webview); - WebKitWebSettings* setting = webkit_web_view_get_settings(vp.gui.webview); + WebKitWebSettings* setting = webkit_web_view_get_settings(c->gui.webview); g_object_get(G_OBJECT(setting), "zoom-step", &step, NULL); webkit_web_view_set_full_content_zoom( - vp.gui.webview, (arg->i & COMMAND_ZOOM_FULL) > 0 + c->gui.webview, (arg->i & COMMAND_ZOOM_FULL) > 0 ); webkit_web_view_set_zoom_level( - vp.gui.webview, + c->gui.webview, level + (float)(count *step) * (arg->i & COMMAND_ZOOM_IN ? 1.0 : -1.0) ); - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return TRUE; } -gboolean command_history(const Arg* arg) +gboolean command_history(Client* c, const Arg* arg) { - const int count = vp.state.count ? vp.state.count : 1; + const int count = c->state.count ? c->state.count : 1; const gint step = count * (arg->i == VP_SEARCH_BACKWARD ? -1 : 1); - const char* entry = history_get(step); + const char* entry = history_get(c, step); if (!entry) { return FALSE; } - command_write_input(entry); + command_write_input(c, entry); return TRUE; } -static void command_write_input(const char* str) +static void command_write_input(Client* c, const char* str) { int pos = 0; + GtkEditable* box = GTK_EDITABLE(c->gui.inputbox); /* reset the colors and fonts to defalts */ vp_set_widget_font( - vp.gui.inputbox, + c->gui.inputbox, &core.style.input_fg[VP_MSG_NORMAL], &core.style.input_bg[VP_MSG_NORMAL], core.style.input_font[VP_MSG_NORMAL] ); /* remove content from input box */ - gtk_editable_delete_text(GTK_EDITABLE(vp.gui.inputbox), 0, -1); + gtk_editable_delete_text(box, 0, -1); /* insert string from arg */ - gtk_editable_insert_text(GTK_EDITABLE(vp.gui.inputbox), str, -1, &pos); - gtk_editable_set_position(GTK_EDITABLE(vp.gui.inputbox), -1); + gtk_editable_insert_text(box, str, -1, &pos); + gtk_editable_set_position(box, -1); } diff --git a/src/command.h b/src/command.h index f9914c7..c0062f7 100644 --- a/src/command.h +++ b/src/command.h @@ -34,7 +34,7 @@ enum { COMMAND_ZOOM_RESET = (1<<2) }; -typedef gboolean (*Command)(const Arg* arg); +typedef gboolean (*Command)(Client* c, const Arg* arg); typedef struct { const char* name; @@ -46,28 +46,28 @@ typedef struct { void command_init(void); void command_cleanup(void); gboolean command_exists(const char* name); -gboolean command_run(const char* name, const char* param); +gboolean command_run(Client* c, const char* name, const char* param); -gboolean command_open(const Arg* arg); -gboolean command_open_home(const Arg* arg); -gboolean command_open_closed(const Arg* arg); -gboolean command_input(const Arg* arg); -gboolean command_close(const Arg* arg); -gboolean command_view_source(const Arg* arg); -gboolean command_navigate(const Arg* arg); -gboolean command_scroll(const Arg* arg); -gboolean command_map(const Arg* arg); -gboolean command_unmap(const Arg* arg); -gboolean command_set(const Arg* arg); -gboolean command_complete(const Arg* arg); -gboolean command_inspect(const Arg* arg); -gboolean command_hints(const Arg* arg); -gboolean command_hints_focus(const Arg* arg); -gboolean command_yank(const Arg* arg); -gboolean command_paste(const Arg* arg); -gboolean command_search(const Arg* arg); -gboolean command_searchengine(const Arg* arg); -gboolean command_zoom(const Arg* arg); -gboolean command_history(const Arg* arg); +gboolean command_open(Client* c, const Arg* arg); +gboolean command_open_home(Client* c, const Arg* arg); +gboolean command_open_closed(Client* c, const Arg* arg); +gboolean command_input(Client* c, const Arg* arg); +gboolean command_close(Client* c, const Arg* arg); +gboolean command_view_source(Client* c, const Arg* arg); +gboolean command_navigate(Client* c, const Arg* arg); +gboolean command_scroll(Client* c, const Arg* arg); +gboolean command_map(Client* c, const Arg* arg); +gboolean command_unmap(Client* c, const Arg* arg); +gboolean command_set(Client* c, const Arg* arg); +gboolean command_complete(Client* c, const Arg* arg); +gboolean command_inspect(Client* c, const Arg* arg); +gboolean command_hints(Client* c, const Arg* arg); +gboolean command_hints_focus(Client* c, const Arg* arg); +gboolean command_yank(Client* c, const Arg* arg); +gboolean command_paste(Client* c, const Arg* arg); +gboolean command_search(Client* c, const Arg* arg); +gboolean command_searchengine(Client* c, const Arg* arg); +gboolean command_zoom(Client* c, const Arg* arg); +gboolean command_history(Client* c, const Arg* arg); #endif /* end of include guard: _COMMAND_H */ diff --git a/src/completion.c b/src/completion.c index bb8ee0d..fba9daa 100644 --- a/src/completion.c +++ b/src/completion.c @@ -28,95 +28,99 @@ typedef struct { char* prefix; } Completion; -static GList* completion_init_completion(GList* target, GList* source, +static GList* completion_init_completion(Client* c, GList* target, GList* source, Comp_Func func, const char* input, const char* prefix); -static GList* completion_update(GList* completion, GList* active, gboolean back); -static void completion_show(gboolean back); -static void completion_set_entry_text(Completion* c); -static char* completion_get_text(Completion* c); +static GList* completion_update(Client* c, GList* completion, GList* active, gboolean back); +static void completion_show(Client* c, gboolean back); +static void completion_set_entry_text(Client* c, Completion* completion); +static char* completion_get_text(Client* c, Completion* completion); static Completion* completion_get_new(const char* label, const char* prefix); -gboolean completion_complete(gboolean back) +gboolean completion_complete(Client* c, gboolean back) { - const char* input = GET_TEXT(); + const char* input = gtk_entry_get_text(GTK_ENTRY(c->gui.inputbox)); GList* source = NULL; - if (vp.comps.completions - && vp.comps.active - && (vp.state.mode & VP_MODE_COMPLETE) + if (c->comps.completions + && c->comps.active + && (c->state.mode & VP_MODE_COMPLETE) ) { - char* text = completion_get_text((Completion*)vp.comps.active->data); + char* text = completion_get_text(c, (Completion*)c->comps.active->data); if (!strcmp(input, text)) { /* updatecompletions */ - vp.comps.active = completion_update(vp.comps.completions, vp.comps.active, back); + c->comps.active = completion_update(c, c->comps.completions, c->comps.active, back); return TRUE; } else { /* if current input isn't the content of the completion item */ - completion_clean(); + completion_clean(c); } } /* create new completion */ #ifdef HAS_GTK3 - vp.gui.compbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_set_homogeneous(GTK_BOX(vp.gui.compbox), TRUE); + c->gui.compbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_box_set_homogeneous(GTK_BOX(c->gui.compbox), TRUE); #else - vp.gui.compbox = gtk_vbox_new(TRUE, 0); + c->gui.compbox = gtk_vbox_new(TRUE, 0); #endif - gtk_box_pack_start(GTK_BOX(vp.gui.box), vp.gui.compbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(c->gui.box), c->gui.compbox, FALSE, FALSE, 0); /* TODO move these decision to a more generic place */ if (!strncmp(input, ":set ", 5)) { source = g_hash_table_get_keys(core.settings); source = g_list_sort(source, (GCompareFunc)g_strcmp0); - vp.comps.completions = completion_init_completion( - vp.comps.completions, source, (Comp_Func)g_str_has_prefix, &input[5], ":set " + c->comps.completions = completion_init_completion( + c, + c->comps.completions, source, (Comp_Func)g_str_has_prefix, &input[5], ":set " ); } else if (!strncmp(input, ":open ", 6)) { source = url_history_get_all(); - vp.comps.completions = completion_init_completion( - vp.comps.completions, source, (Comp_Func)util_strcasestr, &input[6], ":open " + c->comps.completions = completion_init_completion( + c, + c->comps.completions, source, (Comp_Func)util_strcasestr, &input[6], ":open " ); } else if (!strncmp(input, ":tabopen ", 9)) { source = url_history_get_all(); - vp.comps.completions = completion_init_completion( - vp.comps.completions, source, (Comp_Func)util_strcasestr, &input[9], ":tabopen " + c->comps.completions = completion_init_completion( + c, + c->comps.completions, source, (Comp_Func)util_strcasestr, &input[9], ":tabopen " ); } else { source = g_hash_table_get_keys(core.behave.commands); source = g_list_sort(source, (GCompareFunc)g_strcmp0); - vp.comps.completions = completion_init_completion( - vp.comps.completions, source, (Comp_Func)g_str_has_prefix, &input[1], ":" + c->comps.completions = completion_init_completion( + c, + c->comps.completions, source, (Comp_Func)g_str_has_prefix, &input[1], ":" ); } - if (!vp.comps.completions) { + if (!c->comps.completions) { return FALSE; } - completion_show(back); + completion_show(c, back); return TRUE; } -void completion_clean(void) +void completion_clean(Client* c) { - g_list_free_full(vp.comps.completions, (GDestroyNotify)g_free); - vp.comps.completions = NULL; + g_list_free_full(c->comps.completions, (GDestroyNotify)g_free); + c->comps.completions = NULL; - if (vp.gui.compbox) { - gtk_widget_destroy(vp.gui.compbox); - vp.gui.compbox = NULL; + if (c->gui.compbox) { + gtk_widget_destroy(c->gui.compbox); + c->gui.compbox = NULL; } - OVERWRITE_STRING(vp.comps.prefix, NULL); - vp.comps.active = NULL; - vp.comps.count = 0; + OVERWRITE_STRING(c->comps.prefix, NULL); + c->comps.active = NULL; + c->comps.count = 0; /* remove completion flag from mode */ - vp.state.mode &= ~VP_MODE_COMPLETE; + c->state.mode &= ~VP_MODE_COMPLETE; } -static GList* completion_init_completion(GList* target, GList* source, +static GList* completion_init_completion(Client* c, GList* target, GList* source, Comp_Func func, const char* input, const char* prefix) { char* command = NULL; @@ -125,8 +129,8 @@ static GList* completion_init_completion(GList* target, GList* source, char **token = NULL; /* remove counts before command and save it to print it later in inputbox */ - vp.comps.count = g_ascii_strtoll(input, &command, 10); - OVERWRITE_STRING(vp.comps.prefix, prefix); + c->comps.count = g_ascii_strtoll(input, &command, 10); + OVERWRITE_STRING(c->comps.prefix, prefix); token = g_strsplit(command, " ", -1); @@ -146,10 +150,10 @@ static GList* completion_init_completion(GList* target, GList* source, } } if (match) { - Completion* c = completion_get_new(data, prefix); - gtk_box_pack_start(GTK_BOX(vp.gui.compbox), c->event, TRUE, TRUE, 0); + Completion* completion = completion_get_new(data, prefix); + gtk_box_pack_start(GTK_BOX(c->gui.compbox), completion->event, TRUE, TRUE, 0); /* use prepend because that faster */ - target = g_list_prepend(target, c); + target = g_list_prepend(target, completion); } } @@ -159,10 +163,10 @@ static GList* completion_init_completion(GList* target, GList* source, return target; } -static GList* completion_update(GList* completion, GList* active, gboolean back) +static GList* completion_update(Client* c, GList* completion, GList* active, gboolean back) { GList *old, *new; - Completion *c; + Completion *comp; int length = g_list_length(completion); int max = core.config.max_completion_items; @@ -177,10 +181,10 @@ static GList* completion_update(GList* completion, GList* active, gboolean back) new = g_list_last(completion); } if (position - 1 > offset && position < items - offset + r) { - c = g_list_nth(completion, position - offset - 2)->data; - gtk_widget_show_all(c->event); - c = g_list_nth(completion, position + offset - r)->data; - gtk_widget_hide(c->event); + comp = g_list_nth(completion, position - offset - 2)->data; + gtk_widget_show_all(comp->event); + comp = g_list_nth(completion, position + offset - r)->data; + gtk_widget_hide(comp->event); } else if (position == 1) { int i = 0; for (GList *l = g_list_first(completion); l && i < max; l = l->next, i++) { @@ -188,8 +192,8 @@ static GList* completion_update(GList* completion, GList* active, gboolean back) } i = 0; for (GList *l = g_list_last(completion); l && i < max; l = l->prev, i++) { - c = l->data; - gtk_widget_show_all(c->event); + comp = l->data; + gtk_widget_show_all(comp->event); } } } else { @@ -197,10 +201,10 @@ static GList* completion_update(GList* completion, GList* active, gboolean back) new = g_list_first(completion); } if (position > offset && position < items - offset - 1 + r) { - c = g_list_nth(completion, position - offset - 1)->data; - gtk_widget_hide(c->event); - c = g_list_nth(completion, position + offset + 1 - r)->data; - gtk_widget_show_all(c->event); + comp = g_list_nth(completion, position - offset - 1)->data; + gtk_widget_hide(comp->event); + comp = g_list_nth(completion, position + offset + 1 - r)->data; + gtk_widget_show_all(comp->event); } else if (position == items || position == 1) { int i = 0; for (GList *l = g_list_last(completion); l && i < max; l = l->prev, i++) { @@ -219,56 +223,60 @@ static GList* completion_update(GList* completion, GList* active, gboolean back) VP_WIDGET_SET_STATE(((Completion*)new->data)->event, VP_GTK_STATE_ACTIVE); active = new; - completion_set_entry_text(active->data); + completion_set_entry_text(c, active->data); return active; } /* allow to chenge the direction of display */ -static void completion_show(gboolean back) +static void completion_show(Client* c, gboolean back) { guint max = core.config.max_completion_items; int i = 0; if (back) { - vp.comps.active = g_list_last(vp.comps.completions); - for (GList *l = vp.comps.active; l && i < max; l = l->prev, i++) { + c->comps.active = g_list_last(c->comps.completions); + for (GList *l = c->comps.active; l && i < max; l = l->prev, i++) { gtk_widget_show_all(((Completion*)l->data)->event); } } else { - vp.comps.active = g_list_first(vp.comps.completions); - for (GList *l = vp.comps.active; l && i < max; l = l->next, i++) { + c->comps.active = g_list_first(c->comps.completions); + for (GList *l = c->comps.active; l && i < max; l = l->next, i++) { gtk_widget_show_all(((Completion*)l->data)->event); } } - if (vp.comps.active != NULL) { - Completion* active = (Completion*)vp.comps.active->data; + if (c->comps.active != NULL) { + Completion* active = (Completion*)c->comps.active->data; VP_WIDGET_SET_STATE(active->label, VP_GTK_STATE_ACTIVE); VP_WIDGET_SET_STATE(active->event, VP_GTK_STATE_ACTIVE); - completion_set_entry_text(active); - gtk_widget_show(vp.gui.compbox); + completion_set_entry_text(c, active); + gtk_widget_show(c->gui.compbox); } } -static void completion_set_entry_text(Completion* c) +static void completion_set_entry_text(Client* c, Completion* completion) { - char* text = completion_get_text(c); - gtk_entry_set_text(GTK_ENTRY(vp.gui.inputbox), text); - gtk_editable_set_position(GTK_EDITABLE(vp.gui.inputbox), -1); + char* text = completion_get_text(c, completion); + gtk_entry_set_text(GTK_ENTRY(c->gui.inputbox), text); + gtk_editable_set_position(GTK_EDITABLE(c->gui.inputbox), -1); g_free(text); } /** * Retrieves the full new allocated entry text for given completion item. */ -static char* completion_get_text(Completion* c) +static char* completion_get_text(Client* c, Completion* completion) { char* text = NULL; /* print the previous typed command count into inputbox too */ - if (vp.comps.count) { - text = g_strdup_printf("%s%d%s", c->prefix, vp.comps.count, gtk_label_get_text(GTK_LABEL(c->label))); + if (c->comps.count) { + text = g_strdup_printf( + "%s%d%s", completion->prefix, c->comps.count, gtk_label_get_text(GTK_LABEL(completion->label)) + ); } else { - text = g_strdup_printf("%s%s", c->prefix, gtk_label_get_text(GTK_LABEL(c->label))); + text = g_strdup_printf( + "%s%s", completion->prefix, gtk_label_get_text(GTK_LABEL(completion->label)) + ); } return text; diff --git a/src/completion.h b/src/completion.h index cdc47e4..5a18a2b 100644 --- a/src/completion.h +++ b/src/completion.h @@ -22,7 +22,7 @@ #include "main.h" -void completion_clean(void); -gboolean completion_complete(gboolean back); +void completion_clean(Client* c); +gboolean completion_complete(Client* c, gboolean back); #endif /* end of include guard: _COMPLETION_H */ diff --git a/src/dom.c b/src/dom.c index 8bccebd..b8f1711 100644 --- a/src/dom.c +++ b/src/dom.c @@ -20,22 +20,22 @@ #include "main.h" #include "dom.h" -static gboolean dom_auto_insert(Element* element); -static gboolean dom_editable_focus_cb(Element* element, Event* event); +static gboolean dom_auto_insert(Client* c, Element* element); +static gboolean dom_editable_focus_cb(Element* element, Event* event, Client* c); static Element* dom_get_active_element(Document* doc); -void dom_check_auto_insert(void) +void dom_check_auto_insert(Client* c) { - Document* doc = webkit_web_view_get_dom_document(vp.gui.webview); + Document* doc = webkit_web_view_get_dom_document(c->gui.webview); Element* active = dom_get_active_element(doc); - if (!dom_auto_insert(active)) { + if (!dom_auto_insert(c, active)) { HtmlElement* element = webkit_dom_document_get_body(doc); if (!element) { element = WEBKIT_DOM_HTML_ELEMENT(webkit_dom_document_get_document_element(doc)); } webkit_dom_event_target_add_event_listener( - WEBKIT_DOM_EVENT_TARGET(element), "focus", G_CALLBACK(dom_editable_focus_cb), true, NULL + WEBKIT_DOM_EVENT_TARGET(element), "focus", G_CALLBACK(dom_editable_focus_cb), true, c ); } } @@ -66,23 +66,23 @@ gboolean dom_is_editable(Element* element) return FALSE; } -static gboolean dom_auto_insert(Element* element) +static gboolean dom_auto_insert(Client* c, Element* element) { if (dom_is_editable(element)) { - vp_set_mode(VP_MODE_INSERT, FALSE); + vp_set_mode(c, VP_MODE_INSERT, FALSE); return TRUE; } return FALSE; } -static gboolean dom_editable_focus_cb(Element* element, Event* event) +static gboolean dom_editable_focus_cb(Element* element, Event* event, Client* c) { webkit_dom_event_target_remove_event_listener( WEBKIT_DOM_EVENT_TARGET(element), "focus", G_CALLBACK(dom_editable_focus_cb), true ); - if (GET_CLEAN_MODE() != VP_MODE_INSERT) { + if (CLEAN_MODE(c->state.mode) != VP_MODE_INSERT) { EventTarget* target = webkit_dom_event_get_target(event); - dom_auto_insert((void*)target); + dom_auto_insert(c, (void*)target); } return FALSE; } diff --git a/src/dom.h b/src/dom.h index 74c87ba..20b1bae 100644 --- a/src/dom.h +++ b/src/dom.h @@ -39,7 +39,7 @@ typedef struct { gulong bottom; } DomBoundingRect; -void dom_check_auto_insert(void); +void dom_check_auto_insert(Client* c); gboolean dom_is_editable(Element* element); #endif /* end of include guard: _DOM_H */ diff --git a/src/hints.c b/src/hints.c index 6433eed..e65b347 100644 --- a/src/hints.c +++ b/src/hints.c @@ -27,11 +27,11 @@ #define HINT_VAR "VpHint" #define HINT_FILE NULL -static void hints_run_script(char* js); -static void hints_fire(void); -static void hints_observe_input(gboolean observe); -static gboolean hints_changed_callback(GtkEditable *entry, gpointer data); -static gboolean hints_keypress_callback(WebKitWebView* webview, GdkEventKey* event); +static void hints_run_script(Client* c, char* js); +static void hints_fire(Client* c); +static void hints_observe_input(Client* c, gboolean observe); +static gboolean hints_changed_callback(GtkEditable *entry, Client* c); +static gboolean hints_keypress_callback(WebKitWebView* webview, GdkEventKey* event, Client* c); void hints_init(WebKitWebFrame* frame) { @@ -42,34 +42,34 @@ void hints_init(WebKitWebFrame* frame) g_free(error); } -void hints_clear(void) +void hints_clear(Client* c) { - hints_observe_input(FALSE); - if (GET_CLEAN_MODE() == VP_MODE_HINTING) { + hints_observe_input(c, FALSE); + if (CLEAN_MODE(c->state.mode) == VP_MODE_HINTING) { char* js = g_strdup_printf("%s.clear();", HINT_VAR); char* value = NULL; char* error = NULL; vp_eval_script( - webkit_web_view_get_main_frame(vp.gui.webview), js, HINT_FILE, &value, &error + webkit_web_view_get_main_frame(c->gui.webview), js, HINT_FILE, &value, &error ); g_free(value); g_free(error); g_free(js); - g_signal_emit_by_name(vp.gui.webview, "hovering-over-link", NULL, NULL); + g_signal_emit_by_name(c->gui.webview, "hovering-over-link", NULL, NULL); } } -void hints_create(const char* input, guint mode, const guint prefixLength) +void hints_create(Client* c, const char* input, guint mode, const guint prefixLength) { char* js = NULL; char type; - if (GET_CLEAN_MODE() != VP_MODE_HINTING) { + if (CLEAN_MODE(c->state.mode) != VP_MODE_HINTING) { Style* style = &core.style; - vp.hints.prefixLength = prefixLength; - vp.hints.mode = mode; - vp.hints.num = 0; + c->hints.prefixLength = prefixLength; + c->hints.mode = mode; + c->hints.num = 0; js = g_strdup_printf( "%s = new VimpHints('%s', '%s', '%s', '%s');", @@ -79,10 +79,10 @@ void hints_create(const char* input, guint mode, const guint prefixLength) style->hint_fg, style->hint_style ); - hints_run_script(js); + hints_run_script(c, js); g_free(js); - hints_observe_input(TRUE); + hints_observe_input(c, TRUE); } /* convert the mode into the type chare used in the hint script */ @@ -93,38 +93,38 @@ void hints_create(const char* input, guint mode, const guint prefixLength) } js = g_strdup_printf("%s.create('%s', '%c');", HINT_VAR, input ? input : "", type); - hints_run_script(js); + hints_run_script(c, js); g_free(js); } -void hints_update(const gulong num) +void hints_update(Client* c, const gulong num) { char* js = g_strdup_printf("%s.update(%lu);", HINT_VAR, num); - hints_run_script(js); + hints_run_script(c, js); g_free(js); } -void hints_focus_next(const gboolean back) +void hints_focus_next(Client* c, const gboolean back) { char* js = g_strdup_printf(back ? "%s.focusPrev()" : "%s.focusNext();", HINT_VAR); - hints_run_script(js); + hints_run_script(c, js); g_free(js); } -static void hints_run_script(char* js) +static void hints_run_script(Client* c, char* js) { char* value = NULL; char* error = NULL; - int mode = vp.hints.mode; + int mode = c->hints.mode; vp_eval_script( - webkit_web_view_get_main_frame(vp.gui.webview), js, HINT_FILE, &value, &error + webkit_web_view_get_main_frame(c->gui.webview), js, HINT_FILE, &value, &error ); if (error) { fprintf(stderr, "%s\n", error); g_free(error); - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); return; } @@ -134,99 +134,95 @@ static void hints_run_script(char* js) if (!strncmp(value, "OVER:", 5)) { g_signal_emit_by_name( - vp.gui.webview, "hovering-over-link", NULL, *(value + 5) == '\0' ? NULL : (value + 5) + c->gui.webview, "hovering-over-link", NULL, *(value + 5) == '\0' ? NULL : (value + 5) ); } else if (!strncmp(value, "DONE:", 5)) { - hints_observe_input(FALSE); - vp_set_mode(VP_MODE_NORMAL, TRUE); + hints_observe_input(c, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, TRUE); } else if (!strncmp(value, "INSERT:", 7)) { - hints_observe_input(FALSE); - vp_set_mode(VP_MODE_INSERT, TRUE); + hints_observe_input(c, FALSE); + vp_set_mode(c, VP_MODE_INSERT, TRUE); } else if (!strncmp(value, "DATA:", 5)) { - hints_observe_input(FALSE); + hints_observe_input(c, FALSE); Arg a = {0}; char* v = (value + 5); if (mode & HINTS_PROCESS_OPEN) { a.s = v; a.i = (mode & HINTS_OPEN_NEW) ? VP_TARGET_NEW : VP_TARGET_CURRENT; - command_open(&a); + command_open(c, &a); } else if (mode & HINTS_PROCESS_INPUT) { a.s = g_strconcat((mode & HINTS_OPEN_NEW) ? ":tabopen " : ":open ", v, NULL); - command_input(&a); + command_input(c, &a); g_free(a.s); } else { a.i = COMMAND_YANK_PRIMARY | COMMAND_YANK_SECONDARY; a.s = v; - command_yank(&a); + command_yank(c, &a); } } g_free(value); } -static void hints_fire(void) +static void hints_fire(Client* c) { - hints_observe_input(FALSE); + hints_observe_input(c, FALSE); char* js = g_strdup_printf("%s.fire();", HINT_VAR); - hints_run_script(js); + hints_run_script(c, js); g_free(js); } -static void hints_observe_input(gboolean observe) +static void hints_observe_input(Client* c, gboolean observe) { - static gulong changeHandler = 0; - static gulong keypressHandler = 0; - if (observe) { - changeHandler = g_signal_connect( - G_OBJECT(vp.gui.inputbox), "changed", G_CALLBACK(hints_changed_callback), NULL + c->hints.change_handler = g_signal_connect( + G_OBJECT(c->gui.inputbox), "changed", G_CALLBACK(hints_changed_callback), c ); - keypressHandler = g_signal_connect( - G_OBJECT(vp.gui.inputbox), "key-press-event", G_CALLBACK(hints_keypress_callback), NULL + c->hints.keypress_handler = g_signal_connect( + G_OBJECT(c->gui.inputbox), "key-press-event", G_CALLBACK(hints_keypress_callback), c ); - } else if (changeHandler && keypressHandler) { - g_signal_handler_disconnect(G_OBJECT(vp.gui.inputbox), changeHandler); - g_signal_handler_disconnect(G_OBJECT(vp.gui.inputbox), keypressHandler); - changeHandler = 0; - keypressHandler = 0; + } else if (c->hints.change_handler && c->hints.keypress_handler) { + g_signal_handler_disconnect(G_OBJECT(c->gui.inputbox), c->hints.change_handler); + g_signal_handler_disconnect(G_OBJECT(c->gui.inputbox), c->hints.keypress_handler); + + c->hints.change_handler = c->hints.keypress_handler = 0; /* clear the input box - TODO move this to a better place */ - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); - gtk_entry_set_text(GTK_ENTRY(vp.gui.inputbox), ""); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); + gtk_entry_set_text(GTK_ENTRY(c->gui.inputbox), ""); } } -static gboolean hints_changed_callback(GtkEditable *entry, gpointer data) +static gboolean hints_changed_callback(GtkEditable *entry, Client* c) { - const char* text = GET_TEXT(); + const char* text = gtk_entry_get_text(GTK_ENTRY(c->gui.inputbox)); /* skip hinting prefixes like '.', ',', ';y' ... */ - hints_create(text + vp.hints.prefixLength, vp.hints.mode, vp.hints.prefixLength); + hints_create(c, text + c->hints.prefixLength, c->hints.mode, c->hints.prefixLength); return TRUE; } -static gboolean hints_keypress_callback(WebKitWebView* webview, GdkEventKey* event) +static gboolean hints_keypress_callback(WebKitWebView* webview, GdkEventKey* event, Client* c) { - Hints* hints = &vp.hints; int numval; guint keyval = event->keyval; guint state = CLEAN_STATE_WITH_SHIFT(event); if (keyval == GDK_Return) { - hints_fire(); + hints_fire(c); return TRUE; } if (keyval == GDK_BackSpace && (state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK)) { - hints->num /= 10; - hints_update(hints->num); + c->hints.num /= 10; + hints_update(c, c->hints.num); return TRUE; } numval = g_unichar_digit_value((gunichar)gdk_keyval_to_unicode(keyval)); - if ((numval >= 1 && numval <= 9) || (numval == 0 && hints->num)) { + if ((numval >= 1 && numval <= 9) || (numval == 0 && c->hints.num)) { /* allow a zero as non-first number */ - hints->num = (hints->num ? hints->num * 10 : 0) + numval; - hints_update(hints->num); + c->hints.num = (c->hints.num ? c->hints.num * 10 : 0) + numval; + hints_update(c, c->hints.num); return TRUE; } diff --git a/src/hints.h b/src/hints.h index bc0b2d8..14e682d 100644 --- a/src/hints.h +++ b/src/hints.h @@ -34,9 +34,9 @@ enum { }; void hints_init(WebKitWebFrame* frame); -void hints_create(const char* input, guint mode, const guint prefixLength); -void hints_update(const gulong num); -void hints_clear(void); -void hints_focus_next(const gboolean back); +void hints_create(Client* c, const char* input, guint mode, const guint prefixLength); +void hints_update(Client* c, const gulong num); +void hints_clear(Client* c); +void hints_focus_next(Client* c, const gboolean back); #endif /* end of include guard: _HINTS_H */ diff --git a/src/history.c b/src/history.c index 55c3a67..f8099a4 100644 --- a/src/history.c +++ b/src/history.c @@ -38,45 +38,45 @@ void history_append(const char* line) core.behave.history = g_list_append(core.behave.history, g_strdup(line)); } -const char* history_get(const int step) +const char* history_get(Client* c, const int step) { const char* command; /* get the search prefix only on start of history search */ - if (!vp.state.history_active) { - OVERWRITE_STRING(vp.state.history_prefix, GET_TEXT()); + if (!c->state.history_active) { + OVERWRITE_STRING(c->state.history_prefix, gtk_entry_get_text(GTK_ENTRY(c->gui.inputbox))); /* generate new history list with the matching items */ for (GList* l = core.behave.history; l; l = l->next) { char* entry = g_strdup((char*)l->data); - if (g_str_has_prefix(entry, vp.state.history_prefix)) { - vp.state.history_active = g_list_prepend(vp.state.history_active, entry); + if (g_str_has_prefix(entry, c->state.history_prefix)) { + c->state.history_active = g_list_prepend(c->state.history_active, entry); } } - vp.state.history_active = g_list_reverse(vp.state.history_active); + c->state.history_active = g_list_reverse(c->state.history_active); } - const int len = g_list_length(vp.state.history_active); + const int len = g_list_length(c->state.history_active); if (!len) { return NULL; } /* if reached end/beginnen start at the opposit site of list again */ - vp.state.history_pointer = (len + vp.state.history_pointer + step) % len; + c->state.history_pointer = (len + c->state.history_pointer + step) % len; - command = (char*)g_list_nth_data(vp.state.history_active, vp.state.history_pointer); + command = (char*)g_list_nth_data(c->state.history_active, c->state.history_pointer); return command; } -void history_rewind(void) +void history_rewind(Client* c) { - if (vp.state.history_active) { - OVERWRITE_STRING(vp.state.history_prefix, NULL); - vp.state.history_pointer = 0; + if (c->state.history_active) { + OVERWRITE_STRING(c->state.history_prefix, NULL); + c->state.history_pointer = 0; /* free temporary used history list */ - g_list_free_full(vp.state.history_active, (GDestroyNotify)g_free); - vp.state.history_active = NULL; + g_list_free_full(c->state.history_active, (GDestroyNotify)g_free); + c->state.history_active = NULL; } } diff --git a/src/history.h b/src/history.h index d6c3ccf..ad48a3f 100644 --- a/src/history.h +++ b/src/history.h @@ -22,7 +22,7 @@ void history_cleanup(void); void history_append(const char* line); -const char* history_get(const int step); -void history_rewind(void); +const char* history_get(Client* c, const int step); +void history_rewind(Client* c); #endif /* end of include guard: _HISTORY_H */ diff --git a/src/keybind.c b/src/keybind.c index e232688..2fbcba1 100644 --- a/src/keybind.c +++ b/src/keybind.c @@ -27,14 +27,18 @@ static GSList* keybind_find(int mode, guint modkey, guint modmask, guint keyval) static void keybind_str_to_keybind(char* str, Keybind* key); static guint keybind_str_to_modmask(const char* str); static guint keybind_str_to_value(const char* str); -static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* event); +static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* event, Client* c); static void keybind_free(Keybind* keybind); void keybind_init(void) { core.behave.modkeys = g_string_new(""); - g_signal_connect(G_OBJECT(vp.gui.window), "key-press-event", G_CALLBACK(keybind_keypress_callback), NULL); +} + +void keybind_init_client(Client* c) +{ + g_signal_connect(G_OBJECT(c->gui.window), "key-press-event", G_CALLBACK(keybind_keypress_callback), c); } void keybind_cleanup(void) @@ -223,7 +227,7 @@ static guint keybind_str_to_value(const char* str) return str[0]; } -static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* event) +static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* event, Client* c) { guint keyval = event->keyval; guint state = CLEAN_STATE_WITH_SHIFT(event); @@ -231,34 +235,34 @@ static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* e /* check for escape or modkeys or counts */ if (IS_ESCAPE_KEY(keyval, state)) { /* switch to normal mode and clear the input box */ - vp_set_mode(VP_MODE_NORMAL, TRUE); + vp_set_mode(c, VP_MODE_NORMAL, TRUE); return TRUE; } /* allow mode keys and counts only in normal mode */ - if ((VP_MODE_SEARCH | VP_MODE_NORMAL) & vp.state.mode) { - if (vp.state.modkey == 0 && ((keyval >= GDK_1 && keyval <= GDK_9) - || (keyval == GDK_0 && vp.state.count))) { + if ((VP_MODE_SEARCH | VP_MODE_NORMAL) & c->state.mode) { + if (c->state.modkey == 0 && ((keyval >= GDK_1 && keyval <= GDK_9) + || (keyval == GDK_0 && c->state.count))) { /* append the new entered count to previous one */ - vp.state.count = (vp.state.count ? vp.state.count * 10 : 0) + (keyval - GDK_0); - vp_update_statusbar(); + c->state.count = (c->state.count ? c->state.count * 10 : 0) + (keyval - GDK_0); + vp_update_statusbar(c); return TRUE; } - if (strchr(core.behave.modkeys->str, keyval) && vp.state.modkey != keyval) { - vp.state.modkey = (char)keyval; - vp_update_statusbar(); + if (strchr(core.behave.modkeys->str, keyval) && c->state.modkey != keyval) { + c->state.modkey = (char)keyval; + vp_update_statusbar(c); return TRUE; } } /* check for keybinding */ - GSList* link = keybind_find(GET_CLEAN_MODE(), vp.state.modkey, state, keyval); + GSList* link = keybind_find(CLEAN_MODE(c->state.mode), c->state.modkey, state, keyval); if (link) { Keybind* keybind = (Keybind*)link->data; - command_run(keybind->command, keybind->param); + command_run(c, keybind->command, keybind->param); return TRUE; } diff --git a/src/keybind.h b/src/keybind.h index 84c2b0c..7ca7b69 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -33,6 +33,7 @@ typedef struct { } Keybind; void keybind_init(void); +void keybind_init_client(Client* c); void keybind_cleanup(void); gboolean keybind_add_from_string(char* keys, const char* command, const Mode mode); gboolean keybind_remove_from_string(char* str, const Mode mode); diff --git a/src/main.c b/src/main.c index 6a15f66..90d4335 100644 --- a/src/main.c +++ b/src/main.c @@ -32,83 +32,64 @@ /* variables */ static char **args; -VpClient vp; -VpCore core; +VpCore core; +Client* clients = NULL; /* callbacks */ -static void vp_webview_progress_cb(WebKitWebView* view, GParamSpec* pspec, gboolean download); -static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gpointer user_data); -static void vp_destroy_window_cb(GtkWidget* widget, GtkWidget* window, gpointer user_data); -static void vp_inputbox_activate_cb(GtkEntry* entry, gpointer user_data); -static gboolean vp_inputbox_keyrelease_cb(GtkEntry* entry, GdkEventKey* event); -static void vp_scroll_cb(GtkAdjustment* adjustment, gpointer data); -static void vp_new_request_cb(SoupSession* session, SoupMessage *message, gpointer data); -static void vp_gotheaders_cb(SoupMessage* message, gpointer data); -static WebKitWebView* vp_inspector_new(WebKitWebInspector* inspector, WebKitWebView* webview); -static gboolean vp_inspector_show(WebKitWebInspector* inspector); -static gboolean vp_inspector_close(WebKitWebInspector* inspector); -static void vp_inspector_finished(WebKitWebInspector* inspector); -static gboolean vp_button_relase_cb(WebKitWebView *webview, GdkEventButton* event, gpointer data); +static void vp_webview_progress_cb(WebKitWebView* view, GParamSpec* pspec, Client* c); +static void vp_webview_download_progress_cb(WebKitWebView* view, GParamSpec* pspec, Client* c); +static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, Client* c); +static void vp_destroy_window_cb(GtkWidget* widget, Client* c); +static void vp_inputbox_activate_cb(GtkEntry* entry, Client* c); +static gboolean vp_inputbox_keyrelease_cb(GtkEntry* entry, GdkEventKey* event, Client* c); +static void vp_scroll_cb(GtkAdjustment* adjustment, Client* c); +static void vp_new_request_cb(SoupSession* session, SoupMessage *message, Client* c); +static void vp_gotheaders_cb(SoupMessage* message, Client* c); +static WebKitWebView* vp_inspector_new(WebKitWebInspector* inspector, WebKitWebView* webview, Client* c); +static gboolean vp_inspector_show(WebKitWebInspector* inspector, Client* c); +static gboolean vp_inspector_close(WebKitWebInspector* inspector, Client* c); +static void vp_inspector_finished(WebKitWebInspector* inspector, Client* c); +static gboolean vp_button_relase_cb(WebKitWebView *webview, GdkEventButton* event, Client* c); static gboolean vp_new_window_policy_cb( WebKitWebView* view, WebKitWebFrame* frame, WebKitNetworkRequest* request, - WebKitWebNavigationAction* navig, WebKitWebPolicyDecision* policy, gpointer data); -static WebKitWebView* vp_create_new_webview_cb(WebKitWebView* webview, WebKitWebFrame* frame, gpointer data); -static void vp_create_new_webview_uri_cb(WebKitWebView* view, GParamSpec param_spec); -static void vp_hover_link_cb(WebKitWebView* webview, const char* title, const char* link, gpointer data); -static void vp_title_changed_cb(WebKitWebView* webview, WebKitWebFrame* frame, const char* title, gpointer data); + WebKitWebNavigationAction* navig, WebKitWebPolicyDecision* policy, Client* c); +static WebKitWebView* vp_create_new_webview_cb(WebKitWebView* webview, WebKitWebFrame* frame, Client* c); +static void vp_hover_link_cb(WebKitWebView* webview, const char* title, const char* link, Client* c); +static void vp_title_changed_cb(WebKitWebView* webview, WebKitWebFrame* frame, const char* title, Client* c); static gboolean vp_mimetype_decision_cb(WebKitWebView* webview, WebKitWebFrame* frame, WebKitNetworkRequest* request, char* - mime_type, WebKitWebPolicyDecision* decision, gpointer data); -static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* download, gpointer data); -static void vp_download_progress_cp(WebKitDownload* download, GParamSpec* pspec); + mime_type, WebKitWebPolicyDecision* decision, Client* c); +static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* download, Client* c); +static void vp_download_progress_cp(WebKitDownload* download, GParamSpec* pspec, Client* c); static void vp_request_start_cb(WebKitWebView* webview, WebKitWebFrame* frame, WebKitWebResource* resource, WebKitNetworkRequest* request, - WebKitNetworkResponse* response, gpointer data); + WebKitNetworkResponse* response, Client* c); /* functions */ -static gboolean vp_process_input(const char* input); +static gboolean vp_process_input(Client* c, const char* input); static void vp_run_user_script(WebKitWebFrame* frame); static char* vp_jsref_to_string(JSContextRef context, JSValueRef ref); -static void vp_print_version(void); -static void vp_init(void); -static void vp_read_config(void); -static void vp_init_gui(void); +static void vp_init_core(void); +static void vp_read_global_config(void); +static void vp_process_config_file(Client* c, VpFile file); +static Client* vp_client_new(void); +static void vp_setup_signals(Client* c); static void vp_init_files(void); -static void vp_setup_signals(void); -static void vp_setup_settings(void); static void vp_set_cookie(SoupCookie* cookie); static const char* vp_get_cookies(SoupURI *uri); -static gboolean vp_hide_message(void); -static void vp_set_status(const StatusType status); +static gboolean vp_hide_message(Client* c); +static void vp_set_status(Client* c, const StatusType status); +static void vp_destroy_client(Client* c); +static void vp_clean_up(void); -void vp_clean_input(void) +void vp_clean_input(Client* c) { /* move focus from input box to clean it */ - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); - vp_echo(VP_MSG_NORMAL, FALSE, ""); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); + vp_echo(c, VP_MSG_NORMAL, FALSE, ""); } -void vp_clean_up(void) -{ - const char* uri = CURRENT_URL(); - /* write last URL into file for recreation */ - if (uri) { - g_file_set_contents(core.files[FILES_CLOSED], uri, -1, NULL); - } - - command_cleanup(); - setting_cleanup(); - keybind_cleanup(); - completion_clean(); - searchengine_cleanup(); - url_history_cleanup(); - - for (int i = 0; i < FILES_LAST; i++) { - g_free(core.files[i]); - } -} - -void vp_echo(const MessageType type, gboolean hide, const char *error, ...) +void vp_echo(Client* c, const MessageType type, gboolean hide, const char *error, ...) { va_list arg_list; @@ -118,20 +99,14 @@ void vp_echo(const MessageType type, gboolean hide, const char *error, ...) va_end(arg_list); /* don't print message if the input is focussed */ - if (gtk_widget_is_focus(GTK_WIDGET(vp.gui.inputbox))) { + if (gtk_widget_is_focus(GTK_WIDGET(c->gui.inputbox))) { return; } - /* set the collors according to message type */ - vp_set_widget_font( - vp.gui.inputbox, - &core.style.input_fg[type], - &core.style.input_bg[type], - core.style.input_font[type] - ); - gtk_entry_set_text(GTK_ENTRY(vp.gui.inputbox), message); + vp_update_input_style(c, type); + gtk_entry_set_text(GTK_ENTRY(c->gui.inputbox), message); if (hide) { - g_timeout_add_seconds(MESSAGE_TIMEOUT, (GSourceFunc)vp_hide_message, NULL); + g_timeout_add_seconds(MESSAGE_TIMEOUT, (GSourceFunc)vp_hide_message, c); } } @@ -156,7 +131,7 @@ void vp_eval_script(WebKitWebFrame* frame, char* script, char* file, char** valu } } -gboolean vp_load_uri(const Arg* arg) +gboolean vp_load_uri(Client* c, const Arg* arg) { char* uri; char* path = arg->s; @@ -179,29 +154,14 @@ gboolean vp_load_uri(const Arg* arg) } /* change state to normal mode */ - vp_set_mode(VP_MODE_NORMAL, FALSE); + vp_set_mode(c, VP_MODE_NORMAL, FALSE); if (arg->i == VP_TARGET_NEW) { - char *argv[64]; - - argv[0] = *args; - if (vp.state.embed) { - char tmp[64]; - snprintf(tmp, LENGTH(tmp), "%u", (int)vp.state.embed); - argv[1] = "-e"; - argv[2] = tmp; - argv[3] = uri; - argv[4] = NULL; - } else { - argv[1] = uri; - argv[2] = NULL; - } - - /* spawn a new browser instance */ - g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); + Client* new = vp_client_new(); + webkit_web_view_load_uri(new->gui.webview, uri); } else { /* Load a web page into the browser instance */ - webkit_web_view_load_uri(vp.gui.webview, uri); + webkit_web_view_load_uri(c->gui.webview, uri); } g_free(uri); @@ -229,58 +189,62 @@ gboolean vp_set_clipboard(const Arg* arg) /** * Set the base modes. All other mode flags like completion can be set directly - * to vp.state.mode. + * to c->state.mode. */ -gboolean vp_set_mode(Mode mode, gboolean clean) +gboolean vp_set_mode(Client* c, Mode mode, gboolean clean) { - if ((vp.state.mode & VP_MODE_COMPLETE) + if (!c) { + return FALSE; + } + if ((c->state.mode & VP_MODE_COMPLETE) && !(mode & VP_MODE_COMPLETE) ) { - completion_clean(); + completion_clean(c); } + int clean_mode = CLEAN_MODE(c->state.mode); switch (CLEAN_MODE(mode)) { case VP_MODE_NORMAL: /* do this only if the mode is really switched */ - if (GET_CLEAN_MODE() != VP_MODE_NORMAL) { - history_rewind(); + if (clean_mode != VP_MODE_NORMAL) { + history_rewind(c); } - if (GET_CLEAN_MODE() == VP_MODE_HINTING) { + if (clean_mode == VP_MODE_HINTING) { /* if previous mode was hinting clear the hints */ - hints_clear(); - } else if (GET_CLEAN_MODE() == VP_MODE_INSERT) { + hints_clear(c); + } else if (clean_mode == VP_MODE_INSERT) { /* clean the input if current mode is insert to remove -- INPUT -- */ clean = TRUE; - } else if (GET_CLEAN_MODE() == VP_MODE_SEARCH) { + } else if (clean_mode == VP_MODE_SEARCH) { /* cleaup previous search */ - command_search(&((Arg){VP_SEARCH_OFF})); + command_search(c, &((Arg){VP_SEARCH_OFF})); } - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); break; case VP_MODE_COMMAND: case VP_MODE_HINTING: - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.inputbox)); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.inputbox)); break; case VP_MODE_INSERT: - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); - vp_echo(VP_MSG_NORMAL, FALSE, "-- INPUT --"); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); + vp_echo(c, VP_MSG_NORMAL, FALSE, "-- INPUT --"); break; case VP_MODE_PATH_THROUGH: - gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); break; } - vp.state.mode = mode; - vp.state.modkey = vp.state.count = 0; + c->state.mode = mode; + c->state.modkey = c->state.count = 0; /* echo message if given */ if (clean) { - vp_echo(VP_MSG_NORMAL, FALSE, ""); + vp_echo(c, VP_MSG_NORMAL, FALSE, ""); } - vp_update_statusbar(); + vp_update_statusbar(c); return TRUE; } @@ -288,38 +252,37 @@ gboolean vp_set_mode(Mode mode, gboolean clean) void vp_set_widget_font(GtkWidget* widget, const VpColor* fg, const VpColor* bg, PangoFontDescription* font) { VP_WIDGET_OVERRIDE_FONT(widget, font); - /* TODO are they all required? */ VP_WIDGET_OVERRIDE_TEXT(widget, GTK_STATE_NORMAL, fg); VP_WIDGET_OVERRIDE_COLOR(widget, GTK_STATE_NORMAL, fg); VP_WIDGET_OVERRIDE_BASE(widget, GTK_STATE_NORMAL, bg); VP_WIDGET_OVERRIDE_BACKGROUND(widget, GTK_STATE_NORMAL, bg); } -void vp_update_statusbar(void) +void vp_update_statusbar(Client* c) { GString* status = g_string_new(""); /* show current count */ - g_string_append_printf(status, "%.0d", vp.state.count); + g_string_append_printf(status, "%.0d", c->state.count); /* show current modkey */ - if (vp.state.modkey) { - g_string_append_c(status, vp.state.modkey); + if (c->state.modkey) { + g_string_append_c(status, c->state.modkey); } /* show the active downloads */ - if (vp.state.downloads) { - int num = g_list_length(vp.state.downloads); + if (c->state.downloads) { + int num = g_list_length(c->state.downloads); g_string_append_printf(status, " %d %s", num, num == 1 ? "download" : "downloads"); } /* show load status of page or the downloads */ - if (vp.state.progress != 100) { - g_string_append_printf(status, " [%i%%]", vp.state.progress); + if (c->state.progress != 100) { + g_string_append_printf(status, " [%i%%]", c->state.progress); } /* show the scroll status */ - int max = gtk_adjustment_get_upper(vp.gui.adjust_v) - gtk_adjustment_get_page_size(vp.gui.adjust_v); - int val = (int)(gtk_adjustment_get_value(vp.gui.adjust_v) / max * 100); + int max = gtk_adjustment_get_upper(c->gui.adjust_v) - gtk_adjustment_get_page_size(c->gui.adjust_v); + int val = (int)(gtk_adjustment_get_value(c->gui.adjust_v) / max * 100); if (max == 0) { g_string_append(status, " All"); @@ -331,61 +294,76 @@ void vp_update_statusbar(void) g_string_append_printf(status, " %d%%", val); } - gtk_label_set_text(GTK_LABEL(vp.gui.statusbar.right), status->str); + gtk_label_set_text(GTK_LABEL(c->gui.statusbar.right), status->str); g_string_free(status, TRUE); } -void vp_update_status_style(void) +void vp_update_status_style(Client* c) { - StatusType type = vp.state.status; - vp_set_widget_font(vp.gui.eventbox, &core.style.status_fg[type], &core.style.status_bg[type], core.style.status_font[type]); - vp_set_widget_font(vp.gui.statusbar.left, &core.style.status_fg[type], &core.style.status_bg[type], core.style.status_font[type]); - vp_set_widget_font(vp.gui.statusbar.right, &core.style.status_fg[type], &core.style.status_bg[type], core.style.status_font[type]); + StatusType type = c->state.status; + vp_set_widget_font( + c->gui.eventbox, &core.style.status_fg[type], &core.style.status_bg[type], core.style.status_font[type] + ); + vp_set_widget_font( + c->gui.statusbar.left, &core.style.status_fg[type], &core.style.status_bg[type], core.style.status_font[type] + ); + vp_set_widget_font( + c->gui.statusbar.right, &core.style.status_fg[type], &core.style.status_bg[type], core.style.status_font[type] + ); } -void vp_update_urlbar(const char* uri) +void vp_update_input_style(Client* c, MessageType type) { - gtk_label_set_text(GTK_LABEL(vp.gui.statusbar.left), uri); + vp_set_widget_font( + c->gui.inputbox, &core.style.input_fg[type], &core.style.input_bg[type], core.style.input_font[type] + ); } -static gboolean vp_hide_message(void) +void vp_update_urlbar(Client* c, const char* uri) { - vp_echo(VP_MSG_NORMAL, FALSE, ""); + gtk_label_set_text(GTK_LABEL(c->gui.statusbar.left), uri); +} + +static gboolean vp_hide_message(Client* c) +{ + vp_echo(c, VP_MSG_NORMAL, FALSE, ""); return FALSE; } -static void vp_webview_progress_cb(WebKitWebView* view, GParamSpec* pspec, gboolean download) +static void vp_webview_progress_cb(WebKitWebView* view, GParamSpec* pspec, Client* c) { - if (download) { - if (vp.state.downloads) { - vp.state.progress = 0; - GList* ptr; - for (ptr = vp.state.downloads; ptr; ptr = g_list_next(ptr)) { - vp.state.progress += 100 * webkit_download_get_progress(ptr->data); - } - vp.state.progress /= g_list_length(vp.state.downloads); + c->state.progress = webkit_web_view_get_progress(view) * 100; + vp_update_statusbar(c); +} + +static void vp_webview_download_progress_cb(WebKitWebView* view, GParamSpec* pspec, Client* c) +{ + if (c->state.downloads) { + c->state.progress = 0; + GList* ptr; + for (ptr = c->state.downloads; ptr; ptr = g_list_next(ptr)) { + c->state.progress += 100 * webkit_download_get_progress(ptr->data); } - } else { - vp.state.progress = webkit_web_view_get_progress(view) * 100; + c->state.progress /= g_list_length(c->state.downloads); } - vp_update_statusbar(); + vp_update_statusbar(c); } -static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gpointer user_data) +static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, Client* c) { - const char* uri = CURRENT_URL(); + const char* uri = webkit_web_view_get_uri(c->gui.webview); - switch (webkit_web_view_get_load_status(vp.gui.webview)) { + switch (webkit_web_view_get_load_status(c->gui.webview)) { case WEBKIT_LOAD_PROVISIONAL: /* update load progress in statusbar */ - vp.state.progress = 0; - vp_update_statusbar(); + c->state.progress = 0; + vp_update_statusbar(c); break; case WEBKIT_LOAD_COMMITTED: { - WebKitWebFrame* frame = webkit_web_view_get_main_frame(vp.gui.webview); + WebKitWebFrame* frame = webkit_web_view_get_main_frame(c->gui.webview); /* set the status */ if (g_str_has_prefix(uri, "https://")) { WebKitWebDataSource* src = webkit_web_frame_get_data_source(frame); @@ -393,10 +371,11 @@ static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gp SoupMessage* msg = webkit_network_request_get_message(request); SoupMessageFlags flags = soup_message_get_flags(msg); vp_set_status( + c, (flags & SOUP_MESSAGE_CERTIFICATE_TRUSTED) ? VP_STATUS_SSL_VALID : VP_STATUS_SSL_INVALID ); } else { - vp_set_status(VP_STATUS_NORMAL); + vp_set_status(c, VP_STATUS_NORMAL); } /* inject the hinting javascript */ @@ -407,8 +386,8 @@ static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gp } /* status bar is updated by vp_set_mode */ - vp_set_mode(VP_MODE_NORMAL , FALSE); - vp_update_urlbar(uri); + vp_set_mode(c, VP_MODE_NORMAL , FALSE); + vp_update_urlbar(c, uri); break; @@ -417,12 +396,12 @@ static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gp case WEBKIT_LOAD_FINISHED: /* update load progress in statusbar */ - vp.state.progress = 100; - vp_update_statusbar(); + c->state.progress = 100; + vp_update_statusbar(c); - dom_check_auto_insert(); + dom_check_auto_insert(c); - url_history_add(uri, webkit_web_view_get_title(vp.gui.webview)); + url_history_add(uri, webkit_web_view_get_title(c->gui.webview)); break; case WEBKIT_LOAD_FAILED: @@ -430,24 +409,23 @@ static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gp } } -static void vp_destroy_window_cb(GtkWidget* widget, GtkWidget* window, gpointer user_data) +static void vp_destroy_window_cb(GtkWidget* widget, Client* c) { - command_close(0); + vp_destroy_client(c); } -static void vp_inputbox_activate_cb(GtkEntry *entry, gpointer user_data) +static void vp_inputbox_activate_cb(GtkEntry *entry, Client* c) { const char* text; gboolean hist_save = FALSE; char* command = NULL; guint16 length = gtk_entry_get_text_length(entry); - Gui* gui = &vp.gui; if (0 == length) { return; } - gtk_widget_grab_focus(GTK_WIDGET(gui->webview)); + gtk_widget_grab_focus(GTK_WIDGET(c->gui.webview)); if (length <= 1) { return; @@ -467,13 +445,13 @@ static void vp_inputbox_activate_cb(GtkEntry *entry, gpointer user_data) case '?': a.i = *text == '/' ? VP_SEARCH_FORWARD : VP_SEARCH_BACKWARD; a.s = (command + 1); - command_search(&a); + command_search(c, &a); hist_save = TRUE; break; case ':': - completion_clean(); - vp_process_input((command + 1)); + completion_clean(c); + vp_process_input(c, (command + 1)); hist_save = TRUE; break; } @@ -485,17 +463,17 @@ static void vp_inputbox_activate_cb(GtkEntry *entry, gpointer user_data) g_free(command); } -static gboolean vp_inputbox_keyrelease_cb(GtkEntry* entry, GdkEventKey* event) +static gboolean vp_inputbox_keyrelease_cb(GtkEntry* entry, GdkEventKey* event, Client* c) { return FALSE; } -static void vp_scroll_cb(GtkAdjustment* adjustment, gpointer data) +static void vp_scroll_cb(GtkAdjustment* adjustment, Client* c) { - vp_update_statusbar(); + vp_update_statusbar(c); } -static void vp_new_request_cb(SoupSession* session, SoupMessage *message, gpointer data) +static void vp_new_request_cb(SoupSession* session, SoupMessage *message, Client* c) { SoupMessageHeaders* header = message->request_headers; SoupURI* uri; @@ -506,10 +484,10 @@ static void vp_new_request_cb(SoupSession* session, SoupMessage *message, gpoint if ((cookie = vp_get_cookies(uri))) { soup_message_headers_append(header, "Cookie", cookie); } - g_signal_connect_after(G_OBJECT(message), "got-headers", G_CALLBACK(vp_gotheaders_cb), NULL); + g_signal_connect_after(G_OBJECT(message), "got-headers", G_CALLBACK(vp_gotheaders_cb), c); } -static void vp_gotheaders_cb(SoupMessage* message, gpointer data) +static void vp_gotheaders_cb(SoupMessage* message, Client* c) { GSList* list = NULL; GSList* p = NULL; @@ -520,60 +498,60 @@ static void vp_gotheaders_cb(SoupMessage* message, gpointer data) soup_cookies_free(list); } -static WebKitWebView* vp_inspector_new(WebKitWebInspector* inspector, WebKitWebView* webview) +static WebKitWebView* vp_inspector_new(WebKitWebInspector* inspector, WebKitWebView* webview, Client* c) { return WEBKIT_WEB_VIEW(webkit_web_view_new()); } -static gboolean vp_inspector_show(WebKitWebInspector* inspector) +static gboolean vp_inspector_show(WebKitWebInspector* inspector, Client* c) { WebKitWebView* webview; int height; - if (vp.state.is_inspecting) { + if (c->state.is_inspecting) { return FALSE; } webview = webkit_web_inspector_get_web_view(inspector); /* use about 1/3 of window height for the inspector */ - gtk_window_get_size(GTK_WINDOW(vp.gui.window), NULL, &height); - gtk_paned_set_position(GTK_PANED(vp.gui.pane), 2 * height / 3); + gtk_window_get_size(GTK_WINDOW(c->gui.window), NULL, &height); + gtk_paned_set_position(GTK_PANED(c->gui.pane), 2 * height / 3); - gtk_paned_pack2(GTK_PANED(vp.gui.pane), GTK_WIDGET(webview), TRUE, TRUE); + gtk_paned_pack2(GTK_PANED(c->gui.pane), GTK_WIDGET(webview), TRUE, TRUE); gtk_widget_show(GTK_WIDGET(webview)); - vp.state.is_inspecting = TRUE; + c->state.is_inspecting = TRUE; return TRUE; } -static gboolean vp_inspector_close(WebKitWebInspector* inspector) +static gboolean vp_inspector_close(WebKitWebInspector* inspector, Client* c) { WebKitWebView* webview; - if (!vp.state.is_inspecting) { + if (!c->state.is_inspecting) { return FALSE; } webview = webkit_web_inspector_get_web_view(inspector); gtk_widget_hide(GTK_WIDGET(webview)); gtk_widget_destroy(GTK_WIDGET(webview)); - vp.state.is_inspecting = FALSE; + c->state.is_inspecting = FALSE; return TRUE; } -static void vp_inspector_finished(WebKitWebInspector* inspector) +static void vp_inspector_finished(WebKitWebInspector* inspector, Client* c) { - g_free(vp.gui.inspector); + g_free(c->gui.inspector); } /** * Processed input from input box without trailing : or ? /, input from config * file and default config. */ -static gboolean vp_process_input(const char* input) +static gboolean vp_process_input(Client* c, const char* input) { gboolean success; char* command = NULL; @@ -584,7 +562,11 @@ static gboolean vp_process_input(const char* input) } /* get a possible command count */ - vp.state.count = g_ascii_strtoll(input, &command, 10); + if (c) { + c->state.count = g_ascii_strtoll(input, &command, 10); + } else { + command = (char*)input; + } /* split the input string into command and parameter part */ token = g_strsplit(command, " ", 2); @@ -593,7 +575,7 @@ static gboolean vp_process_input(const char* input) g_strfreev(token); return FALSE; } - success = command_run(token[0], token[1] ? token[1] : NULL); + success = command_run(c, token[0], token[1] ? token[1] : NULL); g_strfreev(token); return success; @@ -626,12 +608,12 @@ static const char* vp_get_cookies(SoupURI *uri) } #endif -static void vp_set_status(const StatusType status) +static void vp_set_status(Client* c, const StatusType status) { - if (vp.state.status != status) { - vp.state.status = status; + if (c->state.status != status) { + c->state.status = status; /* update the statusbar style only if the status changed */ - vp_update_status_style(); + vp_update_status_style(c); } } @@ -670,16 +652,9 @@ static char* vp_jsref_to_string(JSContextRef context, JSValueRef ref) return string; } -static void vp_print_version(void) +static void vp_init_core(void) { - fprintf(stderr, "%s/%s (build %s %s)\n", "vimp", VERSION, __DATE__, __TIME__); -} - -static void vp_init(void) -{ - /* initialize the gui elements and event callbacks */ - vp_init_gui(); - + /* TODO */ /* initialize the commands hash map */ command_init(); @@ -689,29 +664,37 @@ static void vp_init(void) /* initialize the keybindings */ keybind_init(); + /* init soup session */ + core.soup_session = webkit_get_default_session(); + soup_session_remove_feature_by_type(core.soup_session, soup_cookie_jar_get_type()); + g_object_set(core.soup_session, "max-conns", SETTING_MAX_CONNS , NULL); + g_object_set(core.soup_session, "max-conns-per-host", SETTING_MAX_CONNS_PER_HOST, NULL); + /* initialize settings */ setting_init(); /* read additional configuration from config files */ - vp_read_config(); - - /* set the configuration to the required objects */ - vp_setup_settings(); + vp_read_global_config(); url_history_init(); } -static void vp_read_config(void) +static void vp_read_global_config(void) { /* load default config */ for (guint i = 0; default_config[i].command != NULL; i++) { - if (!vp_process_input(default_config[i].command)) { + if (!vp_process_input(NULL, default_config[i].command)) { fprintf(stderr, "Invalid default config: %s\n", default_config[i].command); } } + vp_process_config_file(NULL, FILES_GLOBAL_CONFIG); +} + +static void vp_process_config_file(Client* c, VpFile file) +{ /* read config from config files */ - char **lines = util_get_lines(core.files[FILES_CONFIG]); + char **lines = util_get_lines(core.files[file]); char *line; if (lines) { @@ -723,7 +706,7 @@ static void vp_read_config(void) if (!g_ascii_isalpha(line[0])) { continue; } - if (!vp_process_input(line)) { + if (!vp_process_input(c, line)) { fprintf(stderr, "Invalid config: %s\n", line); } } @@ -731,12 +714,13 @@ static void vp_read_config(void) } } -static void vp_init_gui(void) +static Client* vp_client_new(void) { - Gui* gui = &vp.gui; + Client* c = g_new0(Client, 1); + Gui* gui = &c->gui; - if (vp.state.embed) { - gui->window = gtk_plug_new(vp.state.embed); + if (core.embed) { + gui->window = gtk_plug_new(core.embed); } else { gui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_wmclass(GTK_WINDOW(gui->window), "vimp", "Vimp"); @@ -754,10 +738,6 @@ static void vp_init_gui(void) gui->webview = WEBKIT_WEB_VIEW(webkit_web_view_new()); gui->inspector = webkit_web_view_get_inspector(gui->webview); - /* init soup session */ - core.soup_session = webkit_get_default_session(); - soup_session_remove_feature_by_type(core.soup_session, soup_cookie_jar_get_type()); - /* Create a scrollable area */ gui->scroll = gtk_scrolled_window_new(NULL, NULL); gui->adjust_h = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(gui->scroll)); @@ -785,7 +765,7 @@ static void vp_init_gui(void) gtk_paned_pack1(GTK_PANED(gui->pane), GTK_WIDGET(gui->box), TRUE, TRUE); - vp_setup_signals(); + vp_setup_signals(c); /* Put all part together */ gtk_container_add(GTK_CONTAINER(gui->scroll), GTK_WIDGET(gui->webview)); @@ -807,92 +787,102 @@ static void vp_init_gui(void) /* Make sure the main window and all its contents are visible */ gtk_widget_show_all(gui->window); -} - -static void vp_init_files(void) -{ - char* path = util_get_config_dir(); - - core.files[FILES_CONFIG] = g_build_filename(path, "config", NULL); - util_create_file_if_not_exists(core.files[FILES_CONFIG]); - core.files[FILES_COOKIE] = g_build_filename(path, "cookies", NULL); - util_create_file_if_not_exists(core.files[FILES_COOKIE]); + keybind_init_client(c); + setting_init_client(c); - core.files[FILES_CLOSED] = g_build_filename(path, "closed", NULL); - util_create_file_if_not_exists(core.files[FILES_CLOSED]); + vp_process_config_file(c, FILES_LOCAL_CONFIG); - core.files[FILES_SCRIPT] = g_build_filename(path, "scripts.js", NULL); + /* apply global settings to the status bar and input box */ + vp_update_status_style(c); + vp_update_input_style(c, VP_MSG_NORMAL); - core.files[FILES_HISTORY] = g_build_filename(path, "history", NULL); - util_create_file_if_not_exists(core.files[FILES_HISTORY]); + c->next = clients; + clients = c; - core.files[FILES_USER_STYLE] = g_build_filename(path, "style.css", NULL); - util_create_file_if_not_exists(core.files[FILES_USER_STYLE]); - - g_free(path); + return c; } -static void vp_setup_signals(void) +static void vp_setup_signals(Client* c) { - Gui* gui = &vp.gui; - /* Set up callbacks so that if either the main window or the browser * instance is closed, the program will exit */ - g_signal_connect(gui->window, "destroy", G_CALLBACK(vp_destroy_window_cb), NULL); + g_signal_connect(c->gui.window, "destroy", G_CALLBACK(vp_destroy_window_cb), c); g_object_connect( - G_OBJECT(gui->webview), - "signal::notify::progress", G_CALLBACK(vp_webview_progress_cb), (gpointer)FALSE, - "signal::notify::load-status", G_CALLBACK(vp_webview_load_status_cb), NULL, - "signal::button-release-event", G_CALLBACK(vp_button_relase_cb), NULL, - "signal::new-window-policy-decision-requested", G_CALLBACK(vp_new_window_policy_cb), NULL, - "signal::create-web-view", G_CALLBACK(vp_create_new_webview_cb), NULL, - "signal::hovering-over-link", G_CALLBACK(vp_hover_link_cb), NULL, - "signal::title-changed", G_CALLBACK(vp_title_changed_cb), NULL, - "signal::mime-type-policy-decision-requested", G_CALLBACK(vp_mimetype_decision_cb), NULL, - "signal::download-requested", G_CALLBACK(vp_download_requested_cb), NULL, - "signal::resource-request-starting", G_CALLBACK(vp_request_start_cb), NULL, + G_OBJECT(c->gui.webview), + "signal::notify::progress", G_CALLBACK(vp_webview_progress_cb), c, + "signal::notify::load-status", G_CALLBACK(vp_webview_load_status_cb), c, + "signal::button-release-event", G_CALLBACK(vp_button_relase_cb), c, + "signal::new-window-policy-decision-requested", G_CALLBACK(vp_new_window_policy_cb), c, + "signal::create-web-view", G_CALLBACK(vp_create_new_webview_cb), c, + "signal::hovering-over-link", G_CALLBACK(vp_hover_link_cb), c, + "signal::title-changed", G_CALLBACK(vp_title_changed_cb), c, + "signal::mime-type-policy-decision-requested", G_CALLBACK(vp_mimetype_decision_cb), c, + "signal::download-requested", G_CALLBACK(vp_download_requested_cb), c, + "signal::resource-request-starting", G_CALLBACK(vp_request_start_cb), c, NULL ); g_object_connect( - G_OBJECT(gui->inputbox), - "signal::activate", G_CALLBACK(vp_inputbox_activate_cb), NULL, - "signal::key-release-event", G_CALLBACK(vp_inputbox_keyrelease_cb), NULL, + G_OBJECT(c->gui.inputbox), + "signal::activate", G_CALLBACK(vp_inputbox_activate_cb), c, + "signal::key-release-event", G_CALLBACK(vp_inputbox_keyrelease_cb), c, NULL ); /* webview adjustment */ - g_object_connect(G_OBJECT(vp.gui.adjust_v), - "signal::value-changed", G_CALLBACK(vp_scroll_cb), NULL, + g_object_connect(G_OBJECT(c->gui.adjust_v), + "signal::value-changed", G_CALLBACK(vp_scroll_cb), c, NULL ); - g_signal_connect_after(G_OBJECT(core.soup_session), "request-started", G_CALLBACK(vp_new_request_cb), NULL); + g_signal_connect_after(G_OBJECT(core.soup_session), "request-started", G_CALLBACK(vp_new_request_cb), c); /* inspector */ - g_signal_connect(G_OBJECT(vp.gui.inspector), "inspect-web-view", G_CALLBACK(vp_inspector_new), NULL); - g_signal_connect(G_OBJECT(vp.gui.inspector), "show-window", G_CALLBACK(vp_inspector_show), NULL); - g_signal_connect(G_OBJECT(vp.gui.inspector), "close-window", G_CALLBACK(vp_inspector_close), NULL); - g_signal_connect(G_OBJECT(vp.gui.inspector), "finished", G_CALLBACK(vp_inspector_finished), NULL); + /* TODO use g_object_connect instead */ + g_signal_connect(G_OBJECT(c->gui.inspector), "inspect-web-view", G_CALLBACK(vp_inspector_new), c); + g_signal_connect(G_OBJECT(c->gui.inspector), "show-window", G_CALLBACK(vp_inspector_show), c); + g_signal_connect(G_OBJECT(c->gui.inspector), "close-window", G_CALLBACK(vp_inspector_close), c); + g_signal_connect(G_OBJECT(c->gui.inspector), "finished", G_CALLBACK(vp_inspector_finished), c); } -static void vp_setup_settings(void) +static void vp_init_files(void) { - g_object_set(core.soup_session, "max-conns", SETTING_MAX_CONNS , NULL); - g_object_set(core.soup_session, "max-conns-per-host", SETTING_MAX_CONNS_PER_HOST, NULL); + char* path = util_get_config_dir(); + + core.files[FILES_GLOBAL_CONFIG] = g_build_filename(path, "global", NULL); + util_create_file_if_not_exists(core.files[FILES_GLOBAL_CONFIG]); + + core.files[FILES_LOCAL_CONFIG] = g_build_filename(path, "local", NULL); + util_create_file_if_not_exists(core.files[FILES_LOCAL_CONFIG]); + + core.files[FILES_COOKIE] = g_build_filename(path, "cookies", NULL); + util_create_file_if_not_exists(core.files[FILES_COOKIE]); + + core.files[FILES_CLOSED] = g_build_filename(path, "closed", NULL); + util_create_file_if_not_exists(core.files[FILES_CLOSED]); + + core.files[FILES_SCRIPT] = g_build_filename(path, "scripts.js", NULL); + + core.files[FILES_HISTORY] = g_build_filename(path, "history", NULL); + util_create_file_if_not_exists(core.files[FILES_HISTORY]); + + core.files[FILES_USER_STYLE] = g_build_filename(path, "style.css", NULL); + util_create_file_if_not_exists(core.files[FILES_USER_STYLE]); + + g_free(path); } -static gboolean vp_button_relase_cb(WebKitWebView* webview, GdkEventButton* event, gpointer data) +static gboolean vp_button_relase_cb(WebKitWebView* webview, GdkEventButton* event, Client* c) { gboolean propagate = FALSE; WebKitHitTestResultContext context; - Mode mode = GET_CLEAN_MODE(); + Mode mode = CLEAN_MODE(c->state.mode); WebKitHitTestResult *result = webkit_web_view_get_hit_test_result(webview, event); g_object_get(result, "context", &context, NULL); if (mode == VP_MODE_NORMAL && context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) { - vp_set_mode(VP_MODE_INSERT, FALSE); + vp_set_mode(c, VP_MODE_INSERT, FALSE); propagate = TRUE; } @@ -900,7 +890,7 @@ static gboolean vp_button_relase_cb(WebKitWebView* webview, GdkEventButton* even if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK && event->button == 2) { Arg a = {VP_TARGET_NEW}; g_object_get(result, "link-uri", &a.s, NULL); - vp_load_uri(&a); + vp_load_uri(c, &a); propagate = TRUE; } @@ -911,57 +901,43 @@ static gboolean vp_button_relase_cb(WebKitWebView* webview, GdkEventButton* even static gboolean vp_new_window_policy_cb( WebKitWebView* view, WebKitWebFrame* frame, WebKitNetworkRequest* request, - WebKitWebNavigationAction* navig, WebKitWebPolicyDecision* policy, gpointer data) + WebKitWebNavigationAction* navig, WebKitWebPolicyDecision* policy, Client* c) { if (webkit_web_navigation_action_get_reason(navig) == WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED) { /* open in a new window */ Arg a = {VP_TARGET_NEW, (char*)webkit_network_request_get_uri(request)}; - vp_load_uri(&a); + vp_load_uri(c, &a); webkit_web_policy_decision_ignore(policy); return TRUE; } return FALSE; } -static WebKitWebView* vp_create_new_webview_cb(WebKitWebView* webview, WebKitWebFrame* frame, gpointer data) +static WebKitWebView* vp_create_new_webview_cb(WebKitWebView* webview, WebKitWebFrame* frame, Client* c) { - /* create only a temporary webview */ - WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new()); - - /* wait until the new webview receives its new URI */ - g_object_connect(view, "signal::notify::uri", G_CALLBACK(vp_create_new_webview_uri_cb), NULL, NULL); - return view; + Client* new = vp_client_new(); + return new->gui.webview; } -static void vp_create_new_webview_uri_cb(WebKitWebView* view, GParamSpec param_spec) -{ - Arg a = {VP_TARGET_NEW, (char*)webkit_web_view_get_uri(view)}; - /* clean up */ - webkit_web_view_stop_loading(view); - gtk_widget_destroy(GTK_WIDGET(view)); - /* open the requested window */ - vp_load_uri(&a); -} - -static void vp_hover_link_cb(WebKitWebView* webview, const char* title, const char* link, gpointer data) +static void vp_hover_link_cb(WebKitWebView* webview, const char* title, const char* link, Client* c) { if (link) { char* message = g_strdup_printf("Link: %s", link); - gtk_label_set_text(GTK_LABEL(vp.gui.statusbar.left), message); + gtk_label_set_text(GTK_LABEL(c->gui.statusbar.left), message); g_free(message); } else { - vp_update_urlbar(webkit_web_view_get_uri(webview)); + vp_update_urlbar(c, webkit_web_view_get_uri(webview)); } } -static void vp_title_changed_cb(WebKitWebView* webview, WebKitWebFrame* frame, const char* title, gpointer data) +static void vp_title_changed_cb(WebKitWebView* webview, WebKitWebFrame* frame, const char* title, Client* c) { - gtk_window_set_title(GTK_WINDOW(vp.gui.window), title); + gtk_window_set_title(GTK_WINDOW(c->gui.window), title); } static gboolean vp_mimetype_decision_cb(WebKitWebView* webview, WebKitWebFrame* frame, WebKitNetworkRequest* request, char* - mime_type, WebKitWebPolicyDecision* decision, gpointer data) + mime_type, WebKitWebPolicyDecision* decision, Client* c) { if (webkit_web_view_can_show_mime_type(webview, mime_type) == FALSE) { webkit_web_policy_decision_download(decision); @@ -971,7 +947,7 @@ static gboolean vp_mimetype_decision_cb(WebKitWebView* webview, return FALSE; } -static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* download, gpointer data) +static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* download, Client* c) { WebKitDownloadStatus status; char* uri = NULL; @@ -988,9 +964,9 @@ static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* do guint64 size = webkit_download_get_total_size(download); if (size > 0) { - vp_echo(VP_MSG_NORMAL, FALSE, "Download %s [~%uB] started ...", filename, size); + vp_echo(c, VP_MSG_NORMAL, FALSE, "Download %s [~%uB] started ...", filename, size); } else { - vp_echo(VP_MSG_NORMAL, FALSE, "Download %s started ...", filename); + vp_echo(c, VP_MSG_NORMAL, FALSE, "Download %s started ...", filename); } status = webkit_download_get_status(download); @@ -999,13 +975,13 @@ static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* do } /* prepend the download to the download list */ - vp.state.downloads = g_list_prepend(vp.state.downloads, download); + c->state.downloads = g_list_prepend(c->state.downloads, download); /* connect signal handler to check if the download is done */ - g_signal_connect(download, "notify::status", G_CALLBACK(vp_download_progress_cp), NULL); - g_signal_connect(download, "notify::progress", G_CALLBACK(vp_webview_progress_cb), (gpointer)TRUE); + g_signal_connect(download, "notify::status", G_CALLBACK(vp_download_progress_cp), c); + g_signal_connect(download, "notify::progress", G_CALLBACK(vp_webview_download_progress_cb), c); - vp_update_statusbar(); + vp_update_statusbar(c); return TRUE; } @@ -1015,7 +991,7 @@ static gboolean vp_download_requested_cb(WebKitWebView* view, WebKitDownload* do */ static void vp_request_start_cb(WebKitWebView* webview, WebKitWebFrame* frame, WebKitWebResource* resource, WebKitNetworkRequest* request, - WebKitNetworkResponse* response, gpointer data) + WebKitNetworkResponse* response, Client* c) { const char* uri = webkit_network_request_get_uri(request); if (g_str_has_suffix(uri, "/favicon.ico")) { @@ -1023,7 +999,7 @@ static void vp_request_start_cb(WebKitWebView* webview, WebKitWebFrame* frame, } } -static void vp_download_progress_cp(WebKitDownload* download, GParamSpec* pspec) +static void vp_download_progress_cp(WebKitDownload* download, GParamSpec* pspec, Client* c) { WebKitDownloadStatus status = webkit_download_get_status(download); @@ -1033,16 +1009,61 @@ static void vp_download_progress_cp(WebKitDownload* download, GParamSpec* pspec) char* file = g_path_get_basename(webkit_download_get_destination_uri(download)); if (status != WEBKIT_DOWNLOAD_STATUS_FINISHED) { - vp_echo(VP_MSG_ERROR, FALSE, "Error downloading %s", file); + vp_echo(c, VP_MSG_ERROR, FALSE, "Error downloading %s", file); } else { - vp_echo(VP_MSG_NORMAL, FALSE, "Download %s finished", file); + vp_echo(c, VP_MSG_NORMAL, FALSE, "Download %s finished", file); } g_free(file); /* remove the donwload from the list */ - vp.state.downloads = g_list_remove(vp.state.downloads, download); + c->state.downloads = g_list_remove(c->state.downloads, download); - vp_update_statusbar(); + vp_update_statusbar(c); +} + +static void vp_destroy_client(Client* c) +{ + const char* uri = webkit_web_view_get_uri(c->gui.webview); + /* write last URL into file for recreation */ + if (uri) { + g_file_set_contents(core.files[FILES_CLOSED], uri, -1, NULL); + } + + Client* p; + + completion_clean(c); + + webkit_web_view_stop_loading(c->gui.webview); + gtk_widget_destroy(GTK_WIDGET(c->gui.webview)); + gtk_widget_destroy(GTK_WIDGET(c->gui.window)); + + for(p = clients; p && p->next != c; p = p->next); + if (p) { + p->next = c->next; + } else { + clients = c->next; + } + g_free(c); + if (clients == NULL) { + gtk_main_quit(); + } +} + +static void vp_clean_up(void) +{ + while (clients) { + vp_destroy_client(clients); + } + + command_cleanup(); + setting_cleanup(); + keybind_cleanup(); + searchengine_cleanup(); + url_history_cleanup(); + + for (int i = 0; i < FILES_LAST; i++) { + g_free(core.files[i]); + } } int main(int argc, char* argv[]) @@ -1064,7 +1085,7 @@ int main(int argc, char* argv[]) } if (ver) { - vp_print_version(); + fprintf(stderr, "%s/%s (build %s %s)\n", PROJECT, VERSION, __DATE__, __TIME__); return EXIT_SUCCESS; } @@ -1072,10 +1093,12 @@ int main(int argc, char* argv[]) args = argv; if (winid) { - vp.state.embed = strtol(winid, NULL, 0); + core.embed = strtol(winid, NULL, 0); } - vp_init(); + vp_init_core(); + + vp_client_new(); /* command line argument: URL */ Arg arg = {VP_TARGET_CURRENT}; @@ -1084,11 +1107,12 @@ int main(int argc, char* argv[]) } else { arg.s = g_strdup(core.config.home_page); } - vp_load_uri(&arg); + vp_load_uri(clients, &arg); g_free(arg.s); /* Run the main GTK+ event loop */ gtk_main(); + vp_clean_up(); return EXIT_SUCCESS; } diff --git a/src/main.h b/src/main.h index c7f59a4..bca66d4 100644 --- a/src/main.h +++ b/src/main.h @@ -53,9 +53,7 @@ #define GET_TEXT() (gtk_entry_get_text(GTK_ENTRY(vp.gui.inputbox))) #define CLEAN_MODE(mode) ((mode) & ~(VP_MODE_COMPLETE)) -#define GET_CLEAN_MODE() (CLEAN_MODE(vp.state.mode)) #define CLEAR_INPUT() (vp_echo(VP_MSG_NORMAL, "")) -#define CURRENT_URL() webkit_web_view_get_uri(vp.gui.webview) #define PRIMARY_CLIPBOARD() gtk_clipboard_get(GDK_SELECTION_PRIMARY) #define SECONDARY_CLIPBOARD() gtk_clipboard_get(GDK_NONE) @@ -178,15 +176,16 @@ typedef enum { VP_COMP_LAST } CompletionStyle; -enum { - FILES_CONFIG, +typedef enum { + FILES_GLOBAL_CONFIG, + FILES_LOCAL_CONFIG, FILES_COOKIE, FILES_CLOSED, FILES_SCRIPT, FILES_HISTORY, FILES_USER_STYLE, FILES_LAST -}; +} VpFile; typedef enum { TYPE_CHAR, @@ -238,11 +237,6 @@ typedef struct { Mode mode; char modkey; guint count; -#ifdef HAS_GTK3 - Window embed; -#else - GdkNativeWindow embed; -#endif guint progress; StatusType status; gboolean is_inspecting; @@ -306,40 +300,47 @@ typedef struct { gulong num; guint mode; guint prefixLength; + gulong change_handler; + gulong keypress_handler; } Hints; /* core struct */ -typedef struct { - Gui gui; - State state; - Completions comps; - Hints hints; -} VpClient; +typedef struct Client { + Gui gui; + State state; + Completions comps; + Hints hints; + struct Client* next; +} Client; typedef struct { - char* files[FILES_LAST]; - Config config; - Style style; - Behaviour behave; - GHashTable* settings; - SoupSession* soup_session; + char* files[FILES_LAST]; + Config config; + Style style; + Behaviour behave; + GHashTable* settings; + SoupSession* soup_session; +#ifdef HAS_GTK3 + Window embed; +#else + GdkNativeWindow embed; +#endif } VpCore; /* main object */ -extern VpClient vp; -extern VpCore core; +extern VpCore core; /* functions */ -void vp_clean_input(void); -void vp_clean_up(void); -void vp_echo(const MessageType type, gboolean hide, const char *error, ...); +void vp_clean_input(Client* c); +void vp_echo(Client* c, const MessageType type, gboolean hide, const char *error, ...); void vp_eval_script(WebKitWebFrame* frame, char* script, char* file, char** value, char** error); -gboolean vp_load_uri(const Arg* arg); +gboolean vp_load_uri(Client* c, const Arg* arg); gboolean vp_set_clipboard(const Arg* arg); -gboolean vp_set_mode(Mode mode, gboolean clean); +gboolean vp_set_mode(Client* c, Mode mode, gboolean clean); void vp_set_widget_font(GtkWidget* widget, const VpColor* fg, const VpColor* bg, PangoFontDescription* font); -void vp_update_statusbar(void); -void vp_update_status_style(void); -void vp_update_urlbar(const char* uri); +void vp_update_statusbar(Client* c); +void vp_update_status_style(Client* c); +void vp_update_input_style(Client* c, MessageType type); +void vp_update_urlbar(Client* c, const char* uri); #endif /* end of include guard: _MAIN_H */ diff --git a/src/setting.c b/src/setting.c index 1185fb8..dd03126 100644 --- a/src/setting.c +++ b/src/setting.c @@ -21,106 +21,110 @@ #include "util.h" static Arg* setting_char_to_arg(const char* str, const Type type); -static void setting_print_value(const Setting* s, void* value); -static gboolean setting_webkit(const Setting* s, const SettingType type); -static gboolean setting_cookie_timeout(const Setting* s, const SettingType type); -static gboolean setting_scrollstep(const Setting* s, const SettingType type); -static gboolean setting_status_color_bg(const Setting* s, const SettingType type); -static gboolean setting_status_color_fg(const Setting* s, const SettingType type); -static gboolean setting_status_font(const Setting* s, const SettingType type); -static gboolean setting_input_style(const Setting* s, const SettingType type); -static gboolean setting_completion_style(const Setting* s, const SettingType type); -static gboolean setting_hint_style(const Setting* s, const SettingType type); -static gboolean setting_strict_ssl(const Setting* s, const SettingType type); -static gboolean setting_ca_bundle(const Setting* s, const SettingType type); -static gboolean setting_home_page(const Setting* s, const SettingType type); -static gboolean setting_download_path(const Setting* s, const SettingType type); -static gboolean setting_proxy(const Setting* s, const SettingType type); -static gboolean setting_user_style(const Setting* s, const SettingType type); -static gboolean setting_history_max_items(const Setting* s, const SettingType type); +static void setting_print_value(Client* c, const Setting* s, void* value); +static gboolean setting_webkit(Client* c, const Setting* s, const SettingType type); +static gboolean setting_cookie_timeout(Client* c, const Setting* s, const SettingType type); +static gboolean setting_scrollstep(Client* c, const Setting* s, const SettingType type); +static gboolean setting_status_color_bg(Client* c, const Setting* s, const SettingType type); +static gboolean setting_status_color_fg(Client* c, const Setting* s, const SettingType type); +static gboolean setting_status_font(Client* c, const Setting* s, const SettingType type); +static gboolean setting_input_style(Client* c, const Setting* s, const SettingType type); +static gboolean setting_completion_style(Client* c, const Setting* s, const SettingType type); +static gboolean setting_hint_style(Client* c, const Setting* s, const SettingType type); +static gboolean setting_strict_ssl(Client* c, const Setting* s, const SettingType type); +static gboolean setting_ca_bundle(Client* c, const Setting* s, const SettingType type); +static gboolean setting_home_page(Client* c, const Setting* s, const SettingType type); +static gboolean setting_download_path(Client* c, const Setting* s, const SettingType type); +static gboolean setting_proxy(Client* c, const Setting* s, const SettingType type); +static gboolean setting_user_style(Client* c, const Setting* s, const SettingType type); +static gboolean setting_history_max_items(Client* c, const Setting* s, const SettingType type); static Setting default_settings[] = { /* webkit settings */ - {"images", "auto-load-images", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"shrinkimages", "auto-shrink-images", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"cursivfont", "cursive-font-family", TYPE_CHAR, setting_webkit, {.s = "serif"}}, - {"defaultencondig", "default-encoding", TYPE_CHAR, setting_webkit, {.s = "utf-8"}}, - {"defaultfont", "default-font-family", TYPE_CHAR, setting_webkit, {.s = "sans-serif"}}, - {"fontsize", "default-font-size", TYPE_INTEGER, setting_webkit, {.i = 11}}, - {"monofontsize", "default-monospace-font-size", TYPE_INTEGER, setting_webkit, {.i = 11}}, - {"caret", "enable-caret-browsing", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"webinspector", "enable-developer-extras", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"dnsprefetching", "enable-dns-prefetching", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"dompaste", "enable-dom-paste", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"frameflattening", "enable-frame-flattening", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {NULL, "enable-file-access-from-file-uris", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {NULL, "enable-html5-database", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {NULL, "enable-html5-local-storage", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"javaapplet", "enable-java-applet", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"offlinecache", "enable-offline-web-application-cache", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"pagecache", "enable-page-cache", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"plugins", "enable-plugins", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"scripts", "enable-scripts", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {NULL, "enable-site-specific-quirks", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {NULL, "enable-spatial-navigation", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"spell", "enable-spell-checking", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {NULL, "enable-universal-access-from-file-uris", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {NULL, "enable-webgl", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"xssauditor", "enable-xss-auditor", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {NULL, "enforce-96-dpi", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"fantasyfont", "fantasy-font-family", TYPE_CHAR, setting_webkit, {.s = "serif"}}, - {NULL, "javascript-can-access-clipboard", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {NULL, "javascript-can-open-windows-automatically", TYPE_BOOLEAN, setting_webkit, {.i = 0}}, - {"minimumfontsize", "minimum-font-size", TYPE_INTEGER, setting_webkit, {.i = 5}}, - {NULL, "minimum-logical-font-size", TYPE_INTEGER, setting_webkit, {.i = 5}}, - {"monofont", "monospace-font-family", TYPE_CHAR, setting_webkit, {.s = "monospace"}}, - {"backgrounds", "print-backgrounds", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"resizetextareas", "resizable-text-areas", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"sansfont", "sans-serif-font-family", TYPE_CHAR, setting_webkit, {.s = "sans-serif"}}, - {"seriffont", "serif-font-family", TYPE_CHAR, setting_webkit, {.s = "serif"}}, - {"spelllang", "spell-checking-languages", TYPE_CHAR, setting_webkit, {.s = NULL}}, - {NULL, "tab-key-cycles-through-elements", TYPE_BOOLEAN, setting_webkit, {.i = 1}}, - {"useragent", "user-agent", TYPE_CHAR, setting_webkit, {.s = "vimp/" VERSION " (X11; Linux i686) AppleWebKit/535.22+ Compatible (Safari)"}}, - {"zoomstep", "zoom-step", TYPE_FLOAT, setting_webkit, {.i = 100000}}, + /* alias, name, type, func, arg, global */ + {"images", "auto-load-images", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"shrinkimages", "auto-shrink-images", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"cursivfont", "cursive-font-family", TYPE_CHAR, setting_webkit, {.s = "serif"}, FALSE}, + {"defaultencondig", "default-encoding", TYPE_CHAR, setting_webkit, {.s = "utf-8"}, FALSE}, + {"defaultfont", "default-font-family", TYPE_CHAR, setting_webkit, {.s = "sans-serif"}, FALSE}, + {"fontsize", "default-font-size", TYPE_INTEGER, setting_webkit, {.i = 11}, FALSE}, + {"monofontsize", "default-monospace-font-size", TYPE_INTEGER, setting_webkit, {.i = 11}, FALSE}, + {"caret", "enable-caret-browsing", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"webinspector", "enable-developer-extras", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"dnsprefetching", "enable-dns-prefetching", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"dompaste", "enable-dom-paste", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"frameflattening", "enable-frame-flattening", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {NULL, "enable-file-access-from-file-uris", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {NULL, "enable-html5-database", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {NULL, "enable-html5-local-storage", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"javaapplet", "enable-java-applet", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"offlinecache", "enable-offline-web-application-cache", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"pagecache", "enable-page-cache", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"plugins", "enable-plugins", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"scripts", "enable-scripts", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {NULL, "enable-site-specific-quirks", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {NULL, "enable-spatial-navigation", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"spell", "enable-spell-checking", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {NULL, "enable-universal-access-from-file-uris", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {NULL, "enable-webgl", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"xssauditor", "enable-xss-auditor", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {NULL, "enforce-96-dpi", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"fantasyfont", "fantasy-font-family", TYPE_CHAR, setting_webkit, {.s = "serif"}, FALSE}, + {NULL, "javascript-can-access-clipboard", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {NULL, "javascript-can-open-windows-automatically", TYPE_BOOLEAN, setting_webkit, {.i = 0}, FALSE}, + {"minimumfontsize", "minimum-font-size", TYPE_INTEGER, setting_webkit, {.i = 5}, FALSE}, + {NULL, "minimum-logical-font-size", TYPE_INTEGER, setting_webkit, {.i = 5}, FALSE}, + {"monofont", "monospace-font-family", TYPE_CHAR, setting_webkit, {.s = "monospace"}, FALSE}, + {"backgrounds", "print-backgrounds", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"resizetextareas", "resizable-text-areas", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"sansfont", "sans-serif-font-family", TYPE_CHAR, setting_webkit, {.s = "sans-serif"}, FALSE}, + {"seriffont", "serif-font-family", TYPE_CHAR, setting_webkit, {.s = "serif"}, FALSE}, + {"spelllang", "spell-checking-languages", TYPE_CHAR, setting_webkit, {.s = NULL}, FALSE}, + {NULL, "tab-key-cycles-through-elements", TYPE_BOOLEAN, setting_webkit, {.i = 1}, FALSE}, + {"useragent", "user-agent", TYPE_CHAR, setting_webkit, {.s = "vimp/" VERSION " (X11; Linux i686) AppleWebKit/535.22+ Compatible (Safari)"}, FALSE}, + {"zoomstep", "zoom-step", TYPE_FLOAT, setting_webkit, {.i = 100000}, FALSE}, + /* internal variables */ - {NULL, "proxy", TYPE_BOOLEAN, setting_proxy, {.i = 1}}, - {NULL, "cookie-timeout", TYPE_INTEGER, setting_cookie_timeout, {.i = 4800}}, - {NULL, "scrollstep", TYPE_INTEGER, setting_scrollstep, {.i = 40}}, - - {NULL, "status-color-bg", TYPE_CHAR, setting_status_color_bg, {.s = "#000"}}, - {NULL, "status-color-fg", TYPE_CHAR, setting_status_color_fg, {.s = "#fff"}}, - {NULL, "status-font", TYPE_FONT, setting_status_font, {.s = "monospace bold 8"}}, - {NULL, "status-ssl-color-bg", TYPE_CHAR, setting_status_color_bg, {.s = "#95e454"}}, - {NULL, "status-ssl-color-fg", TYPE_CHAR, setting_status_color_fg, {.s = "#000"}}, - {NULL, "status-ssl-font", TYPE_FONT, setting_status_font, {.s = "monospace bold 8"}}, - {NULL, "status-sslinvalid-color-bg", TYPE_CHAR, setting_status_color_bg, {.s = "#f08080"}}, - {NULL, "status-sslinvalid-color-fg", TYPE_CHAR, setting_status_color_fg, {.s = "#000"}}, - {NULL, "status-sslinvalid-font", TYPE_FONT, setting_status_font, {.s = "monospace bold 8"}}, - - {NULL, "input-bg-normal", TYPE_COLOR, setting_input_style, {.s = "#fff"}}, - {NULL, "input-bg-error", TYPE_COLOR, setting_input_style, {.s = "#f00"}}, - {NULL, "input-fg-normal", TYPE_COLOR, setting_input_style, {.s = "#000"}}, - {NULL, "input-fg-error", TYPE_COLOR, setting_input_style, {.s = "#000"}}, - {NULL, "input-font-normal", TYPE_FONT, setting_input_style, {.s = "monospace normal 8"}}, - {NULL, "input-font-error", TYPE_FONT, setting_input_style, {.s = "monospace bold 8"}}, - {NULL, "completion-font", TYPE_FONT, setting_completion_style, {.s = "monospace normal 8"}}, - {NULL, "completion-fg-normal", TYPE_COLOR, setting_completion_style, {.s = "#f6f3e8"}}, - {NULL, "completion-fg-active", TYPE_COLOR, setting_completion_style, {.s = "#fff"}}, - {NULL, "completion-bg-normal", TYPE_COLOR, setting_completion_style, {.s = "#656565"}}, - {NULL, "completion-bg-active", TYPE_COLOR, setting_completion_style, {.s = "#777777"}}, - {NULL, "max-completion-items", TYPE_INTEGER, setting_completion_style, {.i = 15}}, - {NULL, "hint-bg", TYPE_CHAR, setting_hint_style, {.s = "#ff0"}}, - {NULL, "hint-bg-focus", TYPE_CHAR, setting_hint_style, {.s = "#8f0"}}, - {NULL, "hint-fg", TYPE_CHAR, setting_hint_style, {.s = "#000"}}, - {NULL, "hint-style", TYPE_CHAR, setting_hint_style, {.s = "position:absolute;z-index:100000;font-family:monospace;font-weight:bold;font-size:10px;color:#000;background-color:#fff;margin:0;padding:0px 1px;border:1px solid #444;opacity:0.7;"}}, - {NULL, "strict-ssl", TYPE_BOOLEAN, setting_strict_ssl, {.i = 1}}, - {NULL, "ca-bundle", TYPE_CHAR, setting_ca_bundle, {.s = "/etc/ssl/certs/ca-certificates.crt"}}, - {NULL, "home-page", TYPE_CHAR, setting_home_page, {.s = "https://github.com/fanglingsu/vimp"}}, - {NULL, "download-path", TYPE_CHAR, setting_download_path, {.s = "/tmp/vimp"}}, - {NULL, "stylesheet", TYPE_BOOLEAN, setting_user_style, {.i = 1}}, - {NULL, "history-max-items", TYPE_INTEGER, setting_history_max_items, {.i = 500}}, + {NULL, "stylesheet", TYPE_BOOLEAN, setting_user_style, {.i = 1}, FALSE}, + + /* TODO make soup setting local */ + {NULL, "proxy", TYPE_BOOLEAN, setting_proxy, {.i = 1}, TRUE}, + {NULL, "cookie-timeout", TYPE_INTEGER, setting_cookie_timeout, {.i = 4800}, TRUE}, + {NULL, "strict-ssl", TYPE_BOOLEAN, setting_strict_ssl, {.i = 1}, TRUE}, + + {NULL, "scrollstep", TYPE_INTEGER, setting_scrollstep, {.i = 40}, TRUE}, + {NULL, "status-color-bg", TYPE_COLOR, setting_status_color_bg, {.s = "#000"}, TRUE}, + {NULL, "status-color-fg", TYPE_COLOR, setting_status_color_fg, {.s = "#fff"}, TRUE}, + {NULL, "status-font", TYPE_FONT, setting_status_font, {.s = "monospace bold 8"}, TRUE}, + {NULL, "status-ssl-color-bg", TYPE_COLOR, setting_status_color_bg, {.s = "#95e454"}, TRUE}, + {NULL, "status-ssl-color-fg", TYPE_COLOR, setting_status_color_fg, {.s = "#000"}, TRUE}, + {NULL, "status-ssl-font", TYPE_FONT, setting_status_font, {.s = "monospace bold 8"}, TRUE}, + {NULL, "status-sslinvalid-color-bg", TYPE_COLOR, setting_status_color_bg, {.s = "#f08080"}, TRUE}, + {NULL, "status-sslinvalid-color-fg", TYPE_COLOR, setting_status_color_fg, {.s = "#000"}, TRUE}, + {NULL, "status-sslinvalid-font", TYPE_FONT, setting_status_font, {.s = "monospace bold 8"}, TRUE}, + {NULL, "input-bg-normal", TYPE_COLOR, setting_input_style, {.s = "#fff"}, TRUE}, + {NULL, "input-bg-error", TYPE_COLOR, setting_input_style, {.s = "#f00"}, TRUE}, + {NULL, "input-fg-normal", TYPE_COLOR, setting_input_style, {.s = "#000"}, TRUE}, + {NULL, "input-fg-error", TYPE_COLOR, setting_input_style, {.s = "#000"}, TRUE}, + {NULL, "input-font-normal", TYPE_FONT, setting_input_style, {.s = "monospace normal 8"}, TRUE}, + {NULL, "input-font-error", TYPE_FONT, setting_input_style, {.s = "monospace bold 8"}, TRUE}, + {NULL, "completion-font", TYPE_FONT, setting_completion_style, {.s = "monospace normal 8"}, TRUE}, + {NULL, "completion-fg-normal", TYPE_COLOR, setting_completion_style, {.s = "#f6f3e8"}, TRUE}, + {NULL, "completion-fg-active", TYPE_COLOR, setting_completion_style, {.s = "#fff"}, TRUE}, + {NULL, "completion-bg-normal", TYPE_COLOR, setting_completion_style, {.s = "#656565"}, TRUE}, + {NULL, "completion-bg-active", TYPE_COLOR, setting_completion_style, {.s = "#777777"}, TRUE}, + {NULL, "max-completion-items", TYPE_INTEGER, setting_completion_style, {.i = 15}, FALSE}, + {NULL, "hint-bg", TYPE_CHAR, setting_hint_style, {.s = "#ff0"}, TRUE}, + {NULL, "hint-bg-focus", TYPE_CHAR, setting_hint_style, {.s = "#8f0"}, TRUE}, + {NULL, "hint-fg", TYPE_CHAR, setting_hint_style, {.s = "#000"}, TRUE}, + {NULL, "hint-style", TYPE_CHAR, setting_hint_style, {.s = "position:absolute;z-index:100000;font-family:monospace;font-weight:bold;font-size:10px;color:#000;background-color:#fff;margin:0;padding:0px 1px;border:1px solid #444;opacity:0.7;"}, TRUE}, + {NULL, "ca-bundle", TYPE_CHAR, setting_ca_bundle, {.s = "/etc/ssl/certs/ca-certificates.crt"}, TRUE}, + {NULL, "home-page", TYPE_CHAR, setting_home_page, {.s = "https://github.com/fanglingsu/vimp"}, TRUE}, + {NULL, "download-path", TYPE_CHAR, setting_download_path, {.s = "/tmp/vimp"}, TRUE}, + {NULL, "history-max-items", TYPE_INTEGER, setting_history_max_items, {.i = 500}, TRUE}, }; +extern Client* clients; void setting_init(void) { @@ -133,8 +137,22 @@ void setting_init(void) /* use alias as key if available */ g_hash_table_insert(core.settings, (gpointer)s->alias != NULL ? s->alias : s->name, s); - /* set the default settings */ - s->func(s, FALSE); + /* set the global settings */ + if (s->global) { + s->func(NULL, s, FALSE); + } + } +} + +void setting_init_client(Client* c) +{ + Setting* s = NULL; + /* set the default settings */ + for (int i = 0; i < LENGTH(default_settings); i++) { + s = &default_settings[i]; + if (!s->global) { + s->func(c, s, FALSE); + } } } @@ -145,14 +163,13 @@ void setting_cleanup(void) } } -gboolean setting_run(char* name, const char* param) +gboolean setting_run(Client* c, char* name, const char* param) { Arg* a = NULL; gboolean result = FALSE; gboolean get = FALSE; SettingType type = SETTING_SET; - /* determine the type to names last char and param */ int len = strlen(name); if (name[len - 1] == '?') { @@ -167,7 +184,13 @@ gboolean setting_run(char* name, const char* param) Setting* s = g_hash_table_lookup(core.settings, name); if (!s) { - vp_echo(VP_MSG_ERROR, TRUE, "Config '%s' not found", name); + vp_echo(c, VP_MSG_ERROR, TRUE, "Config '%s' not found", name); + return FALSE; + } + + /* don't process locl settings if no client is given */ + if (!c && !s->global) { + fprintf(stderr, "Can't set local config %s without client\n", s->alias ? s->alias : s->name); return FALSE; } @@ -176,28 +199,28 @@ gboolean setting_run(char* name, const char* param) * it to the arg of the setting */ a = setting_char_to_arg(param, s->type); if (a == NULL) { - vp_echo(VP_MSG_ERROR, TRUE, "No valid value"); + vp_echo(c, VP_MSG_ERROR, TRUE, "No valid value"); return FALSE; } s->arg = *a; - result = s->func(s, get); + result = s->func(c, s, get); if (a->s) { g_free(a->s); } g_free(a); if (!result) { - vp_echo(VP_MSG_ERROR, TRUE, "Could not set %s", s->alias ? s->alias : s->name); + vp_echo(c, VP_MSG_ERROR, TRUE, "Could not set %s", s->alias ? s->alias : s->name); } return result; } if (type == SETTING_GET) { - result = s->func(s, type); + result = s->func(c, s, type); if (!result) { - vp_echo(VP_MSG_ERROR, TRUE, "Could not get %s", s->alias ? s->alias : s->name); + vp_echo(c, VP_MSG_ERROR, TRUE, "Could not get %s", s->alias ? s->alias : s->name); } return result; @@ -205,14 +228,14 @@ gboolean setting_run(char* name, const char* param) /* toggle bolean vars */ if (s->type != TYPE_BOOLEAN) { - vp_echo(VP_MSG_ERROR, TRUE, "Could not toggle none boolean %s", s->alias ? s->alias : s->name); + vp_echo(c, VP_MSG_ERROR, TRUE, "Could not toggle none boolean %s", s->alias ? s->alias : s->name); return FALSE; } - result = s->func(s, type); + result = s->func(c, s, type); if (!result) { - vp_echo(VP_MSG_ERROR, TRUE, "Could not toggle %s", s->alias ? s->alias : s->name); + vp_echo(c, VP_MSG_ERROR, TRUE, "Could not toggle %s", s->alias ? s->alias : s->name); } return result; @@ -255,45 +278,48 @@ static Arg* setting_char_to_arg(const char* str, const Type type) /** * Print the setting value to the input box. */ -static void setting_print_value(const Setting* s, void* value) +static void setting_print_value(Client* c, const Setting* s, void* value) { + if (!c) { + return; + } const char* name = s->alias ? s->alias : s->name; char* string = NULL; switch (s->type) { case TYPE_BOOLEAN: - vp_echo(VP_MSG_NORMAL, FALSE, " %s=%s", name, *(gboolean*)value ? "true" : "false"); + vp_echo(c, VP_MSG_NORMAL, FALSE, " %s=%s", name, *(gboolean*)value ? "true" : "false"); break; case TYPE_INTEGER: - vp_echo(VP_MSG_NORMAL, FALSE, " %s=%d", name, *(int*)value); + vp_echo(c, VP_MSG_NORMAL, FALSE, " %s=%d", name, *(int*)value); break; case TYPE_FLOAT: - vp_echo(VP_MSG_NORMAL, FALSE, " %s=%g", name, *(gfloat*)value); + vp_echo(c, VP_MSG_NORMAL, FALSE, " %s=%g", name, *(gfloat*)value); break; case TYPE_CHAR: - vp_echo(VP_MSG_NORMAL, FALSE, " %s=%s", name, (char*)value); + vp_echo(c, VP_MSG_NORMAL, FALSE, " %s=%s", name, (char*)value); break; case TYPE_COLOR: string = VP_COLOR_TO_STRING((VpColor*)value); - vp_echo(VP_MSG_NORMAL, FALSE, " %s=%s", name, string); + vp_echo(c, VP_MSG_NORMAL, FALSE, " %s=%s", name, string); g_free(string); break; case TYPE_FONT: string = pango_font_description_to_string((PangoFontDescription*)value); - vp_echo(VP_MSG_NORMAL, FALSE, " %s=%s", name, string); + vp_echo(c, VP_MSG_NORMAL, FALSE, " %s=%s", name, string); g_free(string); break; } } -static gboolean setting_webkit(const Setting* s, const SettingType type) +static gboolean setting_webkit(Client* c, const Setting* s, const SettingType type) { - WebKitWebSettings* web_setting = webkit_web_view_get_settings(vp.gui.webview); + WebKitWebSettings* web_setting = webkit_web_view_get_settings(c->gui.webview); switch (s->type) { case TYPE_BOOLEAN: @@ -309,7 +335,7 @@ static gboolean setting_webkit(const Setting* s, const SettingType type) } /* print the new value */ - setting_print_value(s, &value); + setting_print_value(c, s, &value); } else { g_object_set(G_OBJECT(web_setting), s->name, s->arg.i ? TRUE : FALSE, NULL); } @@ -319,7 +345,7 @@ static gboolean setting_webkit(const Setting* s, const SettingType type) if (type == SETTING_GET) { int value; g_object_get(G_OBJECT(web_setting), s->name, &value, NULL); - setting_print_value(s, &value); + setting_print_value(c, s, &value); } else { g_object_set(G_OBJECT(web_setting), s->name, s->arg.i, NULL); } @@ -329,7 +355,7 @@ static gboolean setting_webkit(const Setting* s, const SettingType type) if (type == SETTING_GET) { gfloat value; g_object_get(G_OBJECT(web_setting), s->name, &value, NULL); - setting_print_value(s, &value); + setting_print_value(c, s, &value); } else { g_object_set(G_OBJECT(web_setting), s->name, (gfloat)(s->arg.i / 1000000.0), NULL); } @@ -341,7 +367,7 @@ static gboolean setting_webkit(const Setting* s, const SettingType type) if (type == SETTING_GET) { char* value = NULL; g_object_get(G_OBJECT(web_setting), s->name, &value, NULL); - setting_print_value(s, value); + setting_print_value(c, s, value); } else { g_object_set(G_OBJECT(web_setting), s->name, s->arg.s, NULL); } @@ -350,10 +376,10 @@ static gboolean setting_webkit(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_cookie_timeout(const Setting* s, const SettingType type) +static gboolean setting_cookie_timeout(Client* c, const Setting* s, const SettingType type) { if (type == SETTING_GET) { - setting_print_value(s, &core.config.cookie_timeout); + setting_print_value(c, s, &core.config.cookie_timeout); } else { core.config.cookie_timeout = s->arg.i; } @@ -361,10 +387,10 @@ static gboolean setting_cookie_timeout(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_scrollstep(const Setting* s, const SettingType type) +static gboolean setting_scrollstep(Client* c, const Setting* s, const SettingType type) { if (type == SETTING_GET) { - setting_print_value(s, &core.config.scrollstep); + setting_print_value(c, s, &core.config.scrollstep); } else { core.config.scrollstep = s->arg.i; } @@ -372,7 +398,7 @@ static gboolean setting_scrollstep(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_status_color_bg(const Setting* s, const SettingType type) +static gboolean setting_status_color_bg(Client* c, const Setting* s, const SettingType type) { StatusType stype; if (g_str_has_prefix(s->name, "status-sslinvalid")) { @@ -384,16 +410,19 @@ static gboolean setting_status_color_bg(const Setting* s, const SettingType type } if (type == SETTING_GET) { - setting_print_value(s, &core.style.status_bg[stype]); + setting_print_value(c, s, &core.style.status_bg[stype]); } else { VP_COLOR_PARSE(&core.style.status_bg[stype], s->arg.s); - vp_update_status_style(); + /* update the status style for all clients */ + for(Client* p = clients; p; p = p->next) { + vp_update_status_style(p); + } } return TRUE; } -static gboolean setting_status_color_fg(const Setting* s, const SettingType type) +static gboolean setting_status_color_fg(Client* c, const Setting* s, const SettingType type) { StatusType stype; if (g_str_has_prefix(s->name, "status-sslinvalid")) { @@ -405,16 +434,19 @@ static gboolean setting_status_color_fg(const Setting* s, const SettingType type } if (type == SETTING_GET) { - setting_print_value(s, &core.style.status_fg[stype]); + setting_print_value(c, s, &core.style.status_fg[stype]); } else { VP_COLOR_PARSE(&core.style.status_fg[stype], s->arg.s); - vp_update_status_style(); + /* update the status style for all clients */ + for(Client* p = clients; p; p = p->next) { + vp_update_status_style(p); + } } return TRUE; } -static gboolean setting_status_font(const Setting* s, const SettingType type) +static gboolean setting_status_font(Client* c, const Setting* s, const SettingType type) { StatusType stype; if (g_str_has_prefix(s->name, "status-sslinvalid")) { @@ -426,21 +458,23 @@ static gboolean setting_status_font(const Setting* s, const SettingType type) } if (type == SETTING_GET) { - setting_print_value(s, core.style.status_font[stype]); + setting_print_value(c, s, core.style.status_font[stype]); } else { if (core.style.status_font[stype]) { /* free previous font description */ pango_font_description_free(core.style.status_font[stype]); } core.style.status_font[stype] = pango_font_description_from_string(s->arg.s); - - vp_update_status_style(); + /* update the status style for all clients */ + for(Client* p = clients; p; p = p->next) { + vp_update_status_style(p); + } } return TRUE; } -static gboolean setting_input_style(const Setting* s, const SettingType type) +static gboolean setting_input_style(Client* c, const Setting* s, const SettingType type) { Style* style = &core.style; MessageType itype = g_str_has_suffix(s->name, "normal") ? VP_MSG_NORMAL : VP_MSG_ERROR; @@ -448,7 +482,7 @@ static gboolean setting_input_style(const Setting* s, const SettingType type) if (s->type == TYPE_FONT) { /* input font */ if (type == SETTING_GET) { - setting_print_value(s, style->input_font[itype]); + setting_print_value(c, s, style->input_font[itype]); } else { if (style->input_font[itype]) { pango_font_description_free(style->input_font[itype]); @@ -466,20 +500,23 @@ static gboolean setting_input_style(const Setting* s, const SettingType type) } if (type == SETTING_GET) { - setting_print_value(s, color); + setting_print_value(c, s, color); } else { VP_COLOR_PARSE(color, s->arg.s); } } if (type != SETTING_GET) { - /* echo already visible input text to apply the new style to input box */ - vp_echo(VP_MSG_NORMAL, FALSE, GET_TEXT()); + /* update the inputbox style for all clients */ + for(Client* p = clients; p; p = p->next) { + /* vp_update_input_style seems to take no immediatly effect */ + vp_echo(p, VP_MSG_NORMAL, FALSE, gtk_entry_get_text(GTK_ENTRY(p->gui.inputbox))); + } } return TRUE; } -static gboolean setting_completion_style(const Setting* s, const SettingType type) +static gboolean setting_completion_style(Client* c, const Setting* s, const SettingType type) { Style* style = &core.style; CompletionStyle ctype = g_str_has_suffix(s->name, "normal") ? VP_COMP_NORMAL : VP_COMP_ACTIVE; @@ -487,13 +524,13 @@ static gboolean setting_completion_style(const Setting* s, const SettingType typ if (s->type == TYPE_INTEGER) { /* max completion items */ if (type == SETTING_GET) { - setting_print_value(s, &core.config.max_completion_items); + setting_print_value(c, s, &core.config.max_completion_items); } else { core.config.max_completion_items = s->arg.i; } } else if (s->type == TYPE_FONT) { if (type == SETTING_GET) { - setting_print_value(s, style->comp_font); + setting_print_value(c, s, style->comp_font); } else { if (style->comp_font) { pango_font_description_free(style->comp_font); @@ -511,7 +548,7 @@ static gboolean setting_completion_style(const Setting* s, const SettingType typ } if (type == SETTING_GET) { - setting_print_value(s, color); + setting_print_value(c, s, color); } else { VP_COLOR_PARSE(color, s->arg.s); } @@ -520,30 +557,30 @@ static gboolean setting_completion_style(const Setting* s, const SettingType typ return TRUE; } -static gboolean setting_hint_style(const Setting* s, const SettingType type) +static gboolean setting_hint_style(Client* c, const Setting* s, const SettingType type) { Style* style = &core.style; if (!g_strcmp0(s->name, "hint-bg")) { if (type == SETTING_GET) { - setting_print_value(s, style->hint_bg); + setting_print_value(c, s, style->hint_bg); } else { OVERWRITE_STRING(style->hint_bg, s->arg.s) } } else if (!g_strcmp0(s->name, "hint-bg-focus")) { if (type == SETTING_GET) { - setting_print_value(s, style->hint_bg_focus); + setting_print_value(c, s, style->hint_bg_focus); } else { OVERWRITE_STRING(style->hint_bg_focus, s->arg.s) } } else if (!g_strcmp0(s->name, "hint-fg")) { if (type == SETTING_GET) { - setting_print_value(s, style->hint_fg); + setting_print_value(c, s, style->hint_fg); } else { OVERWRITE_STRING(style->hint_fg, s->arg.s) } } else { if (type == SETTING_GET) { - setting_print_value(s, style->hint_style); + setting_print_value(c, s, style->hint_style); } else { OVERWRITE_STRING(style->hint_style, s->arg.s); } @@ -552,13 +589,13 @@ static gboolean setting_hint_style(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_strict_ssl(const Setting* s, const SettingType type) +static gboolean setting_strict_ssl(Client* c, const Setting* s, const SettingType type) { gboolean value; if (type != SETTING_SET) { g_object_get(core.soup_session, "ssl-strict", &value, NULL); if (type == SETTING_GET) { - setting_print_value(s, &value); + setting_print_value(c, s, &value); return TRUE; } @@ -571,12 +608,12 @@ static gboolean setting_strict_ssl(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_ca_bundle(const Setting* s, const SettingType type) +static gboolean setting_ca_bundle(Client* c, const Setting* s, const SettingType type) { if (type == SETTING_GET) { char* value = NULL; g_object_get(core.soup_session, "ssl-ca-file", &value, NULL); - setting_print_value(s, value); + setting_print_value(c, s, value); g_free(value); } else { g_object_set(core.soup_session, "ssl-ca-file", s->arg.s, NULL); @@ -585,10 +622,10 @@ static gboolean setting_ca_bundle(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_home_page(const Setting* s, const SettingType type) +static gboolean setting_home_page(Client* c, const Setting* s, const SettingType type) { if (type == SETTING_GET) { - setting_print_value(s, core.config.home_page); + setting_print_value(c, s, core.config.home_page); } else { OVERWRITE_STRING(core.config.home_page, s->arg.s); } @@ -596,10 +633,10 @@ static gboolean setting_home_page(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_download_path(const Setting* s, const SettingType type) +static gboolean setting_download_path(Client* c, const Setting* s, const SettingType type) { if (type == SETTING_GET) { - setting_print_value(s, core.config.download_dir); + setting_print_value(c, s, core.config.download_dir); } else { if (core.config.download_dir) { g_free(core.config.download_dir); @@ -618,7 +655,7 @@ static gboolean setting_download_path(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_proxy(const Setting* s, const SettingType type) +static gboolean setting_proxy(Client* c, const Setting* s, const SettingType type) { gboolean enabled; SoupURI* proxy_uri = NULL; @@ -629,7 +666,7 @@ static gboolean setting_proxy(const Setting* s, const SettingType type) enabled = (proxy_uri != NULL); if (type == SETTING_GET) { - setting_print_value(s, &enabled); + setting_print_value(c, s, &enabled); return TRUE; } @@ -638,7 +675,7 @@ static gboolean setting_proxy(const Setting* s, const SettingType type) if (type == SETTING_TOGGLE) { enabled = !enabled; /* print the new value */ - setting_print_value(s, &enabled); + setting_print_value(c, s, &enabled); } else { enabled = s->arg.i; } @@ -663,17 +700,17 @@ static gboolean setting_proxy(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_user_style(const Setting* s, const SettingType type) +static gboolean setting_user_style(Client* c, const Setting* s, const SettingType type) { gboolean enabled = FALSE; char* uri = NULL; - WebKitWebSettings* web_setting = webkit_web_view_get_settings(vp.gui.webview); + WebKitWebSettings* web_setting = webkit_web_view_get_settings(c->gui.webview); if (type != SETTING_SET) { g_object_get(web_setting, "user-stylesheet-uri", &uri, NULL); enabled = (uri != NULL); if (type == SETTING_GET) { - setting_print_value(s, &enabled); + setting_print_value(c, s, &enabled); return TRUE; } @@ -682,7 +719,7 @@ static gboolean setting_user_style(const Setting* s, const SettingType type) if (type == SETTING_TOGGLE) { enabled = !enabled; /* print the new value */ - setting_print_value(s, &enabled); + setting_print_value(c, s, &enabled); } else { enabled = s->arg.i; } @@ -698,10 +735,10 @@ static gboolean setting_user_style(const Setting* s, const SettingType type) return TRUE; } -static gboolean setting_history_max_items(const Setting* s, const SettingType type) +static gboolean setting_history_max_items(Client* c, const Setting* s, const SettingType type) { if (type == SETTING_GET) { - setting_print_value(s, &core.config.url_history_max); + setting_print_value(c, s, &core.config.url_history_max); return TRUE; } diff --git a/src/setting.h b/src/setting.h index 2c32b69..713c8aa 100644 --- a/src/setting.h +++ b/src/setting.h @@ -29,18 +29,20 @@ typedef enum { } SettingType; typedef struct _Setting Setting; -typedef gboolean (*SettingFunc)(const Setting*, const SettingType); +typedef gboolean (*SettingFunc)(Client* c, const Setting*, const SettingType); struct _Setting { - char* alias; - char* name; + char* alias; + char* name; Type type; SettingFunc func; Arg arg; + gboolean global; }; void setting_init(void); +void setting_init_client(Client* c); void setting_cleanup(void); -gboolean setting_run(char* name, const char* param); +gboolean setting_run(Client* c, char* name, const char* param); #endif /* end of include guard: _SETTING_H */ diff --git a/src/url_history.c b/src/url_history.c index 8ae771e..1381c5d 100644 --- a/src/url_history.c +++ b/src/url_history.c @@ -92,6 +92,7 @@ GList* url_history_get_all(void) out = g_list_prepend(out, hi->uri); } + out = g_list_reverse(out); return out; } -- 2.20.1