Use some logic together for all windows.
authorDaniel Carl <danielcarl@gmx.de>
Mon, 4 Mar 2013 21:45:20 +0000 (22:45 +0100)
committerDaniel Carl <danielcarl@gmx.de>
Tue, 5 Mar 2013 11:37:46 +0000 (12:37 +0100)
18 files changed:
config.mk
src/command.c
src/command.h
src/completion.c
src/completion.h
src/dom.c
src/dom.h
src/hints.c
src/hints.h
src/history.c
src/history.h
src/keybind.c
src/keybind.h
src/main.c
src/main.h
src/setting.c
src/setting.h
src/url_history.c

index cbc8c6b..f26da6f 100644 (file)
--- 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
index dc62778..562150f 100644 (file)
@@ -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);
 }
index f9914c7..c0062f7 100644 (file)
@@ -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 */
index bb8ee0d..fba9daa 100644 (file)
@@ -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;
index cdc47e4..5a18a2b 100644 (file)
@@ -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 */
index 8bccebd..b8f1711 100644 (file)
--- a/src/dom.c
+++ b/src/dom.c
 #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;
 }
index 74c87ba..20b1bae 100644 (file)
--- 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 */
index 6433eed..e65b347 100644 (file)
 #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;
     }
index bc0b2d8..14e682d 100644 (file)
@@ -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 */
index 55c3a67..f8099a4 100644 (file)
@@ -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;
     }
 }
index d6c3ccf..ad48a3f 100644 (file)
@@ -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 */
index e232688..2fbcba1 100644 (file)
@@ -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;
     }
index 84c2b0c..7ca7b69 100644 (file)
@@ -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);
index 6a15f66..90d4335 100644 (file)
 
 /* 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;
 }
index c7f59a4..bca66d4 100644 (file)
@@ -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 */
index 1185fb8..dd03126 100644 (file)
 #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;
     }
index 2c32b69..713c8aa 100644 (file)
@@ -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 */
index 8ae771e..1381c5d 100644 (file)
@@ -92,6 +92,7 @@ GList* url_history_get_all(void)
         out = g_list_prepend(out, hi->uri);
     }
 
+    out = g_list_reverse(out);
     return out;
 }