From 9a26162a491a9aa9ccd72fb48b14b4e12a431f01 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Wed, 19 Dec 2012 19:27:28 +0100 Subject: [PATCH] Allow to open links into new window. --- doc/config | 1 + src/command.c | 3 +- src/hints.c | 27 ++++++++++----- src/hints.h | 5 +-- src/main.c | 91 ++++++++++++++++++++++++++++++++++++++++++--------- src/main.h | 5 +++ 6 files changed, 106 insertions(+), 26 deletions(-) diff --git a/doc/config b/doc/config index 12703c9..cf5089e 100644 --- a/doc/config +++ b/doc/config @@ -22,6 +22,7 @@ nmap l scrollright nmap k scrollup nmap j scrolldown nmap f hint-link +nmap F hint-link-new cmap complete cmap complete-back hmap hint-focus-next diff --git a/src/command.c b/src/command.c index 5348a40..927d74a 100644 --- a/src/command.c +++ b/src/command.c @@ -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}, }; diff --git a/src/hints.c b/src/hints.c index db65d9e..ea4f58b 100644 --- a/src/hints.c +++ b/src/hints.c @@ -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'] | " diff --git a/src/hints.h b/src/hints.h index 9f9360d..6a0840f 100644 --- a/src/hints.h +++ b/src/hints.h @@ -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); diff --git a/src/main.c b/src/main.c index 9101bc3..19cd7c2 100644 --- a/src/main.c +++ b/src/main.c @@ -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 { diff --git a/src/main.h b/src/main.h index 422357e..1a81ecc 100644 --- a/src/main.h +++ b/src/main.h @@ -89,6 +89,11 @@ enum { VP_NAVIG_STOP_LOADING }; +enum { + VP_TARGET_CURRENT, + VP_TARGET_NEW +}; + enum { VP_INPUT_CURRENT_URI = 1 }; -- 2.20.1