about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJosh Rickmar <jrick@devio.us>2012-08-14 16:31:15 -0400
committerJosh Rickmar <jrick@devio.us>2012-08-14 16:31:15 -0400
commit8db050048457eeda2a54f782fe4e6f0c5fabeb57 (patch)
treeca044850d4e856eca9c10d4cba9305095de9cd47
parentd53713ed449dc0afe4bf778158f8438b09fdc703 (diff)
downloadxombrero-8db050048457eeda2a54f782fe4e6f0c5fabeb57.tar.gz
Undo the backout of all the inputfocus changes.
We thought these were the cause of the focus bugs, but it was
something else instead.  Now that we have that fixed, these can go
back in.
-rw-r--r--inputfocus.c196
-rw-r--r--xombrero.c36
-rw-r--r--xombrero.h7
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 *);