1 /* Event system support routines. */
16 #include "intl/gettext/libintl.h"
17 #include "main/main.h" /* terminate */
18 #include "main/object.h"
19 #include "session/session.h"
20 #include "terminal/draw.h"
21 #include "terminal/event.h"
22 #include "terminal/kbd.h"
23 #include "terminal/mouse.h"
24 #include "terminal/tab.h"
25 #include "terminal/terminal.h"
26 #include "terminal/screen.h"
27 #include "terminal/window.h"
28 #include "util/conv.h"
29 #include "util/error.h"
30 #include "util/memory.h"
31 #include "util/snprintf.h"
32 #include "util/string.h"
33 #include "viewer/timer.h"
36 /* Information used for communication between ELinks instances */
37 struct terminal_interlink
{
38 /* How big the input queue is and how much is free */
42 /* UTF8 input key value decoding data. */
49 /* This is the queue of events as coming from the other ELinks instance
50 * owning the hosting terminal. */
51 unsigned char input_queue
[1];
56 term_send_event(struct terminal
*term
, struct term_event
*ev
)
61 if_assert_failed
return;
67 int width
= ev
->info
.size
.width
;
68 int height
= ev
->info
.size
.height
;
70 if (width
< 0 || height
< 0) {
71 ERROR(gettext("Bad terminal size: %d, %d"),
76 resize_screen(term
, width
, height
);
81 /* Nasty hack to avoid assertion failures when doing -remote
82 * stuff and the client exits right away */
83 if (!term
->screen
->image
) break;
86 term
->redrawing
= TREDRAW_DELAYED
;
87 /* Note that you do NOT want to ever go and create new
88 * window inside EVENT_INIT handler (it'll get second
89 * EVENT_INIT here). Perhaps the best thing you could do
90 * is registering a bottom-half handler which will open
93 if (ev
->ev
== EVENT_RESIZE
) {
94 /* We want to propagate EVENT_RESIZE even to inactive
95 * tabs! Nothing wrong will get drawn (in the final
96 * result) as the active tab is always the first one,
97 * thus will be drawn last here. Thanks, Witek!
99 foreachback (win
, term
->windows
)
100 win
->handler(win
, ev
);
103 foreachback (win
, term
->windows
)
104 if (!inactive_tab(win
))
105 win
->handler(win
, ev
);
107 term
->redrawing
= TREDRAW_READY
;
113 assert(!list_empty(term
->windows
));
114 if_assert_failed
break;
116 /* We need to send event to correct tab, not to the first one. --karpov */
117 /* ...if we want to send it to a tab at all. --pasky */
118 win
= term
->windows
.next
;
119 if (win
->type
== WINDOW_TAB
) {
120 win
= get_current_tab(term
);
121 assertm(win
, "No tab to send the event to!");
122 if_assert_failed
return;
125 win
->handler(win
, ev
);
130 term_send_ucs(struct terminal
*term
, struct term_event
*ev
, unicode_val_T u
)
132 unsigned char *recoded
;
134 recoded
= u2cp_no_nbsp(u
, get_opt_codepage_tree(term
->spec
, "charset"));
135 if (!recoded
) recoded
= "*";
137 ev
->info
.keyboard
.key
= *recoded
;
138 term_send_event(term
, ev
);
144 check_terminal_name(struct terminal
*term
, struct terminal_info
*info
)
146 unsigned char name
[MAX_TERM_LEN
+ 10];
149 /* We check TERM env. var for sanity, and fallback to _template_ if
150 * needed. This way we prevent elinks.conf potential corruption. */
151 for (i
= 0; info
->name
[i
]; i
++) {
152 if (isident(info
->name
[i
])) continue;
154 usrerror(_("Warning: terminal name contains illicit chars.", term
));
158 snprintf(name
, sizeof(name
), "terminal.%s", info
->name
);
160 /* Unlock the default _template_ option tree that was asigned by
161 * init_term() and get the correct one. */
162 object_unlock(term
->spec
);
163 term
->spec
= get_opt_rec(config_options
, name
);
164 object_lock(term
->spec
);
166 /* Probably not best place for set this. But now we finally have
167 * term->spec and term->utf8 should be set before decode session info.
169 term
->utf8
= get_opt_bool_tree(term
->spec
, "utf_8_io");
170 #endif /* CONFIG_UTF_8 */
175 ignore_mouse_event(struct terminal
*term
, struct term_event
*ev
)
177 struct term_event_mouse
*prev
= &term
->prev_mouse_event
;
178 struct term_event_mouse
*current
= &ev
->info
.mouse
;
180 if (check_mouse_action(ev
, B_UP
)
181 && current
->y
== prev
->y
182 && (current
->button
& ~BM_ACT
) == (prev
->button
& ~BM_ACT
)) {
183 do_not_ignore_next_mouse_event(term
);
188 copy_struct(prev
, current
);
195 handle_interlink_event(struct terminal
*term
, struct term_event
*ev
)
197 struct terminal_info
*info
= NULL
;
198 struct terminal_interlink
*interlink
= term
->interlink
;
202 if (interlink
->qlen
< TERMINAL_INFO_SIZE
)
205 info
= (struct terminal_info
*) ev
;
207 if (interlink
->qlen
< TERMINAL_INFO_SIZE
+ info
->length
)
210 info
->name
[MAX_TERM_LEN
- 1] = 0;
211 check_terminal_name(term
, info
);
213 memcpy(term
->cwd
, info
->cwd
, MAX_CWD_LEN
);
214 term
->cwd
[MAX_CWD_LEN
- 1] = 0;
216 term
->environment
= info
->system_env
;
218 /* We need to make sure that it is possible to draw on the
219 * terminal screen before decoding the session info so that
220 * handling of bad URL syntax by openning msg_box() will be
222 term_send_event(term
, ev
);
224 /* Either the initialization of the first session failed or we
225 * are doing a remote session so quit.*/
226 if (!decode_session_info(term
, info
)) {
227 destroy_terminal(term
);
228 /* Make sure the user is notified if the initialization
229 * of the first session fails. */
230 if (program
.terminate
) {
231 usrerror(_("Failed to create session.", term
));
232 program
.retval
= RET_FATAL
;
237 ev
->ev
= EVENT_REDRAW
;
241 term_send_event(term
, ev
);
247 if (!ignore_mouse_event(term
, ev
))
248 term_send_event(term
, ev
);
256 #endif /* CONFIG_UTF_8 */
257 int key
= get_kbd_key(ev
);
261 if (check_kbd_modifier(ev
, KBD_MOD_CTRL
) && toupper(key
) == 'L') {
262 redraw_terminal_cls(term
);
265 } else if (key
== KBD_CTRL_C
) {
266 destroy_terminal(term
);
270 if (interlink
->utf_8
.len
) {
272 if ((key
& 0xC0) == 0x80 && term
->utf8
)
274 utf8_io
= get_opt_bool_tree(term
->spec
, "utf_8_io");
275 if ((key
& 0xC0) == 0x80 && utf8_io
)
276 #endif /* CONFIG_UTF_8 */
278 interlink
->utf_8
.ucs
<<= 6;
279 interlink
->utf_8
.ucs
|= key
& 0x3F;
280 if (! --interlink
->utf_8
.len
) {
281 unicode_val_T u
= interlink
->utf_8
.ucs
;
283 if (u
< interlink
->utf_8
.min
)
285 term_send_ucs(term
, ev
, u
);
290 interlink
->utf_8
.len
= 0;
291 term_send_ucs(term
, ev
, UCS_NO_CHAR
);
296 if (key
< 0x80 || key
> 0xFF || !term
->utf8
)
298 if (key
< 0x80 || key
> 0xFF
300 ? !get_opt_bool_tree(term
->spec
, "utf_8_io")
302 #endif /* CONFIG_UTF_8 */
304 term_send_event(term
, ev
);
307 } else if ((key
& 0xC0) == 0xC0 && (key
& 0xFE) != 0xFE) {
308 unsigned int mask
, cov
= 0x80;
311 for (mask
= 0x80; key
& mask
; mask
>>= 1) {
313 interlink
->utf_8
.min
= cov
;
314 cov
= 1 << (1 + 5 * len
);
317 interlink
->utf_8
.len
= len
- 1;
318 interlink
->utf_8
.ucs
= key
& (mask
- 1);
322 term_send_ucs(term
, ev
, UCS_NO_CHAR
);
327 destroy_terminal(term
);
331 ERROR(gettext("Bad event %d"), ev
->ev
);
334 /* For EVENT_INIT we read a liitle more */
335 if (info
) return TERMINAL_INFO_SIZE
+ info
->length
;
340 in_term(struct terminal
*term
)
342 struct terminal_interlink
*interlink
= term
->interlink
;
347 || !interlink
->qfreespace
348 || interlink
->qfreespace
- interlink
->qlen
> ALLOC_GR
) {
349 int qlen
= interlink
? interlink
->qlen
: 0;
350 int queuesize
= ((qlen
+ ALLOC_GR
) & ~(ALLOC_GR
- 1));
351 int newsize
= sizeof(*interlink
) + queuesize
;
353 interlink
= mem_realloc(interlink
, newsize
);
355 destroy_terminal(term
);
359 /* Blank the members for the first allocation */
360 if (!term
->interlink
)
361 memset(interlink
, 0, sizeof(*interlink
));
363 term
->interlink
= interlink
;
364 interlink
->qfreespace
= queuesize
- interlink
->qlen
;
367 iq
= interlink
->input_queue
;
368 r
= safe_read(term
->fdin
, iq
+ interlink
->qlen
, interlink
->qfreespace
);
370 if (r
== -1 && errno
!= ECONNRESET
)
371 ERROR(gettext("Could not read event: %d (%s)"),
372 errno
, (unsigned char *) strerror(errno
));
374 destroy_terminal(term
);
378 interlink
->qlen
+= r
;
379 interlink
->qfreespace
-= r
;
381 while (interlink
->qlen
>= sizeof(struct term_event
)) {
382 struct term_event
*ev
= (struct term_event
*) iq
;
383 int event_size
= handle_interlink_event(term
, ev
);
385 /* If the event was not handled save the bytes in the queue for
386 * later in case more stuff is read later. */
387 if (!event_size
) break;
389 /* Acount for the handled bytes */
390 interlink
->qlen
-= event_size
;
391 interlink
->qfreespace
+= event_size
;
393 /* If there are no more bytes to handle stop else move next
394 * event bytes to the front of the queue. */
395 if (!interlink
->qlen
) break;
396 memmove(iq
, iq
+ event_size
, interlink
->qlen
);