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