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