1 /** Event system support routines.
17 #include "intl/gettext/libintl.h"
18 #include "main/main.h" /* terminate */
19 #include "main/object.h"
20 #include "session/session.h"
21 #include "terminal/draw.h"
22 #include "terminal/event.h"
23 #include "terminal/kbd.h"
24 #include "terminal/mouse.h"
25 #include "terminal/tab.h"
26 #include "terminal/terminal.h"
27 #include "terminal/screen.h"
28 #include "terminal/window.h"
29 #include "util/conv.h"
30 #include "util/error.h"
31 #include "util/memory.h"
32 #include "util/snprintf.h"
33 #include "util/string.h"
34 #include "viewer/text/textarea.h"
35 #include "viewer/timer.h"
38 /** Information used for communication between ELinks instances */
39 struct terminal_interlink
{
40 /** How big the input queue is */
42 /** How much is free */
45 /** UTF-8 input key value decoding data. */
50 /** Modifier keys from the key event that carried the
51 * first byte of the character. We need this because
52 * ELinks sees e.g. ESC U+00F6 as 0x1B 0xC3 0xB6 and
53 * converts it to Alt-0xC3 0xB6, attaching the
54 * modifier to the first byte only. */
55 term_event_modifier_T modifier
;
58 /** This is the queue of events as coming from the other
59 * ELinks instance owning the hosting terminal. */
60 unsigned char input_queue
[1];
65 term_send_event(struct terminal
*term
, struct term_event
*ev
)
70 if_assert_failed
return;
76 int width
= ev
->info
.size
.width
;
77 int height
= ev
->info
.size
.height
;
79 if (width
< 0 || height
< 0) {
80 ERROR(gettext("Bad terminal size: %d, %d"),
85 resize_screen(term
, width
, height
);
90 /* Nasty hack to avoid assertion failures when doing -remote
91 * stuff and the client exits right away */
92 if (!term
->screen
->image
) break;
95 term
->redrawing
= TREDRAW_DELAYED
;
96 /* Note that you do NOT want to ever go and create new
97 * window inside EVENT_INIT handler (it'll get second
98 * EVENT_INIT here). Perhaps the best thing you could do
99 * is registering a bottom-half handler which will open
100 * additional windows.
102 if (ev
->ev
== EVENT_RESIZE
) {
103 /* We want to propagate EVENT_RESIZE even to inactive
104 * tabs! Nothing wrong will get drawn (in the final
105 * result) as the active tab is always the first one,
106 * thus will be drawn last here. Thanks, Witek!
108 foreachback (win
, term
->windows
)
109 win
->handler(win
, ev
);
112 foreachback (win
, term
->windows
)
113 if (!inactive_tab(win
))
114 win
->handler(win
, ev
);
116 term
->redrawing
= TREDRAW_READY
;
122 assert(!list_empty(term
->windows
));
123 if_assert_failed
break;
125 /* We need to send event to correct tab, not to the first one. --karpov */
126 /* ...if we want to send it to a tab at all. --pasky */
127 win
= term
->windows
.next
;
128 if (win
->type
== WINDOW_TAB
) {
129 win
= get_current_tab(term
);
130 assertm(win
!= NULL
, "No tab to send the event to!");
131 if_assert_failed
return;
134 win
->handler(win
, ev
);
139 term_send_ucs(struct terminal
*term
, unicode_val_T u
,
140 term_event_modifier_T modifier
)
143 struct term_event ev
;
145 set_kbd_term_event(&ev
, u
, modifier
);
146 term_send_event(term
, &ev
);
147 #else /* !CONFIG_UTF8 */
148 struct term_event ev
;
149 const unsigned char *recoded
;
151 set_kbd_term_event(&ev
, KBD_UNDEF
, modifier
);
152 recoded
= u2cp_no_nbsp(u
, get_terminal_codepage(term
));
153 if (!recoded
) recoded
= "*";
155 ev
.info
.keyboard
.key
= *recoded
;
156 term_send_event(term
, &ev
);
159 #endif /* !CONFIG_UTF8 */
163 check_terminal_name(struct terminal
*term
, struct terminal_info
*info
)
165 unsigned char name
[MAX_TERM_LEN
+ 10];
168 /* We check TERM env. var for sanity, and fallback to _template_ if
169 * needed. This way we prevent elinks.conf potential corruption. */
170 for (i
= 0; info
->name
[i
]; i
++) {
171 if (isident(info
->name
[i
])) continue;
173 usrerror(_("Warning: terminal name contains illicit chars.", term
));
177 snprintf(name
, sizeof(name
), "terminal.%s", info
->name
);
179 /* Unlock the default _template_ option tree that was asigned by
180 * init_term() and get the correct one. */
181 object_unlock(term
->spec
);
182 term
->spec
= get_opt_rec(config_options
, name
);
183 object_lock(term
->spec
);
185 /* Probably not best place for set this. But now we finally have
186 * term->spec and term->utf8 should be set before decode session info.
188 term
->utf8_cp
= is_cp_utf8(get_terminal_codepage(term
));
189 /* Force UTF-8 I/O if the UTF-8 charset is selected. Various
190 * places assume that the terminal's charset is unibyte if
191 * UTF-8 I/O is disabled. (bug 827) */
192 term
->utf8_io
= term
->utf8_cp
193 || get_opt_bool_tree(term
->spec
, "utf_8_io", NULL
);
194 #endif /* CONFIG_UTF8 */
199 ignore_mouse_event(struct terminal
*term
, struct term_event
*ev
)
201 struct term_event_mouse
*prev
= &term
->prev_mouse_event
;
202 struct term_event_mouse
*current
= &ev
->info
.mouse
;
204 if (check_mouse_action(ev
, B_UP
)
205 && current
->y
== prev
->y
206 && (current
->button
& ~BM_ACT
) == (prev
->button
& ~BM_ACT
)) {
207 do_not_ignore_next_mouse_event(term
);
212 copy_struct(prev
, current
);
219 handle_interlink_event(struct terminal
*term
, struct interlink_event
*ilev
)
221 struct terminal_info
*info
= NULL
;
222 struct terminal_interlink
*interlink
= term
->interlink
;
223 struct term_event tev
;
227 if (interlink
->qlen
< TERMINAL_INFO_SIZE
)
230 info
= (struct terminal_info
*) ilev
;
232 if (interlink
->qlen
< TERMINAL_INFO_SIZE
+ info
->length
)
235 info
->name
[MAX_TERM_LEN
- 1] = 0;
236 check_terminal_name(term
, info
);
238 memcpy(term
->cwd
, info
->cwd
, MAX_CWD_LEN
);
239 term
->cwd
[MAX_CWD_LEN
- 1] = 0;
241 term
->environment
= info
->system_env
;
243 /* We need to make sure that it is possible to draw on the
244 * terminal screen before decoding the session info so that
245 * handling of bad URL syntax by openning msg_box() will be
247 set_init_term_event(&tev
,
248 ilev
->info
.size
.width
,
249 ilev
->info
.size
.height
);
250 term_send_event(term
, &tev
);
252 /* Either the initialization of the first session failed or we
253 * are doing a remote session so quit.*/
254 if (!decode_session_info(term
, info
)) {
255 destroy_terminal(term
);
256 /* Make sure the user is notified if the initialization
257 * of the first session fails. */
258 if (program
.terminate
) {
259 usrerror(_("Failed to create session.", term
));
260 program
.retval
= RET_FATAL
;
265 ilev
->ev
= EVENT_REDRAW
;
269 set_wh_term_event(&tev
, ilev
->ev
,
270 ilev
->info
.size
.width
,
271 ilev
->info
.size
.height
);
272 term_send_event(term
, &tev
);
274 /* If textarea_data is set and the terminal is not blocked,
275 * then this resize event must be the result of exiting the
276 * external editor. */
277 if (term
->textarea_data
&& term
->blocked
== -1)
278 textarea_edit(1, term
, NULL
, NULL
, NULL
);
286 copy_struct(&tev
.info
.mouse
, &ilev
->info
.mouse
);
287 if (!ignore_mouse_event(term
, &tev
))
288 term_send_event(term
, &tev
);
295 int key
= ilev
->info
.keyboard
.key
;
296 term_event_modifier_T modifier
= ilev
->info
.keyboard
.modifier
;
303 if (key
== KBD_CTRL_C
) {
304 destroy_terminal(term
);
308 /* Character Conversions. */
310 /* struct term_event_keyboard carries UCS-4.
311 * - If the "utf_8_io" option is true or the "charset"
312 * option refers to UTF-8, then term->utf8_io is true,
313 * and handle_interlink_event() converts from UTF-8
315 * - Otherwise, handle_interlink_event() converts from
316 * the codepage specified with the "charset" option
318 utf8_io
= term
->utf8_io
;
320 /* struct term_event_keyboard carries bytes in the
321 * charset of the terminal.
322 * - If the "utf_8_io" option is true, then
323 * handle_interlink_event() converts from UTF-8 to
324 * UCS-4, and term_send_ucs() converts from UCS-4 to
325 * the codepage specified with the "charset" option;
326 * this codepage cannot be UTF-8.
327 * - Otherwise, handle_interlink_event() passes the
328 * bytes straight through. */
329 utf8_io
= get_opt_bool_tree(term
->spec
, "utf_8_io", NULL
);
330 #endif /* CONFIG_UTF8 */
332 /* In UTF-8 byte sequences that have more than one byte, the
333 * first byte is between 0xC0 and 0xFF and the remaining bytes
334 * are between 0x80 and 0xBF. If there is just one byte, then
335 * it is between 0x00 and 0x7F and it is straight ASCII.
336 * (All 'betweens' are inclusive.) */
338 if (interlink
->utf8
.len
) {
339 /* A previous call to handle_interlink_event
340 * got a UTF-8 start byte. */
342 if (key
>= 0x80 && key
<= 0xBF && utf8_io
) {
343 /* This is a UTF-8 continuation byte. */
345 interlink
->utf8
.ucs
<<= 6;
346 interlink
->utf8
.ucs
|= key
& 0x3F;
347 if (! --interlink
->utf8
.len
) {
348 unicode_val_T u
= interlink
->utf8
.ucs
;
350 /* UTF-8 allows neither overlong
351 * sequences nor surrogates. */
352 if (u
< interlink
->utf8
.min
353 || is_utf16_surrogate(u
))
354 u
= UCS_REPLACEMENT_CHARACTER
;
355 term_send_ucs(term
, u
,
356 term
->interlink
->utf8
.modifier
);
361 /* The byte sequence for this character
362 * is ending prematurely. Send
363 * UCS_REPLACEMENT_CHARACTER for the
364 * terminated character, but don't break;
365 * let this byte be handled below. */
367 interlink
->utf8
.len
= 0;
368 term_send_ucs(term
, UCS_REPLACEMENT_CHARACTER
,
369 term
->interlink
->utf8
.modifier
);
373 /* Note: We know that key <= 0xFF. */
375 if (key
< 0x80 || !utf8_io
) {
376 /* This byte is not part of a multibyte character
377 * encoding: either it is outside of the ranges for
378 * UTF-8 start and continuation bytes or UTF-8 I/O mode
382 if (key
>= 0 && !utf8_io
) {
383 /* Not special and UTF-8 mode is disabled:
384 * recode from the terminal charset to UCS-4. */
386 key
= cp2u(get_terminal_codepage(term
), key
);
387 term_send_ucs(term
, key
, modifier
);
390 #endif /* !CONFIG_UTF8 */
392 /* It must be special (e.g., F1 or Enter)
393 * or a single-byte UTF-8 character. */
394 set_kbd_term_event(&tev
, key
, modifier
);
395 term_send_event(term
, &tev
);
398 } else if ((key
& 0xC0) == 0xC0 && (key
& 0xFE) != 0xFE) {
399 /* This is a UTF-8 start byte. */
401 /* Minimum character values for UTF-8 octet
402 * sequences of each length, from RFC 2279.
403 * According to the RFC, UTF-8 decoders should
404 * reject characters that are encoded with
405 * more octets than necessary. (RFC 3629,
406 * which ELinks does not yet otherwise follow,
407 * tightened the "should" to "MUST".) */
408 static const unicode_val_T min
[] = {
409 0x00000080, /* ... 0x000007FF with 2 octets */
410 0x00000800, /* ... 0x0000FFFF with 3 octets */
411 0x00010000, /* ... 0x001FFFFF with 4 octets */
412 0x00200000, /* ... 0x03FFFFFF with 5 octets */
413 0x04000000 /* ... 0x7FFFFFFF with 6 octets */
418 /* Set @len = the number of contiguous 1's
419 * in the most significant bits of the first
420 * octet, i.e. @key. It is also the number
421 * of octets in the character. Leave @mask
422 * pointing to the first 0 bit found. */
423 for (mask
= 0x80; key
& mask
; mask
>>= 1)
426 /* This will hold because @key was checked above. */
427 assert(len
>= 2 && len
<= 6);
428 if_assert_failed
goto invalid_utf8_start_byte
;
430 interlink
->utf8
.min
= min
[len
- 2];
431 interlink
->utf8
.len
= len
- 1;
432 interlink
->utf8
.ucs
= key
& (mask
- 1);
433 interlink
->utf8
.modifier
= modifier
;
437 invalid_utf8_start_byte
:
438 term_send_ucs(term
, UCS_REPLACEMENT_CHARACTER
, modifier
);
443 destroy_terminal(term
);
447 ERROR(gettext("Bad event %d"), ilev
->ev
);
450 /* For EVENT_INIT we read a liitle more */
451 if (info
) return TERMINAL_INFO_SIZE
+ info
->length
;
452 return sizeof(*ilev
);
456 in_term(struct terminal
*term
)
458 struct terminal_interlink
*interlink
= term
->interlink
;
462 /* Mark this as the most recently used terminal. */
463 move_to_top_of_list(terminals
, term
);
466 || !interlink
->qfreespace
467 || interlink
->qfreespace
- interlink
->qlen
> ALLOC_GR
) {
468 int qlen
= interlink
? interlink
->qlen
: 0;
469 int queuesize
= ((qlen
+ ALLOC_GR
) & ~(ALLOC_GR
- 1));
470 int newsize
= sizeof(*interlink
) + queuesize
;
472 interlink
= mem_realloc(interlink
, newsize
);
474 destroy_terminal(term
);
478 /* Blank the members for the first allocation */
479 if (!term
->interlink
)
480 memset(interlink
, 0, sizeof(*interlink
));
482 term
->interlink
= interlink
;
483 interlink
->qfreespace
= queuesize
- interlink
->qlen
;
486 iq
= interlink
->input_queue
;
487 r
= safe_read(term
->fdin
, iq
+ interlink
->qlen
, interlink
->qfreespace
);
489 if (r
== -1 && errno
!= ECONNRESET
)
490 ERROR(gettext("Could not read event: %d (%s)"),
491 errno
, (unsigned char *) strerror(errno
));
493 destroy_terminal(term
);
497 interlink
->qlen
+= r
;
498 interlink
->qfreespace
-= r
;
500 while (interlink
->qlen
>= sizeof(struct interlink_event
)) {
501 struct interlink_event
*ev
= (struct interlink_event
*) iq
;
502 int event_size
= handle_interlink_event(term
, ev
);
504 /* If the event was not handled save the bytes in the queue for
505 * later in case more stuff is read later. */
506 if (!event_size
) break;
508 /* Acount for the handled bytes */
509 interlink
->qlen
-= event_size
;
510 interlink
->qfreespace
+= event_size
;
512 /* If there are no more bytes to handle stop else move next
513 * event bytes to the front of the queue. */
514 if (!interlink
->qlen
) break;
515 memmove(iq
, iq
+ event_size
, interlink
->qlen
);