Merge branch 'obsd-master'
[tmux.git] / server-client.c
blob3bf38627af839fa902b70c020a8dc19a926aa2d7
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/uio.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
30 #include "tmux.h"
32 static void server_client_free(int, short, void *);
33 static void server_client_check_pane_resize(struct window_pane *);
34 static void server_client_check_pane_buffer(struct window_pane *);
35 static void server_client_check_window_resize(struct window *);
36 static key_code server_client_check_mouse(struct client *, struct key_event *);
37 static void server_client_repeat_timer(int, short, void *);
38 static void server_client_click_timer(int, short, void *);
39 static void server_client_check_exit(struct client *);
40 static void server_client_check_redraw(struct client *);
41 static void server_client_check_modes(struct client *);
42 static void server_client_set_title(struct client *);
43 static void server_client_set_path(struct client *);
44 static void server_client_reset_state(struct client *);
45 static void server_client_update_latest(struct client *);
47 static void server_client_dispatch(struct imsg *, void *);
48 static void server_client_dispatch_command(struct client *, struct imsg *);
49 static void server_client_dispatch_identify(struct client *, struct imsg *);
50 static void server_client_dispatch_shell(struct client *);
52 /* Compare client windows. */
53 static int
54 server_client_window_cmp(struct client_window *cw1,
55 struct client_window *cw2)
57 if (cw1->window < cw2->window)
58 return (-1);
59 if (cw1->window > cw2->window)
60 return (1);
61 return (0);
63 RB_GENERATE(client_windows, client_window, entry, server_client_window_cmp);
65 /* Number of attached clients. */
66 u_int
67 server_client_how_many(void)
69 struct client *c;
70 u_int n;
72 n = 0;
73 TAILQ_FOREACH(c, &clients, entry) {
74 if (c->session != NULL && (~c->flags & CLIENT_UNATTACHEDFLAGS))
75 n++;
77 return (n);
80 /* Overlay timer callback. */
81 static void
82 server_client_overlay_timer(__unused int fd, __unused short events, void *data)
84 server_client_clear_overlay(data);
87 /* Set an overlay on client. */
88 void
89 server_client_set_overlay(struct client *c, u_int delay,
90 overlay_check_cb checkcb, overlay_mode_cb modecb,
91 overlay_draw_cb drawcb, overlay_key_cb keycb, overlay_free_cb freecb,
92 overlay_resize_cb resizecb, void *data)
94 struct timeval tv;
96 if (c->overlay_draw != NULL)
97 server_client_clear_overlay(c);
99 tv.tv_sec = delay / 1000;
100 tv.tv_usec = (delay % 1000) * 1000L;
102 if (event_initialized(&c->overlay_timer))
103 evtimer_del(&c->overlay_timer);
104 evtimer_set(&c->overlay_timer, server_client_overlay_timer, c);
105 if (delay != 0)
106 evtimer_add(&c->overlay_timer, &tv);
108 c->overlay_check = checkcb;
109 c->overlay_mode = modecb;
110 c->overlay_draw = drawcb;
111 c->overlay_key = keycb;
112 c->overlay_free = freecb;
113 c->overlay_resize = resizecb;
114 c->overlay_data = data;
116 if (c->overlay_check == NULL)
117 c->tty.flags |= TTY_FREEZE;
118 if (c->overlay_mode == NULL)
119 c->tty.flags |= TTY_NOCURSOR;
120 window_update_focus(c->session->curw->window);
121 server_redraw_client(c);
124 /* Clear overlay mode on client. */
125 void
126 server_client_clear_overlay(struct client *c)
128 if (c->overlay_draw == NULL)
129 return;
131 if (event_initialized(&c->overlay_timer))
132 evtimer_del(&c->overlay_timer);
134 if (c->overlay_free != NULL)
135 c->overlay_free(c, c->overlay_data);
137 c->overlay_check = NULL;
138 c->overlay_mode = NULL;
139 c->overlay_draw = NULL;
140 c->overlay_key = NULL;
141 c->overlay_free = NULL;
142 c->overlay_data = NULL;
144 c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
145 window_update_focus(c->session->curw->window);
146 server_redraw_client(c);
150 * Given overlay position and dimensions, return parts of the input range which
151 * are visible.
153 void
154 server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px,
155 u_int py, u_int nx, struct overlay_ranges *r)
157 u_int ox, onx;
159 /* Return up to 2 ranges. */
160 r->px[2] = 0;
161 r->nx[2] = 0;
163 /* Trivial case of no overlap in the y direction. */
164 if (py < y || py > y + sy - 1) {
165 r->px[0] = px;
166 r->nx[0] = nx;
167 r->px[1] = 0;
168 r->nx[1] = 0;
169 return;
172 /* Visible bit to the left of the popup. */
173 if (px < x) {
174 r->px[0] = px;
175 r->nx[0] = x - px;
176 if (r->nx[0] > nx)
177 r->nx[0] = nx;
178 } else {
179 r->px[0] = 0;
180 r->nx[0] = 0;
183 /* Visible bit to the right of the popup. */
184 ox = x + sx;
185 if (px > ox)
186 ox = px;
187 onx = px + nx;
188 if (onx > ox) {
189 r->px[1] = ox;
190 r->nx[1] = onx - ox;
191 } else {
192 r->px[1] = 0;
193 r->nx[1] = 0;
197 /* Check if this client is inside this server. */
199 server_client_check_nested(struct client *c)
201 struct environ_entry *envent;
202 struct window_pane *wp;
204 envent = environ_find(c->environ, "TMUX");
205 if (envent == NULL || *envent->value == '\0')
206 return (0);
208 RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
209 if (strcmp(wp->tty, c->ttyname) == 0)
210 return (1);
212 return (0);
215 /* Set client key table. */
216 void
217 server_client_set_key_table(struct client *c, const char *name)
219 if (name == NULL)
220 name = server_client_get_key_table(c);
222 key_bindings_unref_table(c->keytable);
223 c->keytable = key_bindings_get_table(name, 1);
224 c->keytable->references++;
225 if (gettimeofday(&c->keytable->activity_time, NULL) != 0)
226 fatal("gettimeofday failed");
229 static uint64_t
230 server_client_key_table_activity_diff(struct client *c)
232 struct timeval diff;
234 timersub(&c->activity_time, &c->keytable->activity_time, &diff);
235 return ((diff.tv_sec * 1000ULL) + (diff.tv_usec / 1000ULL));
238 /* Get default key table. */
239 const char *
240 server_client_get_key_table(struct client *c)
242 struct session *s = c->session;
243 const char *name;
245 if (s == NULL)
246 return ("root");
248 name = options_get_string(s->options, "key-table");
249 if (*name == '\0')
250 return ("root");
251 return (name);
254 /* Is this table the default key table? */
255 static int
256 server_client_is_default_key_table(struct client *c, struct key_table *table)
258 return (strcmp(table->name, server_client_get_key_table(c)) == 0);
261 /* Create a new client. */
262 struct client *
263 server_client_create(int fd)
265 struct client *c;
267 setblocking(fd, 0);
269 c = xcalloc(1, sizeof *c);
270 c->references = 1;
271 c->peer = proc_add_peer(server_proc, fd, server_client_dispatch, c);
273 if (gettimeofday(&c->creation_time, NULL) != 0)
274 fatal("gettimeofday failed");
275 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
277 c->environ = environ_create();
279 c->fd = -1;
280 c->out_fd = -1;
282 c->queue = cmdq_new();
283 RB_INIT(&c->windows);
284 RB_INIT(&c->files);
286 c->tty.sx = 80;
287 c->tty.sy = 24;
289 status_init(c);
290 c->flags |= CLIENT_FOCUSED;
292 c->keytable = key_bindings_get_table("root", 1);
293 c->keytable->references++;
295 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
296 evtimer_set(&c->click_timer, server_client_click_timer, c);
298 TAILQ_INSERT_TAIL(&clients, c, entry);
299 log_debug("new client %p", c);
300 return (c);
303 /* Open client terminal if needed. */
305 server_client_open(struct client *c, char **cause)
307 const char *ttynam = _PATH_TTY;
309 if (c->flags & CLIENT_CONTROL)
310 return (0);
312 if (strcmp(c->ttyname, ttynam) == 0||
313 ((isatty(STDIN_FILENO) &&
314 (ttynam = ttyname(STDIN_FILENO)) != NULL &&
315 strcmp(c->ttyname, ttynam) == 0) ||
316 (isatty(STDOUT_FILENO) &&
317 (ttynam = ttyname(STDOUT_FILENO)) != NULL &&
318 strcmp(c->ttyname, ttynam) == 0) ||
319 (isatty(STDERR_FILENO) &&
320 (ttynam = ttyname(STDERR_FILENO)) != NULL &&
321 strcmp(c->ttyname, ttynam) == 0))) {
322 xasprintf(cause, "can't use %s", c->ttyname);
323 return (-1);
326 if (!(c->flags & CLIENT_TERMINAL)) {
327 *cause = xstrdup("not a terminal");
328 return (-1);
331 if (tty_open(&c->tty, cause) != 0)
332 return (-1);
334 return (0);
337 /* Lost an attached client. */
338 static void
339 server_client_attached_lost(struct client *c)
341 struct session *s;
342 struct window *w;
343 struct client *loop;
344 struct client *found;
346 log_debug("lost attached client %p", c);
349 * By this point the session in the client has been cleared so walk all
350 * windows to find any with this client as the latest.
352 RB_FOREACH(w, windows, &windows) {
353 if (w->latest != c)
354 continue;
356 found = NULL;
357 TAILQ_FOREACH(loop, &clients, entry) {
358 s = loop->session;
359 if (loop == c || s == NULL || s->curw->window != w)
360 continue;
361 if (found == NULL || timercmp(&loop->activity_time,
362 &found->activity_time, >))
363 found = loop;
365 if (found != NULL)
366 server_client_update_latest(found);
370 /* Set client session. */
371 void
372 server_client_set_session(struct client *c, struct session *s)
374 struct session *old = c->session;
376 if (s != NULL && c->session != NULL && c->session != s)
377 c->last_session = c->session;
378 else if (s == NULL)
379 c->last_session = NULL;
380 c->session = s;
381 c->flags |= CLIENT_FOCUSED;
383 if (old != NULL && old->curw != NULL)
384 window_update_focus(old->curw->window);
385 if (s != NULL) {
386 recalculate_sizes();
387 window_update_focus(s->curw->window);
388 session_update_activity(s, NULL);
389 gettimeofday(&s->last_attached_time, NULL);
390 s->curw->flags &= ~WINLINK_ALERTFLAGS;
391 s->curw->window->latest = c;
392 alerts_check_session(s);
393 tty_update_client_offset(c);
394 status_timer_start(c);
395 notify_client("client-session-changed", c);
396 server_redraw_client(c);
399 server_check_unattached();
400 server_update_socket();
403 /* Lost a client. */
404 void
405 server_client_lost(struct client *c)
407 struct client_file *cf, *cf1;
408 struct client_window *cw, *cw1;
410 c->flags |= CLIENT_DEAD;
412 server_client_clear_overlay(c);
413 status_prompt_clear(c);
414 status_message_clear(c);
416 RB_FOREACH_SAFE(cf, client_files, &c->files, cf1) {
417 cf->error = EINTR;
418 file_fire_done(cf);
420 RB_FOREACH_SAFE(cw, client_windows, &c->windows, cw1) {
421 RB_REMOVE(client_windows, &c->windows, cw);
422 free(cw);
425 TAILQ_REMOVE(&clients, c, entry);
426 log_debug("lost client %p", c);
428 if (c->flags & CLIENT_ATTACHED) {
429 server_client_attached_lost(c);
430 notify_client("client-detached", c);
433 if (c->flags & CLIENT_CONTROL)
434 control_stop(c);
435 if (c->flags & CLIENT_TERMINAL)
436 tty_free(&c->tty);
437 free(c->ttyname);
438 free(c->clipboard_panes);
440 free(c->term_name);
441 free(c->term_type);
442 tty_term_free_list(c->term_caps, c->term_ncaps);
444 status_free(c);
446 free(c->title);
447 free((void *)c->cwd);
449 evtimer_del(&c->repeat_timer);
450 evtimer_del(&c->click_timer);
452 key_bindings_unref_table(c->keytable);
454 free(c->message_string);
455 if (event_initialized(&c->message_timer))
456 evtimer_del(&c->message_timer);
458 free(c->prompt_saved);
459 free(c->prompt_string);
460 free(c->prompt_buffer);
462 format_lost_client(c);
463 environ_free(c->environ);
465 proc_remove_peer(c->peer);
466 c->peer = NULL;
468 if (c->out_fd != -1)
469 close(c->out_fd);
470 if (c->fd != -1) {
471 close(c->fd);
472 c->fd = -1;
474 server_client_unref(c);
476 server_add_accept(0); /* may be more file descriptors now */
478 recalculate_sizes();
479 server_check_unattached();
480 server_update_socket();
483 /* Remove reference from a client. */
484 void
485 server_client_unref(struct client *c)
487 log_debug("unref client %p (%d references)", c, c->references);
489 c->references--;
490 if (c->references == 0)
491 event_once(-1, EV_TIMEOUT, server_client_free, c, NULL);
494 /* Free dead client. */
495 static void
496 server_client_free(__unused int fd, __unused short events, void *arg)
498 struct client *c = arg;
500 log_debug("free client %p (%d references)", c, c->references);
502 cmdq_free(c->queue);
504 if (c->references == 0) {
505 free((void *)c->name);
506 free(c);
510 /* Suspend a client. */
511 void
512 server_client_suspend(struct client *c)
514 struct session *s = c->session;
516 if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
517 return;
519 tty_stop_tty(&c->tty);
520 c->flags |= CLIENT_SUSPENDED;
521 proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
524 /* Detach a client. */
525 void
526 server_client_detach(struct client *c, enum msgtype msgtype)
528 struct session *s = c->session;
530 if (s == NULL || (c->flags & CLIENT_NODETACHFLAGS))
531 return;
533 c->flags |= CLIENT_EXIT;
535 c->exit_type = CLIENT_EXIT_DETACH;
536 c->exit_msgtype = msgtype;
537 c->exit_session = xstrdup(s->name);
540 /* Execute command to replace a client. */
541 void
542 server_client_exec(struct client *c, const char *cmd)
544 struct session *s = c->session;
545 char *msg;
546 const char *shell;
547 size_t cmdsize, shellsize;
549 if (*cmd == '\0')
550 return;
551 cmdsize = strlen(cmd) + 1;
553 if (s != NULL)
554 shell = options_get_string(s->options, "default-shell");
555 else
556 shell = options_get_string(global_s_options, "default-shell");
557 if (!checkshell(shell))
558 shell = _PATH_BSHELL;
559 shellsize = strlen(shell) + 1;
561 msg = xmalloc(cmdsize + shellsize);
562 memcpy(msg, cmd, cmdsize);
563 memcpy(msg + cmdsize, shell, shellsize);
565 proc_send(c->peer, MSG_EXEC, -1, msg, cmdsize + shellsize);
566 free(msg);
569 /* Check for mouse keys. */
570 static key_code
571 server_client_check_mouse(struct client *c, struct key_event *event)
573 struct mouse_event *m = &event->m;
574 struct session *s = c->session, *fs;
575 struct options *wo = s->curw->window->options;
576 struct winlink *fwl;
577 struct window_pane *wp, *fwp;
578 u_int x, y, b, sx, sy, px, py, line = 0, sb_pos;
579 u_int sl_top, sl_bottom, sl_mpos = 0;
580 int ignore = 0, sb, sb_w, sb_pad, pane_status;
581 key_code key;
582 struct timeval tv;
583 struct style_range *sr;
584 enum { NOTYPE,
585 MOVE,
586 DOWN,
588 DRAG,
589 WHEEL,
590 SECOND,
591 DOUBLE,
592 TRIPLE } type = NOTYPE;
593 enum { NOWHERE,
594 PANE,
595 STATUS,
596 STATUS_LEFT,
597 STATUS_RIGHT,
598 STATUS_DEFAULT,
599 BORDER,
600 SCROLLBAR_UP,
601 SCROLLBAR_SLIDER,
602 SCROLLBAR_DOWN } where = NOWHERE;
604 log_debug("%s mouse %02x at %u,%u (last %u,%u) (%d)", c->name, m->b,
605 m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag);
607 /* What type of event is this? */
608 if (event->key == KEYC_DOUBLECLICK) {
609 type = DOUBLE;
610 x = m->x, y = m->y, b = m->b;
611 ignore = 1;
612 log_debug("double-click at %u,%u", x, y);
613 } else if ((m->sgr_type != ' ' &&
614 MOUSE_DRAG(m->sgr_b) &&
615 MOUSE_RELEASE(m->sgr_b)) ||
616 (m->sgr_type == ' ' &&
617 MOUSE_DRAG(m->b) &&
618 MOUSE_RELEASE(m->b) &&
619 MOUSE_RELEASE(m->lb))) {
620 type = MOVE;
621 x = m->x, y = m->y, b = 0;
622 log_debug("move at %u,%u", x, y);
623 } else if (MOUSE_DRAG(m->b)) {
624 type = DRAG;
625 if (c->tty.mouse_drag_flag) {
626 x = m->x, y = m->y, b = m->b;
627 if (x == m->lx && y == m->ly)
628 return (KEYC_UNKNOWN);
629 log_debug("drag update at %u,%u", x, y);
630 } else {
631 x = m->lx, y = m->ly, b = m->lb;
632 log_debug("drag start at %u,%u", x, y);
634 } else if (MOUSE_WHEEL(m->b)) {
635 type = WHEEL;
636 x = m->x, y = m->y, b = m->b;
637 log_debug("wheel at %u,%u", x, y);
638 } else if (MOUSE_RELEASE(m->b)) {
639 type = UP;
640 x = m->x, y = m->y, b = m->lb;
641 if (m->sgr_type == 'm')
642 b = m->sgr_b;
643 log_debug("up at %u,%u", x, y);
644 } else {
645 if (c->flags & CLIENT_DOUBLECLICK) {
646 evtimer_del(&c->click_timer);
647 c->flags &= ~CLIENT_DOUBLECLICK;
648 if (m->b == c->click_button) {
649 type = SECOND;
650 x = m->x, y = m->y, b = m->b;
651 log_debug("second-click at %u,%u", x, y);
652 c->flags |= CLIENT_TRIPLECLICK;
654 } else if (c->flags & CLIENT_TRIPLECLICK) {
655 evtimer_del(&c->click_timer);
656 c->flags &= ~CLIENT_TRIPLECLICK;
657 if (m->b == c->click_button) {
658 type = TRIPLE;
659 x = m->x, y = m->y, b = m->b;
660 log_debug("triple-click at %u,%u", x, y);
661 goto have_event;
665 /* DOWN is the only remaining event type. */
666 if (type == NOTYPE) {
667 type = DOWN;
668 x = m->x, y = m->y, b = m->b;
669 log_debug("down at %u,%u", x, y);
670 c->flags |= CLIENT_DOUBLECLICK;
673 if (KEYC_CLICK_TIMEOUT != 0) {
674 memcpy(&c->click_event, m, sizeof c->click_event);
675 c->click_button = m->b;
677 log_debug("click timer started");
678 tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000;
679 tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L;
680 evtimer_del(&c->click_timer);
681 evtimer_add(&c->click_timer, &tv);
685 have_event:
686 if (type == NOTYPE)
687 return (KEYC_UNKNOWN);
689 /* Save the session. */
690 m->s = s->id;
691 m->w = -1;
692 m->wp = -1;
693 m->ignore = ignore;
695 /* Is this on the status line? */
696 m->statusat = status_at_line(c);
697 m->statuslines = status_line_size(c);
698 if (m->statusat != -1 &&
699 y >= (u_int)m->statusat &&
700 y < m->statusat + m->statuslines) {
701 sr = status_get_range(c, x, y - m->statusat);
702 if (sr == NULL) {
703 where = STATUS_DEFAULT;
704 } else {
705 switch (sr->type) {
706 case STYLE_RANGE_NONE:
707 return (KEYC_UNKNOWN);
708 case STYLE_RANGE_LEFT:
709 log_debug("mouse range: left");
710 where = STATUS_LEFT;
711 break;
712 case STYLE_RANGE_RIGHT:
713 log_debug("mouse range: right");
714 where = STATUS_RIGHT;
715 break;
716 case STYLE_RANGE_PANE:
717 fwp = window_pane_find_by_id(sr->argument);
718 if (fwp == NULL)
719 return (KEYC_UNKNOWN);
720 m->wp = sr->argument;
722 log_debug("mouse range: pane %%%u", m->wp);
723 where = STATUS;
724 break;
725 case STYLE_RANGE_WINDOW:
726 fwl = winlink_find_by_index(&s->windows,
727 sr->argument);
728 if (fwl == NULL)
729 return (KEYC_UNKNOWN);
730 m->w = fwl->window->id;
732 log_debug("mouse range: window @%u", m->w);
733 where = STATUS;
734 break;
735 case STYLE_RANGE_SESSION:
736 fs = session_find_by_id(sr->argument);
737 if (fs == NULL)
738 return (KEYC_UNKNOWN);
739 m->s = sr->argument;
741 log_debug("mouse range: session $%u", m->s);
742 where = STATUS;
743 break;
744 case STYLE_RANGE_USER:
745 where = STATUS;
746 break;
752 * Not on status line. Adjust position and check for border, pane, or
753 * scrollbar.
755 if (where == NOWHERE) {
756 if (c->tty.mouse_scrolling_flag)
757 where = SCROLLBAR_SLIDER;
758 else {
759 px = x;
760 if (m->statusat == 0 && y >= m->statuslines)
761 py = y - m->statuslines;
762 else if (m->statusat > 0 && y >= (u_int)m->statusat)
763 py = m->statusat - 1;
764 else
765 py = y;
767 tty_window_offset(&c->tty, &m->ox, &m->oy, &sx, &sy);
768 log_debug("mouse window @%u at %u,%u (%ux%u)",
769 s->curw->window->id, m->ox, m->oy, sx, sy);
770 if (px > sx || py > sy)
771 return (KEYC_UNKNOWN);
772 px = px + m->ox;
773 py = py + m->oy;
775 /* Try inside the pane. */
776 wp = window_get_active_at(s->curw->window, px, py);
777 if (wp == NULL)
778 return (KEYC_UNKNOWN);
780 /* Try the scrollbar next to a pane. */
781 sb = options_get_number(wo, "pane-scrollbars");
782 sb_pos = options_get_number(wo,
783 "pane-scrollbars-position");
784 if (window_pane_show_scrollbar(wp, sb)) {
785 sb_w = wp->scrollbar_style.width;
786 sb_pad = wp->scrollbar_style.pad;
787 } else {
788 sb_w = 0;
789 sb_pad = 0;
791 pane_status = options_get_number(wo,
792 "pane-border-status");
793 if (pane_status == PANE_STATUS_TOP)
794 line = wp->yoff - 1;
795 else if (pane_status == PANE_STATUS_BOTTOM)
796 line = wp->yoff + wp->sy;
799 * Check if py could lie within a scrollbar
800 * (but not within the padding). If the pane is
801 * at the top, then py is 0; if not then the
802 * top, then yoff to yoff + sy.
804 if ((pane_status != PANE_STATUS_OFF && py != line) ||
805 (wp->yoff == 0 && py < wp->sy) ||
806 (py >= wp->yoff && py < wp->yoff + wp->sy)) {
807 sb_pos = options_get_number(wo,
808 "pane-scrollbars-position");
809 if ((sb_pos == PANE_SCROLLBARS_RIGHT &&
810 (px >= wp->xoff + wp->sx + sb_pad &&
811 px < wp->xoff + wp->sx + sb_pad + sb_w)) ||
812 (sb_pos == PANE_SCROLLBARS_LEFT &&
813 (px >= wp->xoff - sb_pad - sb_w &&
814 px < wp->xoff - sb_pad))) {
815 sl_top = wp->yoff + wp->sb_slider_y;
816 sl_bottom = (wp->yoff +
817 wp->sb_slider_y +
818 wp->sb_slider_h - 1);
819 if (py < sl_top)
820 where = SCROLLBAR_UP;
821 else if (py >= sl_top &&
822 py <= sl_bottom) {
823 where = SCROLLBAR_SLIDER;
824 sl_mpos = (py -
825 wp->sb_slider_y - wp->yoff);
826 } else /* py > sl_bottom */
827 where = SCROLLBAR_DOWN;
828 } else
829 where = PANE;
830 } else {
831 /* Try the pane borders if not zoomed. */
832 if (~s->curw->window->flags & WINDOW_ZOOMED) {
833 TAILQ_FOREACH(wp,
834 &s->curw->window->panes, entry) {
835 if ((wp->xoff + wp->sx == px &&
836 wp->yoff <= 1 + py &&
837 wp->yoff + wp->sy >= py) ||
838 (wp->yoff + wp->sy == py &&
839 wp->xoff <= 1 + px &&
840 wp->xoff + wp->sx >= px))
841 break;
843 if (wp != NULL)
844 where = BORDER;
847 if (where == PANE) {
848 log_debug("mouse %u,%u on pane %%%u", x, y,
849 wp->id);
850 } else if (where == BORDER)
851 log_debug("mouse on pane %%%u border", wp->id);
852 else if (where == SCROLLBAR_UP ||
853 where == SCROLLBAR_SLIDER ||
854 where == SCROLLBAR_DOWN) {
855 log_debug("mouse on pane %%%u scrollbar",
856 wp->id);
858 m->wp = wp->id;
859 m->w = wp->window->id;
861 } else
862 m->wp = -1;
864 /* Stop dragging if needed. */
865 if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) {
866 if (c->tty.mouse_drag_release != NULL)
867 c->tty.mouse_drag_release(c, m);
869 c->tty.mouse_drag_update = NULL;
870 c->tty.mouse_drag_release = NULL;
871 c->tty.mouse_scrolling_flag = 0;
874 * End a mouse drag by passing a MouseDragEnd key corresponding
875 * to the button that started the drag.
877 switch (c->tty.mouse_drag_flag - 1) {
878 case MOUSE_BUTTON_1:
879 if (where == PANE)
880 key = KEYC_MOUSEDRAGEND1_PANE;
881 if (where == STATUS)
882 key = KEYC_MOUSEDRAGEND1_STATUS;
883 if (where == STATUS_LEFT)
884 key = KEYC_MOUSEDRAGEND1_STATUS_LEFT;
885 if (where == STATUS_RIGHT)
886 key = KEYC_MOUSEDRAGEND1_STATUS_RIGHT;
887 if (where == STATUS_DEFAULT)
888 key = KEYC_MOUSEDRAGEND1_STATUS_DEFAULT;
889 if (where == SCROLLBAR_SLIDER)
890 key = KEYC_MOUSEDRAGEND1_SCROLLBAR_SLIDER;
891 if (where == BORDER)
892 key = KEYC_MOUSEDRAGEND1_BORDER;
893 break;
894 case MOUSE_BUTTON_2:
895 if (where == PANE)
896 key = KEYC_MOUSEDRAGEND2_PANE;
897 if (where == STATUS)
898 key = KEYC_MOUSEDRAGEND2_STATUS;
899 if (where == STATUS_LEFT)
900 key = KEYC_MOUSEDRAGEND2_STATUS_LEFT;
901 if (where == STATUS_RIGHT)
902 key = KEYC_MOUSEDRAGEND2_STATUS_RIGHT;
903 if (where == STATUS_DEFAULT)
904 key = KEYC_MOUSEDRAGEND2_STATUS_DEFAULT;
905 if (where == SCROLLBAR_SLIDER)
906 key = KEYC_MOUSEDRAGEND2_SCROLLBAR_SLIDER;
907 if (where == BORDER)
908 key = KEYC_MOUSEDRAGEND2_BORDER;
909 break;
910 case MOUSE_BUTTON_3:
911 if (where == PANE)
912 key = KEYC_MOUSEDRAGEND3_PANE;
913 if (where == STATUS)
914 key = KEYC_MOUSEDRAGEND3_STATUS;
915 if (where == STATUS_LEFT)
916 key = KEYC_MOUSEDRAGEND3_STATUS_LEFT;
917 if (where == STATUS_RIGHT)
918 key = KEYC_MOUSEDRAGEND3_STATUS_RIGHT;
919 if (where == STATUS_DEFAULT)
920 key = KEYC_MOUSEDRAGEND3_STATUS_DEFAULT;
921 if (where == SCROLLBAR_SLIDER)
922 key = KEYC_MOUSEDRAGEND3_SCROLLBAR_SLIDER;
923 if (where == BORDER)
924 key = KEYC_MOUSEDRAGEND3_BORDER;
925 break;
926 case MOUSE_BUTTON_6:
927 if (where == PANE)
928 key = KEYC_MOUSEDRAGEND6_PANE;
929 if (where == STATUS)
930 key = KEYC_MOUSEDRAGEND6_STATUS;
931 if (where == STATUS_LEFT)
932 key = KEYC_MOUSEDRAGEND6_STATUS_LEFT;
933 if (where == STATUS_RIGHT)
934 key = KEYC_MOUSEDRAGEND6_STATUS_RIGHT;
935 if (where == STATUS_DEFAULT)
936 key = KEYC_MOUSEDRAGEND6_STATUS_DEFAULT;
937 if (where == SCROLLBAR_SLIDER)
938 key = KEYC_MOUSEDRAGEND6_SCROLLBAR_SLIDER;
939 if (where == BORDER)
940 key = KEYC_MOUSEDRAGEND6_BORDER;
941 break;
942 case MOUSE_BUTTON_7:
943 if (where == PANE)
944 key = KEYC_MOUSEDRAGEND7_PANE;
945 if (where == STATUS)
946 key = KEYC_MOUSEDRAGEND7_STATUS;
947 if (where == STATUS_LEFT)
948 key = KEYC_MOUSEDRAGEND7_STATUS_LEFT;
949 if (where == STATUS_RIGHT)
950 key = KEYC_MOUSEDRAGEND7_STATUS_RIGHT;
951 if (where == STATUS_DEFAULT)
952 key = KEYC_MOUSEDRAGEND7_STATUS_DEFAULT;
953 if (where == SCROLLBAR_SLIDER)
954 key = KEYC_MOUSEDRAGEND7_SCROLLBAR_SLIDER;
955 if (where == BORDER)
956 key = KEYC_MOUSEDRAGEND7_BORDER;
957 break;
958 case MOUSE_BUTTON_8:
959 if (where == PANE)
960 key = KEYC_MOUSEDRAGEND8_PANE;
961 if (where == STATUS)
962 key = KEYC_MOUSEDRAGEND8_STATUS;
963 if (where == STATUS_LEFT)
964 key = KEYC_MOUSEDRAGEND8_STATUS_LEFT;
965 if (where == STATUS_RIGHT)
966 key = KEYC_MOUSEDRAGEND8_STATUS_RIGHT;
967 if (where == STATUS_DEFAULT)
968 key = KEYC_MOUSEDRAGEND8_STATUS_DEFAULT;
969 if (where == SCROLLBAR_SLIDER)
970 key = KEYC_MOUSEDRAGEND8_SCROLLBAR_SLIDER;
971 if (where == BORDER)
972 key = KEYC_MOUSEDRAGEND8_BORDER;
973 break;
974 case MOUSE_BUTTON_9:
975 if (where == PANE)
976 key = KEYC_MOUSEDRAGEND9_PANE;
977 if (where == STATUS)
978 key = KEYC_MOUSEDRAGEND9_STATUS;
979 if (where == STATUS_LEFT)
980 key = KEYC_MOUSEDRAGEND9_STATUS_LEFT;
981 if (where == STATUS_RIGHT)
982 key = KEYC_MOUSEDRAGEND9_STATUS_RIGHT;
983 if (where == STATUS_DEFAULT)
984 key = KEYC_MOUSEDRAGEND9_STATUS_DEFAULT;
985 if (where == SCROLLBAR_SLIDER)
986 key = KEYC_MOUSEDRAGEND9_SCROLLBAR_SLIDER;
987 if (where == BORDER)
988 key = KEYC_MOUSEDRAGEND9_BORDER;
989 break;
990 case MOUSE_BUTTON_10:
991 if (where == PANE)
992 key = KEYC_MOUSEDRAGEND10_PANE;
993 if (where == STATUS)
994 key = KEYC_MOUSEDRAGEND10_STATUS;
995 if (where == STATUS_LEFT)
996 key = KEYC_MOUSEDRAGEND10_STATUS_LEFT;
997 if (where == STATUS_RIGHT)
998 key = KEYC_MOUSEDRAGEND10_STATUS_RIGHT;
999 if (where == STATUS_DEFAULT)
1000 key = KEYC_MOUSEDRAGEND10_STATUS_DEFAULT;
1001 if (where == SCROLLBAR_SLIDER)
1002 key = KEYC_MOUSEDRAGEND10_SCROLLBAR_SLIDER;
1003 if (where == BORDER)
1004 key = KEYC_MOUSEDRAGEND10_BORDER;
1005 break;
1006 case MOUSE_BUTTON_11:
1007 if (where == PANE)
1008 key = KEYC_MOUSEDRAGEND11_PANE;
1009 if (where == STATUS)
1010 key = KEYC_MOUSEDRAGEND11_STATUS;
1011 if (where == STATUS_LEFT)
1012 key = KEYC_MOUSEDRAGEND11_STATUS_LEFT;
1013 if (where == STATUS_RIGHT)
1014 key = KEYC_MOUSEDRAGEND11_STATUS_RIGHT;
1015 if (where == STATUS_DEFAULT)
1016 key = KEYC_MOUSEDRAGEND11_STATUS_DEFAULT;
1017 if (where == SCROLLBAR_SLIDER)
1018 key = KEYC_MOUSEDRAGEND11_SCROLLBAR_SLIDER;
1019 if (where == BORDER)
1020 key = KEYC_MOUSEDRAGEND11_BORDER;
1021 break;
1022 default:
1023 key = KEYC_MOUSE;
1024 break;
1026 c->tty.mouse_drag_flag = 0;
1027 c->tty.mouse_slider_mpos = -1;
1028 goto out;
1031 /* Convert to a key binding. */
1032 key = KEYC_UNKNOWN;
1033 switch (type) {
1034 case NOTYPE:
1035 break;
1036 case MOVE:
1037 if (where == PANE)
1038 key = KEYC_MOUSEMOVE_PANE;
1039 if (where == STATUS)
1040 key = KEYC_MOUSEMOVE_STATUS;
1041 if (where == STATUS_LEFT)
1042 key = KEYC_MOUSEMOVE_STATUS_LEFT;
1043 if (where == STATUS_RIGHT)
1044 key = KEYC_MOUSEMOVE_STATUS_RIGHT;
1045 if (where == STATUS_DEFAULT)
1046 key = KEYC_MOUSEMOVE_STATUS_DEFAULT;
1047 if (where == BORDER)
1048 key = KEYC_MOUSEMOVE_BORDER;
1049 break;
1050 case DRAG:
1051 if (c->tty.mouse_drag_update != NULL)
1052 key = KEYC_DRAGGING;
1053 else {
1054 switch (MOUSE_BUTTONS(b)) {
1055 case MOUSE_BUTTON_1:
1056 if (where == PANE)
1057 key = KEYC_MOUSEDRAG1_PANE;
1058 if (where == STATUS)
1059 key = KEYC_MOUSEDRAG1_STATUS;
1060 if (where == STATUS_LEFT)
1061 key = KEYC_MOUSEDRAG1_STATUS_LEFT;
1062 if (where == STATUS_RIGHT)
1063 key = KEYC_MOUSEDRAG1_STATUS_RIGHT;
1064 if (where == STATUS_DEFAULT)
1065 key = KEYC_MOUSEDRAG1_STATUS_DEFAULT;
1066 if (where == SCROLLBAR_UP)
1067 key = KEYC_MOUSEDRAG1_SCROLLBAR_UP;
1068 if (where == SCROLLBAR_SLIDER)
1069 key = KEYC_MOUSEDRAG1_SCROLLBAR_SLIDER;
1070 if (where == SCROLLBAR_DOWN)
1071 key = KEYC_MOUSEDRAG1_SCROLLBAR_DOWN;
1072 if (where == BORDER)
1073 key = KEYC_MOUSEDRAG1_BORDER;
1074 break;
1075 case MOUSE_BUTTON_2:
1076 if (where == PANE)
1077 key = KEYC_MOUSEDRAG2_PANE;
1078 if (where == STATUS)
1079 key = KEYC_MOUSEDRAG2_STATUS;
1080 if (where == STATUS_LEFT)
1081 key = KEYC_MOUSEDRAG2_STATUS_LEFT;
1082 if (where == STATUS_RIGHT)
1083 key = KEYC_MOUSEDRAG2_STATUS_RIGHT;
1084 if (where == STATUS_DEFAULT)
1085 key = KEYC_MOUSEDRAG2_STATUS_DEFAULT;
1086 if (where == SCROLLBAR_UP)
1087 key = KEYC_MOUSEDRAG2_SCROLLBAR_UP;
1088 if (where == SCROLLBAR_SLIDER)
1089 key = KEYC_MOUSEDRAG2_SCROLLBAR_SLIDER;
1090 if (where == SCROLLBAR_DOWN)
1091 key = KEYC_MOUSEDRAG2_SCROLLBAR_DOWN;
1092 if (where == BORDER)
1093 key = KEYC_MOUSEDRAG2_BORDER;
1094 break;
1095 case MOUSE_BUTTON_3:
1096 if (where == PANE)
1097 key = KEYC_MOUSEDRAG3_PANE;
1098 if (where == STATUS)
1099 key = KEYC_MOUSEDRAG3_STATUS;
1100 if (where == STATUS_LEFT)
1101 key = KEYC_MOUSEDRAG3_STATUS_LEFT;
1102 if (where == STATUS_RIGHT)
1103 key = KEYC_MOUSEDRAG3_STATUS_RIGHT;
1104 if (where == STATUS_DEFAULT)
1105 key = KEYC_MOUSEDRAG3_STATUS_DEFAULT;
1106 if (where == SCROLLBAR_UP)
1107 key = KEYC_MOUSEDRAG3_SCROLLBAR_UP;
1108 if (where == SCROLLBAR_SLIDER)
1109 key = KEYC_MOUSEDRAG3_SCROLLBAR_SLIDER;
1110 if (where == SCROLLBAR_DOWN)
1111 key = KEYC_MOUSEDRAG3_SCROLLBAR_DOWN;
1112 if (where == BORDER)
1113 key = KEYC_MOUSEDRAG3_BORDER;
1114 break;
1115 case MOUSE_BUTTON_6:
1116 if (where == PANE)
1117 key = KEYC_MOUSEDRAG6_PANE;
1118 if (where == STATUS)
1119 key = KEYC_MOUSEDRAG6_STATUS;
1120 if (where == STATUS_LEFT)
1121 key = KEYC_MOUSEDRAG6_STATUS_LEFT;
1122 if (where == STATUS_RIGHT)
1123 key = KEYC_MOUSEDRAG6_STATUS_RIGHT;
1124 if (where == STATUS_DEFAULT)
1125 key = KEYC_MOUSEDRAG6_STATUS_DEFAULT;
1126 if (where == SCROLLBAR_UP)
1127 key = KEYC_MOUSEDRAG6_SCROLLBAR_UP;
1128 if (where == SCROLLBAR_SLIDER)
1129 key = KEYC_MOUSEDRAG6_SCROLLBAR_SLIDER;
1130 if (where == SCROLLBAR_DOWN)
1131 key = KEYC_MOUSEDRAG6_SCROLLBAR_DOWN;
1132 if (where == BORDER)
1133 key = KEYC_MOUSEDRAG6_BORDER;
1134 break;
1135 case MOUSE_BUTTON_7:
1136 if (where == PANE)
1137 key = KEYC_MOUSEDRAG7_PANE;
1138 if (where == STATUS)
1139 key = KEYC_MOUSEDRAG7_STATUS;
1140 if (where == STATUS_LEFT)
1141 key = KEYC_MOUSEDRAG7_STATUS_LEFT;
1142 if (where == STATUS_RIGHT)
1143 key = KEYC_MOUSEDRAG7_STATUS_RIGHT;
1144 if (where == STATUS_DEFAULT)
1145 key = KEYC_MOUSEDRAG7_STATUS_DEFAULT;
1146 if (where == SCROLLBAR_UP)
1147 key = KEYC_MOUSEDRAG7_SCROLLBAR_UP;
1148 if (where == SCROLLBAR_SLIDER)
1149 key = KEYC_MOUSEDRAG7_SCROLLBAR_SLIDER;
1150 if (where == SCROLLBAR_DOWN)
1151 key = KEYC_MOUSEDRAG7_SCROLLBAR_DOWN;
1152 if (where == BORDER)
1153 key = KEYC_MOUSEDRAG7_BORDER;
1154 break;
1155 case MOUSE_BUTTON_8:
1156 if (where == PANE)
1157 key = KEYC_MOUSEDRAG8_PANE;
1158 if (where == STATUS)
1159 key = KEYC_MOUSEDRAG8_STATUS;
1160 if (where == STATUS_LEFT)
1161 key = KEYC_MOUSEDRAG8_STATUS_LEFT;
1162 if (where == STATUS_RIGHT)
1163 key = KEYC_MOUSEDRAG8_STATUS_RIGHT;
1164 if (where == STATUS_DEFAULT)
1165 key = KEYC_MOUSEDRAG8_STATUS_DEFAULT;
1166 if (where == SCROLLBAR_UP)
1167 key = KEYC_MOUSEDRAG8_SCROLLBAR_UP;
1168 if (where == SCROLLBAR_SLIDER)
1169 key = KEYC_MOUSEDRAG8_SCROLLBAR_SLIDER;
1170 if (where == SCROLLBAR_DOWN)
1171 key = KEYC_MOUSEDRAG8_SCROLLBAR_DOWN;
1172 if (where == BORDER)
1173 key = KEYC_MOUSEDRAG8_BORDER;
1174 break;
1175 case MOUSE_BUTTON_9:
1176 if (where == PANE)
1177 key = KEYC_MOUSEDRAG9_PANE;
1178 if (where == STATUS)
1179 key = KEYC_MOUSEDRAG9_STATUS;
1180 if (where == STATUS_LEFT)
1181 key = KEYC_MOUSEDRAG9_STATUS_LEFT;
1182 if (where == STATUS_RIGHT)
1183 key = KEYC_MOUSEDRAG9_STATUS_RIGHT;
1184 if (where == STATUS_DEFAULT)
1185 key = KEYC_MOUSEDRAG9_STATUS_DEFAULT;
1186 if (where == SCROLLBAR_UP)
1187 key = KEYC_MOUSEDRAG9_SCROLLBAR_UP;
1188 if (where == SCROLLBAR_SLIDER)
1189 key = KEYC_MOUSEDRAG9_SCROLLBAR_SLIDER;
1190 if (where == SCROLLBAR_DOWN)
1191 key = KEYC_MOUSEDRAG9_SCROLLBAR_DOWN;
1192 if (where == BORDER)
1193 key = KEYC_MOUSEDRAG9_BORDER;
1194 break;
1195 case MOUSE_BUTTON_10:
1196 if (where == PANE)
1197 key = KEYC_MOUSEDRAG10_PANE;
1198 if (where == STATUS)
1199 key = KEYC_MOUSEDRAG10_STATUS;
1200 if (where == STATUS_LEFT)
1201 key = KEYC_MOUSEDRAG10_STATUS_LEFT;
1202 if (where == STATUS_RIGHT)
1203 key = KEYC_MOUSEDRAG10_STATUS_RIGHT;
1204 if (where == STATUS_DEFAULT)
1205 key = KEYC_MOUSEDRAG10_STATUS_DEFAULT;
1206 if (where == SCROLLBAR_UP)
1207 key = KEYC_MOUSEDRAG10_SCROLLBAR_UP;
1208 if (where == SCROLLBAR_SLIDER)
1209 key = KEYC_MOUSEDRAG10_SCROLLBAR_SLIDER;
1210 if (where == SCROLLBAR_DOWN)
1211 key = KEYC_MOUSEDRAG10_SCROLLBAR_DOWN;
1212 if (where == BORDER)
1213 key = KEYC_MOUSEDRAG10_BORDER;
1214 break;
1215 case MOUSE_BUTTON_11:
1216 if (where == PANE)
1217 key = KEYC_MOUSEDRAG11_PANE;
1218 if (where == STATUS)
1219 key = KEYC_MOUSEDRAG11_STATUS;
1220 if (where == STATUS_LEFT)
1221 key = KEYC_MOUSEDRAG11_STATUS_LEFT;
1222 if (where == STATUS_RIGHT)
1223 key = KEYC_MOUSEDRAG11_STATUS_RIGHT;
1224 if (where == STATUS_DEFAULT)
1225 key = KEYC_MOUSEDRAG11_STATUS_DEFAULT;
1226 if (where == SCROLLBAR_UP)
1227 key = KEYC_MOUSEDRAG11_SCROLLBAR_UP;
1228 if (where == SCROLLBAR_SLIDER)
1229 key = KEYC_MOUSEDRAG11_SCROLLBAR_SLIDER;
1230 if (where == SCROLLBAR_DOWN)
1231 key = KEYC_MOUSEDRAG11_SCROLLBAR_DOWN;
1232 if (where == BORDER)
1233 key = KEYC_MOUSEDRAG11_BORDER;
1234 break;
1239 * Begin a drag by setting the flag to a non-zero value that
1240 * corresponds to the mouse button in use. If starting to drag
1241 * the scrollbar, store the relative position in the slider
1242 * where the user grabbed.
1244 c->tty.mouse_drag_flag = MOUSE_BUTTONS(b) + 1;
1245 if (c->tty.mouse_scrolling_flag == 0 &&
1246 where == SCROLLBAR_SLIDER) {
1247 c->tty.mouse_scrolling_flag = 1;
1248 c->tty.mouse_slider_mpos = sl_mpos;
1250 break;
1251 case WHEEL:
1252 if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) {
1253 if (where == PANE)
1254 key = KEYC_WHEELUP_PANE;
1255 if (where == STATUS)
1256 key = KEYC_WHEELUP_STATUS;
1257 if (where == STATUS_LEFT)
1258 key = KEYC_WHEELUP_STATUS_LEFT;
1259 if (where == STATUS_RIGHT)
1260 key = KEYC_WHEELUP_STATUS_RIGHT;
1261 if (where == STATUS_DEFAULT)
1262 key = KEYC_WHEELUP_STATUS_DEFAULT;
1263 if (where == BORDER)
1264 key = KEYC_WHEELUP_BORDER;
1265 } else {
1266 if (where == PANE)
1267 key = KEYC_WHEELDOWN_PANE;
1268 if (where == STATUS)
1269 key = KEYC_WHEELDOWN_STATUS;
1270 if (where == STATUS_LEFT)
1271 key = KEYC_WHEELDOWN_STATUS_LEFT;
1272 if (where == STATUS_RIGHT)
1273 key = KEYC_WHEELDOWN_STATUS_RIGHT;
1274 if (where == STATUS_DEFAULT)
1275 key = KEYC_WHEELDOWN_STATUS_DEFAULT;
1276 if (where == BORDER)
1277 key = KEYC_WHEELDOWN_BORDER;
1279 break;
1280 case UP:
1281 switch (MOUSE_BUTTONS(b)) {
1282 case MOUSE_BUTTON_1:
1283 if (where == PANE)
1284 key = KEYC_MOUSEUP1_PANE;
1285 if (where == STATUS)
1286 key = KEYC_MOUSEUP1_STATUS;
1287 if (where == STATUS_LEFT)
1288 key = KEYC_MOUSEUP1_STATUS_LEFT;
1289 if (where == STATUS_RIGHT)
1290 key = KEYC_MOUSEUP1_STATUS_RIGHT;
1291 if (where == STATUS_DEFAULT)
1292 key = KEYC_MOUSEUP1_STATUS_DEFAULT;
1293 if (where == SCROLLBAR_UP)
1294 key = KEYC_MOUSEUP1_SCROLLBAR_UP;
1295 if (where == SCROLLBAR_SLIDER)
1296 key = KEYC_MOUSEUP1_SCROLLBAR_SLIDER;
1297 if (where == SCROLLBAR_DOWN)
1298 key = KEYC_MOUSEUP1_SCROLLBAR_DOWN;
1299 if (where == BORDER)
1300 key = KEYC_MOUSEUP1_BORDER;
1301 break;
1302 case MOUSE_BUTTON_2:
1303 if (where == PANE)
1304 key = KEYC_MOUSEUP2_PANE;
1305 if (where == STATUS)
1306 key = KEYC_MOUSEUP2_STATUS;
1307 if (where == STATUS_LEFT)
1308 key = KEYC_MOUSEUP2_STATUS_LEFT;
1309 if (where == STATUS_RIGHT)
1310 key = KEYC_MOUSEUP2_STATUS_RIGHT;
1311 if (where == STATUS_DEFAULT)
1312 key = KEYC_MOUSEUP2_STATUS_DEFAULT;
1313 if (where == SCROLLBAR_UP)
1314 key = KEYC_MOUSEUP2_SCROLLBAR_UP;
1315 if (where == SCROLLBAR_SLIDER)
1316 key = KEYC_MOUSEUP2_SCROLLBAR_SLIDER;
1317 if (where == SCROLLBAR_DOWN)
1318 key = KEYC_MOUSEUP2_SCROLLBAR_DOWN;
1319 if (where == BORDER)
1320 key = KEYC_MOUSEUP2_BORDER;
1321 break;
1322 case MOUSE_BUTTON_3:
1323 if (where == PANE)
1324 key = KEYC_MOUSEUP3_PANE;
1325 if (where == STATUS)
1326 key = KEYC_MOUSEUP3_STATUS;
1327 if (where == STATUS_LEFT)
1328 key = KEYC_MOUSEUP3_STATUS_LEFT;
1329 if (where == STATUS_RIGHT)
1330 key = KEYC_MOUSEUP3_STATUS_RIGHT;
1331 if (where == STATUS_DEFAULT)
1332 key = KEYC_MOUSEUP3_STATUS_DEFAULT;
1333 if (where == SCROLLBAR_UP)
1334 key = KEYC_MOUSEUP3_SCROLLBAR_UP;
1335 if (where == SCROLLBAR_SLIDER)
1336 key = KEYC_MOUSEUP3_SCROLLBAR_SLIDER;
1337 if (where == SCROLLBAR_DOWN)
1338 key = KEYC_MOUSEUP3_SCROLLBAR_DOWN;
1339 if (where == BORDER)
1340 key = KEYC_MOUSEUP3_BORDER;
1341 break;
1342 case MOUSE_BUTTON_6:
1343 if (where == PANE)
1344 key = KEYC_MOUSEUP6_PANE;
1345 if (where == STATUS)
1346 key = KEYC_MOUSEUP6_STATUS;
1347 if (where == STATUS_LEFT)
1348 key = KEYC_MOUSEUP6_STATUS_LEFT;
1349 if (where == STATUS_RIGHT)
1350 key = KEYC_MOUSEUP6_STATUS_RIGHT;
1351 if (where == STATUS_DEFAULT)
1352 key = KEYC_MOUSEUP6_STATUS_DEFAULT;
1353 if (where == SCROLLBAR_UP)
1354 key = KEYC_MOUSEUP6_SCROLLBAR_UP;
1355 if (where == SCROLLBAR_SLIDER)
1356 key = KEYC_MOUSEUP6_SCROLLBAR_SLIDER;
1357 if (where == SCROLLBAR_DOWN)
1358 key = KEYC_MOUSEUP6_SCROLLBAR_DOWN;
1359 if (where == BORDER)
1360 key = KEYC_MOUSEUP6_BORDER;
1361 break;
1362 case MOUSE_BUTTON_7:
1363 if (where == PANE)
1364 key = KEYC_MOUSEUP7_PANE;
1365 if (where == STATUS)
1366 key = KEYC_MOUSEUP7_STATUS;
1367 if (where == STATUS_LEFT)
1368 key = KEYC_MOUSEUP7_STATUS_LEFT;
1369 if (where == STATUS_RIGHT)
1370 key = KEYC_MOUSEUP7_STATUS_RIGHT;
1371 if (where == STATUS_DEFAULT)
1372 key = KEYC_MOUSEUP7_STATUS_DEFAULT;
1373 if (where == SCROLLBAR_UP)
1374 key = KEYC_MOUSEUP7_SCROLLBAR_UP;
1375 if (where == SCROLLBAR_SLIDER)
1376 key = KEYC_MOUSEUP7_SCROLLBAR_SLIDER;
1377 if (where == SCROLLBAR_DOWN)
1378 key = KEYC_MOUSEUP7_SCROLLBAR_DOWN;
1379 if (where == BORDER)
1380 key = KEYC_MOUSEUP7_BORDER;
1381 break;
1382 case MOUSE_BUTTON_8:
1383 if (where == PANE)
1384 key = KEYC_MOUSEUP8_PANE;
1385 if (where == STATUS)
1386 key = KEYC_MOUSEUP8_STATUS;
1387 if (where == STATUS_LEFT)
1388 key = KEYC_MOUSEUP8_STATUS_LEFT;
1389 if (where == STATUS_RIGHT)
1390 key = KEYC_MOUSEUP8_STATUS_RIGHT;
1391 if (where == STATUS_DEFAULT)
1392 key = KEYC_MOUSEUP8_STATUS_DEFAULT;
1393 if (where == SCROLLBAR_UP)
1394 key = KEYC_MOUSEUP8_SCROLLBAR_UP;
1395 if (where == SCROLLBAR_SLIDER)
1396 key = KEYC_MOUSEUP8_SCROLLBAR_SLIDER;
1397 if (where == SCROLLBAR_DOWN)
1398 key = KEYC_MOUSEUP8_SCROLLBAR_DOWN;
1399 if (where == BORDER)
1400 key = KEYC_MOUSEUP8_BORDER;
1401 break;
1402 case MOUSE_BUTTON_9:
1403 if (where == PANE)
1404 key = KEYC_MOUSEUP9_PANE;
1405 if (where == STATUS)
1406 key = KEYC_MOUSEUP9_STATUS;
1407 if (where == STATUS_LEFT)
1408 key = KEYC_MOUSEUP9_STATUS_LEFT;
1409 if (where == STATUS_RIGHT)
1410 key = KEYC_MOUSEUP9_STATUS_RIGHT;
1411 if (where == STATUS_DEFAULT)
1412 key = KEYC_MOUSEUP9_STATUS_DEFAULT;
1413 if (where == SCROLLBAR_UP)
1414 key = KEYC_MOUSEUP9_SCROLLBAR_UP;
1415 if (where == SCROLLBAR_SLIDER)
1416 key = KEYC_MOUSEUP9_SCROLLBAR_SLIDER;
1417 if (where == SCROLLBAR_DOWN)
1418 key = KEYC_MOUSEUP9_SCROLLBAR_DOWN;
1419 if (where == BORDER)
1420 key = KEYC_MOUSEUP9_BORDER;
1421 break;
1422 case MOUSE_BUTTON_10:
1423 if (where == PANE)
1424 key = KEYC_MOUSEUP1_PANE;
1425 if (where == STATUS)
1426 key = KEYC_MOUSEUP1_STATUS;
1427 if (where == STATUS_LEFT)
1428 key = KEYC_MOUSEUP1_STATUS_LEFT;
1429 if (where == STATUS_RIGHT)
1430 key = KEYC_MOUSEUP1_STATUS_RIGHT;
1431 if (where == STATUS_DEFAULT)
1432 key = KEYC_MOUSEUP10_STATUS_DEFAULT;
1433 if (where == SCROLLBAR_UP)
1434 key = KEYC_MOUSEUP10_SCROLLBAR_UP;
1435 if (where == SCROLLBAR_SLIDER)
1436 key = KEYC_MOUSEUP10_SCROLLBAR_SLIDER;
1437 if (where == SCROLLBAR_DOWN)
1438 key = KEYC_MOUSEUP1_SCROLLBAR_DOWN;
1439 if (where == BORDER)
1440 key = KEYC_MOUSEUP1_BORDER;
1441 break;
1442 case MOUSE_BUTTON_11:
1443 if (where == PANE)
1444 key = KEYC_MOUSEUP11_PANE;
1445 if (where == STATUS)
1446 key = KEYC_MOUSEUP11_STATUS;
1447 if (where == STATUS_LEFT)
1448 key = KEYC_MOUSEUP11_STATUS_LEFT;
1449 if (where == STATUS_RIGHT)
1450 key = KEYC_MOUSEUP11_STATUS_RIGHT;
1451 if (where == STATUS_DEFAULT)
1452 key = KEYC_MOUSEUP11_STATUS_DEFAULT;
1453 if (where == SCROLLBAR_UP)
1454 key = KEYC_MOUSEUP11_SCROLLBAR_UP;
1455 if (where == SCROLLBAR_SLIDER)
1456 key = KEYC_MOUSEUP11_SCROLLBAR_SLIDER;
1457 if (where == SCROLLBAR_DOWN)
1458 key = KEYC_MOUSEUP11_SCROLLBAR_DOWN;
1459 if (where == BORDER)
1460 key = KEYC_MOUSEUP11_BORDER;
1461 break;
1463 break;
1464 case DOWN:
1465 switch (MOUSE_BUTTONS(b)) {
1466 case MOUSE_BUTTON_1:
1467 if (where == PANE)
1468 key = KEYC_MOUSEDOWN1_PANE;
1469 if (where == STATUS)
1470 key = KEYC_MOUSEDOWN1_STATUS;
1471 if (where == STATUS_LEFT)
1472 key = KEYC_MOUSEDOWN1_STATUS_LEFT;
1473 if (where == STATUS_RIGHT)
1474 key = KEYC_MOUSEDOWN1_STATUS_RIGHT;
1475 if (where == STATUS_DEFAULT)
1476 key = KEYC_MOUSEDOWN1_STATUS_DEFAULT;
1477 if (where == SCROLLBAR_UP)
1478 key = KEYC_MOUSEDOWN1_SCROLLBAR_UP;
1479 if (where == SCROLLBAR_SLIDER)
1480 key = KEYC_MOUSEDOWN1_SCROLLBAR_SLIDER;
1481 if (where == SCROLLBAR_DOWN)
1482 key = KEYC_MOUSEDOWN1_SCROLLBAR_DOWN;
1483 if (where == BORDER)
1484 key = KEYC_MOUSEDOWN1_BORDER;
1485 break;
1486 case MOUSE_BUTTON_2:
1487 if (where == PANE)
1488 key = KEYC_MOUSEDOWN2_PANE;
1489 if (where == STATUS)
1490 key = KEYC_MOUSEDOWN2_STATUS;
1491 if (where == STATUS_LEFT)
1492 key = KEYC_MOUSEDOWN2_STATUS_LEFT;
1493 if (where == STATUS_RIGHT)
1494 key = KEYC_MOUSEDOWN2_STATUS_RIGHT;
1495 if (where == STATUS_DEFAULT)
1496 key = KEYC_MOUSEDOWN2_STATUS_DEFAULT;
1497 if (where == SCROLLBAR_UP)
1498 key = KEYC_MOUSEDOWN2_SCROLLBAR_UP;
1499 if (where == SCROLLBAR_SLIDER)
1500 key = KEYC_MOUSEDOWN2_SCROLLBAR_SLIDER;
1501 if (where == SCROLLBAR_DOWN)
1502 key = KEYC_MOUSEDOWN2_SCROLLBAR_DOWN;
1503 if (where == BORDER)
1504 key = KEYC_MOUSEDOWN2_BORDER;
1505 break;
1506 case MOUSE_BUTTON_3:
1507 if (where == PANE)
1508 key = KEYC_MOUSEDOWN3_PANE;
1509 if (where == STATUS)
1510 key = KEYC_MOUSEDOWN3_STATUS;
1511 if (where == STATUS_LEFT)
1512 key = KEYC_MOUSEDOWN3_STATUS_LEFT;
1513 if (where == STATUS_RIGHT)
1514 key = KEYC_MOUSEDOWN3_STATUS_RIGHT;
1515 if (where == STATUS_DEFAULT)
1516 key = KEYC_MOUSEDOWN3_STATUS_DEFAULT;
1517 if (where == SCROLLBAR_UP)
1518 key = KEYC_MOUSEDOWN3_SCROLLBAR_UP;
1519 if (where == SCROLLBAR_SLIDER)
1520 key = KEYC_MOUSEDOWN3_SCROLLBAR_SLIDER;
1521 if (where == SCROLLBAR_DOWN)
1522 key = KEYC_MOUSEDOWN3_SCROLLBAR_DOWN;
1523 if (where == BORDER)
1524 key = KEYC_MOUSEDOWN3_BORDER;
1525 break;
1526 case MOUSE_BUTTON_6:
1527 if (where == PANE)
1528 key = KEYC_MOUSEDOWN6_PANE;
1529 if (where == STATUS)
1530 key = KEYC_MOUSEDOWN6_STATUS;
1531 if (where == STATUS_LEFT)
1532 key = KEYC_MOUSEDOWN6_STATUS_LEFT;
1533 if (where == STATUS_RIGHT)
1534 key = KEYC_MOUSEDOWN6_STATUS_RIGHT;
1535 if (where == STATUS_DEFAULT)
1536 key = KEYC_MOUSEDOWN6_STATUS_DEFAULT;
1537 if (where == SCROLLBAR_UP)
1538 key = KEYC_MOUSEDOWN6_SCROLLBAR_UP;
1539 if (where == SCROLLBAR_SLIDER)
1540 key = KEYC_MOUSEDOWN6_SCROLLBAR_SLIDER;
1541 if (where == SCROLLBAR_DOWN)
1542 key = KEYC_MOUSEDOWN6_SCROLLBAR_DOWN;
1543 if (where == BORDER)
1544 key = KEYC_MOUSEDOWN6_BORDER;
1545 break;
1546 case MOUSE_BUTTON_7:
1547 if (where == PANE)
1548 key = KEYC_MOUSEDOWN7_PANE;
1549 if (where == STATUS)
1550 key = KEYC_MOUSEDOWN7_STATUS;
1551 if (where == STATUS_LEFT)
1552 key = KEYC_MOUSEDOWN7_STATUS_LEFT;
1553 if (where == STATUS_RIGHT)
1554 key = KEYC_MOUSEDOWN7_STATUS_RIGHT;
1555 if (where == STATUS_DEFAULT)
1556 key = KEYC_MOUSEDOWN7_STATUS_DEFAULT;
1557 if (where == SCROLLBAR_UP)
1558 key = KEYC_MOUSEDOWN7_SCROLLBAR_UP;
1559 if (where == SCROLLBAR_SLIDER)
1560 key = KEYC_MOUSEDOWN7_SCROLLBAR_SLIDER;
1561 if (where == SCROLLBAR_DOWN)
1562 key = KEYC_MOUSEDOWN7_SCROLLBAR_DOWN;
1563 if (where == BORDER)
1564 key = KEYC_MOUSEDOWN7_BORDER;
1565 break;
1566 case MOUSE_BUTTON_8:
1567 if (where == PANE)
1568 key = KEYC_MOUSEDOWN8_PANE;
1569 if (where == STATUS)
1570 key = KEYC_MOUSEDOWN8_STATUS;
1571 if (where == STATUS_LEFT)
1572 key = KEYC_MOUSEDOWN8_STATUS_LEFT;
1573 if (where == STATUS_RIGHT)
1574 key = KEYC_MOUSEDOWN8_STATUS_RIGHT;
1575 if (where == STATUS_DEFAULT)
1576 key = KEYC_MOUSEDOWN8_STATUS_DEFAULT;
1577 if (where == SCROLLBAR_UP)
1578 key = KEYC_MOUSEDOWN8_SCROLLBAR_UP;
1579 if (where == SCROLLBAR_SLIDER)
1580 key = KEYC_MOUSEDOWN8_SCROLLBAR_SLIDER;
1581 if (where == SCROLLBAR_DOWN)
1582 key = KEYC_MOUSEDOWN8_SCROLLBAR_DOWN;
1583 if (where == BORDER)
1584 key = KEYC_MOUSEDOWN8_BORDER;
1585 break;
1586 case MOUSE_BUTTON_9:
1587 if (where == PANE)
1588 key = KEYC_MOUSEDOWN9_PANE;
1589 if (where == STATUS)
1590 key = KEYC_MOUSEDOWN9_STATUS;
1591 if (where == STATUS_LEFT)
1592 key = KEYC_MOUSEDOWN9_STATUS_LEFT;
1593 if (where == STATUS_RIGHT)
1594 key = KEYC_MOUSEDOWN9_STATUS_RIGHT;
1595 if (where == STATUS_DEFAULT)
1596 key = KEYC_MOUSEDOWN9_STATUS_DEFAULT;
1597 if (where == SCROLLBAR_UP)
1598 key = KEYC_MOUSEDOWN9_SCROLLBAR_UP;
1599 if (where == SCROLLBAR_SLIDER)
1600 key = KEYC_MOUSEDOWN9_SCROLLBAR_SLIDER;
1601 if (where == SCROLLBAR_DOWN)
1602 key = KEYC_MOUSEDOWN9_SCROLLBAR_DOWN;
1603 if (where == BORDER)
1604 key = KEYC_MOUSEDOWN9_BORDER;
1605 break;
1606 case MOUSE_BUTTON_10:
1607 if (where == PANE)
1608 key = KEYC_MOUSEDOWN10_PANE;
1609 if (where == STATUS)
1610 key = KEYC_MOUSEDOWN10_STATUS;
1611 if (where == STATUS_LEFT)
1612 key = KEYC_MOUSEDOWN10_STATUS_LEFT;
1613 if (where == STATUS_RIGHT)
1614 key = KEYC_MOUSEDOWN10_STATUS_RIGHT;
1615 if (where == STATUS_DEFAULT)
1616 key = KEYC_MOUSEDOWN10_STATUS_DEFAULT;
1617 if (where == SCROLLBAR_UP)
1618 key = KEYC_MOUSEDOWN10_SCROLLBAR_UP;
1619 if (where == SCROLLBAR_SLIDER)
1620 key = KEYC_MOUSEDOWN10_SCROLLBAR_SLIDER;
1621 if (where == SCROLLBAR_DOWN)
1622 key = KEYC_MOUSEDOWN10_SCROLLBAR_DOWN;
1623 if (where == BORDER)
1624 key = KEYC_MOUSEDOWN10_BORDER;
1625 break;
1626 case MOUSE_BUTTON_11:
1627 if (where == PANE)
1628 key = KEYC_MOUSEDOWN11_PANE;
1629 if (where == STATUS)
1630 key = KEYC_MOUSEDOWN11_STATUS;
1631 if (where == STATUS_LEFT)
1632 key = KEYC_MOUSEDOWN11_STATUS_LEFT;
1633 if (where == STATUS_RIGHT)
1634 key = KEYC_MOUSEDOWN11_STATUS_RIGHT;
1635 if (where == STATUS_DEFAULT)
1636 key = KEYC_MOUSEDOWN11_STATUS_DEFAULT;
1637 if (where == SCROLLBAR_UP)
1638 key = KEYC_MOUSEDOWN11_SCROLLBAR_UP;
1639 if (where == SCROLLBAR_SLIDER)
1640 key = KEYC_MOUSEDOWN11_SCROLLBAR_SLIDER;
1641 if (where == SCROLLBAR_DOWN)
1642 key = KEYC_MOUSEDOWN11_SCROLLBAR_DOWN;
1643 if (where == BORDER)
1644 key = KEYC_MOUSEDOWN11_BORDER;
1645 break;
1647 break;
1648 case SECOND:
1649 switch (MOUSE_BUTTONS(b)) {
1650 case MOUSE_BUTTON_1:
1651 if (where == PANE)
1652 key = KEYC_SECONDCLICK1_PANE;
1653 if (where == STATUS)
1654 key = KEYC_SECONDCLICK1_STATUS;
1655 if (where == STATUS_LEFT)
1656 key = KEYC_SECONDCLICK1_STATUS_LEFT;
1657 if (where == STATUS_RIGHT)
1658 key = KEYC_SECONDCLICK1_STATUS_RIGHT;
1659 if (where == STATUS_DEFAULT)
1660 key = KEYC_SECONDCLICK1_STATUS_DEFAULT;
1661 if (where == SCROLLBAR_UP)
1662 key = KEYC_SECONDCLICK1_SCROLLBAR_UP;
1663 if (where == SCROLLBAR_SLIDER)
1664 key = KEYC_SECONDCLICK1_SCROLLBAR_SLIDER;
1665 if (where == SCROLLBAR_DOWN)
1666 key = KEYC_SECONDCLICK1_SCROLLBAR_DOWN;
1667 if (where == BORDER)
1668 key = KEYC_SECONDCLICK1_BORDER;
1669 break;
1670 case MOUSE_BUTTON_2:
1671 if (where == PANE)
1672 key = KEYC_SECONDCLICK2_PANE;
1673 if (where == STATUS)
1674 key = KEYC_SECONDCLICK2_STATUS;
1675 if (where == STATUS_LEFT)
1676 key = KEYC_SECONDCLICK2_STATUS_LEFT;
1677 if (where == STATUS_RIGHT)
1678 key = KEYC_SECONDCLICK2_STATUS_RIGHT;
1679 if (where == STATUS_DEFAULT)
1680 key = KEYC_SECONDCLICK2_STATUS_DEFAULT;
1681 if (where == SCROLLBAR_UP)
1682 key = KEYC_SECONDCLICK2_SCROLLBAR_UP;
1683 if (where == SCROLLBAR_SLIDER)
1684 key = KEYC_SECONDCLICK2_SCROLLBAR_SLIDER;
1685 if (where == SCROLLBAR_DOWN)
1686 key = KEYC_SECONDCLICK2_SCROLLBAR_DOWN;
1687 if (where == BORDER)
1688 key = KEYC_SECONDCLICK2_BORDER;
1689 break;
1690 case MOUSE_BUTTON_3:
1691 if (where == PANE)
1692 key = KEYC_SECONDCLICK3_PANE;
1693 if (where == STATUS)
1694 key = KEYC_SECONDCLICK3_STATUS;
1695 if (where == STATUS_LEFT)
1696 key = KEYC_SECONDCLICK3_STATUS_LEFT;
1697 if (where == STATUS_RIGHT)
1698 key = KEYC_SECONDCLICK3_STATUS_RIGHT;
1699 if (where == STATUS_DEFAULT)
1700 key = KEYC_SECONDCLICK3_STATUS_DEFAULT;
1701 if (where == SCROLLBAR_UP)
1702 key = KEYC_SECONDCLICK3_SCROLLBAR_UP;
1703 if (where == SCROLLBAR_SLIDER)
1704 key = KEYC_SECONDCLICK3_SCROLLBAR_SLIDER;
1705 if (where == SCROLLBAR_DOWN)
1706 key = KEYC_SECONDCLICK3_SCROLLBAR_DOWN;
1707 if (where == BORDER)
1708 key = KEYC_SECONDCLICK3_BORDER;
1709 break;
1710 case MOUSE_BUTTON_6:
1711 if (where == PANE)
1712 key = KEYC_SECONDCLICK6_PANE;
1713 if (where == STATUS)
1714 key = KEYC_SECONDCLICK6_STATUS;
1715 if (where == STATUS_LEFT)
1716 key = KEYC_SECONDCLICK6_STATUS_LEFT;
1717 if (where == STATUS_RIGHT)
1718 key = KEYC_SECONDCLICK6_STATUS_RIGHT;
1719 if (where == STATUS_DEFAULT)
1720 key = KEYC_SECONDCLICK6_STATUS_DEFAULT;
1721 if (where == SCROLLBAR_UP)
1722 key = KEYC_SECONDCLICK6_SCROLLBAR_UP;
1723 if (where == SCROLLBAR_SLIDER)
1724 key = KEYC_SECONDCLICK6_SCROLLBAR_SLIDER;
1725 if (where == SCROLLBAR_DOWN)
1726 key = KEYC_SECONDCLICK6_SCROLLBAR_DOWN;
1727 if (where == BORDER)
1728 key = KEYC_SECONDCLICK6_BORDER;
1729 break;
1730 case MOUSE_BUTTON_7:
1731 if (where == PANE)
1732 key = KEYC_SECONDCLICK7_PANE;
1733 if (where == STATUS)
1734 key = KEYC_SECONDCLICK7_STATUS;
1735 if (where == STATUS_LEFT)
1736 key = KEYC_SECONDCLICK7_STATUS_LEFT;
1737 if (where == STATUS_RIGHT)
1738 key = KEYC_SECONDCLICK7_STATUS_RIGHT;
1739 if (where == STATUS_DEFAULT)
1740 key = KEYC_SECONDCLICK7_STATUS_DEFAULT;
1741 if (where == SCROLLBAR_UP)
1742 key = KEYC_SECONDCLICK7_SCROLLBAR_UP;
1743 if (where == SCROLLBAR_SLIDER)
1744 key = KEYC_SECONDCLICK7_SCROLLBAR_SLIDER;
1745 if (where == SCROLLBAR_DOWN)
1746 key = KEYC_SECONDCLICK7_SCROLLBAR_DOWN;
1747 if (where == BORDER)
1748 key = KEYC_SECONDCLICK7_BORDER;
1749 break;
1750 case MOUSE_BUTTON_8:
1751 if (where == PANE)
1752 key = KEYC_SECONDCLICK8_PANE;
1753 if (where == STATUS)
1754 key = KEYC_SECONDCLICK8_STATUS;
1755 if (where == STATUS_LEFT)
1756 key = KEYC_SECONDCLICK8_STATUS_LEFT;
1757 if (where == STATUS_RIGHT)
1758 key = KEYC_SECONDCLICK8_STATUS_RIGHT;
1759 if (where == STATUS_DEFAULT)
1760 key = KEYC_SECONDCLICK8_STATUS_DEFAULT;
1761 if (where == SCROLLBAR_UP)
1762 key = KEYC_SECONDCLICK8_SCROLLBAR_UP;
1763 if (where == SCROLLBAR_SLIDER)
1764 key = KEYC_SECONDCLICK8_SCROLLBAR_SLIDER;
1765 if (where == SCROLLBAR_DOWN)
1766 key = KEYC_SECONDCLICK8_SCROLLBAR_DOWN;
1767 if (where == BORDER)
1768 key = KEYC_SECONDCLICK8_BORDER;
1769 break;
1770 case MOUSE_BUTTON_9:
1771 if (where == PANE)
1772 key = KEYC_SECONDCLICK9_PANE;
1773 if (where == STATUS)
1774 key = KEYC_SECONDCLICK9_STATUS;
1775 if (where == STATUS_LEFT)
1776 key = KEYC_SECONDCLICK9_STATUS_LEFT;
1777 if (where == STATUS_RIGHT)
1778 key = KEYC_SECONDCLICK9_STATUS_RIGHT;
1779 if (where == STATUS_DEFAULT)
1780 key = KEYC_SECONDCLICK9_STATUS_DEFAULT;
1781 if (where == SCROLLBAR_UP)
1782 key = KEYC_SECONDCLICK9_SCROLLBAR_UP;
1783 if (where == SCROLLBAR_SLIDER)
1784 key = KEYC_SECONDCLICK9_SCROLLBAR_SLIDER;
1785 if (where == SCROLLBAR_DOWN)
1786 key = KEYC_SECONDCLICK9_SCROLLBAR_DOWN;
1787 if (where == BORDER)
1788 key = KEYC_SECONDCLICK9_BORDER;
1789 break;
1790 case MOUSE_BUTTON_10:
1791 if (where == PANE)
1792 key = KEYC_SECONDCLICK10_PANE;
1793 if (where == STATUS)
1794 key = KEYC_SECONDCLICK10_STATUS;
1795 if (where == STATUS_LEFT)
1796 key = KEYC_SECONDCLICK10_STATUS_LEFT;
1797 if (where == STATUS_RIGHT)
1798 key = KEYC_SECONDCLICK10_STATUS_RIGHT;
1799 if (where == STATUS_DEFAULT)
1800 key = KEYC_SECONDCLICK10_STATUS_DEFAULT;
1801 if (where == SCROLLBAR_UP)
1802 key = KEYC_SECONDCLICK10_SCROLLBAR_UP;
1803 if (where == SCROLLBAR_SLIDER)
1804 key = KEYC_SECONDCLICK10_SCROLLBAR_SLIDER;
1805 if (where == SCROLLBAR_DOWN)
1806 key = KEYC_SECONDCLICK10_SCROLLBAR_DOWN;
1807 if (where == BORDER)
1808 key = KEYC_SECONDCLICK10_BORDER;
1809 break;
1810 case MOUSE_BUTTON_11:
1811 if (where == PANE)
1812 key = KEYC_SECONDCLICK11_PANE;
1813 if (where == STATUS)
1814 key = KEYC_SECONDCLICK11_STATUS;
1815 if (where == STATUS_LEFT)
1816 key = KEYC_SECONDCLICK11_STATUS_LEFT;
1817 if (where == STATUS_RIGHT)
1818 key = KEYC_SECONDCLICK11_STATUS_RIGHT;
1819 if (where == STATUS_DEFAULT)
1820 key = KEYC_SECONDCLICK11_STATUS_DEFAULT;
1821 if (where == SCROLLBAR_UP)
1822 key = KEYC_SECONDCLICK11_SCROLLBAR_UP;
1823 if (where == SCROLLBAR_SLIDER)
1824 key = KEYC_SECONDCLICK11_SCROLLBAR_SLIDER;
1825 if (where == SCROLLBAR_DOWN)
1826 key = KEYC_SECONDCLICK11_SCROLLBAR_DOWN;
1827 if (where == BORDER)
1828 key = KEYC_SECONDCLICK11_BORDER;
1829 break;
1831 break;
1832 case DOUBLE:
1833 switch (MOUSE_BUTTONS(b)) {
1834 case MOUSE_BUTTON_1:
1835 if (where == PANE)
1836 key = KEYC_DOUBLECLICK1_PANE;
1837 if (where == STATUS)
1838 key = KEYC_DOUBLECLICK1_STATUS;
1839 if (where == STATUS_LEFT)
1840 key = KEYC_DOUBLECLICK1_STATUS_LEFT;
1841 if (where == STATUS_RIGHT)
1842 key = KEYC_DOUBLECLICK1_STATUS_RIGHT;
1843 if (where == STATUS_DEFAULT)
1844 key = KEYC_DOUBLECLICK1_STATUS_DEFAULT;
1845 if (where == SCROLLBAR_UP)
1846 key = KEYC_DOUBLECLICK1_SCROLLBAR_UP;
1847 if (where == SCROLLBAR_SLIDER)
1848 key = KEYC_DOUBLECLICK1_SCROLLBAR_SLIDER;
1849 if (where == SCROLLBAR_DOWN)
1850 key = KEYC_DOUBLECLICK1_SCROLLBAR_DOWN;
1851 if (where == BORDER)
1852 key = KEYC_DOUBLECLICK1_BORDER;
1853 break;
1854 case MOUSE_BUTTON_2:
1855 if (where == PANE)
1856 key = KEYC_DOUBLECLICK2_PANE;
1857 if (where == STATUS)
1858 key = KEYC_DOUBLECLICK2_STATUS;
1859 if (where == STATUS_LEFT)
1860 key = KEYC_DOUBLECLICK2_STATUS_LEFT;
1861 if (where == STATUS_RIGHT)
1862 key = KEYC_DOUBLECLICK2_STATUS_RIGHT;
1863 if (where == STATUS_DEFAULT)
1864 key = KEYC_DOUBLECLICK2_STATUS_DEFAULT;
1865 if (where == SCROLLBAR_UP)
1866 key = KEYC_DOUBLECLICK2_SCROLLBAR_UP;
1867 if (where == SCROLLBAR_SLIDER)
1868 key = KEYC_DOUBLECLICK2_SCROLLBAR_SLIDER;
1869 if (where == SCROLLBAR_DOWN)
1870 key = KEYC_DOUBLECLICK2_SCROLLBAR_DOWN;
1871 if (where == BORDER)
1872 key = KEYC_DOUBLECLICK2_BORDER;
1873 break;
1874 case MOUSE_BUTTON_3:
1875 if (where == PANE)
1876 key = KEYC_DOUBLECLICK3_PANE;
1877 if (where == STATUS)
1878 key = KEYC_DOUBLECLICK3_STATUS;
1879 if (where == STATUS_LEFT)
1880 key = KEYC_DOUBLECLICK3_STATUS_LEFT;
1881 if (where == STATUS_RIGHT)
1882 key = KEYC_DOUBLECLICK3_STATUS_RIGHT;
1883 if (where == STATUS_DEFAULT)
1884 key = KEYC_DOUBLECLICK3_STATUS_DEFAULT;
1885 if (where == SCROLLBAR_UP)
1886 key = KEYC_DOUBLECLICK3_SCROLLBAR_UP;
1887 if (where == SCROLLBAR_SLIDER)
1888 key = KEYC_DOUBLECLICK3_SCROLLBAR_SLIDER;
1889 if (where == SCROLLBAR_DOWN)
1890 key = KEYC_DOUBLECLICK3_SCROLLBAR_DOWN;
1891 if (where == BORDER)
1892 key = KEYC_DOUBLECLICK3_BORDER;
1893 break;
1894 case MOUSE_BUTTON_6:
1895 if (where == PANE)
1896 key = KEYC_DOUBLECLICK6_PANE;
1897 if (where == STATUS)
1898 key = KEYC_DOUBLECLICK6_STATUS;
1899 if (where == STATUS_LEFT)
1900 key = KEYC_DOUBLECLICK6_STATUS_LEFT;
1901 if (where == STATUS_RIGHT)
1902 key = KEYC_DOUBLECLICK6_STATUS_RIGHT;
1903 if (where == STATUS_DEFAULT)
1904 key = KEYC_DOUBLECLICK6_STATUS_DEFAULT;
1905 if (where == SCROLLBAR_UP)
1906 key = KEYC_DOUBLECLICK6_SCROLLBAR_UP;
1907 if (where == SCROLLBAR_SLIDER)
1908 key = KEYC_DOUBLECLICK6_SCROLLBAR_SLIDER;
1909 if (where == SCROLLBAR_DOWN)
1910 key = KEYC_DOUBLECLICK6_SCROLLBAR_DOWN;
1911 if (where == BORDER)
1912 key = KEYC_DOUBLECLICK6_BORDER;
1913 break;
1914 case MOUSE_BUTTON_7:
1915 if (where == PANE)
1916 key = KEYC_DOUBLECLICK7_PANE;
1917 if (where == STATUS)
1918 key = KEYC_DOUBLECLICK7_STATUS;
1919 if (where == STATUS_LEFT)
1920 key = KEYC_DOUBLECLICK7_STATUS_LEFT;
1921 if (where == STATUS_RIGHT)
1922 key = KEYC_DOUBLECLICK7_STATUS_RIGHT;
1923 if (where == STATUS_DEFAULT)
1924 key = KEYC_DOUBLECLICK7_STATUS_DEFAULT;
1925 if (where == SCROLLBAR_UP)
1926 key = KEYC_DOUBLECLICK7_SCROLLBAR_UP;
1927 if (where == SCROLLBAR_SLIDER)
1928 key = KEYC_DOUBLECLICK7_SCROLLBAR_SLIDER;
1929 if (where == SCROLLBAR_DOWN)
1930 key = KEYC_DOUBLECLICK7_SCROLLBAR_DOWN;
1931 if (where == BORDER)
1932 key = KEYC_DOUBLECLICK7_BORDER;
1933 break;
1934 case MOUSE_BUTTON_8:
1935 if (where == PANE)
1936 key = KEYC_DOUBLECLICK8_PANE;
1937 if (where == STATUS)
1938 key = KEYC_DOUBLECLICK8_STATUS;
1939 if (where == STATUS_LEFT)
1940 key = KEYC_DOUBLECLICK8_STATUS_LEFT;
1941 if (where == STATUS_RIGHT)
1942 key = KEYC_DOUBLECLICK8_STATUS_RIGHT;
1943 if (where == STATUS_DEFAULT)
1944 key = KEYC_DOUBLECLICK8_STATUS_DEFAULT;
1945 if (where == SCROLLBAR_UP)
1946 key = KEYC_DOUBLECLICK8_SCROLLBAR_UP;
1947 if (where == SCROLLBAR_SLIDER)
1948 key = KEYC_DOUBLECLICK8_SCROLLBAR_SLIDER;
1949 if (where == SCROLLBAR_DOWN)
1950 key = KEYC_DOUBLECLICK8_SCROLLBAR_DOWN;
1951 if (where == BORDER)
1952 key = KEYC_DOUBLECLICK8_BORDER;
1953 break;
1954 case MOUSE_BUTTON_9:
1955 if (where == PANE)
1956 key = KEYC_DOUBLECLICK9_PANE;
1957 if (where == STATUS)
1958 key = KEYC_DOUBLECLICK9_STATUS;
1959 if (where == STATUS_LEFT)
1960 key = KEYC_DOUBLECLICK9_STATUS_LEFT;
1961 if (where == STATUS_RIGHT)
1962 key = KEYC_DOUBLECLICK9_STATUS_RIGHT;
1963 if (where == STATUS_DEFAULT)
1964 key = KEYC_DOUBLECLICK9_STATUS_DEFAULT;
1965 if (where == SCROLLBAR_UP)
1966 key = KEYC_DOUBLECLICK9_SCROLLBAR_UP;
1967 if (where == SCROLLBAR_SLIDER)
1968 key = KEYC_DOUBLECLICK9_SCROLLBAR_SLIDER;
1969 if (where == SCROLLBAR_DOWN)
1970 key = KEYC_DOUBLECLICK9_SCROLLBAR_DOWN;
1971 if (where == BORDER)
1972 key = KEYC_DOUBLECLICK9_BORDER;
1973 break;
1974 case MOUSE_BUTTON_10:
1975 if (where == PANE)
1976 key = KEYC_DOUBLECLICK10_PANE;
1977 if (where == STATUS)
1978 key = KEYC_DOUBLECLICK10_STATUS;
1979 if (where == STATUS_LEFT)
1980 key = KEYC_DOUBLECLICK10_STATUS_LEFT;
1981 if (where == STATUS_RIGHT)
1982 key = KEYC_DOUBLECLICK10_STATUS_RIGHT;
1983 if (where == STATUS_DEFAULT)
1984 key = KEYC_DOUBLECLICK10_STATUS_DEFAULT;
1985 if (where == SCROLLBAR_UP)
1986 key = KEYC_DOUBLECLICK10_SCROLLBAR_UP;
1987 if (where == SCROLLBAR_SLIDER)
1988 key = KEYC_DOUBLECLICK10_SCROLLBAR_SLIDER;
1989 if (where == SCROLLBAR_DOWN)
1990 key = KEYC_DOUBLECLICK10_SCROLLBAR_DOWN;
1991 if (where == BORDER)
1992 key = KEYC_DOUBLECLICK10_BORDER;
1993 break;
1994 case MOUSE_BUTTON_11:
1995 if (where == PANE)
1996 key = KEYC_DOUBLECLICK11_PANE;
1997 if (where == STATUS)
1998 key = KEYC_DOUBLECLICK11_STATUS;
1999 if (where == STATUS_LEFT)
2000 key = KEYC_DOUBLECLICK11_STATUS_LEFT;
2001 if (where == STATUS_RIGHT)
2002 key = KEYC_DOUBLECLICK11_STATUS_RIGHT;
2003 if (where == STATUS_DEFAULT)
2004 key = KEYC_DOUBLECLICK11_STATUS_DEFAULT;
2005 if (where == SCROLLBAR_UP)
2006 key = KEYC_DOUBLECLICK11_SCROLLBAR_UP;
2007 if (where == SCROLLBAR_SLIDER)
2008 key = KEYC_DOUBLECLICK11_SCROLLBAR_SLIDER;
2009 if (where == SCROLLBAR_DOWN)
2010 key = KEYC_DOUBLECLICK11_SCROLLBAR_DOWN;
2011 if (where == BORDER)
2012 key = KEYC_DOUBLECLICK11_BORDER;
2013 break;
2015 break;
2016 case TRIPLE:
2017 switch (MOUSE_BUTTONS(b)) {
2018 case MOUSE_BUTTON_1:
2019 if (where == PANE)
2020 key = KEYC_TRIPLECLICK1_PANE;
2021 if (where == STATUS)
2022 key = KEYC_TRIPLECLICK1_STATUS;
2023 if (where == STATUS_LEFT)
2024 key = KEYC_TRIPLECLICK1_STATUS_LEFT;
2025 if (where == STATUS_RIGHT)
2026 key = KEYC_TRIPLECLICK1_STATUS_RIGHT;
2027 if (where == STATUS_DEFAULT)
2028 key = KEYC_TRIPLECLICK1_STATUS_DEFAULT;
2029 if (where == SCROLLBAR_UP)
2030 key = KEYC_TRIPLECLICK1_SCROLLBAR_UP;
2031 if (where == SCROLLBAR_SLIDER)
2032 key = KEYC_TRIPLECLICK1_SCROLLBAR_SLIDER;
2033 if (where == SCROLLBAR_DOWN)
2034 key = KEYC_TRIPLECLICK1_SCROLLBAR_DOWN;
2035 if (where == BORDER)
2036 key = KEYC_TRIPLECLICK1_BORDER;
2037 break;
2038 case MOUSE_BUTTON_2:
2039 if (where == PANE)
2040 key = KEYC_TRIPLECLICK2_PANE;
2041 if (where == STATUS)
2042 key = KEYC_TRIPLECLICK2_STATUS;
2043 if (where == STATUS_LEFT)
2044 key = KEYC_TRIPLECLICK2_STATUS_LEFT;
2045 if (where == STATUS_RIGHT)
2046 key = KEYC_TRIPLECLICK2_STATUS_RIGHT;
2047 if (where == STATUS_DEFAULT)
2048 key = KEYC_TRIPLECLICK2_STATUS_DEFAULT;
2049 if (where == SCROLLBAR_UP)
2050 key = KEYC_TRIPLECLICK2_SCROLLBAR_UP;
2051 if (where == SCROLLBAR_SLIDER)
2052 key = KEYC_TRIPLECLICK2_SCROLLBAR_SLIDER;
2053 if (where == SCROLLBAR_DOWN)
2054 key = KEYC_TRIPLECLICK2_SCROLLBAR_DOWN;
2055 if (where == BORDER)
2056 key = KEYC_TRIPLECLICK2_BORDER;
2057 break;
2058 case MOUSE_BUTTON_3:
2059 if (where == PANE)
2060 key = KEYC_TRIPLECLICK3_PANE;
2061 if (where == STATUS)
2062 key = KEYC_TRIPLECLICK3_STATUS;
2063 if (where == STATUS_LEFT)
2064 key = KEYC_TRIPLECLICK3_STATUS_LEFT;
2065 if (where == STATUS_RIGHT)
2066 key = KEYC_TRIPLECLICK3_STATUS_RIGHT;
2067 if (where == STATUS_DEFAULT)
2068 key = KEYC_TRIPLECLICK3_STATUS_DEFAULT;
2069 if (where == SCROLLBAR_UP)
2070 key = KEYC_TRIPLECLICK3_SCROLLBAR_UP;
2071 if (where == SCROLLBAR_SLIDER)
2072 key = KEYC_TRIPLECLICK3_SCROLLBAR_SLIDER;
2073 if (where == SCROLLBAR_DOWN)
2074 key = KEYC_TRIPLECLICK3_SCROLLBAR_DOWN;
2075 if (where == BORDER)
2076 key = KEYC_TRIPLECLICK3_BORDER;
2077 break;
2078 case MOUSE_BUTTON_6:
2079 if (where == PANE)
2080 key = KEYC_TRIPLECLICK6_PANE;
2081 if (where == STATUS)
2082 key = KEYC_TRIPLECLICK6_STATUS;
2083 if (where == STATUS_LEFT)
2084 key = KEYC_TRIPLECLICK6_STATUS_LEFT;
2085 if (where == STATUS_RIGHT)
2086 key = KEYC_TRIPLECLICK6_STATUS_RIGHT;
2087 if (where == STATUS_DEFAULT)
2088 key = KEYC_TRIPLECLICK6_STATUS_DEFAULT;
2089 if (where == SCROLLBAR_UP)
2090 key = KEYC_TRIPLECLICK6_SCROLLBAR_UP;
2091 if (where == SCROLLBAR_SLIDER)
2092 key = KEYC_TRIPLECLICK6_SCROLLBAR_SLIDER;
2093 if (where == SCROLLBAR_DOWN)
2094 key = KEYC_TRIPLECLICK6_SCROLLBAR_DOWN;
2095 if (where == BORDER)
2096 key = KEYC_TRIPLECLICK6_BORDER;
2097 break;
2098 case MOUSE_BUTTON_7:
2099 if (where == PANE)
2100 key = KEYC_TRIPLECLICK7_PANE;
2101 if (where == STATUS)
2102 key = KEYC_TRIPLECLICK7_STATUS;
2103 if (where == STATUS_LEFT)
2104 key = KEYC_TRIPLECLICK7_STATUS_LEFT;
2105 if (where == STATUS_RIGHT)
2106 key = KEYC_TRIPLECLICK7_STATUS_RIGHT;
2107 if (where == STATUS_DEFAULT)
2108 key = KEYC_TRIPLECLICK7_STATUS_DEFAULT;
2109 if (where == SCROLLBAR_UP)
2110 key = KEYC_TRIPLECLICK7_SCROLLBAR_UP;
2111 if (where == SCROLLBAR_SLIDER)
2112 key = KEYC_TRIPLECLICK7_SCROLLBAR_SLIDER;
2113 if (where == SCROLLBAR_DOWN)
2114 key = KEYC_TRIPLECLICK7_SCROLLBAR_DOWN;
2115 if (where == BORDER)
2116 key = KEYC_TRIPLECLICK7_BORDER;
2117 break;
2118 case MOUSE_BUTTON_8:
2119 if (where == PANE)
2120 key = KEYC_TRIPLECLICK8_PANE;
2121 if (where == STATUS)
2122 key = KEYC_TRIPLECLICK8_STATUS;
2123 if (where == STATUS_LEFT)
2124 key = KEYC_TRIPLECLICK8_STATUS_LEFT;
2125 if (where == STATUS_RIGHT)
2126 key = KEYC_TRIPLECLICK8_STATUS_RIGHT;
2127 if (where == STATUS_DEFAULT)
2128 key = KEYC_TRIPLECLICK8_STATUS_DEFAULT;
2129 if (where == SCROLLBAR_UP)
2130 key = KEYC_TRIPLECLICK8_SCROLLBAR_UP;
2131 if (where == SCROLLBAR_SLIDER)
2132 key = KEYC_TRIPLECLICK8_SCROLLBAR_SLIDER;
2133 if (where == SCROLLBAR_DOWN)
2134 key = KEYC_TRIPLECLICK8_SCROLLBAR_DOWN;
2135 if (where == BORDER)
2136 key = KEYC_TRIPLECLICK8_BORDER;
2137 break;
2138 case MOUSE_BUTTON_9:
2139 if (where == PANE)
2140 key = KEYC_TRIPLECLICK9_PANE;
2141 if (where == STATUS)
2142 key = KEYC_TRIPLECLICK9_STATUS;
2143 if (where == STATUS_LEFT)
2144 key = KEYC_TRIPLECLICK9_STATUS_LEFT;
2145 if (where == STATUS_RIGHT)
2146 key = KEYC_TRIPLECLICK9_STATUS_RIGHT;
2147 if (where == STATUS_DEFAULT)
2148 key = KEYC_TRIPLECLICK9_STATUS_DEFAULT;
2149 if (where == SCROLLBAR_UP)
2150 key = KEYC_TRIPLECLICK9_SCROLLBAR_UP;
2151 if (where == SCROLLBAR_SLIDER)
2152 key = KEYC_TRIPLECLICK9_SCROLLBAR_SLIDER;
2153 if (where == SCROLLBAR_DOWN)
2154 key = KEYC_TRIPLECLICK9_SCROLLBAR_DOWN;
2155 if (where == BORDER)
2156 key = KEYC_TRIPLECLICK9_BORDER;
2157 break;
2158 case MOUSE_BUTTON_10:
2159 if (where == PANE)
2160 key = KEYC_TRIPLECLICK10_PANE;
2161 if (where == STATUS)
2162 key = KEYC_TRIPLECLICK10_STATUS;
2163 if (where == STATUS_LEFT)
2164 key = KEYC_TRIPLECLICK10_STATUS_LEFT;
2165 if (where == STATUS_RIGHT)
2166 key = KEYC_TRIPLECLICK10_STATUS_RIGHT;
2167 if (where == STATUS_DEFAULT)
2168 key = KEYC_TRIPLECLICK10_STATUS_DEFAULT;
2169 if (where == SCROLLBAR_UP)
2170 key = KEYC_TRIPLECLICK10_SCROLLBAR_UP;
2171 if (where == SCROLLBAR_SLIDER)
2172 key = KEYC_TRIPLECLICK10_SCROLLBAR_SLIDER;
2173 if (where == SCROLLBAR_DOWN)
2174 key = KEYC_TRIPLECLICK10_SCROLLBAR_DOWN;
2175 if (where == BORDER)
2176 key = KEYC_TRIPLECLICK10_BORDER;
2177 break;
2178 case MOUSE_BUTTON_11:
2179 if (where == PANE)
2180 key = KEYC_TRIPLECLICK11_PANE;
2181 if (where == STATUS)
2182 key = KEYC_TRIPLECLICK11_STATUS;
2183 if (where == STATUS_LEFT)
2184 key = KEYC_TRIPLECLICK11_STATUS_LEFT;
2185 if (where == STATUS_RIGHT)
2186 key = KEYC_TRIPLECLICK11_STATUS_RIGHT;
2187 if (where == STATUS_DEFAULT)
2188 key = KEYC_TRIPLECLICK11_STATUS_DEFAULT;
2189 if (where == SCROLLBAR_UP)
2190 key = KEYC_TRIPLECLICK11_SCROLLBAR_UP;
2191 if (where == SCROLLBAR_SLIDER)
2192 key = KEYC_TRIPLECLICK11_SCROLLBAR_SLIDER;
2193 if (where == SCROLLBAR_DOWN)
2194 key = KEYC_TRIPLECLICK11_SCROLLBAR_DOWN;
2195 if (where == BORDER)
2196 key = KEYC_TRIPLECLICK11_BORDER;
2197 break;
2199 break;
2201 if (key == KEYC_UNKNOWN)
2202 return (KEYC_UNKNOWN);
2204 out:
2205 /* Apply modifiers if any. */
2206 if (b & MOUSE_MASK_META)
2207 key |= KEYC_META;
2208 if (b & MOUSE_MASK_CTRL)
2209 key |= KEYC_CTRL;
2210 if (b & MOUSE_MASK_SHIFT)
2211 key |= KEYC_SHIFT;
2213 if (log_get_level() != 0)
2214 log_debug("mouse key is %s", key_string_lookup_key (key, 1));
2215 return (key);
2218 /* Is this a bracket paste key? */
2219 static int
2220 server_client_is_bracket_paste(struct client *c, key_code key)
2222 if (key == KEYC_PASTE_START) {
2223 c->flags |= CLIENT_BRACKETPASTING;
2224 log_debug("%s: bracket paste on", c->name);
2225 return (0);
2228 if (key == KEYC_PASTE_END) {
2229 c->flags &= ~CLIENT_BRACKETPASTING;
2230 log_debug("%s: bracket paste off", c->name);
2231 return (0);
2234 return !!(c->flags & CLIENT_BRACKETPASTING);
2237 /* Is this fast enough to probably be a paste? */
2238 static int
2239 server_client_is_assume_paste(struct client *c)
2241 struct session *s = c->session;
2242 struct timeval tv;
2243 int t;
2245 if (c->flags & CLIENT_BRACKETPASTING)
2246 return (0);
2247 if ((t = options_get_number(s->options, "assume-paste-time")) == 0)
2248 return (0);
2250 timersub(&c->activity_time, &c->last_activity_time, &tv);
2251 if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) {
2252 if (c->flags & CLIENT_ASSUMEPASTING)
2253 return (1);
2254 c->flags |= CLIENT_ASSUMEPASTING;
2255 log_debug("%s: assume paste on", c->name);
2256 return (0);
2258 if (c->flags & CLIENT_ASSUMEPASTING) {
2259 c->flags &= ~CLIENT_ASSUMEPASTING;
2260 log_debug("%s: assume paste off", c->name);
2262 return (0);
2265 /* Has the latest client changed? */
2266 static void
2267 server_client_update_latest(struct client *c)
2269 struct window *w;
2271 if (c->session == NULL)
2272 return;
2273 w = c->session->curw->window;
2275 if (w->latest == c)
2276 return;
2277 w->latest = c;
2279 if (options_get_number(w->options, "window-size") == WINDOW_SIZE_LATEST)
2280 recalculate_size(w, 0);
2282 notify_client("client-active", c);
2285 /* Get repeat time. */
2286 static u_int
2287 server_client_repeat_time(struct client *c, struct key_binding *bd)
2289 struct session *s = c->session;
2290 u_int repeat, initial;
2292 if (~bd->flags & KEY_BINDING_REPEAT)
2293 return (0);
2294 repeat = options_get_number(s->options, "repeat-time");
2295 if (repeat == 0)
2296 return (0);
2297 if ((~c->flags & CLIENT_REPEAT) || bd->key != c->last_key) {
2298 initial = options_get_number(s->options, "initial-repeat-time");
2299 if (initial != 0)
2300 repeat = initial;
2302 return (repeat);
2306 * Handle data key input from client. This owns and can modify the key event it
2307 * is given and is responsible for freeing it.
2309 static enum cmd_retval
2310 server_client_key_callback(struct cmdq_item *item, void *data)
2312 struct client *c = cmdq_get_client(item);
2313 struct key_event *event = data;
2314 key_code key = event->key;
2315 struct mouse_event *m = &event->m;
2316 struct session *s = c->session;
2317 struct winlink *wl;
2318 struct window_pane *wp;
2319 struct window_mode_entry *wme;
2320 struct timeval tv;
2321 struct key_table *table, *first;
2322 struct key_binding *bd;
2323 u_int repeat;
2324 uint64_t flags, prefix_delay;
2325 struct cmd_find_state fs;
2326 key_code key0, prefix, prefix2;
2328 /* Check the client is good to accept input. */
2329 if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
2330 goto out;
2331 wl = s->curw;
2333 /* Update the activity timer. */
2334 memcpy(&c->last_activity_time, &c->activity_time,
2335 sizeof c->last_activity_time);
2336 if (gettimeofday(&c->activity_time, NULL) != 0)
2337 fatal("gettimeofday failed");
2338 session_update_activity(s, &c->activity_time);
2340 /* Check for mouse keys. */
2341 m->valid = 0;
2342 if (key == KEYC_MOUSE || key == KEYC_DOUBLECLICK) {
2343 if (c->flags & CLIENT_READONLY)
2344 goto out;
2345 key = server_client_check_mouse(c, event);
2346 if (key == KEYC_UNKNOWN)
2347 goto out;
2349 m->valid = 1;
2350 m->key = key;
2353 * Mouse drag is in progress, so fire the callback (now that
2354 * the mouse event is valid).
2356 if ((key & KEYC_MASK_KEY) == KEYC_DRAGGING) {
2357 c->tty.mouse_drag_update(c, m);
2358 goto out;
2360 event->key = key;
2363 /* Find affected pane. */
2364 if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
2365 cmd_find_from_client(&fs, c, 0);
2366 wp = fs.wp;
2368 /* Forward mouse keys if disabled. */
2369 if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse"))
2370 goto forward_key;
2372 /* Forward if bracket pasting. */
2373 if (server_client_is_bracket_paste (c, key))
2374 goto paste_key;
2376 /* Treat everything as a regular key when pasting is detected. */
2377 if (!KEYC_IS_MOUSE(key) &&
2378 key != KEYC_FOCUS_IN &&
2379 key != KEYC_FOCUS_OUT &&
2380 (~key & KEYC_SENT) &&
2381 server_client_is_assume_paste(c))
2382 goto paste_key;
2385 * Work out the current key table. If the pane is in a mode, use
2386 * the mode table instead of the default key table.
2388 if (server_client_is_default_key_table(c, c->keytable) &&
2389 wp != NULL &&
2390 (wme = TAILQ_FIRST(&wp->modes)) != NULL &&
2391 wme->mode->key_table != NULL)
2392 table = key_bindings_get_table(wme->mode->key_table(wme), 1);
2393 else
2394 table = c->keytable;
2395 first = table;
2397 table_changed:
2399 * The prefix always takes precedence and forces a switch to the prefix
2400 * table, unless we are already there.
2402 prefix = (key_code)options_get_number(s->options, "prefix");
2403 prefix2 = (key_code)options_get_number(s->options, "prefix2");
2404 key0 = (key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS));
2405 if ((key0 == (prefix & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) ||
2406 key0 == (prefix2 & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS))) &&
2407 strcmp(table->name, "prefix") != 0) {
2408 server_client_set_key_table(c, "prefix");
2409 server_status_client(c);
2410 goto out;
2412 flags = c->flags;
2414 try_again:
2415 /* Log key table. */
2416 if (wp == NULL)
2417 log_debug("key table %s (no pane)", table->name);
2418 else
2419 log_debug("key table %s (pane %%%u)", table->name, wp->id);
2420 if (c->flags & CLIENT_REPEAT)
2421 log_debug("currently repeating");
2423 bd = key_bindings_get(table, key0);
2426 * If prefix-timeout is enabled and we're in the prefix table, see if
2427 * the timeout has been exceeded. Revert to the root table if so.
2429 prefix_delay = options_get_number(global_options, "prefix-timeout");
2430 if (prefix_delay > 0 &&
2431 strcmp(table->name, "prefix") == 0 &&
2432 server_client_key_table_activity_diff(c) > prefix_delay) {
2434 * If repeating is active and this is a repeating binding,
2435 * ignore the timeout.
2437 if (bd != NULL &&
2438 (c->flags & CLIENT_REPEAT) &&
2439 (bd->flags & KEY_BINDING_REPEAT)) {
2440 log_debug("prefix timeout ignored, repeat is active");
2441 } else {
2442 log_debug("prefix timeout exceeded");
2443 server_client_set_key_table(c, NULL);
2444 first = table = c->keytable;
2445 server_status_client(c);
2446 goto table_changed;
2450 /* Try to see if there is a key binding in the current table. */
2451 if (bd != NULL) {
2453 * Key was matched in this table. If currently repeating but a
2454 * non-repeating binding was found, stop repeating and try
2455 * again in the root table.
2457 if ((c->flags & CLIENT_REPEAT) &&
2458 (~bd->flags & KEY_BINDING_REPEAT)) {
2459 log_debug("found in key table %s (not repeating)",
2460 table->name);
2461 server_client_set_key_table(c, NULL);
2462 first = table = c->keytable;
2463 c->flags &= ~CLIENT_REPEAT;
2464 server_status_client(c);
2465 goto table_changed;
2467 log_debug("found in key table %s", table->name);
2470 * Take a reference to this table to make sure the key binding
2471 * doesn't disappear.
2473 table->references++;
2476 * If this is a repeating key, start the timer. Otherwise reset
2477 * the client back to the root table.
2479 repeat = server_client_repeat_time(c, bd);
2480 if (repeat != 0) {
2481 c->flags |= CLIENT_REPEAT;
2482 c->last_key = bd->key;
2484 tv.tv_sec = repeat / 1000;
2485 tv.tv_usec = (repeat % 1000) * 1000L;
2486 evtimer_del(&c->repeat_timer);
2487 evtimer_add(&c->repeat_timer, &tv);
2488 } else {
2489 c->flags &= ~CLIENT_REPEAT;
2490 server_client_set_key_table(c, NULL);
2492 server_status_client(c);
2494 /* Execute the key binding. */
2495 key_bindings_dispatch(bd, item, c, event, &fs);
2496 key_bindings_unref_table(table);
2497 goto out;
2501 * No match, try the ANY key.
2503 if (key0 != KEYC_ANY) {
2504 key0 = KEYC_ANY;
2505 goto try_again;
2509 * Binding movement keys is useless since we only turn them on when the
2510 * application requests, so don't let them exit the prefix table.
2512 if (key == KEYC_MOUSEMOVE_PANE ||
2513 key == KEYC_MOUSEMOVE_STATUS ||
2514 key == KEYC_MOUSEMOVE_STATUS_LEFT ||
2515 key == KEYC_MOUSEMOVE_STATUS_RIGHT ||
2516 key == KEYC_MOUSEMOVE_STATUS_DEFAULT ||
2517 key == KEYC_MOUSEMOVE_BORDER)
2518 goto forward_key;
2521 * No match in this table. If not in the root table or if repeating
2522 * switch the client back to the root table and try again.
2524 log_debug("not found in key table %s", table->name);
2525 if (!server_client_is_default_key_table(c, table) ||
2526 (c->flags & CLIENT_REPEAT)) {
2527 log_debug("trying in root table");
2528 server_client_set_key_table(c, NULL);
2529 table = c->keytable;
2530 if (c->flags & CLIENT_REPEAT)
2531 first = table;
2532 c->flags &= ~CLIENT_REPEAT;
2533 server_status_client(c);
2534 goto table_changed;
2538 * No match in the root table either. If this wasn't the first table
2539 * tried, don't pass the key to the pane.
2541 if (first != table && (~flags & CLIENT_REPEAT)) {
2542 server_client_set_key_table(c, NULL);
2543 server_status_client(c);
2544 goto out;
2547 forward_key:
2548 if (c->flags & CLIENT_READONLY)
2549 goto out;
2550 if (wp != NULL)
2551 window_pane_key(wp, c, s, wl, key, m);
2552 goto out;
2554 paste_key:
2555 if (c->flags & CLIENT_READONLY)
2556 goto out;
2557 if (event->buf != NULL)
2558 window_pane_paste(wp, event->buf, event->len);
2559 key = KEYC_NONE;
2560 goto out;
2562 out:
2563 if (s != NULL && key != KEYC_FOCUS_OUT)
2564 server_client_update_latest(c);
2565 free(event->buf);
2566 free(event);
2567 return (CMD_RETURN_NORMAL);
2570 /* Handle a key event. */
2572 server_client_handle_key(struct client *c, struct key_event *event)
2574 struct session *s = c->session;
2575 struct cmdq_item *item;
2577 /* Check the client is good to accept input. */
2578 if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
2579 return (0);
2582 * Key presses in overlay mode and the command prompt are a special
2583 * case. The queue might be blocked so they need to be processed
2584 * immediately rather than queued.
2586 if (~c->flags & CLIENT_READONLY) {
2587 if (c->message_string != NULL) {
2588 if (c->message_ignore_keys)
2589 return (0);
2590 status_message_clear(c);
2592 if (c->overlay_key != NULL) {
2593 switch (c->overlay_key(c, c->overlay_data, event)) {
2594 case 0:
2595 return (0);
2596 case 1:
2597 server_client_clear_overlay(c);
2598 return (0);
2601 server_client_clear_overlay(c);
2602 if (c->prompt_string != NULL) {
2603 if (status_prompt_key(c, event->key) == 0)
2604 return (0);
2609 * Add the key to the queue so it happens after any commands queued by
2610 * previous keys.
2612 item = cmdq_get_callback(server_client_key_callback, event);
2613 cmdq_append(c, item);
2614 return (1);
2617 /* Client functions that need to happen every loop. */
2618 void
2619 server_client_loop(void)
2621 struct client *c;
2622 struct window *w;
2623 struct window_pane *wp;
2625 /* Check for window resize. This is done before redrawing. */
2626 RB_FOREACH(w, windows, &windows)
2627 server_client_check_window_resize(w);
2629 /* Check clients. */
2630 TAILQ_FOREACH(c, &clients, entry) {
2631 server_client_check_exit(c);
2632 if (c->session != NULL) {
2633 server_client_check_modes(c);
2634 server_client_check_redraw(c);
2635 server_client_reset_state(c);
2640 * Any windows will have been redrawn as part of clients, so clear
2641 * their flags now.
2643 RB_FOREACH(w, windows, &windows) {
2644 TAILQ_FOREACH(wp, &w->panes, entry) {
2645 if (wp->fd != -1) {
2646 server_client_check_pane_resize(wp);
2647 server_client_check_pane_buffer(wp);
2649 wp->flags &= ~(PANE_REDRAW|PANE_REDRAWSCROLLBAR);
2651 check_window_name(w);
2655 /* Check if window needs to be resized. */
2656 static void
2657 server_client_check_window_resize(struct window *w)
2659 struct winlink *wl;
2661 if (~w->flags & WINDOW_RESIZE)
2662 return;
2664 TAILQ_FOREACH(wl, &w->winlinks, wentry) {
2665 if (wl->session->attached != 0 && wl->session->curw == wl)
2666 break;
2668 if (wl == NULL)
2669 return;
2671 log_debug("%s: resizing window @%u", __func__, w->id);
2672 resize_window(w, w->new_sx, w->new_sy, w->new_xpixel, w->new_ypixel);
2675 /* Resize timer event. */
2676 static void
2677 server_client_resize_timer(__unused int fd, __unused short events, void *data)
2679 struct window_pane *wp = data;
2681 log_debug("%s: %%%u resize timer expired", __func__, wp->id);
2682 evtimer_del(&wp->resize_timer);
2685 /* Check if pane should be resized. */
2686 static void
2687 server_client_check_pane_resize(struct window_pane *wp)
2689 struct window_pane_resize *r;
2690 struct window_pane_resize *r1;
2691 struct window_pane_resize *first;
2692 struct window_pane_resize *last;
2693 struct timeval tv = { .tv_usec = 250000 };
2695 if (TAILQ_EMPTY(&wp->resize_queue))
2696 return;
2698 if (!event_initialized(&wp->resize_timer))
2699 evtimer_set(&wp->resize_timer, server_client_resize_timer, wp);
2700 if (evtimer_pending(&wp->resize_timer, NULL))
2701 return;
2703 log_debug("%s: %%%u needs to be resized", __func__, wp->id);
2704 TAILQ_FOREACH(r, &wp->resize_queue, entry) {
2705 log_debug("queued resize: %ux%u -> %ux%u", r->osx, r->osy,
2706 r->sx, r->sy);
2710 * There are three cases that matter:
2712 * - Only one resize. It can just be applied.
2714 * - Multiple resizes and the ending size is different from the
2715 * starting size. We can discard all resizes except the most recent.
2717 * - Multiple resizes and the ending size is the same as the starting
2718 * size. We must resize at least twice to force the application to
2719 * redraw. So apply the first and leave the last on the queue for
2720 * next time.
2722 first = TAILQ_FIRST(&wp->resize_queue);
2723 last = TAILQ_LAST(&wp->resize_queue, window_pane_resizes);
2724 if (first == last) {
2725 /* Only one resize. */
2726 window_pane_send_resize(wp, first->sx, first->sy);
2727 TAILQ_REMOVE(&wp->resize_queue, first, entry);
2728 free(first);
2729 } else if (last->sx != first->osx || last->sy != first->osy) {
2730 /* Multiple resizes ending up with a different size. */
2731 window_pane_send_resize(wp, last->sx, last->sy);
2732 TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
2733 TAILQ_REMOVE(&wp->resize_queue, r, entry);
2734 free(r);
2736 } else {
2738 * Multiple resizes ending up with the same size. There will
2739 * not be more than one to the same size in succession so we
2740 * can just use the last-but-one on the list and leave the last
2741 * for later. We reduce the time until the next check to avoid
2742 * a long delay between the resizes.
2744 r = TAILQ_PREV(last, window_pane_resizes, entry);
2745 window_pane_send_resize(wp, r->sx, r->sy);
2746 TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
2747 if (r == last)
2748 break;
2749 TAILQ_REMOVE(&wp->resize_queue, r, entry);
2750 free(r);
2752 tv.tv_usec = 10000;
2754 evtimer_add(&wp->resize_timer, &tv);
2757 /* Check pane buffer size. */
2758 static void
2759 server_client_check_pane_buffer(struct window_pane *wp)
2761 struct evbuffer *evb = wp->event->input;
2762 size_t minimum;
2763 struct client *c;
2764 struct window_pane_offset *wpo;
2765 int off = 1, flag;
2766 u_int attached_clients = 0;
2767 size_t new_size;
2770 * Work out the minimum used size. This is the most that can be removed
2771 * from the buffer.
2773 minimum = wp->offset.used;
2774 if (wp->pipe_fd != -1 && wp->pipe_offset.used < minimum)
2775 minimum = wp->pipe_offset.used;
2776 TAILQ_FOREACH(c, &clients, entry) {
2777 if (c->session == NULL)
2778 continue;
2779 attached_clients++;
2781 if (~c->flags & CLIENT_CONTROL) {
2782 off = 0;
2783 continue;
2785 wpo = control_pane_offset(c, wp, &flag);
2786 if (wpo == NULL) {
2787 if (!flag)
2788 off = 0;
2789 continue;
2791 if (!flag)
2792 off = 0;
2794 window_pane_get_new_data(wp, wpo, &new_size);
2795 log_debug("%s: %s has %zu bytes used and %zu left for %%%u",
2796 __func__, c->name, wpo->used - wp->base_offset, new_size,
2797 wp->id);
2798 if (wpo->used < minimum)
2799 minimum = wpo->used;
2801 if (attached_clients == 0)
2802 off = 0;
2803 minimum -= wp->base_offset;
2804 if (minimum == 0)
2805 goto out;
2807 /* Drain the buffer. */
2808 log_debug("%s: %%%u has %zu minimum (of %zu) bytes used", __func__,
2809 wp->id, minimum, EVBUFFER_LENGTH(evb));
2810 evbuffer_drain(evb, minimum);
2813 * Adjust the base offset. If it would roll over, all the offsets into
2814 * the buffer need to be adjusted.
2816 if (wp->base_offset > SIZE_MAX - minimum) {
2817 log_debug("%s: %%%u base offset has wrapped", __func__, wp->id);
2818 wp->offset.used -= wp->base_offset;
2819 if (wp->pipe_fd != -1)
2820 wp->pipe_offset.used -= wp->base_offset;
2821 TAILQ_FOREACH(c, &clients, entry) {
2822 if (c->session == NULL || (~c->flags & CLIENT_CONTROL))
2823 continue;
2824 wpo = control_pane_offset(c, wp, &flag);
2825 if (wpo != NULL && !flag)
2826 wpo->used -= wp->base_offset;
2828 wp->base_offset = minimum;
2829 } else
2830 wp->base_offset += minimum;
2832 out:
2834 * If there is data remaining, and there are no clients able to consume
2835 * it, do not read any more. This is true when there are attached
2836 * clients, all of which are control clients which are not able to
2837 * accept any more data.
2839 log_debug("%s: pane %%%u is %s", __func__, wp->id, off ? "off" : "on");
2840 if (off)
2841 bufferevent_disable(wp->event, EV_READ);
2842 else
2843 bufferevent_enable(wp->event, EV_READ);
2847 * Update cursor position and mode settings. The scroll region and attributes
2848 * are cleared when idle (waiting for an event) as this is the most likely time
2849 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
2850 * compromise between excessive resets and likelihood of an interrupt.
2852 * tty_region/tty_reset/tty_update_mode already take care of not resetting
2853 * things that are already in their default state.
2855 static void
2856 server_client_reset_state(struct client *c)
2858 struct tty *tty = &c->tty;
2859 struct window *w = c->session->curw->window;
2860 struct window_pane *wp = server_client_get_pane(c), *loop;
2861 struct screen *s = NULL;
2862 struct options *oo = c->session->options;
2863 int mode = 0, cursor, flags, n;
2864 u_int cx = 0, cy = 0, ox, oy, sx, sy;
2866 if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
2867 return;
2869 /* Disable the block flag. */
2870 flags = (tty->flags & TTY_BLOCK);
2871 tty->flags &= ~TTY_BLOCK;
2873 /* Get mode from overlay if any, else from screen. */
2874 if (c->overlay_draw != NULL) {
2875 if (c->overlay_mode != NULL)
2876 s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
2877 } else if (c->prompt_string == NULL)
2878 s = wp->screen;
2879 else
2880 s = c->status.active;
2881 if (s != NULL)
2882 mode = s->mode;
2883 if (log_get_level() != 0) {
2884 log_debug("%s: client %s mode %s", __func__, c->name,
2885 screen_mode_to_string(mode));
2888 /* Reset region and margin. */
2889 tty_region_off(tty);
2890 tty_margin_off(tty);
2892 /* Move cursor to pane cursor and offset. */
2893 if (c->prompt_string != NULL) {
2894 n = options_get_number(oo, "status-position");
2895 if (n == 0)
2896 cy = 0;
2897 else {
2898 n = status_line_size(c);
2899 if (n == 0)
2900 cy = tty->sy - 1;
2901 else
2902 cy = tty->sy - n;
2904 cx = c->prompt_cursor;
2905 } else if (c->overlay_draw == NULL) {
2906 cursor = 0;
2907 tty_window_offset(tty, &ox, &oy, &sx, &sy);
2908 if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
2909 wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
2910 cursor = 1;
2912 cx = wp->xoff + s->cx - ox;
2913 cy = wp->yoff + s->cy - oy;
2915 if (status_at_line(c) == 0)
2916 cy += status_line_size(c);
2918 if (!cursor)
2919 mode &= ~MODE_CURSOR;
2921 log_debug("%s: cursor to %u,%u", __func__, cx, cy);
2922 tty_cursor(tty, cx, cy);
2925 * Set mouse mode if requested. To support dragging, always use button
2926 * mode.
2928 if (options_get_number(oo, "mouse")) {
2929 if (c->overlay_draw == NULL) {
2930 mode &= ~ALL_MOUSE_MODES;
2931 TAILQ_FOREACH(loop, &w->panes, entry) {
2932 if (loop->screen->mode & MODE_MOUSE_ALL)
2933 mode |= MODE_MOUSE_ALL;
2936 if (~mode & MODE_MOUSE_ALL)
2937 mode |= MODE_MOUSE_BUTTON;
2940 /* Clear bracketed paste mode if at the prompt. */
2941 if (c->overlay_draw == NULL && c->prompt_string != NULL)
2942 mode &= ~MODE_BRACKETPASTE;
2944 /* Set the terminal mode and reset attributes. */
2945 tty_update_mode(tty, mode, s);
2946 tty_reset(tty);
2948 /* All writing must be done, send a sync end (if it was started). */
2949 tty_sync_end(tty);
2950 tty->flags |= flags;
2953 /* Repeat time callback. */
2954 static void
2955 server_client_repeat_timer(__unused int fd, __unused short events, void *data)
2957 struct client *c = data;
2959 if (c->flags & CLIENT_REPEAT) {
2960 server_client_set_key_table(c, NULL);
2961 c->flags &= ~CLIENT_REPEAT;
2962 server_status_client(c);
2966 /* Double-click callback. */
2967 static void
2968 server_client_click_timer(__unused int fd, __unused short events, void *data)
2970 struct client *c = data;
2971 struct key_event *event;
2973 log_debug("click timer expired");
2975 if (c->flags & CLIENT_TRIPLECLICK) {
2977 * Waiting for a third click that hasn't happened, so this must
2978 * have been a double click.
2980 event = xcalloc(1, sizeof *event);
2981 event->key = KEYC_DOUBLECLICK;
2982 memcpy(&event->m, &c->click_event, sizeof event->m);
2983 if (!server_client_handle_key(c, event)) {
2984 free(event->buf);
2985 free(event);
2988 c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK);
2991 /* Check if client should be exited. */
2992 static void
2993 server_client_check_exit(struct client *c)
2995 struct client_file *cf;
2996 const char *name = c->exit_session;
2997 char *data;
2998 size_t size, msize;
3000 if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
3001 return;
3002 if (~c->flags & CLIENT_EXIT)
3003 return;
3005 if (c->flags & CLIENT_CONTROL) {
3006 control_discard(c);
3007 if (!control_all_done(c))
3008 return;
3010 RB_FOREACH(cf, client_files, &c->files) {
3011 if (EVBUFFER_LENGTH(cf->buffer) != 0)
3012 return;
3014 c->flags |= CLIENT_EXITED;
3016 switch (c->exit_type) {
3017 case CLIENT_EXIT_RETURN:
3018 if (c->exit_message != NULL)
3019 msize = strlen(c->exit_message) + 1;
3020 else
3021 msize = 0;
3022 size = (sizeof c->retval) + msize;
3023 data = xmalloc(size);
3024 memcpy(data, &c->retval, sizeof c->retval);
3025 if (c->exit_message != NULL)
3026 memcpy(data + sizeof c->retval, c->exit_message, msize);
3027 proc_send(c->peer, MSG_EXIT, -1, data, size);
3028 free(data);
3029 break;
3030 case CLIENT_EXIT_SHUTDOWN:
3031 proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
3032 break;
3033 case CLIENT_EXIT_DETACH:
3034 proc_send(c->peer, c->exit_msgtype, -1, name, strlen(name) + 1);
3035 break;
3037 free(c->exit_session);
3038 free(c->exit_message);
3041 /* Redraw timer callback. */
3042 static void
3043 server_client_redraw_timer(__unused int fd, __unused short events,
3044 __unused void *data)
3046 log_debug("redraw timer fired");
3050 * Check if modes need to be updated. Only modes in the current window are
3051 * updated and it is done when the status line is redrawn.
3053 static void
3054 server_client_check_modes(struct client *c)
3056 struct window *w = c->session->curw->window;
3057 struct window_pane *wp;
3058 struct window_mode_entry *wme;
3060 if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
3061 return;
3062 if (~c->flags & CLIENT_REDRAWSTATUS)
3063 return;
3064 TAILQ_FOREACH(wp, &w->panes, entry) {
3065 wme = TAILQ_FIRST(&wp->modes);
3066 if (wme != NULL && wme->mode->update != NULL)
3067 wme->mode->update(wme);
3071 /* Check for client redraws. */
3072 static void
3073 server_client_check_redraw(struct client *c)
3075 struct session *s = c->session;
3076 struct tty *tty = &c->tty;
3077 struct window *w = c->session->curw->window;
3078 struct window_pane *wp;
3079 int needed, tty_flags, mode = tty->mode;
3080 uint64_t client_flags = 0;
3081 int redraw_pane, redraw_scrollbar_only;
3082 u_int bit = 0;
3083 struct timeval tv = { .tv_usec = 1000 };
3084 static struct event ev;
3085 size_t left;
3087 if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
3088 return;
3089 if (c->flags & CLIENT_ALLREDRAWFLAGS) {
3090 log_debug("%s: redraw%s%s%s%s%s%s", c->name,
3091 (c->flags & CLIENT_REDRAWWINDOW) ? " window" : "",
3092 (c->flags & CLIENT_REDRAWSTATUS) ? " status" : "",
3093 (c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "",
3094 (c->flags & CLIENT_REDRAWOVERLAY) ? " overlay" : "",
3095 (c->flags & CLIENT_REDRAWPANES) ? " panes" : "",
3096 (c->flags & CLIENT_REDRAWSCROLLBARS) ? " scrollbars" : "");
3100 * If there is outstanding data, defer the redraw until it has been
3101 * consumed. We can just add a timer to get out of the event loop and
3102 * end up back here.
3104 needed = 0;
3105 if (c->flags & CLIENT_ALLREDRAWFLAGS)
3106 needed = 1;
3107 else {
3108 TAILQ_FOREACH(wp, &w->panes, entry) {
3109 if (wp->flags & PANE_REDRAW) {
3110 needed = 1;
3111 client_flags |= CLIENT_REDRAWPANES;
3112 break;
3114 if (wp->flags & PANE_REDRAWSCROLLBAR) {
3115 needed = 1;
3116 client_flags |= CLIENT_REDRAWSCROLLBARS;
3117 /* no break - later panes may need redraw */
3121 if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) {
3122 log_debug("%s: redraw deferred (%zu left)", c->name, left);
3123 if (!evtimer_initialized(&ev))
3124 evtimer_set(&ev, server_client_redraw_timer, NULL);
3125 if (!evtimer_pending(&ev, NULL)) {
3126 log_debug("redraw timer started");
3127 evtimer_add(&ev, &tv);
3130 if (~c->flags & CLIENT_REDRAWWINDOW) {
3131 TAILQ_FOREACH(wp, &w->panes, entry) {
3132 if (wp->flags & (PANE_REDRAW)) {
3133 log_debug("%s: pane %%%u needs redraw",
3134 c->name, wp->id);
3135 c->redraw_panes |= (1 << bit);
3136 } else if (wp->flags & PANE_REDRAWSCROLLBAR) {
3137 log_debug("%s: pane %%%u scrollbar "
3138 "needs redraw", c->name, wp->id);
3139 c->redraw_scrollbars |= (1 << bit);
3141 if (++bit == 64) {
3143 * If more that 64 panes, give up and
3144 * just redraw the window.
3146 client_flags &= ~(CLIENT_REDRAWPANES|
3147 CLIENT_REDRAWSCROLLBARS);
3148 client_flags |= CLIENT_REDRAWWINDOW;
3149 break;
3152 if (c->redraw_panes != 0)
3153 c->flags |= CLIENT_REDRAWPANES;
3154 if (c->redraw_scrollbars != 0)
3155 c->flags |= CLIENT_REDRAWSCROLLBARS;
3157 c->flags |= client_flags;
3158 return;
3159 } else if (needed)
3160 log_debug("%s: redraw needed", c->name);
3162 tty_flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
3163 tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE))|TTY_NOCURSOR;
3165 if (~c->flags & CLIENT_REDRAWWINDOW) {
3167 * If not redrawing the entire window, check whether each pane
3168 * needs to be redrawn.
3170 TAILQ_FOREACH(wp, &w->panes, entry) {
3171 redraw_pane = 0;
3172 redraw_scrollbar_only = 0;
3173 if (wp->flags & PANE_REDRAW)
3174 redraw_pane = 1;
3175 else if (c->flags & CLIENT_REDRAWPANES) {
3176 if (c->redraw_panes & (1 << bit))
3177 redraw_pane = 1;
3178 } else if (c->flags & CLIENT_REDRAWSCROLLBARS) {
3179 if (c->redraw_scrollbars & (1 << bit))
3180 redraw_scrollbar_only = 1;
3182 bit++;
3183 if (!redraw_pane && !redraw_scrollbar_only)
3184 continue;
3185 if (redraw_scrollbar_only) {
3186 log_debug("%s: redrawing (scrollbar only) pane "
3187 "%%%u", __func__, wp->id);
3188 } else {
3189 log_debug("%s: redrawing pane %%%u", __func__,
3190 wp->id);
3192 screen_redraw_pane(c, wp, redraw_scrollbar_only);
3194 c->redraw_panes = 0;
3195 c->redraw_scrollbars = 0;
3196 c->flags &= ~(CLIENT_REDRAWPANES|CLIENT_REDRAWSCROLLBARS);
3199 if (c->flags & CLIENT_ALLREDRAWFLAGS) {
3200 if (options_get_number(s->options, "set-titles")) {
3201 server_client_set_title(c);
3202 server_client_set_path(c);
3204 screen_redraw_screen(c);
3207 tty->flags = (tty->flags & ~TTY_NOCURSOR)|(tty_flags & TTY_NOCURSOR);
3208 tty_update_mode(tty, mode, NULL);
3209 tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR))|
3210 tty_flags;
3212 c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE);
3214 if (needed) {
3216 * We would have deferred the redraw unless the output buffer
3217 * was empty, so we can record how many bytes the redraw
3218 * generated.
3220 c->redraw = EVBUFFER_LENGTH(tty->out);
3221 log_debug("%s: redraw added %zu bytes", c->name, c->redraw);
3225 /* Set client title. */
3226 static void
3227 server_client_set_title(struct client *c)
3229 struct session *s = c->session;
3230 const char *template;
3231 char *title;
3232 struct format_tree *ft;
3234 template = options_get_string(s->options, "set-titles-string");
3236 ft = format_create(c, NULL, FORMAT_NONE, 0);
3237 format_defaults(ft, c, NULL, NULL, NULL);
3239 title = format_expand_time(ft, template);
3240 if (c->title == NULL || strcmp(title, c->title) != 0) {
3241 free(c->title);
3242 c->title = xstrdup(title);
3243 tty_set_title(&c->tty, c->title);
3245 free(title);
3247 format_free(ft);
3250 /* Set client path. */
3251 static void
3252 server_client_set_path(struct client *c)
3254 struct session *s = c->session;
3255 const char *path;
3257 if (s->curw == NULL)
3258 return;
3259 if (s->curw->window->active->base.path == NULL)
3260 path = "";
3261 else
3262 path = s->curw->window->active->base.path;
3263 if (c->path == NULL || strcmp(path, c->path) != 0) {
3264 free(c->path);
3265 c->path = xstrdup(path);
3266 tty_set_path(&c->tty, c->path);
3270 /* Dispatch message from client. */
3271 static void
3272 server_client_dispatch(struct imsg *imsg, void *arg)
3274 struct client *c = arg;
3275 ssize_t datalen;
3276 struct session *s;
3278 if (c->flags & CLIENT_DEAD)
3279 return;
3281 if (imsg == NULL) {
3282 server_client_lost(c);
3283 return;
3286 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
3288 switch (imsg->hdr.type) {
3289 case MSG_IDENTIFY_CLIENTPID:
3290 case MSG_IDENTIFY_CWD:
3291 case MSG_IDENTIFY_ENVIRON:
3292 case MSG_IDENTIFY_FEATURES:
3293 case MSG_IDENTIFY_FLAGS:
3294 case MSG_IDENTIFY_LONGFLAGS:
3295 case MSG_IDENTIFY_STDIN:
3296 case MSG_IDENTIFY_STDOUT:
3297 case MSG_IDENTIFY_TERM:
3298 case MSG_IDENTIFY_TERMINFO:
3299 case MSG_IDENTIFY_TTYNAME:
3300 case MSG_IDENTIFY_DONE:
3301 server_client_dispatch_identify(c, imsg);
3302 break;
3303 case MSG_COMMAND:
3304 server_client_dispatch_command(c, imsg);
3305 break;
3306 case MSG_RESIZE:
3307 if (datalen != 0)
3308 fatalx("bad MSG_RESIZE size");
3310 if (c->flags & CLIENT_CONTROL)
3311 break;
3312 server_client_update_latest(c);
3313 tty_resize(&c->tty);
3314 tty_repeat_requests(&c->tty);
3315 recalculate_sizes();
3316 if (c->overlay_resize == NULL)
3317 server_client_clear_overlay(c);
3318 else
3319 c->overlay_resize(c, c->overlay_data);
3320 server_redraw_client(c);
3321 if (c->session != NULL)
3322 notify_client("client-resized", c);
3323 break;
3324 case MSG_EXITING:
3325 if (datalen != 0)
3326 fatalx("bad MSG_EXITING size");
3327 server_client_set_session(c, NULL);
3328 recalculate_sizes();
3329 tty_close(&c->tty);
3330 proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
3331 break;
3332 case MSG_WAKEUP:
3333 case MSG_UNLOCK:
3334 if (datalen != 0)
3335 fatalx("bad MSG_WAKEUP size");
3337 if (!(c->flags & CLIENT_SUSPENDED))
3338 break;
3339 c->flags &= ~CLIENT_SUSPENDED;
3341 if (c->fd == -1 || c->session == NULL) /* exited already */
3342 break;
3343 s = c->session;
3345 if (gettimeofday(&c->activity_time, NULL) != 0)
3346 fatal("gettimeofday failed");
3348 tty_start_tty(&c->tty);
3349 server_redraw_client(c);
3350 recalculate_sizes();
3352 if (s != NULL)
3353 session_update_activity(s, &c->activity_time);
3354 break;
3355 case MSG_SHELL:
3356 if (datalen != 0)
3357 fatalx("bad MSG_SHELL size");
3359 server_client_dispatch_shell(c);
3360 break;
3361 case MSG_WRITE_READY:
3362 file_write_ready(&c->files, imsg);
3363 break;
3364 case MSG_READ:
3365 file_read_data(&c->files, imsg);
3366 break;
3367 case MSG_READ_DONE:
3368 file_read_done(&c->files, imsg);
3369 break;
3373 /* Callback when command is not allowed. */
3374 static enum cmd_retval
3375 server_client_read_only(struct cmdq_item *item, __unused void *data)
3377 cmdq_error(item, "client is read-only");
3378 return (CMD_RETURN_ERROR);
3381 /* Callback when command is done. */
3382 static enum cmd_retval
3383 server_client_command_done(struct cmdq_item *item, __unused void *data)
3385 struct client *c = cmdq_get_client(item);
3387 if (~c->flags & CLIENT_ATTACHED)
3388 c->flags |= CLIENT_EXIT;
3389 else if (~c->flags & CLIENT_EXIT) {
3390 if (c->flags & CLIENT_CONTROL)
3391 control_ready(c);
3392 tty_send_requests(&c->tty);
3394 return (CMD_RETURN_NORMAL);
3397 /* Handle command message. */
3398 static void
3399 server_client_dispatch_command(struct client *c, struct imsg *imsg)
3401 struct msg_command data;
3402 char *buf;
3403 size_t len;
3404 int argc;
3405 char **argv, *cause;
3406 struct cmd_parse_result *pr;
3407 struct args_value *values;
3408 struct cmdq_item *new_item;
3410 if (c->flags & CLIENT_EXIT)
3411 return;
3413 if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data)
3414 fatalx("bad MSG_COMMAND size");
3415 memcpy(&data, imsg->data, sizeof data);
3417 buf = (char *)imsg->data + sizeof data;
3418 len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data;
3419 if (len > 0 && buf[len - 1] != '\0')
3420 fatalx("bad MSG_COMMAND string");
3422 argc = data.argc;
3423 if (cmd_unpack_argv(buf, len, argc, &argv) != 0) {
3424 cause = xstrdup("command too long");
3425 goto error;
3428 if (argc == 0) {
3429 argc = 1;
3430 argv = xcalloc(1, sizeof *argv);
3431 *argv = xstrdup("new-session");
3434 values = args_from_vector(argc, argv);
3435 pr = cmd_parse_from_arguments(values, argc, NULL);
3436 switch (pr->status) {
3437 case CMD_PARSE_ERROR:
3438 cause = pr->error;
3439 goto error;
3440 case CMD_PARSE_SUCCESS:
3441 break;
3443 args_free_values(values, argc);
3444 free(values);
3445 cmd_free_argv(argc, argv);
3447 if ((c->flags & CLIENT_READONLY) &&
3448 !cmd_list_all_have(pr->cmdlist, CMD_READONLY))
3449 new_item = cmdq_get_callback(server_client_read_only, NULL);
3450 else
3451 new_item = cmdq_get_command(pr->cmdlist, NULL);
3452 cmdq_append(c, new_item);
3453 cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL));
3455 cmd_list_free(pr->cmdlist);
3456 return;
3458 error:
3459 cmd_free_argv(argc, argv);
3461 cmdq_append(c, cmdq_get_error(cause));
3462 free(cause);
3464 c->flags |= CLIENT_EXIT;
3467 /* Handle identify message. */
3468 static void
3469 server_client_dispatch_identify(struct client *c, struct imsg *imsg)
3471 const char *data, *home;
3472 size_t datalen;
3473 int flags, feat;
3474 uint64_t longflags;
3475 char *name;
3477 if (c->flags & CLIENT_IDENTIFIED)
3478 fatalx("out-of-order identify message");
3480 data = imsg->data;
3481 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
3483 switch (imsg->hdr.type) {
3484 case MSG_IDENTIFY_FEATURES:
3485 if (datalen != sizeof feat)
3486 fatalx("bad MSG_IDENTIFY_FEATURES size");
3487 memcpy(&feat, data, sizeof feat);
3488 c->term_features |= feat;
3489 log_debug("client %p IDENTIFY_FEATURES %s", c,
3490 tty_get_features(feat));
3491 break;
3492 case MSG_IDENTIFY_FLAGS:
3493 if (datalen != sizeof flags)
3494 fatalx("bad MSG_IDENTIFY_FLAGS size");
3495 memcpy(&flags, data, sizeof flags);
3496 c->flags |= flags;
3497 log_debug("client %p IDENTIFY_FLAGS %#x", c, flags);
3498 break;
3499 case MSG_IDENTIFY_LONGFLAGS:
3500 if (datalen != sizeof longflags)
3501 fatalx("bad MSG_IDENTIFY_LONGFLAGS size");
3502 memcpy(&longflags, data, sizeof longflags);
3503 c->flags |= longflags;
3504 log_debug("client %p IDENTIFY_LONGFLAGS %#llx", c,
3505 (unsigned long long)longflags);
3506 break;
3507 case MSG_IDENTIFY_TERM:
3508 if (datalen == 0 || data[datalen - 1] != '\0')
3509 fatalx("bad MSG_IDENTIFY_TERM string");
3510 if (*data == '\0')
3511 c->term_name = xstrdup("unknown");
3512 else
3513 c->term_name = xstrdup(data);
3514 log_debug("client %p IDENTIFY_TERM %s", c, data);
3515 break;
3516 case MSG_IDENTIFY_TERMINFO:
3517 if (datalen == 0 || data[datalen - 1] != '\0')
3518 fatalx("bad MSG_IDENTIFY_TERMINFO string");
3519 c->term_caps = xreallocarray(c->term_caps, c->term_ncaps + 1,
3520 sizeof *c->term_caps);
3521 c->term_caps[c->term_ncaps++] = xstrdup(data);
3522 log_debug("client %p IDENTIFY_TERMINFO %s", c, data);
3523 break;
3524 case MSG_IDENTIFY_TTYNAME:
3525 if (datalen == 0 || data[datalen - 1] != '\0')
3526 fatalx("bad MSG_IDENTIFY_TTYNAME string");
3527 c->ttyname = xstrdup(data);
3528 log_debug("client %p IDENTIFY_TTYNAME %s", c, data);
3529 break;
3530 case MSG_IDENTIFY_CWD:
3531 if (datalen == 0 || data[datalen - 1] != '\0')
3532 fatalx("bad MSG_IDENTIFY_CWD string");
3533 if (access(data, X_OK) == 0)
3534 c->cwd = xstrdup(data);
3535 else if ((home = find_home()) != NULL)
3536 c->cwd = xstrdup(home);
3537 else
3538 c->cwd = xstrdup("/");
3539 log_debug("client %p IDENTIFY_CWD %s", c, data);
3540 break;
3541 case MSG_IDENTIFY_STDIN:
3542 if (datalen != 0)
3543 fatalx("bad MSG_IDENTIFY_STDIN size");
3544 c->fd = imsg_get_fd(imsg);
3545 log_debug("client %p IDENTIFY_STDIN %d", c, c->fd);
3546 break;
3547 case MSG_IDENTIFY_STDOUT:
3548 if (datalen != 0)
3549 fatalx("bad MSG_IDENTIFY_STDOUT size");
3550 c->out_fd = imsg_get_fd(imsg);
3551 log_debug("client %p IDENTIFY_STDOUT %d", c, c->out_fd);
3552 break;
3553 case MSG_IDENTIFY_ENVIRON:
3554 if (datalen == 0 || data[datalen - 1] != '\0')
3555 fatalx("bad MSG_IDENTIFY_ENVIRON string");
3556 if (strchr(data, '=') != NULL)
3557 environ_put(c->environ, data, 0);
3558 log_debug("client %p IDENTIFY_ENVIRON %s", c, data);
3559 break;
3560 case MSG_IDENTIFY_CLIENTPID:
3561 if (datalen != sizeof c->pid)
3562 fatalx("bad MSG_IDENTIFY_CLIENTPID size");
3563 memcpy(&c->pid, data, sizeof c->pid);
3564 log_debug("client %p IDENTIFY_CLIENTPID %ld", c, (long)c->pid);
3565 break;
3566 default:
3567 break;
3570 if (imsg->hdr.type != MSG_IDENTIFY_DONE)
3571 return;
3572 c->flags |= CLIENT_IDENTIFIED;
3574 if (*c->ttyname != '\0')
3575 name = xstrdup(c->ttyname);
3576 else
3577 xasprintf(&name, "client-%ld", (long)c->pid);
3578 c->name = name;
3579 log_debug("client %p name is %s", c, c->name);
3581 #ifdef __CYGWIN__
3582 c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
3583 c->out_fd = dup(c->fd);
3584 #endif
3586 if (c->flags & CLIENT_CONTROL)
3587 control_start(c);
3588 else if (c->fd != -1) {
3589 if (tty_init(&c->tty, c) != 0) {
3590 close(c->fd);
3591 c->fd = -1;
3592 } else {
3593 tty_resize(&c->tty);
3594 c->flags |= CLIENT_TERMINAL;
3596 close(c->out_fd);
3597 c->out_fd = -1;
3601 * If this is the first client, load configuration files. Any later
3602 * clients are allowed to continue with their command even if the
3603 * config has not been loaded - they might have been run from inside it
3605 if ((~c->flags & CLIENT_EXIT) &&
3606 !cfg_finished &&
3607 c == TAILQ_FIRST(&clients))
3608 start_cfg();
3611 /* Handle shell message. */
3612 static void
3613 server_client_dispatch_shell(struct client *c)
3615 const char *shell;
3617 shell = options_get_string(global_s_options, "default-shell");
3618 if (!checkshell(shell))
3619 shell = _PATH_BSHELL;
3620 proc_send(c->peer, MSG_SHELL, -1, shell, strlen(shell) + 1);
3622 proc_kill_peer(c->peer);
3625 /* Get client working directory. */
3626 const char *
3627 server_client_get_cwd(struct client *c, struct session *s)
3629 const char *home;
3631 if (!cfg_finished && cfg_client != NULL)
3632 return (cfg_client->cwd);
3633 if (c != NULL && c->session == NULL && c->cwd != NULL)
3634 return (c->cwd);
3635 if (s != NULL && s->cwd != NULL)
3636 return (s->cwd);
3637 if (c != NULL && (s = c->session) != NULL && s->cwd != NULL)
3638 return (s->cwd);
3639 if ((home = find_home()) != NULL)
3640 return (home);
3641 return ("/");
3644 /* Get control client flags. */
3645 static uint64_t
3646 server_client_control_flags(struct client *c, const char *next)
3648 if (strcmp(next, "pause-after") == 0) {
3649 c->pause_age = 0;
3650 return (CLIENT_CONTROL_PAUSEAFTER);
3652 if (sscanf(next, "pause-after=%u", &c->pause_age) == 1) {
3653 c->pause_age *= 1000;
3654 return (CLIENT_CONTROL_PAUSEAFTER);
3656 if (strcmp(next, "no-output") == 0)
3657 return (CLIENT_CONTROL_NOOUTPUT);
3658 if (strcmp(next, "wait-exit") == 0)
3659 return (CLIENT_CONTROL_WAITEXIT);
3660 return (0);
3663 /* Set client flags. */
3664 void
3665 server_client_set_flags(struct client *c, const char *flags)
3667 char *s, *copy, *next;
3668 uint64_t flag;
3669 int not;
3671 s = copy = xstrdup(flags);
3672 while ((next = strsep(&s, ",")) != NULL) {
3673 not = (*next == '!');
3674 if (not)
3675 next++;
3677 if (c->flags & CLIENT_CONTROL)
3678 flag = server_client_control_flags(c, next);
3679 else
3680 flag = 0;
3681 if (strcmp(next, "read-only") == 0)
3682 flag = CLIENT_READONLY;
3683 else if (strcmp(next, "ignore-size") == 0)
3684 flag = CLIENT_IGNORESIZE;
3685 else if (strcmp(next, "active-pane") == 0)
3686 flag = CLIENT_ACTIVEPANE;
3687 else if (strcmp(next, "no-detach-on-destroy") == 0)
3688 flag = CLIENT_NO_DETACH_ON_DESTROY;
3689 if (flag == 0)
3690 continue;
3692 log_debug("client %s set flag %s", c->name, next);
3693 if (not) {
3694 if (c->flags & CLIENT_READONLY)
3695 flag &= ~CLIENT_READONLY;
3696 c->flags &= ~flag;
3697 } else
3698 c->flags |= flag;
3699 if (flag == CLIENT_CONTROL_NOOUTPUT)
3700 control_reset_offsets(c);
3702 free(copy);
3703 proc_send(c->peer, MSG_FLAGS, -1, &c->flags, sizeof c->flags);
3706 /* Get client flags. This is only flags useful to show to users. */
3707 const char *
3708 server_client_get_flags(struct client *c)
3710 static char s[256];
3711 char tmp[32];
3713 *s = '\0';
3714 if (c->flags & CLIENT_ATTACHED)
3715 strlcat(s, "attached,", sizeof s);
3716 if (c->flags & CLIENT_FOCUSED)
3717 strlcat(s, "focused,", sizeof s);
3718 if (c->flags & CLIENT_CONTROL)
3719 strlcat(s, "control-mode,", sizeof s);
3720 if (c->flags & CLIENT_IGNORESIZE)
3721 strlcat(s, "ignore-size,", sizeof s);
3722 if (c->flags & CLIENT_NO_DETACH_ON_DESTROY)
3723 strlcat(s, "no-detach-on-destroy,", sizeof s);
3724 if (c->flags & CLIENT_CONTROL_NOOUTPUT)
3725 strlcat(s, "no-output,", sizeof s);
3726 if (c->flags & CLIENT_CONTROL_WAITEXIT)
3727 strlcat(s, "wait-exit,", sizeof s);
3728 if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
3729 xsnprintf(tmp, sizeof tmp, "pause-after=%u,",
3730 c->pause_age / 1000);
3731 strlcat(s, tmp, sizeof s);
3733 if (c->flags & CLIENT_READONLY)
3734 strlcat(s, "read-only,", sizeof s);
3735 if (c->flags & CLIENT_ACTIVEPANE)
3736 strlcat(s, "active-pane,", sizeof s);
3737 if (c->flags & CLIENT_SUSPENDED)
3738 strlcat(s, "suspended,", sizeof s);
3739 if (c->flags & CLIENT_UTF8)
3740 strlcat(s, "UTF-8,", sizeof s);
3741 if (*s != '\0')
3742 s[strlen(s) - 1] = '\0';
3743 return (s);
3746 /* Get client window. */
3747 struct client_window *
3748 server_client_get_client_window(struct client *c, u_int id)
3750 struct client_window cw = { .window = id };
3752 return (RB_FIND(client_windows, &c->windows, &cw));
3755 /* Add client window. */
3756 struct client_window *
3757 server_client_add_client_window(struct client *c, u_int id)
3759 struct client_window *cw;
3761 cw = server_client_get_client_window(c, id);
3762 if (cw == NULL) {
3763 cw = xcalloc(1, sizeof *cw);
3764 cw->window = id;
3765 RB_INSERT(client_windows, &c->windows, cw);
3767 return (cw);
3770 /* Get client active pane. */
3771 struct window_pane *
3772 server_client_get_pane(struct client *c)
3774 struct session *s = c->session;
3775 struct client_window *cw;
3777 if (s == NULL)
3778 return (NULL);
3780 if (~c->flags & CLIENT_ACTIVEPANE)
3781 return (s->curw->window->active);
3782 cw = server_client_get_client_window(c, s->curw->window->id);
3783 if (cw == NULL)
3784 return (s->curw->window->active);
3785 return (cw->pane);
3788 /* Set client active pane. */
3789 void
3790 server_client_set_pane(struct client *c, struct window_pane *wp)
3792 struct session *s = c->session;
3793 struct client_window *cw;
3795 if (s == NULL)
3796 return;
3798 cw = server_client_add_client_window(c, s->curw->window->id);
3799 cw->pane = wp;
3800 log_debug("%s pane now %%%u", c->name, wp->id);
3803 /* Remove pane from client lists. */
3804 void
3805 server_client_remove_pane(struct window_pane *wp)
3807 struct client *c;
3808 struct window *w = wp->window;
3809 struct client_window *cw;
3811 TAILQ_FOREACH(c, &clients, entry) {
3812 cw = server_client_get_client_window(c, w->id);
3813 if (cw != NULL && cw->pane == wp) {
3814 RB_REMOVE(client_windows, &c->windows, cw);
3815 free(cw);
3820 /* Print to a client. */
3821 void
3822 server_client_print(struct client *c, int parse, struct evbuffer *evb)
3824 void *data = EVBUFFER_DATA(evb);
3825 size_t size = EVBUFFER_LENGTH(evb);
3826 struct window_pane *wp;
3827 struct window_mode_entry *wme;
3828 char *sanitized, *msg, *line;
3830 if (!parse) {
3831 utf8_stravisx(&msg, data, size,
3832 VIS_OCTAL|VIS_CSTYLE|VIS_NOSLASH);
3833 log_debug("%s: %s", __func__, msg);
3834 } else {
3835 msg = EVBUFFER_DATA(evb);
3836 if (msg[size - 1] != '\0')
3837 evbuffer_add(evb, "", 1);
3840 if (c == NULL)
3841 goto out;
3843 if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
3844 if (~c->flags & CLIENT_UTF8) {
3845 sanitized = utf8_sanitize(msg);
3846 if (c->flags & CLIENT_CONTROL)
3847 control_write(c, "%s", sanitized);
3848 else
3849 file_print(c, "%s\n", sanitized);
3850 free(sanitized);
3851 } else {
3852 if (c->flags & CLIENT_CONTROL)
3853 control_write(c, "%s", msg);
3854 else
3855 file_print(c, "%s\n", msg);
3857 goto out;
3860 wp = server_client_get_pane(c);
3861 wme = TAILQ_FIRST(&wp->modes);
3862 if (wme == NULL || wme->mode != &window_view_mode)
3863 window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
3864 if (parse) {
3865 do {
3866 line = evbuffer_readln(evb, NULL, EVBUFFER_EOL_LF);
3867 if (line != NULL) {
3868 window_copy_add(wp, 1, "%s", line);
3869 free(line);
3871 } while (line != NULL);
3873 size = EVBUFFER_LENGTH(evb);
3874 if (size != 0) {
3875 line = EVBUFFER_DATA(evb);
3876 window_copy_add(wp, 1, "%.*s", (int)size, line);
3878 } else
3879 window_copy_add(wp, 0, "%s", msg);
3881 out:
3882 if (!parse)
3883 free(msg);