Allow to open links into new window.
authorDaniel Carl <danielcarl@gmx.de>
Wed, 19 Dec 2012 18:27:28 +0000 (19:27 +0100)
committerDaniel Carl <danielcarl@gmx.de>
Wed, 19 Dec 2012 18:27:28 +0000 (19:27 +0100)
doc/config
src/command.c
src/hints.c
src/hints.h
src/main.c
src/main.h

index 12703c9..cf5089e 100644 (file)
@@ -22,6 +22,7 @@ nmap l scrollright
 nmap k scrollup
 nmap j scrolldown
 nmap f hint-link
+nmap F hint-link-new
 cmap <tab> complete
 cmap <shift-tab> complete-back
 hmap <tab> hint-focus-next
index 5348a40..927d74a 100644 (file)
@@ -65,7 +65,8 @@ static CommandInfo cmd_list[] = {
     {"complete",         command_complete,    {0},                                                                          VP_MODE_COMMAND | VP_MODE_COMPLETE},
     {"complete-back",    command_complete,    {1},                                                                          VP_MODE_COMMAND | VP_MODE_COMPLETE},
     {"inspect",          command_inspect,     {0},                                                                          VP_MODE_NORMAL},
-    {"hint-link",        command_hints,       {0, "."},                                                                     VP_MODE_HINTING},
+    {"hint-link",        command_hints,       {HINTS_MODE_LINK, "."},                                                       VP_MODE_HINTING},
+    {"hint-link-new",    command_hints,       {HINTS_MODE_LINK_NEW, ","},                                                   VP_MODE_HINTING},
     {"hint-focus-next",  command_hints_focus, {0},                                                                          VP_MODE_HINTING},
     {"hint-focus-prev",  command_hints_focus, {1},                                                                          VP_MODE_HINTING},
 };
