diff options
-rw-r--r-- | inputfocus.c | 196 | ||||
-rw-r--r-- | xombrero.c | 36 | ||||
-rw-r--r-- | xombrero.h | 7 |
3 files changed, 185 insertions, 54 deletions
diff --git a/inputfocus.c b/inputfocus.c index 9115e66..fc6f259 100644 --- a/inputfocus.c +++ b/inputfocus.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2011 Marco Peereboom <marco@peereboom.us> + * Copyright (c) 2012 Josh Rickmar <jrick@devio.us> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,6 +19,43 @@ #if WEBKIT_CHECK_VERSION(1, 5, 0) /* we got the DOM API we need */ + +void +focus_body(WebKitDOMDocument *doc) +{ + WebKitDOMNodeList *body = NULL; + WebKitDOMNode *n; + int i; + + body = webkit_dom_document_get_elements_by_tag_name(doc, "body"); + for (i = 0; i < webkit_dom_node_list_get_length(body); ++i) { + n = webkit_dom_node_list_item(body, i); + webkit_dom_element_focus((WebKitDOMElement *)n); +#if WEBKIT_CHECK_VERSION(1, 8, 0) + webkit_dom_html_element_click((WebKitDOMHTMLElement *)n); +#endif + break; + } +} + +int +node_is_valid_entry(WebKitDOMNode *n) +{ + if (n == NULL) + return (FALSE); + + if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(n) && + webkit_dom_html_input_element_check_validity( + (WebKitDOMHTMLInputElement *)n)) + return (TRUE); + if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(n) && + webkit_dom_html_text_area_element_check_validity( + (WebKitDOMHTMLTextAreaElement *)n)) + return (TRUE); + + return (FALSE); +} + int focus_input_document(struct tab *t, WebKitDOMDocument *doc) { @@ -37,13 +75,16 @@ focus_input_document(struct tab *t, WebKitDOMDocument *doc) n = webkit_dom_node_list_item(input, i); in = (WebKitDOMHTMLInputElement*)n; g_object_get(G_OBJECT(in), "type", &es, (char *)NULL); - if ((!g_str_equal("text", es) && !g_str_equal("password",es)) || + if ((g_strcmp0("text", es) && g_strcmp0("password",es)) || webkit_dom_html_input_element_get_disabled(in)) { /* skip not text */ g_free(es); continue; } webkit_dom_element_focus((WebKitDOMElement*)in); +#if WEBKIT_CHECK_VERSION(1, 8, 0) + webkit_dom_html_element_click((WebKitDOMHTMLElement*)in); +#endif g_free(es); rv = 1; /* found */ goto done; @@ -59,6 +100,9 @@ focus_input_document(struct tab *t, WebKitDOMDocument *doc) continue; } webkit_dom_element_focus((WebKitDOMElement*)ta); +#if WEBKIT_CHECK_VERSION(1, 8, 0) + webkit_dom_html_element_click((WebKitDOMHTMLElement*)ta); +#endif rv = 1; /* found */ goto done; } @@ -70,19 +114,39 @@ done: return (rv); } + +char * +get_element_text(WebKitDOMNode *n) +{ + if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(n)) + return (g_strdup(webkit_dom_html_input_element_get_value( + (WebKitDOMHTMLInputElement *)n))); + else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(n)) + return (g_strdup(webkit_dom_html_text_area_element_get_value( + (WebKitDOMHTMLTextAreaElement *)n))); + return (NULL); +} + int focus_input(struct tab *t) { WebKitDOMDocument *doc; WebKitDOMNode *n; WebKitDOMNodeList *fl = NULL, *ifl = NULL; - int i, fl_count, ifl_count, rv = 0; + WebKitDOMElement *a; + int i, fl_count, ifl_count, rv = 0; /* not found */ WebKitDOMHTMLFrameElement *frame; WebKitDOMHTMLIFrameElement *iframe; /* * Here is what we are doing: + * + * If a textbox is already focused, leave it alone. + * + * Try the tab's previous active entry, for example if it was set by + * some javascript when the page loaded. + * * See if we got frames or iframes * * if we do focus on input or textarea in frame or in iframe @@ -93,6 +157,30 @@ focus_input(struct tab *t) doc = webkit_web_view_get_dom_document(t->wv); + /* try current active element */ + a = webkit_dom_html_document_get_active_element( + (WebKitDOMHTMLDocument*)doc); + if (node_is_valid_entry((WebKitDOMNode *)a)) { + rv = 1; /* found */ + goto done; + } + + /* try previous active element */ + if (node_is_valid_entry((WebKitDOMNode *)t->active)) { + webkit_dom_element_focus((WebKitDOMElement*)t->active); +#if WEBKIT_CHECK_VERSION(1, 8, 0) + webkit_dom_html_element_click((WebKitDOMHTMLElement*)t->active); +#endif + rv = 1; /* found */ + goto done; + } else { + t->active = NULL; + if (t->active_text) { + g_free(t->active_text); + t->active_text = NULL; + } + } + /* get frames */ fl = webkit_dom_document_get_elements_by_tag_name(doc, "frame"); fl_count = webkit_dom_node_list_get_length(fl); @@ -108,7 +196,7 @@ focus_input(struct tab *t) doc = webkit_dom_html_frame_element_get_content_document(frame); if (focus_input_document(t, doc)) { - rv = 1; + rv = 1; /* focus */ goto done; } } @@ -120,16 +208,15 @@ focus_input(struct tab *t) doc = webkit_dom_html_iframe_element_get_content_document(iframe); if (focus_input_document(t, doc)) { - rv = 1; + rv = 1; /* found */ goto done; } } /* if we made it here nothing got focused so use normal heuristic */ - if (focus_input_document(t, webkit_web_view_get_dom_document(t->wv))) { - rv = 1; - goto done; - } + if (focus_input_document(t, webkit_web_view_get_dom_document(t->wv))) + rv = 1; /* found */ + done: if (fl) g_object_unref(fl); @@ -140,7 +227,7 @@ done: } int -dom_is_input(struct tab *t, WebKitDOMElement **active) +dom_is_input(struct tab *t, char **text) { WebKitDOMDocument *doc; WebKitDOMElement *a; @@ -193,7 +280,11 @@ dom_is_input(struct tab *t, WebKitDOMElement **active) aa = (WebKitDOMHTMLElement*)a; if (WEBKIT_DOM_IS_HTML_ELEMENT(aa) && webkit_dom_html_element_get_is_content_editable(aa)) { - *active = a; + if (t->active == NULL) + t->active = a; + *text = get_element_text((WebKitDOMNode *)a); + if (t->active_text == NULL) + t->active_text = g_strdup(*text); return (1); } break; @@ -202,9 +293,19 @@ dom_is_input(struct tab *t, WebKitDOMElement **active) if (a == NULL) return (0); - if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT((WebKitDOMNode *)a) || - WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT((WebKitDOMNode *)a)) { - *active = a; + if (node_is_valid_entry((WebKitDOMNode *)a)) { + if (!node_is_valid_entry((WebKitDOMNode *)t->active)) { + t->active = NULL; + if (t->active_text) { + g_free(t->active_text); + t->active_text = NULL; + } + } + if (t->active == NULL) + t->active = a; + *text = get_element_text((WebKitDOMNode *)a); + if (t->active_text == NULL) + t->active_text = g_strdup(*text); return (1); } @@ -214,35 +315,41 @@ dom_is_input(struct tab *t, WebKitDOMElement **active) void * input_check_mode(struct tab *t) { - WebKitDOMElement *active = NULL; + char *text = NULL; - if (dom_is_input(t, &active)) + if (dom_is_input(t, &text)) { t->mode = XT_MODE_INSERT; - - return (active); -} - -void -input_focus_blur(struct tab *t, void *active) -{ - /* active is (WebKitDOMElement*) */ - if (active) - webkit_dom_element_blur(active); + return (t->active); + } else + return (NULL); } int command_mode(struct tab *t, struct karg *args) { - WebKitDOMElement *active = NULL; + WebKitDOMDocument *doc; + WebKitDOMElement *a; if (args->i == XT_MODE_COMMAND) { - if (dom_is_input(t, &active)) - if (active) - webkit_dom_element_blur(active); + doc = webkit_web_view_get_dom_document(t->wv); + a = webkit_dom_html_document_get_active_element( + (WebKitDOMHTMLDocument *)doc); + if (a) { + webkit_dom_element_blur(a); + focus_body(doc); + } t->mode = XT_MODE_COMMAND; - } else { - if (focus_input(t)) - t->mode = XT_MODE_INSERT; + } else if (args->i == XT_MODE_INSERT && focus_input(t)) + t->mode = XT_MODE_INSERT; + else if (args->i == XT_MODE_HINT || args->i == XT_MODE_PASSTHROUGH) + t->mode = args->i; + + if (!node_is_valid_entry((WebKitDOMNode *)t->active)) { + t->active = NULL; + if (t->active_text) { + g_free(t->active_text); + t->active_text = NULL; + } } return (XT_CB_HANDLED); @@ -251,7 +358,8 @@ command_mode(struct tab *t, struct karg *args) void input_autofocus(struct tab *t) { - WebKitDOMElement *active = NULL; + struct karg args = {0}; + char *text = NULL; if (autofocus_onload && t->tab_id == gtk_notebook_get_current_page(notebook)) { @@ -260,11 +368,18 @@ input_autofocus(struct tab *t) else t->mode = XT_MODE_COMMAND; } else { - if (dom_is_input(t, &active)) - if (active) - webkit_dom_element_blur(active); - t->mode = XT_MODE_COMMAND; + if (dom_is_input(t, &text)) { + if (text != NULL && g_strcmp0(text, t->active_text)) + args.i = XT_MODE_INSERT; + else + args.i = XT_MODE_COMMAND; + } else + args.i = XT_MODE_COMMAND; + command_mode(t, &args); } + + if (text) + g_free(text); } #else /* WEBKIT_CHECK_VERSION */ /* incomplete DOM API */ @@ -288,13 +403,6 @@ input_autofocus(struct tab *t) } } -void -input_focus_blur(struct tab *t, void *active) -{ - run_script(t, "hints.clearFocus();"); - t->mode = XT_MODE_COMMAND; -} - void * input_check_mode(struct tab *t) { diff --git a/xombrero.c b/xombrero.c index d02d471..53b68f3 100644 --- a/xombrero.c +++ b/xombrero.c @@ -476,6 +476,7 @@ hide_cmd(struct tab *t) history_at = NULL; /* just in case */ search_at = NULL; /* just in case */ + gtk_widget_set_can_focus(t->cmd, FALSE); gtk_widget_hide(t->cmd); } @@ -487,6 +488,7 @@ show_cmd(struct tab *t) history_at = NULL; search_at = NULL; gtk_widget_hide(t->oops); + gtk_widget_set_can_focus(t->cmd, TRUE); gtk_widget_show(t->cmd); } @@ -494,6 +496,7 @@ void hide_buffers(struct tab *t) { gtk_widget_hide(t->buffers); + gtk_widget_set_can_focus(t->buffers, FALSE); gtk_list_store_clear(buffers_store); } @@ -567,6 +570,7 @@ show_buffers(struct tab *t) gtk_tree_path_free(path); gtk_widget_show(t->buffers); + gtk_widget_set_can_focus(t->buffers, TRUE); gtk_widget_grab_focus(GTK_WIDGET(t->buffers)); } @@ -2805,7 +2809,7 @@ struct prompt_sub { int command(struct tab *t, struct karg *args) { - struct karg a; + struct karg a = {0}; int i; char *s = NULL, *sp = NULL, *sl = NULL; gchar **sv; @@ -2851,14 +2855,12 @@ command(struct tab *t, struct karg *args) break; case '.': t->mode = XT_MODE_HINT; - bzero(&a, sizeof a); a.i = 0; hint(t, &a); s = "."; break; case ',': t->mode = XT_MODE_HINT; - bzero(&a, sizeof a); a.i = XT_HINT_NEWTAB; hint(t, &a); s = ","; @@ -4227,6 +4229,15 @@ notify_load_status_cb(WebKitWebView* wview, GParamSpec* pspec, struct tab *t) g_free(base); #endif + /* DOM is changing, unreference the previous focused element */ +#if WEBKIT_CHECK_VERSION(1, 5, 0) + t->active = NULL; + if (t->active_text) { + g_free(t->active_text); + t->active_text = NULL; + } +#endif + /* take focus if we are visible */ focus_webview(t); t->focus_wv = 1; @@ -7000,6 +7011,7 @@ create_browser(struct tab *t) } w = gtk_scrolled_window_new(NULL, NULL); + gtk_widget_set_can_focus(w, FALSE); t->adjust_h = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW(w)); t->adjust_v = gtk_scrolled_window_get_vadjustment( @@ -7115,16 +7127,13 @@ create_toolbar(struct tab *t) gtk_widget_set_sensitive(t->forward, FALSE); g_signal_connect(G_OBJECT(t->forward), "clicked", G_CALLBACK(forward_cb), t); - gtk_box_pack_start(GTK_BOX(b), t->forward, FALSE, - FALSE, 0); + gtk_box_pack_start(GTK_BOX(b), t->forward, FALSE, FALSE, 0); /* stop button */ t->stop = create_button("Stop", GTK_STOCK_STOP, 0); gtk_widget_set_sensitive(t->stop, FALSE); - g_signal_connect(G_OBJECT(t->stop), "clicked", - G_CALLBACK(stop_cb), t); - gtk_box_pack_start(GTK_BOX(b), t->stop, FALSE, - FALSE, 0); + g_signal_connect(G_OBJECT(t->stop), "clicked", G_CALLBACK(stop_cb), t); + gtk_box_pack_start(GTK_BOX(b), t->stop, FALSE, FALSE, 0); /* JS button */ t->js_toggle = create_button("JS-Toggle", enable_scripts ? @@ -7651,13 +7660,19 @@ create_new_tab(char *title, struct undo *u, int focus, int position) t->vbox = gtk_vbox_new(FALSE, 0); b = gtk_hbox_new(FALSE, 0); #endif + gtk_widget_set_can_focus(t->vbox, FALSE); /* label + button for tab */ t->tab_content = b; + gtk_widget_set_can_focus(t->tab_content, FALSE); t->user_agent_id = 0; t->http_accept_id = 0; +#if WEBKIT_CHECK_VERSION(1, 5, 0) + t->active = NULL; +#endif + #if GTK_CHECK_VERSION(2, 20, 0) t->spinner = gtk_spinner_new(); #endif @@ -8068,6 +8083,7 @@ create_button(char *name, char *stockid, int size) g_free(newstyle); #endif button = gtk_button_new(); + gtk_widget_set_can_focus(button, FALSE); gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE); gtk_icon_size = icon_size_map(size ? size : icon_size); @@ -8107,6 +8123,7 @@ create_canvas(void) vbox = gtk_vbox_new(FALSE, 0); #endif gtk_box_set_spacing(GTK_BOX(vbox), 0); + gtk_widget_set_can_focus(vbox, FALSE); notebook = GTK_NOTEBOOK(gtk_notebook_new()); #if !GTK_CHECK_VERSION(3, 0, 0) /* XXX seems to be needed with gtk+2 */ @@ -8117,6 +8134,7 @@ create_canvas(void) gtk_widget_set_can_focus(GTK_WIDGET(notebook), FALSE); abtn = gtk_button_new(); + gtk_widget_set_can_focus(abtn, FALSE); arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_widget_set_name(abtn, "Arrow"); gtk_container_add(GTK_CONTAINER(abtn), arrow); diff --git a/xombrero.h b/xombrero.h index 64ac54a..094e3cc 100644 --- a/xombrero.h +++ b/xombrero.h @@ -285,6 +285,12 @@ struct tab { WebKitWebInspector *inspector; GtkWidget *inspector_window; GtkWidget *inspector_view; + + /* focused text entry */ +#if WEBKIT_CHECK_VERSION(1, 5, 0) + WebKitDOMElement *active; + char *active_text; +#endif }; TAILQ_HEAD(tab_list, tab); @@ -566,7 +572,6 @@ int toggle_force_https(struct tab *, struct karg *); /* input autofocus */ void input_autofocus(struct tab *); -void input_focus_blur(struct tab *, void *); void *input_check_mode(struct tab *); int command_mode(struct tab *, struct karg *); |