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