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