Prepare for release 1.9.0.
[xxxterm.git] / inputfocus.c
blobfd3650f2d4783d7b28e530a47785b5f64871d3be
1 /*
2 * Copyright (c) 2011 Marco Peereboom <marco@peereboom.us>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "xxxterm.h"
19 #if WEBKIT_CHECK_VERSION(1, 5, 0)
20 /* we got the DOM API we need */
21 int
22 focus_input_document(struct tab *t, WebKitDOMDocument *doc)
24 WebKitDOMNodeList *input = NULL, *textarea = NULL;
25 WebKitDOMNode *n;
26 char *es;
27 int i, rv = 0 /* not found */;
29 WebKitDOMHTMLTextAreaElement *ta;
30 WebKitDOMHTMLInputElement *in;
32 /* we are deliberately ignoring tab index! */
34 /* try input first */
35 input = webkit_dom_document_get_elements_by_tag_name(doc, "input");
36 for (i = 0; i < webkit_dom_node_list_get_length(input); i++) {
37 n = webkit_dom_node_list_item(input, i);
38 in = (WebKitDOMHTMLInputElement*)n;
39 g_object_get(G_OBJECT(in), "type", &es, (char *)NULL);
40 if ((!g_str_equal("text", es) && !g_str_equal("password",es)) ||
41 webkit_dom_html_input_element_get_disabled(in)) {
42 /* skip not text */
43 g_free(es);
44 continue;
46 webkit_dom_element_focus((WebKitDOMElement*)in);
47 g_free(es);
48 rv = 1; /* found */
49 goto done;
52 /* now try textarea */
53 textarea = webkit_dom_document_get_elements_by_tag_name(doc, "textarea");
54 for (i = 0; i < webkit_dom_node_list_get_length(textarea); i++) {
55 n = webkit_dom_node_list_item(textarea, i);
56 ta = (WebKitDOMHTMLTextAreaElement*)n;
57 if (webkit_dom_html_text_area_element_get_disabled(ta)) {
58 /* it is hidden so skip */
59 continue;
61 webkit_dom_element_focus((WebKitDOMElement*)ta);
62 rv = 1; /* found */
63 goto done;
65 done:
66 if (input)
67 g_object_unref(input);
68 if (textarea)
69 g_object_unref(textarea);
71 return (rv);
73 int
74 focus_input(struct tab *t)
76 WebKitDOMDocument *doc;
77 WebKitDOMNode *n;
78 WebKitDOMNodeList *fl = NULL, *ifl = NULL;
79 int i, fl_count, ifl_count, rv = 0;
81 WebKitDOMHTMLFrameElement *frame;
82 WebKitDOMHTMLIFrameElement *iframe;
85 * Here is what we are doing:
86 * See if we got frames or iframes
88 * if we do focus on input or textarea in frame or in iframe
90 * if we find nothing or there are no frames focus on first input or
91 * text area
94 doc = webkit_web_view_get_dom_document(t->wv);
96 /* get frames */
97 fl = webkit_dom_document_get_elements_by_tag_name(doc, "frame");
98 fl_count = webkit_dom_node_list_get_length(fl);
100 /* get iframes */
101 ifl = webkit_dom_document_get_elements_by_tag_name(doc, "iframe");
102 ifl_count = webkit_dom_node_list_get_length(ifl);
104 /* walk frames and look for a text input */
105 for (i = 0; i < fl_count; i++) {
106 n = webkit_dom_node_list_item(fl, i);
107 frame = (WebKitDOMHTMLFrameElement*)n;
108 doc = webkit_dom_html_frame_element_get_content_document(frame);
110 if (focus_input_document(t, doc)) {
111 rv = 1;
112 goto done;
116 /* walk iframes and look for a text input */
117 for (i = 0; i < ifl_count; i++) {
118 n = webkit_dom_node_list_item(ifl, i);
119 iframe = (WebKitDOMHTMLIFrameElement*)n;
120 doc = webkit_dom_html_iframe_element_get_content_document(iframe);
122 if (focus_input_document(t, doc)) {
123 rv = 1;
124 goto done;
128 /* if we made it here nothing got focused so use normal heuristic */
129 if (focus_input_document(t, webkit_web_view_get_dom_document(t->wv))) {
130 rv = 1;
131 goto done;
133 done:
134 if (fl)
135 g_object_unref(fl);
136 if (ifl)
137 g_object_unref(ifl);
139 return (rv);
143 dom_is_input(struct tab *t, WebKitDOMElement **active)
145 WebKitDOMDocument *doc;
146 WebKitDOMElement *a;
148 WebKitDOMHTMLFrameElement *frame;
149 WebKitDOMHTMLIFrameElement *iframe;
151 /* proof positive that OO is stupid */
153 doc = webkit_web_view_get_dom_document(t->wv);
155 /* unwind frames and iframes until the cows come home */
156 for (;;) {
157 a = webkit_dom_html_document_get_active_element(
158 (WebKitDOMHTMLDocument*)doc);
159 if (a == NULL)
160 return (0);
163 * I think this is a total hack because this property isn't
164 * set for textareas or input however, it is set for jquery
165 * textareas that do rich text. Since this works around issues
166 * in RT we'll simply keep it!
168 * This might break some other stuff but for now it helps.
170 if (webkit_dom_html_element_get_is_content_editable(
171 (WebKitDOMHTMLElement*)a)) {
172 *active = a;
173 return (1);
176 frame = (WebKitDOMHTMLFrameElement *)a;
177 if (WEBKIT_DOM_IS_HTML_FRAME_ELEMENT(frame)) {
178 doc = webkit_dom_html_frame_element_get_content_document(
179 frame);
180 continue;
183 iframe = (WebKitDOMHTMLIFrameElement *)a;
184 if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT(iframe)) {
185 doc = webkit_dom_html_iframe_element_get_content_document(
186 iframe);
187 continue;
190 break;
193 if (a == NULL)
194 return (0);
196 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT((WebKitDOMNode *)a) ||
197 WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT((WebKitDOMNode *)a)) {
198 *active = a;
199 return (1);
202 return (0);
205 void *
206 input_check_mode(struct tab *t)
208 WebKitDOMElement *active = NULL;
210 if (dom_is_input(t, &active))
211 t->mode = XT_MODE_INSERT;
212 else
213 t->mode = XT_MODE_COMMAND;
215 return (active);
218 void
219 input_focus_blur(struct tab *t, void *active)
221 /* active is (WebKitDOMElement*) */
222 if (active)
223 webkit_dom_element_blur(active);
227 command_mode(struct tab *t, struct karg *args)
229 WebKitDOMElement *active = NULL;
231 if (args->i == XT_MODE_COMMAND) {
232 if (dom_is_input(t, &active))
233 if (active)
234 webkit_dom_element_blur(active);
235 t->mode = XT_MODE_COMMAND;
236 } else {
237 if (focus_input(t))
238 t->mode = XT_MODE_INSERT;
241 return (XT_CB_HANDLED);
244 void
245 input_autofocus(struct tab *t)
247 WebKitDOMElement *active = NULL;
249 if (autofocus_onload &&
250 t->tab_id == gtk_notebook_get_current_page(notebook)) {
251 if (focus_input(t))
252 t->mode = XT_MODE_INSERT;
253 else
254 t->mode = XT_MODE_COMMAND;
255 } else {
256 if (dom_is_input(t, &active))
257 if (active)
258 webkit_dom_element_blur(active);
259 t->mode = XT_MODE_COMMAND;
262 #else /* WEBKIT_CHECK_VERSION */
263 /* incomplete DOM API */
266 * XXX
267 * note that we can't check the return value of run_script so we
268 * have to assume that the command worked; this may leave you in
269 * insertmode when in fact you shouldn't be
271 void
272 input_autofocus(struct tab *t)
274 if (autofocus_onload &&
275 t->tab_id == gtk_notebook_get_current_page(notebook)) {
276 run_script(t, "hints.focusInput();");
277 t->mode = XT_MODE_INSERT;
278 } else {
279 run_script(t, "hints.clearFocus();");
280 t->mode = XT_MODE_COMMAND;
284 void
285 input_focus_blur(struct tab *t, void *active)
287 run_script(t, "hints.clearFocus();");
288 t->mode = XT_MODE_COMMAND;
291 void *
292 input_check_mode(struct tab *t)
294 return (NULL);
298 command_mode(struct tab *t, struct karg *args)
300 if (args->i == XT_MODE_COMMAND) {
301 run_script(t, "hints.clearFocus();");
302 t->mode = XT_MODE_COMMAND;
303 } else {
304 run_script(t, "hints.focusInput();");
305 t->mode = XT_MODE_INSERT;
308 return (XT_CB_HANDLED);
310 #endif