index db65d9e..ea4f58b 100644 (file)
@@ -316,22 +316,32 @@ static void hints_fire(const gulong num)
 {
     Hint* hint = hints_get_hint_by_number(num);
     if (hint) {
-        /* TODO
-         * if the elemt has a target attribute - remove it temporary
-         * fire mousedown and click events on the element
-         * if it is an form element focus it and return */
-
         if (dom_is_editable(hint->elem)) {
             webkit_dom_element_focus(hint->elem);
             vp_set_mode(VP_MODE_INSERT, FALSE);
         } else {
-            /* remove possible target attribute */
-            gchar* type = webkit_dom_element_get_attribute(hint->elem, "target");
-            if (g_strcmp0(type, "_blank") == 0) {
+            /* TODO I don't get the mouse click event dispatched here to
+             * invoce the gtk events for button press wich might be the better
+             * way hanlding to open new windows that setting temporary target
+             * attribute here */
+            gchar* target = webkit_dom_element_get_attribute(hint->elem, "target");
+            if (currentMode == HINTS_MODE_LINK_NEW) {       /* open in new window */
+                webkit_dom_element_set_attribute(hint->elem, "target", "_blank", NULL);
+            } else if (g_strcmp0(target, "_blank") == 0) {  /* remove possible target attribute */
                 webkit_dom_element_remove_attribute(hint->elem, "target");
             }
+
+            /* dispatch click event */
             Document* doc = webkit_web_view_get_dom_document(vp.gui.webview);
             dom_dispatch_mouse_event(doc, hint->elem, "click", 0);
+
+            /* reset previous target attribute */
+            if (target && strlen(target)) {
+                webkit_dom_element_set_attribute(hint->elem, "target", target, NULL);
+            } else {
+                webkit_dom_element_remove_attribute(hint->elem, "target");
+            }
+
             /* remove the hint filter input */
             vp_clean_input();
         }
@@ -376,6 +386,7 @@ static gchar* hints_get_xpath(const gchar* input)
 
     switch (currentMode) {
         case HINTS_MODE_LINK:
+        case HINTS_MODE_LINK_NEW:
             if (input == NULL) {
                 xpath = g_strdup(
                     "//*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @ role='link'] | "
index 9f9360d..6a0840f 100644 (file)
@@ -23,8 +23,9 @@
 #include "main.h"
 
 typedef enum {
-    HINTS_MODE_LINK,
-    HINTS_MODE_IMAGE,
+    HINTS_MODE_LINK     = 1,
+    HINTS_MODE_LINK_NEW = 2,
+    HINTS_MODE_IMAGE    = 3,
 } HintMode;
 
 void hints_create(const gchar* input, HintMode mode);
index 9101bc3..19cd7c2 100644 (file)
@@ -28,6 +28,7 @@
 #include "hints.h"
 
 /* variables */
+static gchar **args;
 VpCore vp;
 
 /* callbacks */
@@ -41,6 +42,12 @@ static void vp_new_request_cb(SoupSession* session, SoupMessage *message, gpoint
 static void vp_gotheaders_cb(SoupMessage* message, gpointer data);
 #endif
 static WebKitWebView* vp_inspect_web_view_cb(gpointer inspector, WebKitWebView* web_view);
+static gboolean vp_button_relase_cb(WebKitWebView *webview, GdkEventButton* event, gpointer data);
+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);
 
 /* functions */
 static gboolean vp_process_input(const char* input);
@@ -50,7 +57,6 @@ static void vp_read_config(void);
 static void vp_init_gui(void);
 static void vp_init_files(void);
 static void vp_setup_signals(void);
-static gboolean vp_notify_event_cb(WebKitWebView *webview, GdkEventButton* event, gpointer data);
 #ifdef FEATURE_COOKIE
 static void vp_set_cookie(SoupCookie* cookie);
 static const gchar* vp_get_cookies(SoupURI *uri);
@@ -223,14 +229,23 @@ gboolean vp_load_uri(const Arg* arg)
     }
 
     uri = g_strrstr(line, "://") ? g_strdup(line) : g_strdup_printf("http://%s", line);
+    if (arg->i == VP_TARGET_NEW) {
+        gchar *argv[64];
+        argv[0] = *args;
+        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);
+    } else {
+        /* Load a web page into the browser instance */
+        webkit_web_view_load_uri(vp.gui.webview, uri);
 
-    /* Load a web page into the browser instance */
-    webkit_web_view_load_uri(vp.gui.webview, uri);
+        /* change state to normal mode */
+        vp_set_mode(VP_MODE_NORMAL, FALSE);
+    }
     g_free(uri);
 
-    /* change state to normal mode */
-    vp_set_mode(VP_MODE_NORMAL, FALSE);
-
     return TRUE;
 }
 
@@ -558,7 +573,9 @@ static void vp_setup_signals(void)
     g_signal_connect(G_OBJECT(gui->webview), "notify::load-status", G_CALLBACK(vp_webview_load_status_cb), NULL);
     g_object_connect(
         G_OBJECT(gui->webview),
-        "signal::button-release-event", G_CALLBACK(vp_notify_event_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,
         NULL
     );
 
@@ -579,7 +596,7 @@ static void vp_setup_signals(void)
     g_object_set(vp.net.soup_session, "max-conns-per-host", SETTING_MAX_CONNS_PER_HOST, NULL);
     g_signal_connect_after(G_OBJECT(vp.net.soup_session), "request-started", G_CALLBACK(vp_new_request_cb), NULL);
 #endif
-    
+
     /* inspector */
     g_signal_connect(
         G_OBJECT(vp.gui.inspector),
@@ -589,21 +606,61 @@ static void vp_setup_signals(void)
     );
 }
 
-static gboolean vp_notify_event_cb(WebKitWebView* webview, GdkEventButton* event, gpointer data)
+static gboolean vp_button_relase_cb(WebKitWebView* webview, GdkEventButton* event, gpointer data)
 {
-    if (GET_CLEAN_MODE() == VP_MODE_NORMAL) {
-        return FALSE;
-    }
-    WebKitHitTestResult *result = webkit_web_view_get_hit_test_result(webview, event);
     WebKitHitTestResultContext context;
+    Mode mode = GET_CLEAN_MODE();
+    WebKitHitTestResult *result = webkit_web_view_get_hit_test_result(webview, event);
+
     g_object_get(result, "context", &context, NULL);
-    if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) {
+    if (mode == VP_MODE_NORMAL && context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) {
         vp_set_mode(VP_MODE_INSERT, FALSE);
         return TRUE;
     }
+    /* middle mouse click onto link */
+    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);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean vp_new_window_policy_cb(
+    WebKitWebView* view, WebKitWebFrame* frame, WebKitNetworkRequest* request,
+    WebKitWebNavigationAction* navig, WebKitWebPolicyDecision* policy, gpointer data)
+{
+    if (webkit_web_navigation_action_get_reason(navig) == WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED) {
+        /* open in a new window */
+        Arg a = {VP_TARGET_NEW, (gchar*)webkit_network_request_get_uri(request)};
+        vp_load_uri(&a);
+        webkit_web_policy_decision_ignore(policy);
+        return TRUE;
+    }
     return FALSE;
 }
 
+static WebKitWebView* vp_create_new_webview_cb(WebKitWebView* webview, WebKitWebFrame* frame, gpointer data)
+{
+    /* 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;
+}
+
+static void vp_create_new_webview_uri_cb(WebKitWebView* view, GParamSpec param_spec)
+{
+    Arg a = {VP_TARGET_NEW, (gchar*)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);
+}
+
 int main(int argc, char* argv[])
 {
     static gboolean ver = false;
@@ -624,10 +681,14 @@ int main(int argc, char* argv[])
         vp_print_version();
         return EXIT_SUCCESS;
     }
+
+    /* save arguments */
+    args = argv;
+
     vp_init();
 
     /* command line argument: URL */
-    Arg arg;
+    Arg arg = {VP_TARGET_CURRENT};
     if (argc > 1) {
         arg.s = g_strdup(argv[argc - 1]);
     } else {
index 422357e..1a81ecc 100644 (file)
@@ -89,6 +89,11 @@ enum {
     VP_NAVIG_STOP_LOADING
 };
 
+enum {
+    VP_TARGET_CURRENT,
+    VP_TARGET_NEW
+};
+
 enum {
     VP_INPUT_CURRENT_URI = 1
 };