1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * ui.c: functions that handle the user interface. 12 * 1. Keyboard input stuff, and a bit of windowing stuff. These are called 13 * before the machine specific stuff (mch_*) so that we can call the GUI 14 * stuff instead if the GUI is running. 15 * 2. Clipboard stuff. 16 * 3. Input buffer stuff. 17 */ 18 19 #include "vim.h" 20 21 #ifdef FEAT_CYGWIN_WIN32_CLIPBOARD 22 # define WIN32_LEAN_AND_MEAN 23 # include <windows.h> 24 # include "winclip.pro" 25 #endif 26 27 void 28 ui_write(char_u *s, int len) 29 { 30 #ifdef FEAT_GUI 31 if (gui.in_use && !gui.dying && !gui.starting) 32 { 33 gui_write(s, len); 34 if (p_wd) 35 gui_wait_for_chars(p_wd, typebuf.tb_change_cnt); 36 return; 37 } 38 #endif 39 #ifndef NO_CONSOLE 40 /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */ 41 if (!(silent_mode && p_verbose == 0)) 42 { 43 #if !defined(MSWIN) 44 char_u *tofree = NULL; 45 46 if (output_conv.vc_type != CONV_NONE) 47 { 48 /* Convert characters from 'encoding' to 'termencoding'. */ 49 tofree = string_convert(&output_conv, s, &len); 50 if (tofree != NULL) 51 s = tofree; 52 } 53 #endif 54 55 mch_write(s, len); 56 57 # if !defined(MSWIN) 58 if (output_conv.vc_type != CONV_NONE) 59 vim_free(tofree); 60 # endif 61 } 62 #endif 63 } 64 65 #if defined(UNIX) || defined(VMS) || defined(PROTO) || defined(MSWIN) 66 /* 67 * When executing an external program, there may be some typed characters that 68 * are not consumed by it. Give them back to ui_inchar() and they are stored 69 * here for the next call. 70 */ 71 static char_u *ta_str = NULL; 72 static int ta_off; /* offset for next char to use when ta_str != NULL */ 73 static int ta_len; /* length of ta_str when it's not NULL*/ 74 75 void 76 ui_inchar_undo(char_u *s, int len) 77 { 78 char_u *new; 79 int newlen; 80 81 newlen = len; 82 if (ta_str != NULL) 83 newlen += ta_len - ta_off; 84 new = alloc(newlen); 85 if (new != NULL) 86 { 87 if (ta_str != NULL) 88 { 89 mch_memmove(new, ta_str + ta_off, (size_t)(ta_len - ta_off)); 90 mch_memmove(new + ta_len - ta_off, s, (size_t)len); 91 vim_free(ta_str); 92 } 93 else 94 mch_memmove(new, s, (size_t)len); 95 ta_str = new; 96 ta_len = newlen; 97 ta_off = 0; 98 } 99 } 100 #endif 101 102 /* 103 * ui_inchar(): low level input function. 104 * Get characters from the keyboard. 105 * Return the number of characters that are available. 106 * If "wtime" == 0 do not wait for characters. 107 * If "wtime" == -1 wait forever for characters. 108 * If "wtime" > 0 wait "wtime" milliseconds for a character. 109 * 110 * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into 111 * it. When typebuf.tb_change_cnt changes (e.g., when a message is received 112 * from a remote client) "buf" can no longer be used. "tb_change_cnt" is NULL 113 * otherwise. 114 */ 115 int 116 ui_inchar( 117 char_u *buf, 118 int maxlen, 119 long wtime, /* don't use "time", MIPS cannot handle it */ 120 int tb_change_cnt) 121 { 122 int retval = 0; 123 124 #if defined(FEAT_GUI) && (defined(UNIX) || defined(VMS)) 125 /* 126 * Use the typeahead if there is any. 127 */ 128 if (ta_str != NULL) 129 { 130 if (maxlen >= ta_len - ta_off) 131 { 132 mch_memmove(buf, ta_str + ta_off, (size_t)ta_len); 133 VIM_CLEAR(ta_str); 134 return ta_len; 135 } 136 mch_memmove(buf, ta_str + ta_off, (size_t)maxlen); 137 ta_off += maxlen; 138 return maxlen; 139 } 140 #endif 141 142 #ifdef FEAT_PROFILE 143 if (do_profiling == PROF_YES && wtime != 0) 144 prof_inchar_enter(); 145 #endif 146 147 #ifdef NO_CONSOLE_INPUT 148 /* Don't wait for character input when the window hasn't been opened yet. 149 * Do try reading, this works when redirecting stdin from a file. 150 * Must return something, otherwise we'll loop forever. If we run into 151 * this very often we probably got stuck, exit Vim. */ 152 if (no_console_input()) 153 { 154 static int count = 0; 155 156 # ifndef NO_CONSOLE 157 retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt); 158 if (retval > 0 || typebuf_changed(tb_change_cnt) || wtime >= 0) 159 goto theend; 160 # endif 161 if (wtime == -1 && ++count == 1000) 162 read_error_exit(); 163 buf[0] = CAR; 164 retval = 1; 165 goto theend; 166 } 167 #endif 168 169 /* If we are going to wait for some time or block... */ 170 if (wtime == -1 || wtime > 100L) 171 { 172 /* ... allow signals to kill us. */ 173 (void)vim_handle_signal(SIGNAL_UNBLOCK); 174 175 /* ... there is no need for CTRL-C to interrupt something, don't let 176 * it set got_int when it was mapped. */ 177 if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) 178 ctrl_c_interrupts = FALSE; 179 } 180 181 /* 182 * Here we call gui_inchar() or mch_inchar(), the GUI or machine-dependent 183 * input function. The functionality they implement is like this: 184 * 185 * while (not timed out) 186 * { 187 * handle-resize; 188 * parse-queued-messages; 189 * if (waited for 'updatetime') 190 * trigger-cursorhold; 191 * ui_wait_for_chars_or_timer() 192 * if (character available) 193 * break; 194 * } 195 * 196 * ui_wait_for_chars_or_timer() does: 197 * 198 * while (not timed out) 199 * { 200 * if (any-timer-triggered) 201 * invoke-timer-callback; 202 * wait-for-character(); 203 * if (character available) 204 * break; 205 * } 206 * 207 * wait-for-character() does: 208 * while (not timed out) 209 * { 210 * Wait for event; 211 * if (something on channel) 212 * read/write channel; 213 * else if (resized) 214 * handle_resize(); 215 * else if (system event) 216 * deal-with-system-event; 217 * else if (character available) 218 * break; 219 * } 220 * 221 */ 222 223 #ifdef FEAT_GUI 224 if (gui.in_use) 225 retval = gui_inchar(buf, maxlen, wtime, tb_change_cnt); 226 #endif 227 #ifndef NO_CONSOLE 228 # ifdef FEAT_GUI 229 else 230 # endif 231 retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt); 232 #endif 233 234 if (wtime == -1 || wtime > 100L) 235 /* block SIGHUP et al. */ 236 (void)vim_handle_signal(SIGNAL_BLOCK); 237 238 ctrl_c_interrupts = TRUE; 239 240 #ifdef NO_CONSOLE_INPUT 241 theend: 242 #endif 243 #ifdef FEAT_PROFILE 244 if (do_profiling == PROF_YES && wtime != 0) 245 prof_inchar_exit(); 246 #endif 247 return retval; 248 } 249 250 #if defined(UNIX) || defined(FEAT_GUI) || defined(PROTO) 251 /* 252 * Common code for mch_inchar() and gui_inchar(): Wait for a while or 253 * indefinitely until characters are available, dealing with timers and 254 * messages on channels. 255 * 256 * "buf" may be NULL if the available characters are not to be returned, only 257 * check if they are available. 258 * 259 * Return the number of characters that are available. 260 * If "wtime" == 0 do not wait for characters. 261 * If "wtime" == n wait a short time for characters. 262 * If "wtime" == -1 wait forever for characters. 263 */ 264 int 265 inchar_loop( 266 char_u *buf, 267 int maxlen, 268 long wtime, // don't use "time", MIPS cannot handle it 269 int tb_change_cnt, 270 int (*wait_func)(long wtime, int *interrupted, int ignore_input), 271 int (*resize_func)(int check_only)) 272 { 273 int len; 274 int interrupted = FALSE; 275 int did_call_wait_func = FALSE; 276 int did_start_blocking = FALSE; 277 long wait_time; 278 long elapsed_time = 0; 279 #ifdef ELAPSED_FUNC 280 elapsed_T start_tv; 281 282 ELAPSED_INIT(start_tv); 283 #endif 284 285 /* repeat until we got a character or waited long enough */ 286 for (;;) 287 { 288 /* Check if window changed size while we were busy, perhaps the ":set 289 * columns=99" command was used. */ 290 if (resize_func != NULL) 291 resize_func(FALSE); 292 293 #ifdef MESSAGE_QUEUE 294 // Only process messages when waiting. 295 if (wtime != 0) 296 { 297 parse_queued_messages(); 298 // If input was put directly in typeahead buffer bail out here. 299 if (typebuf_changed(tb_change_cnt)) 300 return 0; 301 } 302 #endif 303 if (wtime < 0 && did_start_blocking) 304 // blocking and already waited for p_ut 305 wait_time = -1; 306 else 307 { 308 if (wtime >= 0) 309 wait_time = wtime; 310 else 311 // going to block after p_ut 312 wait_time = p_ut; 313 #ifdef ELAPSED_FUNC 314 elapsed_time = ELAPSED_FUNC(start_tv); 315 #endif 316 wait_time -= elapsed_time; 317 318 // If the waiting time is now zero or less, we timed out. However, 319 // loop at least once to check for characters and events. Matters 320 // when "wtime" is zero. 321 if (wait_time <= 0 && did_call_wait_func) 322 { 323 if (wtime >= 0) 324 // no character available within "wtime" 325 return 0; 326 327 // No character available within 'updatetime'. 328 did_start_blocking = TRUE; 329 if (trigger_cursorhold() && maxlen >= 3 330 && !typebuf_changed(tb_change_cnt)) 331 { 332 // Put K_CURSORHOLD in the input buffer or return it. 333 if (buf == NULL) 334 { 335 char_u ibuf[3]; 336 337 ibuf[0] = CSI; 338 ibuf[1] = KS_EXTRA; 339 ibuf[2] = (int)KE_CURSORHOLD; 340 add_to_input_buf(ibuf, 3); 341 } 342 else 343 { 344 buf[0] = K_SPECIAL; 345 buf[1] = KS_EXTRA; 346 buf[2] = (int)KE_CURSORHOLD; 347 } 348 return 3; 349 } 350 351 // There is no character available within 'updatetime' seconds: 352 // flush all the swap files to disk. Also done when 353 // interrupted by SIGWINCH. 354 before_blocking(); 355 continue; 356 } 357 } 358 359 #ifdef FEAT_JOB_CHANNEL 360 if (wait_time < 0 || wait_time > 100L) 361 { 362 // Checking if a job ended requires polling. Do this at least 363 // every 100 msec. 364 if (has_pending_job()) 365 wait_time = 100L; 366 367 // If there is readahead then parse_queued_messages() timed out and 368 // we should call it again soon. 369 if (channel_any_readahead()) 370 wait_time = 10L; 371 } 372 #endif 373 #ifdef FEAT_BEVAL_GUI 374 if (p_beval && wait_time > 100L) 375 // The 'balloonexpr' may indirectly invoke a callback while waiting 376 // for a character, need to check often. 377 wait_time = 100L; 378 #endif 379 380 // Wait for a character to be typed or another event, such as the winch 381 // signal or an event on the monitored file descriptors. 382 did_call_wait_func = TRUE; 383 if (wait_func(wait_time, &interrupted, FALSE)) 384 { 385 // If input was put directly in typeahead buffer bail out here. 386 if (typebuf_changed(tb_change_cnt)) 387 return 0; 388 389 // We might have something to return now. 390 if (buf == NULL) 391 // "buf" is NULL, we were just waiting, not actually getting 392 // input. 393 return input_available(); 394 395 len = read_from_input_buf(buf, (long)maxlen); 396 if (len > 0) 397 return len; 398 continue; 399 } 400 // Timed out or interrupted with no character available. 401 402 #ifndef ELAPSED_FUNC 403 // estimate the elapsed time 404 elapsed_time += wait_time; 405 #endif 406 407 if ((resize_func != NULL && resize_func(TRUE)) 408 #if defined(FEAT_CLIENTSERVER) && defined(UNIX) 409 || server_waiting() 410 #endif 411 #ifdef MESSAGE_QUEUE 412 || interrupted 413 #endif 414 || wait_time > 0 415 || (wtime < 0 && !did_start_blocking)) 416 // no character available, but something to be done, keep going 417 continue; 418 419 // no character available or interrupted, return zero 420 break; 421 } 422 return 0; 423 } 424 #endif 425 426 #if defined(FEAT_TIMERS) || defined(PROTO) 427 /* 428 * Wait for a timer to fire or "wait_func" to return non-zero. 429 * Returns OK when something was read. 430 * Returns FAIL when it timed out or was interrupted. 431 */ 432 int 433 ui_wait_for_chars_or_timer( 434 long wtime, 435 int (*wait_func)(long wtime, int *interrupted, int ignore_input), 436 int *interrupted, 437 int ignore_input) 438 { 439 int due_time; 440 long remaining = wtime; 441 int tb_change_cnt = typebuf.tb_change_cnt; 442 # ifdef FEAT_JOB_CHANNEL 443 int brief_wait = FALSE; 444 # endif 445 446 // When waiting very briefly don't trigger timers. 447 if (wtime >= 0 && wtime < 10L) 448 return wait_func(wtime, NULL, ignore_input); 449 450 while (wtime < 0 || remaining > 0) 451 { 452 // Trigger timers and then get the time in wtime until the next one is 453 // due. Wait up to that time. 454 due_time = check_due_timer(); 455 if (typebuf.tb_change_cnt != tb_change_cnt) 456 { 457 /* timer may have used feedkeys() */ 458 return FAIL; 459 } 460 if (due_time <= 0 || (wtime > 0 && due_time > remaining)) 461 due_time = remaining; 462 # ifdef FEAT_JOB_CHANNEL 463 if ((due_time < 0 || due_time > 10L) 464 # ifdef FEAT_GUI 465 && !gui.in_use 466 # endif 467 && (has_pending_job() || channel_any_readahead())) 468 { 469 // There is a pending job or channel, should return soon in order 470 // to handle them ASAP. Do check for input briefly. 471 due_time = 10L; 472 brief_wait = TRUE; 473 } 474 # endif 475 if (wait_func(due_time, interrupted, ignore_input)) 476 return OK; 477 if ((interrupted != NULL && *interrupted) 478 # ifdef FEAT_JOB_CHANNEL 479 || brief_wait 480 # endif 481 ) 482 // Nothing available, but need to return so that side effects get 483 // handled, such as handling a message on a channel. 484 return FAIL; 485 if (wtime > 0) 486 remaining -= due_time; 487 } 488 return FAIL; 489 } 490 #endif 491 492 /* 493 * Return non-zero if a character is available. 494 */ 495 int 496 ui_char_avail(void) 497 { 498 #ifdef FEAT_GUI 499 if (gui.in_use) 500 { 501 gui_mch_update(); 502 return input_available(); 503 } 504 #endif 505 #ifndef NO_CONSOLE 506 # ifdef NO_CONSOLE_INPUT 507 if (no_console_input()) 508 return 0; 509 # endif 510 return mch_char_avail(); 511 #else 512 return 0; 513 #endif 514 } 515 516 /* 517 * Delay for the given number of milliseconds. If ignoreinput is FALSE then we 518 * cancel the delay if a key is hit. 519 */ 520 void 521 ui_delay(long msec, int ignoreinput) 522 { 523 #ifdef FEAT_GUI 524 if (gui.in_use && !ignoreinput) 525 gui_wait_for_chars(msec, typebuf.tb_change_cnt); 526 else 527 #endif 528 mch_delay(msec, ignoreinput); 529 } 530 531 /* 532 * If the machine has job control, use it to suspend the program, 533 * otherwise fake it by starting a new shell. 534 * When running the GUI iconify the window. 535 */ 536 void 537 ui_suspend(void) 538 { 539 #ifdef FEAT_GUI 540 if (gui.in_use) 541 { 542 gui_mch_iconify(); 543 return; 544 } 545 #endif 546 mch_suspend(); 547 } 548 549 #if !defined(UNIX) || !defined(SIGTSTP) || defined(PROTO) || defined(__BEOS__) 550 /* 551 * When the OS can't really suspend, call this function to start a shell. 552 * This is never called in the GUI. 553 */ 554 void 555 suspend_shell(void) 556 { 557 if (*p_sh == NUL) 558 emsg(_(e_shellempty)); 559 else 560 { 561 msg_puts(_("new shell started\n")); 562 do_shell(NULL, 0); 563 } 564 } 565 #endif 566 567 /* 568 * Try to get the current Vim shell size. Put the result in Rows and Columns. 569 * Use the new sizes as defaults for 'columns' and 'lines'. 570 * Return OK when size could be determined, FAIL otherwise. 571 */ 572 int 573 ui_get_shellsize(void) 574 { 575 int retval; 576 577 #ifdef FEAT_GUI 578 if (gui.in_use) 579 retval = gui_get_shellsize(); 580 else 581 #endif 582 retval = mch_get_shellsize(); 583 584 check_shellsize(); 585 586 /* adjust the default for 'lines' and 'columns' */ 587 if (retval == OK) 588 { 589 set_number_default("lines", Rows); 590 set_number_default("columns", Columns); 591 } 592 return retval; 593 } 594 595 /* 596 * Set the size of the Vim shell according to Rows and Columns, if possible. 597 * The gui_set_shellsize() or mch_set_shellsize() function will try to set the 598 * new size. If this is not possible, it will adjust Rows and Columns. 599 */ 600 void 601 ui_set_shellsize( 602 int mustset UNUSED) /* set by the user */ 603 { 604 #ifdef FEAT_GUI 605 if (gui.in_use) 606 gui_set_shellsize(mustset, TRUE, RESIZE_BOTH); 607 else 608 #endif 609 mch_set_shellsize(); 610 } 611 612 /* 613 * Called when Rows and/or Columns changed. Adjust scroll region and mouse 614 * region. 615 */ 616 void 617 ui_new_shellsize(void) 618 { 619 if (full_screen && !exiting) 620 { 621 #ifdef FEAT_GUI 622 if (gui.in_use) 623 gui_new_shellsize(); 624 else 625 #endif 626 mch_new_shellsize(); 627 } 628 } 629 630 #if ((defined(FEAT_EVAL) || defined(FEAT_TERMINAL)) \ 631 && (defined(FEAT_GUI) \ 632 || defined(MSWIN) \ 633 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)))) \ 634 || defined(PROTO) 635 /* 636 * Get the window position in pixels, if possible. 637 * Return FAIL when not possible. 638 */ 639 int 640 ui_get_winpos(int *x, int *y, varnumber_T timeout) 641 { 642 # ifdef FEAT_GUI 643 if (gui.in_use) 644 return gui_mch_get_winpos(x, y); 645 # endif 646 # if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL)) 647 return mch_get_winpos(x, y); 648 # else 649 # if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 650 return term_get_winpos(x, y, timeout); 651 # else 652 return FAIL; 653 # endif 654 # endif 655 } 656 #endif 657 658 void 659 ui_breakcheck(void) 660 { 661 ui_breakcheck_force(FALSE); 662 } 663 664 /* 665 * When "force" is true also check when the terminal is not in raw mode. 666 * This is useful to read input on channels. 667 */ 668 void 669 ui_breakcheck_force(int force) 670 { 671 static int recursive = FALSE; 672 int save_updating_screen = updating_screen; 673 674 // We could be called recursively if stderr is redirected, calling 675 // fill_input_buf() calls settmode() when stdin isn't a tty. settmode() 676 // calls vgetorpeek() which calls ui_breakcheck() again. 677 if (recursive) 678 return; 679 recursive = TRUE; 680 681 // We do not want gui_resize_shell() to redraw the screen here. 682 ++updating_screen; 683 684 #ifdef FEAT_GUI 685 if (gui.in_use) 686 gui_mch_update(); 687 else 688 #endif 689 mch_breakcheck(force); 690 691 if (save_updating_screen) 692 updating_screen = TRUE; 693 else 694 reset_updating_screen(FALSE); 695 696 recursive = FALSE; 697 } 698 699 /***************************************************************************** 700 * Functions for copying and pasting text between applications. 701 * This is always included in a GUI version, but may also be included when the 702 * clipboard and mouse is available to a terminal version such as xterm. 703 * Note: there are some more functions in ops.c that handle selection stuff. 704 * 705 * Also note that the majority of functions here deal with the X 'primary' 706 * (visible - for Visual mode use) selection, and only that. There are no 707 * versions of these for the 'clipboard' selection, as Visual mode has no use 708 * for them. 709 */ 710 711 #if defined(FEAT_CLIPBOARD) || defined(PROTO) 712 713 /* 714 * Selection stuff using Visual mode, for cutting and pasting text to other 715 * windows. 716 */ 717 718 /* 719 * Call this to initialise the clipboard. Pass it FALSE if the clipboard code 720 * is included, but the clipboard can not be used, or TRUE if the clipboard can 721 * be used. Eg unix may call this with FALSE, then call it again with TRUE if 722 * the GUI starts. 723 */ 724 void 725 clip_init(int can_use) 726 { 727 VimClipboard *cb; 728 729 cb = &clip_star; 730 for (;;) 731 { 732 cb->available = can_use; 733 cb->owned = FALSE; 734 cb->start.lnum = 0; 735 cb->start.col = 0; 736 cb->end.lnum = 0; 737 cb->end.col = 0; 738 cb->state = SELECT_CLEARED; 739 740 if (cb == &clip_plus) 741 break; 742 cb = &clip_plus; 743 } 744 } 745 746 /* 747 * Check whether the VIsual area has changed, and if so try to become the owner 748 * of the selection, and free any old converted selection we may still have 749 * lying around. If the VIsual mode has ended, make a copy of what was 750 * selected so we can still give it to others. Will probably have to make sure 751 * this is called whenever VIsual mode is ended. 752 */ 753 void 754 clip_update_selection(VimClipboard *clip) 755 { 756 pos_T start, end; 757 758 /* If visual mode is only due to a redo command ("."), then ignore it */ 759 if (!redo_VIsual_busy && VIsual_active && (State & NORMAL)) 760 { 761 if (LT_POS(VIsual, curwin->w_cursor)) 762 { 763 start = VIsual; 764 end = curwin->w_cursor; 765 if (has_mbyte) 766 end.col += (*mb_ptr2len)(ml_get_cursor()) - 1; 767 } 768 else 769 { 770 start = curwin->w_cursor; 771 end = VIsual; 772 } 773 if (!EQUAL_POS(clip->start, start) 774 || !EQUAL_POS(clip->end, end) 775 || clip->vmode != VIsual_mode) 776 { 777 clip_clear_selection(clip); 778 clip->start = start; 779 clip->end = end; 780 clip->vmode = VIsual_mode; 781 clip_free_selection(clip); 782 clip_own_selection(clip); 783 clip_gen_set_selection(clip); 784 } 785 } 786 } 787 788 void 789 clip_own_selection(VimClipboard *cbd) 790 { 791 /* 792 * Also want to check somehow that we are reading from the keyboard rather 793 * than a mapping etc. 794 */ 795 #ifdef FEAT_X11 796 /* Always own the selection, we might have lost it without being 797 * notified, e.g. during a ":sh" command. */ 798 if (cbd->available) 799 { 800 int was_owned = cbd->owned; 801 802 cbd->owned = (clip_gen_own_selection(cbd) == OK); 803 if (!was_owned && (cbd == &clip_star || cbd == &clip_plus)) 804 { 805 /* May have to show a different kind of highlighting for the 806 * selected area. There is no specific redraw command for this, 807 * just redraw all windows on the current buffer. */ 808 if (cbd->owned 809 && (get_real_state() == VISUAL 810 || get_real_state() == SELECTMODE) 811 && (cbd == &clip_star ? clip_isautosel_star() 812 : clip_isautosel_plus()) 813 && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC)) 814 redraw_curbuf_later(INVERTED_ALL); 815 } 816 } 817 #else 818 /* Only own the clipboard when we didn't own it yet. */ 819 if (!cbd->owned && cbd->available) 820 cbd->owned = (clip_gen_own_selection(cbd) == OK); 821 #endif 822 } 823 824 void 825 clip_lose_selection(VimClipboard *cbd) 826 { 827 #ifdef FEAT_X11 828 int was_owned = cbd->owned; 829 #endif 830 int visual_selection = FALSE; 831 832 if (cbd == &clip_star || cbd == &clip_plus) 833 visual_selection = TRUE; 834 835 clip_free_selection(cbd); 836 cbd->owned = FALSE; 837 if (visual_selection) 838 clip_clear_selection(cbd); 839 clip_gen_lose_selection(cbd); 840 #ifdef FEAT_X11 841 if (visual_selection) 842 { 843 /* May have to show a different kind of highlighting for the selected 844 * area. There is no specific redraw command for this, just redraw all 845 * windows on the current buffer. */ 846 if (was_owned 847 && (get_real_state() == VISUAL 848 || get_real_state() == SELECTMODE) 849 && (cbd == &clip_star ? 850 clip_isautosel_star() : clip_isautosel_plus()) 851 && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC)) 852 { 853 update_curbuf(INVERTED_ALL); 854 setcursor(); 855 cursor_on(); 856 out_flush_cursor(TRUE, FALSE); 857 } 858 } 859 #endif 860 } 861 862 static void 863 clip_copy_selection(VimClipboard *clip) 864 { 865 if (VIsual_active && (State & NORMAL) && clip->available) 866 { 867 clip_update_selection(clip); 868 clip_free_selection(clip); 869 clip_own_selection(clip); 870 if (clip->owned) 871 clip_get_selection(clip); 872 clip_gen_set_selection(clip); 873 } 874 } 875 876 /* 877 * Save and restore clip_unnamed before doing possibly many changes. This 878 * prevents accessing the clipboard very often which might slow down Vim 879 * considerably. 880 */ 881 static int global_change_count = 0; /* if set, inside a start_global_changes */ 882 static int clipboard_needs_update = FALSE; /* clipboard needs to be updated */ 883 static int clip_did_set_selection = TRUE; 884 885 /* 886 * Save clip_unnamed and reset it. 887 */ 888 void 889 start_global_changes(void) 890 { 891 if (++global_change_count > 1) 892 return; 893 clip_unnamed_saved = clip_unnamed; 894 clipboard_needs_update = FALSE; 895 896 if (clip_did_set_selection) 897 { 898 clip_unnamed = FALSE; 899 clip_did_set_selection = FALSE; 900 } 901 } 902 903 /* 904 * Return TRUE if setting the clipboard was postponed, it already contains the 905 * right text. 906 */ 907 int 908 is_clipboard_needs_update() 909 { 910 return clipboard_needs_update; 911 } 912 913 /* 914 * Restore clip_unnamed and set the selection when needed. 915 */ 916 void 917 end_global_changes(void) 918 { 919 if (--global_change_count > 0) 920 /* recursive */ 921 return; 922 if (!clip_did_set_selection) 923 { 924 clip_did_set_selection = TRUE; 925 clip_unnamed = clip_unnamed_saved; 926 clip_unnamed_saved = FALSE; 927 if (clipboard_needs_update) 928 { 929 /* only store something in the clipboard, 930 * if we have yanked anything to it */ 931 if (clip_unnamed & CLIP_UNNAMED) 932 { 933 clip_own_selection(&clip_star); 934 clip_gen_set_selection(&clip_star); 935 } 936 if (clip_unnamed & CLIP_UNNAMED_PLUS) 937 { 938 clip_own_selection(&clip_plus); 939 clip_gen_set_selection(&clip_plus); 940 } 941 } 942 } 943 clipboard_needs_update = FALSE; 944 } 945 946 /* 947 * Called when Visual mode is ended: update the selection. 948 */ 949 void 950 clip_auto_select(void) 951 { 952 if (clip_isautosel_star()) 953 clip_copy_selection(&clip_star); 954 if (clip_isautosel_plus()) 955 clip_copy_selection(&clip_plus); 956 } 957 958 /* 959 * Return TRUE if automatic selection of Visual area is desired for the * 960 * register. 961 */ 962 int 963 clip_isautosel_star(void) 964 { 965 return ( 966 #ifdef FEAT_GUI 967 gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) : 968 #endif 969 clip_autoselect_star); 970 } 971 972 /* 973 * Return TRUE if automatic selection of Visual area is desired for the + 974 * register. 975 */ 976 int 977 clip_isautosel_plus(void) 978 { 979 return ( 980 #ifdef FEAT_GUI 981 gui.in_use ? (vim_strchr(p_go, GO_ASELPLUS) != NULL) : 982 #endif 983 clip_autoselect_plus); 984 } 985 986 987 /* 988 * Stuff for general mouse selection, without using Visual mode. 989 */ 990 991 static void clip_invert_area(int, int, int, int, int how); 992 static void clip_invert_rectangle(int row, int col, int height, int width, int invert); 993 static void clip_get_word_boundaries(VimClipboard *, int, int); 994 static int clip_get_line_end(int); 995 static void clip_update_modeless_selection(VimClipboard *, int, int, 996 int, int); 997 998 /* flags for clip_invert_area() */ 999 #define CLIP_CLEAR 1 1000 #define CLIP_SET 2 1001 #define CLIP_TOGGLE 3 1002 1003 /* 1004 * Start, continue or end a modeless selection. Used when editing the 1005 * command-line and in the cmdline window. 1006 */ 1007 void 1008 clip_modeless(int button, int is_click, int is_drag) 1009 { 1010 int repeat; 1011 1012 repeat = ((clip_star.mode == SELECT_MODE_CHAR 1013 || clip_star.mode == SELECT_MODE_LINE) 1014 && (mod_mask & MOD_MASK_2CLICK)) 1015 || (clip_star.mode == SELECT_MODE_WORD 1016 && (mod_mask & MOD_MASK_3CLICK)); 1017 if (is_click && button == MOUSE_RIGHT) 1018 { 1019 /* Right mouse button: If there was no selection, start one. 1020 * Otherwise extend the existing selection. */ 1021 if (clip_star.state == SELECT_CLEARED) 1022 clip_start_selection(mouse_col, mouse_row, FALSE); 1023 clip_process_selection(button, mouse_col, mouse_row, repeat); 1024 } 1025 else if (is_click) 1026 clip_start_selection(mouse_col, mouse_row, repeat); 1027 else if (is_drag) 1028 { 1029 /* Don't try extending a selection if there isn't one. Happens when 1030 * button-down is in the cmdline and them moving mouse upwards. */ 1031 if (clip_star.state != SELECT_CLEARED) 1032 clip_process_selection(button, mouse_col, mouse_row, repeat); 1033 } 1034 else /* release */ 1035 clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE); 1036 } 1037 1038 /* 1039 * Compare two screen positions ala strcmp() 1040 */ 1041 static int 1042 clip_compare_pos( 1043 int row1, 1044 int col1, 1045 int row2, 1046 int col2) 1047 { 1048 if (row1 > row2) return(1); 1049 if (row1 < row2) return(-1); 1050 if (col1 > col2) return(1); 1051 if (col1 < col2) return(-1); 1052 return(0); 1053 } 1054 1055 /* 1056 * Start the selection 1057 */ 1058 void 1059 clip_start_selection(int col, int row, int repeated_click) 1060 { 1061 VimClipboard *cb = &clip_star; 1062 1063 if (cb->state == SELECT_DONE) 1064 clip_clear_selection(cb); 1065 1066 row = check_row(row); 1067 col = check_col(col); 1068 col = mb_fix_col(col, row); 1069 1070 cb->start.lnum = row; 1071 cb->start.col = col; 1072 cb->end = cb->start; 1073 cb->origin_row = (short_u)cb->start.lnum; 1074 cb->state = SELECT_IN_PROGRESS; 1075 1076 if (repeated_click) 1077 { 1078 if (++cb->mode > SELECT_MODE_LINE) 1079 cb->mode = SELECT_MODE_CHAR; 1080 } 1081 else 1082 cb->mode = SELECT_MODE_CHAR; 1083 1084 #ifdef FEAT_GUI 1085 /* clear the cursor until the selection is made */ 1086 if (gui.in_use) 1087 gui_undraw_cursor(); 1088 #endif 1089 1090 switch (cb->mode) 1091 { 1092 case SELECT_MODE_CHAR: 1093 cb->origin_start_col = cb->start.col; 1094 cb->word_end_col = clip_get_line_end((int)cb->start.lnum); 1095 break; 1096 1097 case SELECT_MODE_WORD: 1098 clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col); 1099 cb->origin_start_col = cb->word_start_col; 1100 cb->origin_end_col = cb->word_end_col; 1101 1102 clip_invert_area((int)cb->start.lnum, cb->word_start_col, 1103 (int)cb->end.lnum, cb->word_end_col, CLIP_SET); 1104 cb->start.col = cb->word_start_col; 1105 cb->end.col = cb->word_end_col; 1106 break; 1107 1108 case SELECT_MODE_LINE: 1109 clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum, 1110 (int)Columns, CLIP_SET); 1111 cb->start.col = 0; 1112 cb->end.col = Columns; 1113 break; 1114 } 1115 1116 cb->prev = cb->start; 1117 1118 #ifdef DEBUG_SELECTION 1119 printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col); 1120 #endif 1121 } 1122 1123 /* 1124 * Continue processing the selection 1125 */ 1126 void 1127 clip_process_selection( 1128 int button, 1129 int col, 1130 int row, 1131 int_u repeated_click) 1132 { 1133 VimClipboard *cb = &clip_star; 1134 int diff; 1135 int slen = 1; /* cursor shape width */ 1136 1137 if (button == MOUSE_RELEASE) 1138 { 1139 /* Check to make sure we have something selected */ 1140 if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col) 1141 { 1142 #ifdef FEAT_GUI 1143 if (gui.in_use) 1144 gui_update_cursor(FALSE, FALSE); 1145 #endif 1146 cb->state = SELECT_CLEARED; 1147 return; 1148 } 1149 1150 #ifdef DEBUG_SELECTION 1151 printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum, 1152 cb->start.col, cb->end.lnum, cb->end.col); 1153 #endif 1154 if (clip_isautosel_star() 1155 || ( 1156 #ifdef FEAT_GUI 1157 gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) : 1158 #endif 1159 clip_autoselectml)) 1160 clip_copy_modeless_selection(FALSE); 1161 #ifdef FEAT_GUI 1162 if (gui.in_use) 1163 gui_update_cursor(FALSE, FALSE); 1164 #endif 1165 1166 cb->state = SELECT_DONE; 1167 return; 1168 } 1169 1170 row = check_row(row); 1171 col = check_col(col); 1172 col = mb_fix_col(col, row); 1173 1174 if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click) 1175 return; 1176 1177 /* 1178 * When extending the selection with the right mouse button, swap the 1179 * start and end if the position is before half the selection 1180 */ 1181 if (cb->state == SELECT_DONE && button == MOUSE_RIGHT) 1182 { 1183 /* 1184 * If the click is before the start, or the click is inside the 1185 * selection and the start is the closest side, set the origin to the 1186 * end of the selection. 1187 */ 1188 if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0 1189 || (clip_compare_pos(row, col, 1190 (int)cb->end.lnum, cb->end.col) < 0 1191 && (((cb->start.lnum == cb->end.lnum 1192 && cb->end.col - col > col - cb->start.col)) 1193 || ((diff = (cb->end.lnum - row) - 1194 (row - cb->start.lnum)) > 0 1195 || (diff == 0 && col < (int)(cb->start.col + 1196 cb->end.col) / 2))))) 1197 { 1198 cb->origin_row = (short_u)cb->end.lnum; 1199 cb->origin_start_col = cb->end.col - 1; 1200 cb->origin_end_col = cb->end.col; 1201 } 1202 else 1203 { 1204 cb->origin_row = (short_u)cb->start.lnum; 1205 cb->origin_start_col = cb->start.col; 1206 cb->origin_end_col = cb->start.col; 1207 } 1208 if (cb->mode == SELECT_MODE_WORD && !repeated_click) 1209 cb->mode = SELECT_MODE_CHAR; 1210 } 1211 1212 /* set state, for when using the right mouse button */ 1213 cb->state = SELECT_IN_PROGRESS; 1214 1215 #ifdef DEBUG_SELECTION 1216 printf("Selection extending to (%d,%d)\n", row, col); 1217 #endif 1218 1219 if (repeated_click && ++cb->mode > SELECT_MODE_LINE) 1220 cb->mode = SELECT_MODE_CHAR; 1221 1222 switch (cb->mode) 1223 { 1224 case SELECT_MODE_CHAR: 1225 /* If we're on a different line, find where the line ends */ 1226 if (row != cb->prev.lnum) 1227 cb->word_end_col = clip_get_line_end(row); 1228 1229 /* See if we are before or after the origin of the selection */ 1230 if (clip_compare_pos(row, col, cb->origin_row, 1231 cb->origin_start_col) >= 0) 1232 { 1233 if (col >= (int)cb->word_end_col) 1234 clip_update_modeless_selection(cb, cb->origin_row, 1235 cb->origin_start_col, row, (int)Columns); 1236 else 1237 { 1238 if (has_mbyte && mb_lefthalve(row, col)) 1239 slen = 2; 1240 clip_update_modeless_selection(cb, cb->origin_row, 1241 cb->origin_start_col, row, col + slen); 1242 } 1243 } 1244 else 1245 { 1246 if (has_mbyte 1247 && mb_lefthalve(cb->origin_row, cb->origin_start_col)) 1248 slen = 2; 1249 if (col >= (int)cb->word_end_col) 1250 clip_update_modeless_selection(cb, row, cb->word_end_col, 1251 cb->origin_row, cb->origin_start_col + slen); 1252 else 1253 clip_update_modeless_selection(cb, row, col, 1254 cb->origin_row, cb->origin_start_col + slen); 1255 } 1256 break; 1257 1258 case SELECT_MODE_WORD: 1259 /* If we are still within the same word, do nothing */ 1260 if (row == cb->prev.lnum && col >= (int)cb->word_start_col 1261 && col < (int)cb->word_end_col && !repeated_click) 1262 return; 1263 1264 /* Get new word boundaries */ 1265 clip_get_word_boundaries(cb, row, col); 1266 1267 /* Handle being after the origin point of selection */ 1268 if (clip_compare_pos(row, col, cb->origin_row, 1269 cb->origin_start_col) >= 0) 1270 clip_update_modeless_selection(cb, cb->origin_row, 1271 cb->origin_start_col, row, cb->word_end_col); 1272 else 1273 clip_update_modeless_selection(cb, row, cb->word_start_col, 1274 cb->origin_row, cb->origin_end_col); 1275 break; 1276 1277 case SELECT_MODE_LINE: 1278 if (row == cb->prev.lnum && !repeated_click) 1279 return; 1280 1281 if (clip_compare_pos(row, col, cb->origin_row, 1282 cb->origin_start_col) >= 0) 1283 clip_update_modeless_selection(cb, cb->origin_row, 0, row, 1284 (int)Columns); 1285 else 1286 clip_update_modeless_selection(cb, row, 0, cb->origin_row, 1287 (int)Columns); 1288 break; 1289 } 1290 1291 cb->prev.lnum = row; 1292 cb->prev.col = col; 1293 1294 #ifdef DEBUG_SELECTION 1295 printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum, 1296 cb->start.col, cb->end.lnum, cb->end.col); 1297 #endif 1298 } 1299 1300 # if defined(FEAT_GUI) || defined(PROTO) 1301 /* 1302 * Redraw part of the selection if character at "row,col" is inside of it. 1303 * Only used for the GUI. 1304 */ 1305 void 1306 clip_may_redraw_selection(int row, int col, int len) 1307 { 1308 int start = col; 1309 int end = col + len; 1310 1311 if (clip_star.state != SELECT_CLEARED 1312 && row >= clip_star.start.lnum 1313 && row <= clip_star.end.lnum) 1314 { 1315 if (row == clip_star.start.lnum && start < (int)clip_star.start.col) 1316 start = clip_star.start.col; 1317 if (row == clip_star.end.lnum && end > (int)clip_star.end.col) 1318 end = clip_star.end.col; 1319 if (end > start) 1320 clip_invert_area(row, start, row, end, 0); 1321 } 1322 } 1323 # endif 1324 1325 /* 1326 * Called from outside to clear selected region from the display 1327 */ 1328 void 1329 clip_clear_selection(VimClipboard *cbd) 1330 { 1331 1332 if (cbd->state == SELECT_CLEARED) 1333 return; 1334 1335 clip_invert_area((int)cbd->start.lnum, cbd->start.col, (int)cbd->end.lnum, 1336 cbd->end.col, CLIP_CLEAR); 1337 cbd->state = SELECT_CLEARED; 1338 } 1339 1340 /* 1341 * Clear the selection if any lines from "row1" to "row2" are inside of it. 1342 */ 1343 void 1344 clip_may_clear_selection(int row1, int row2) 1345 { 1346 if (clip_star.state == SELECT_DONE 1347 && row2 >= clip_star.start.lnum 1348 && row1 <= clip_star.end.lnum) 1349 clip_clear_selection(&clip_star); 1350 } 1351 1352 /* 1353 * Called before the screen is scrolled up or down. Adjusts the line numbers 1354 * of the selection. Call with big number when clearing the screen. 1355 */ 1356 void 1357 clip_scroll_selection( 1358 int rows) /* negative for scroll down */ 1359 { 1360 int lnum; 1361 1362 if (clip_star.state == SELECT_CLEARED) 1363 return; 1364 1365 lnum = clip_star.start.lnum - rows; 1366 if (lnum <= 0) 1367 clip_star.start.lnum = 0; 1368 else if (lnum >= screen_Rows) /* scrolled off of the screen */ 1369 clip_star.state = SELECT_CLEARED; 1370 else 1371 clip_star.start.lnum = lnum; 1372 1373 lnum = clip_star.end.lnum - rows; 1374 if (lnum < 0) /* scrolled off of the screen */ 1375 clip_star.state = SELECT_CLEARED; 1376 else if (lnum >= screen_Rows) 1377 clip_star.end.lnum = screen_Rows - 1; 1378 else 1379 clip_star.end.lnum = lnum; 1380 } 1381 1382 /* 1383 * Invert a region of the display between a starting and ending row and column 1384 * Values for "how": 1385 * CLIP_CLEAR: undo inversion 1386 * CLIP_SET: set inversion 1387 * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise. 1388 * 0: invert (GUI only). 1389 */ 1390 static void 1391 clip_invert_area( 1392 int row1, 1393 int col1, 1394 int row2, 1395 int col2, 1396 int how) 1397 { 1398 int invert = FALSE; 1399 1400 if (how == CLIP_SET) 1401 invert = TRUE; 1402 1403 /* Swap the from and to positions so the from is always before */ 1404 if (clip_compare_pos(row1, col1, row2, col2) > 0) 1405 { 1406 int tmp_row, tmp_col; 1407 1408 tmp_row = row1; 1409 tmp_col = col1; 1410 row1 = row2; 1411 col1 = col2; 1412 row2 = tmp_row; 1413 col2 = tmp_col; 1414 } 1415 else if (how == CLIP_TOGGLE) 1416 invert = TRUE; 1417 1418 /* If all on the same line, do it the easy way */ 1419 if (row1 == row2) 1420 { 1421 clip_invert_rectangle(row1, col1, 1, col2 - col1, invert); 1422 } 1423 else 1424 { 1425 /* Handle a piece of the first line */ 1426 if (col1 > 0) 1427 { 1428 clip_invert_rectangle(row1, col1, 1, (int)Columns - col1, invert); 1429 row1++; 1430 } 1431 1432 /* Handle a piece of the last line */ 1433 if (col2 < Columns - 1) 1434 { 1435 clip_invert_rectangle(row2, 0, 1, col2, invert); 1436 row2--; 1437 } 1438 1439 /* Handle the rectangle thats left */ 1440 if (row2 >= row1) 1441 clip_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns, 1442 invert); 1443 } 1444 } 1445 1446 /* 1447 * Invert or un-invert a rectangle of the screen. 1448 * "invert" is true if the result is inverted. 1449 */ 1450 static void 1451 clip_invert_rectangle( 1452 int row, 1453 int col, 1454 int height, 1455 int width, 1456 int invert) 1457 { 1458 #ifdef FEAT_GUI 1459 if (gui.in_use) 1460 gui_mch_invert_rectangle(row, col, height, width); 1461 else 1462 #endif 1463 screen_draw_rectangle(row, col, height, width, invert); 1464 } 1465 1466 /* 1467 * Copy the currently selected area into the '*' register so it will be 1468 * available for pasting. 1469 * When "both" is TRUE also copy to the '+' register. 1470 */ 1471 void 1472 clip_copy_modeless_selection(int both UNUSED) 1473 { 1474 char_u *buffer; 1475 char_u *bufp; 1476 int row; 1477 int start_col; 1478 int end_col; 1479 int line_end_col; 1480 int add_newline_flag = FALSE; 1481 int len; 1482 char_u *p; 1483 int row1 = clip_star.start.lnum; 1484 int col1 = clip_star.start.col; 1485 int row2 = clip_star.end.lnum; 1486 int col2 = clip_star.end.col; 1487 1488 /* Can't use ScreenLines unless initialized */ 1489 if (ScreenLines == NULL) 1490 return; 1491 1492 /* 1493 * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2. 1494 */ 1495 if (row1 > row2) 1496 { 1497 row = row1; row1 = row2; row2 = row; 1498 row = col1; col1 = col2; col2 = row; 1499 } 1500 else if (row1 == row2 && col1 > col2) 1501 { 1502 row = col1; col1 = col2; col2 = row; 1503 } 1504 /* correct starting point for being on right halve of double-wide char */ 1505 p = ScreenLines + LineOffset[row1]; 1506 if (enc_dbcs != 0) 1507 col1 -= (*mb_head_off)(p, p + col1); 1508 else if (enc_utf8 && p[col1] == 0) 1509 --col1; 1510 1511 /* Create a temporary buffer for storing the text */ 1512 len = (row2 - row1 + 1) * Columns + 1; 1513 if (enc_dbcs != 0) 1514 len *= 2; /* max. 2 bytes per display cell */ 1515 else if (enc_utf8) 1516 len *= MB_MAXBYTES; 1517 buffer = lalloc((long_u)len, TRUE); 1518 if (buffer == NULL) /* out of memory */ 1519 return; 1520 1521 /* Process each row in the selection */ 1522 for (bufp = buffer, row = row1; row <= row2; row++) 1523 { 1524 if (row == row1) 1525 start_col = col1; 1526 else 1527 start_col = 0; 1528 1529 if (row == row2) 1530 end_col = col2; 1531 else 1532 end_col = Columns; 1533 1534 line_end_col = clip_get_line_end(row); 1535 1536 /* See if we need to nuke some trailing whitespace */ 1537 if (end_col >= Columns && (row < row2 || end_col > line_end_col)) 1538 { 1539 /* Get rid of trailing whitespace */ 1540 end_col = line_end_col; 1541 if (end_col < start_col) 1542 end_col = start_col; 1543 1544 /* If the last line extended to the end, add an extra newline */ 1545 if (row == row2) 1546 add_newline_flag = TRUE; 1547 } 1548 1549 /* If after the first row, we need to always add a newline */ 1550 if (row > row1 && !LineWraps[row - 1]) 1551 *bufp++ = NL; 1552 1553 if (row < screen_Rows && end_col <= screen_Columns) 1554 { 1555 if (enc_dbcs != 0) 1556 { 1557 int i; 1558 1559 p = ScreenLines + LineOffset[row]; 1560 for (i = start_col; i < end_col; ++i) 1561 if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e) 1562 { 1563 /* single-width double-byte char */ 1564 *bufp++ = 0x8e; 1565 *bufp++ = ScreenLines2[LineOffset[row] + i]; 1566 } 1567 else 1568 { 1569 *bufp++ = p[i]; 1570 if (MB_BYTE2LEN(p[i]) == 2) 1571 *bufp++ = p[++i]; 1572 } 1573 } 1574 else if (enc_utf8) 1575 { 1576 int off; 1577 int i; 1578 int ci; 1579 1580 off = LineOffset[row]; 1581 for (i = start_col; i < end_col; ++i) 1582 { 1583 /* The base character is either in ScreenLinesUC[] or 1584 * ScreenLines[]. */ 1585 if (ScreenLinesUC[off + i] == 0) 1586 *bufp++ = ScreenLines[off + i]; 1587 else 1588 { 1589 bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp); 1590 for (ci = 0; ci < Screen_mco; ++ci) 1591 { 1592 /* Add a composing character. */ 1593 if (ScreenLinesC[ci][off + i] == 0) 1594 break; 1595 bufp += utf_char2bytes(ScreenLinesC[ci][off + i], 1596 bufp); 1597 } 1598 } 1599 /* Skip right halve of double-wide character. */ 1600 if (ScreenLines[off + i + 1] == 0) 1601 ++i; 1602 } 1603 } 1604 else 1605 { 1606 STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col, 1607 end_col - start_col); 1608 bufp += end_col - start_col; 1609 } 1610 } 1611 } 1612 1613 /* Add a newline at the end if the selection ended there */ 1614 if (add_newline_flag) 1615 *bufp++ = NL; 1616 1617 /* First cleanup any old selection and become the owner. */ 1618 clip_free_selection(&clip_star); 1619 clip_own_selection(&clip_star); 1620 1621 /* Yank the text into the '*' register. */ 1622 clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star); 1623 1624 /* Make the register contents available to the outside world. */ 1625 clip_gen_set_selection(&clip_star); 1626 1627 #ifdef FEAT_X11 1628 if (both) 1629 { 1630 /* Do the same for the '+' register. */ 1631 clip_free_selection(&clip_plus); 1632 clip_own_selection(&clip_plus); 1633 clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus); 1634 clip_gen_set_selection(&clip_plus); 1635 } 1636 #endif 1637 vim_free(buffer); 1638 } 1639 1640 /* 1641 * Find the starting and ending positions of the word at the given row and 1642 * column. Only white-separated words are recognized here. 1643 */ 1644 #define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c)) 1645 1646 static void 1647 clip_get_word_boundaries(VimClipboard *cb, int row, int col) 1648 { 1649 int start_class; 1650 int temp_col; 1651 char_u *p; 1652 int mboff; 1653 1654 if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL) 1655 return; 1656 1657 p = ScreenLines + LineOffset[row]; 1658 /* Correct for starting in the right halve of a double-wide char */ 1659 if (enc_dbcs != 0) 1660 col -= dbcs_screen_head_off(p, p + col); 1661 else if (enc_utf8 && p[col] == 0) 1662 --col; 1663 start_class = CHAR_CLASS(p[col]); 1664 1665 temp_col = col; 1666 for ( ; temp_col > 0; temp_col--) 1667 if (enc_dbcs != 0 1668 && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0) 1669 temp_col -= mboff; 1670 else if (CHAR_CLASS(p[temp_col - 1]) != start_class 1671 && !(enc_utf8 && p[temp_col - 1] == 0)) 1672 break; 1673 cb->word_start_col = temp_col; 1674 1675 temp_col = col; 1676 for ( ; temp_col < screen_Columns; temp_col++) 1677 if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2) 1678 ++temp_col; 1679 else if (CHAR_CLASS(p[temp_col]) != start_class 1680 && !(enc_utf8 && p[temp_col] == 0)) 1681 break; 1682 cb->word_end_col = temp_col; 1683 } 1684 1685 /* 1686 * Find the column position for the last non-whitespace character on the given 1687 * line. 1688 */ 1689 static int 1690 clip_get_line_end(int row) 1691 { 1692 int i; 1693 1694 if (row >= screen_Rows || ScreenLines == NULL) 1695 return 0; 1696 for (i = screen_Columns; i > 0; i--) 1697 if (ScreenLines[LineOffset[row] + i - 1] != ' ') 1698 break; 1699 return i; 1700 } 1701 1702 /* 1703 * Update the currently selected region by adding and/or subtracting from the 1704 * beginning or end and inverting the changed area(s). 1705 */ 1706 static void 1707 clip_update_modeless_selection( 1708 VimClipboard *cb, 1709 int row1, 1710 int col1, 1711 int row2, 1712 int col2) 1713 { 1714 /* See if we changed at the beginning of the selection */ 1715 if (row1 != cb->start.lnum || col1 != (int)cb->start.col) 1716 { 1717 clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col, 1718 CLIP_TOGGLE); 1719 cb->start.lnum = row1; 1720 cb->start.col = col1; 1721 } 1722 1723 /* See if we changed at the end of the selection */ 1724 if (row2 != cb->end.lnum || col2 != (int)cb->end.col) 1725 { 1726 clip_invert_area((int)cb->end.lnum, cb->end.col, row2, col2, 1727 CLIP_TOGGLE); 1728 cb->end.lnum = row2; 1729 cb->end.col = col2; 1730 } 1731 } 1732 1733 int 1734 clip_gen_own_selection(VimClipboard *cbd) 1735 { 1736 #ifdef FEAT_XCLIPBOARD 1737 # ifdef FEAT_GUI 1738 if (gui.in_use) 1739 return clip_mch_own_selection(cbd); 1740 else 1741 # endif 1742 return clip_xterm_own_selection(cbd); 1743 #else 1744 return clip_mch_own_selection(cbd); 1745 #endif 1746 } 1747 1748 void 1749 clip_gen_lose_selection(VimClipboard *cbd) 1750 { 1751 #ifdef FEAT_XCLIPBOARD 1752 # ifdef FEAT_GUI 1753 if (gui.in_use) 1754 clip_mch_lose_selection(cbd); 1755 else 1756 # endif 1757 clip_xterm_lose_selection(cbd); 1758 #else 1759 clip_mch_lose_selection(cbd); 1760 #endif 1761 } 1762 1763 void 1764 clip_gen_set_selection(VimClipboard *cbd) 1765 { 1766 if (!clip_did_set_selection) 1767 { 1768 /* Updating postponed, so that accessing the system clipboard won't 1769 * hang Vim when accessing it many times (e.g. on a :g command). */ 1770 if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS)) 1771 || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED))) 1772 { 1773 clipboard_needs_update = TRUE; 1774 return; 1775 } 1776 } 1777 #ifdef FEAT_XCLIPBOARD 1778 # ifdef FEAT_GUI 1779 if (gui.in_use) 1780 clip_mch_set_selection(cbd); 1781 else 1782 # endif 1783 clip_xterm_set_selection(cbd); 1784 #else 1785 clip_mch_set_selection(cbd); 1786 #endif 1787 } 1788 1789 void 1790 clip_gen_request_selection(VimClipboard *cbd) 1791 { 1792 #ifdef FEAT_XCLIPBOARD 1793 # ifdef FEAT_GUI 1794 if (gui.in_use) 1795 clip_mch_request_selection(cbd); 1796 else 1797 # endif 1798 clip_xterm_request_selection(cbd); 1799 #else 1800 clip_mch_request_selection(cbd); 1801 #endif 1802 } 1803 1804 #if (defined(FEAT_X11) && defined(USE_SYSTEM)) || defined(PROTO) 1805 int 1806 clip_gen_owner_exists(VimClipboard *cbd UNUSED) 1807 { 1808 #ifdef FEAT_XCLIPBOARD 1809 # ifdef FEAT_GUI_GTK 1810 if (gui.in_use) 1811 return clip_gtk_owner_exists(cbd); 1812 else 1813 # endif 1814 return clip_x11_owner_exists(cbd); 1815 #else 1816 return TRUE; 1817 #endif 1818 } 1819 #endif 1820 1821 #endif /* FEAT_CLIPBOARD */ 1822 1823 /***************************************************************************** 1824 * Functions that handle the input buffer. 1825 * This is used for any GUI version, and the unix terminal version. 1826 * 1827 * For Unix, the input characters are buffered to be able to check for a 1828 * CTRL-C. This should be done with signals, but I don't know how to do that 1829 * in a portable way for a tty in RAW mode. 1830 * 1831 * For the client-server code in the console the received keys are put in the 1832 * input buffer. 1833 */ 1834 1835 #if defined(USE_INPUT_BUF) || defined(PROTO) 1836 1837 /* 1838 * Internal typeahead buffer. Includes extra space for long key code 1839 * descriptions which would otherwise overflow. The buffer is considered full 1840 * when only this extra space (or part of it) remains. 1841 */ 1842 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER) 1843 /* 1844 * NetBeans stuffs debugger commands into the input buffer. 1845 * This requires a larger buffer... 1846 * (Madsen) Go with this for remote input as well ... 1847 */ 1848 # define INBUFLEN 4096 1849 #else 1850 # define INBUFLEN 250 1851 #endif 1852 1853 static char_u inbuf[INBUFLEN + MAX_KEY_CODE_LEN]; 1854 static int inbufcount = 0; /* number of chars in inbuf[] */ 1855 1856 /* 1857 * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and 1858 * trash_input_buf() are functions for manipulating the input buffer. These 1859 * are used by the gui_* calls when a GUI is used to handle keyboard input. 1860 */ 1861 1862 int 1863 vim_is_input_buf_full(void) 1864 { 1865 return (inbufcount >= INBUFLEN); 1866 } 1867 1868 int 1869 vim_is_input_buf_empty(void) 1870 { 1871 return (inbufcount == 0); 1872 } 1873 1874 #if defined(FEAT_OLE) || defined(PROTO) 1875 int 1876 vim_free_in_input_buf(void) 1877 { 1878 return (INBUFLEN - inbufcount); 1879 } 1880 #endif 1881 1882 #if defined(FEAT_GUI_GTK) || defined(PROTO) 1883 int 1884 vim_used_in_input_buf(void) 1885 { 1886 return inbufcount; 1887 } 1888 #endif 1889 1890 /* 1891 * Return the current contents of the input buffer and make it empty. 1892 * The returned pointer must be passed to set_input_buf() later. 1893 */ 1894 char_u * 1895 get_input_buf(void) 1896 { 1897 garray_T *gap; 1898 1899 /* We use a growarray to store the data pointer and the length. */ 1900 gap = (garray_T *)alloc((unsigned)sizeof(garray_T)); 1901 if (gap != NULL) 1902 { 1903 /* Add one to avoid a zero size. */ 1904 gap->ga_data = alloc((unsigned)inbufcount + 1); 1905 if (gap->ga_data != NULL) 1906 mch_memmove(gap->ga_data, inbuf, (size_t)inbufcount); 1907 gap->ga_len = inbufcount; 1908 } 1909 trash_input_buf(); 1910 return (char_u *)gap; 1911 } 1912 1913 /* 1914 * Restore the input buffer with a pointer returned from get_input_buf(). 1915 * The allocated memory is freed, this only works once! 1916 */ 1917 void 1918 set_input_buf(char_u *p) 1919 { 1920 garray_T *gap = (garray_T *)p; 1921 1922 if (gap != NULL) 1923 { 1924 if (gap->ga_data != NULL) 1925 { 1926 mch_memmove(inbuf, gap->ga_data, gap->ga_len); 1927 inbufcount = gap->ga_len; 1928 vim_free(gap->ga_data); 1929 } 1930 vim_free(gap); 1931 } 1932 } 1933 1934 /* 1935 * Add the given bytes to the input buffer 1936 * Special keys start with CSI. A real CSI must have been translated to 1937 * CSI KS_EXTRA KE_CSI. K_SPECIAL doesn't require translation. 1938 */ 1939 void 1940 add_to_input_buf(char_u *s, int len) 1941 { 1942 if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN) 1943 return; /* Shouldn't ever happen! */ 1944 1945 #ifdef FEAT_HANGULIN 1946 if ((State & (INSERT|CMDLINE)) && hangul_input_state_get()) 1947 if ((len = hangul_input_process(s, len)) == 0) 1948 return; 1949 #endif 1950 1951 while (len--) 1952 inbuf[inbufcount++] = *s++; 1953 } 1954 1955 /* 1956 * Add "str[len]" to the input buffer while escaping CSI bytes. 1957 */ 1958 void 1959 add_to_input_buf_csi(char_u *str, int len) 1960 { 1961 int i; 1962 char_u buf[2]; 1963 1964 for (i = 0; i < len; ++i) 1965 { 1966 add_to_input_buf(str + i, 1); 1967 if (str[i] == CSI) 1968 { 1969 /* Turn CSI into K_CSI. */ 1970 buf[0] = KS_EXTRA; 1971 buf[1] = (int)KE_CSI; 1972 add_to_input_buf(buf, 2); 1973 } 1974 } 1975 } 1976 1977 #if defined(FEAT_HANGULIN) || defined(PROTO) 1978 void 1979 push_raw_key(char_u *s, int len) 1980 { 1981 char_u *tmpbuf; 1982 char_u *inp = s; 1983 1984 /* use the conversion result if possible */ 1985 tmpbuf = hangul_string_convert(s, &len); 1986 if (tmpbuf != NULL) 1987 inp = tmpbuf; 1988 1989 for (; len--; inp++) 1990 { 1991 inbuf[inbufcount++] = *inp; 1992 if (*inp == CSI) 1993 { 1994 /* Turn CSI into K_CSI. */ 1995 inbuf[inbufcount++] = KS_EXTRA; 1996 inbuf[inbufcount++] = (int)KE_CSI; 1997 } 1998 } 1999 vim_free(tmpbuf); 2000 } 2001 #endif 2002 2003 /* Remove everything from the input buffer. Called when ^C is found */ 2004 void 2005 trash_input_buf(void) 2006 { 2007 inbufcount = 0; 2008 } 2009 2010 /* 2011 * Read as much data from the input buffer as possible up to maxlen, and store 2012 * it in buf. 2013 */ 2014 int 2015 read_from_input_buf(char_u *buf, long maxlen) 2016 { 2017 if (inbufcount == 0) /* if the buffer is empty, fill it */ 2018 fill_input_buf(TRUE); 2019 if (maxlen > inbufcount) 2020 maxlen = inbufcount; 2021 mch_memmove(buf, inbuf, (size_t)maxlen); 2022 inbufcount -= maxlen; 2023 if (inbufcount) 2024 mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount); 2025 return (int)maxlen; 2026 } 2027 2028 void 2029 fill_input_buf(int exit_on_error UNUSED) 2030 { 2031 #if defined(UNIX) || defined(VMS) || defined(MACOS_X) 2032 int len; 2033 int try; 2034 static int did_read_something = FALSE; 2035 static char_u *rest = NULL; /* unconverted rest of previous read */ 2036 static int restlen = 0; 2037 int unconverted; 2038 #endif 2039 2040 #ifdef FEAT_GUI 2041 if (gui.in_use 2042 # ifdef NO_CONSOLE_INPUT 2043 /* Don't use the GUI input when the window hasn't been opened yet. 2044 * We get here from ui_inchar() when we should try reading from stdin. */ 2045 && !no_console_input() 2046 # endif 2047 ) 2048 { 2049 gui_mch_update(); 2050 return; 2051 } 2052 #endif 2053 #if defined(UNIX) || defined(VMS) || defined(MACOS_X) 2054 if (vim_is_input_buf_full()) 2055 return; 2056 /* 2057 * Fill_input_buf() is only called when we really need a character. 2058 * If we can't get any, but there is some in the buffer, just return. 2059 * If we can't get any, and there isn't any in the buffer, we give up and 2060 * exit Vim. 2061 */ 2062 # ifdef __BEOS__ 2063 /* 2064 * On the BeBox version (for now), all input is secretly performed within 2065 * beos_select() which is called from RealWaitForChar(). 2066 */ 2067 while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0, NULL)) 2068 ; 2069 len = inbufcount; 2070 inbufcount = 0; 2071 # else 2072 2073 if (rest != NULL) 2074 { 2075 /* Use remainder of previous call, starts with an invalid character 2076 * that may become valid when reading more. */ 2077 if (restlen > INBUFLEN - inbufcount) 2078 unconverted = INBUFLEN - inbufcount; 2079 else 2080 unconverted = restlen; 2081 mch_memmove(inbuf + inbufcount, rest, unconverted); 2082 if (unconverted == restlen) 2083 VIM_CLEAR(rest); 2084 else 2085 { 2086 restlen -= unconverted; 2087 mch_memmove(rest, rest + unconverted, restlen); 2088 } 2089 inbufcount += unconverted; 2090 } 2091 else 2092 unconverted = 0; 2093 2094 len = 0; /* to avoid gcc warning */ 2095 for (try = 0; try < 100; ++try) 2096 { 2097 size_t readlen = (size_t)((INBUFLEN - inbufcount) 2098 / input_conv.vc_factor); 2099 # ifdef VMS 2100 len = vms_read((char *)inbuf + inbufcount, readlen); 2101 # else 2102 len = read(read_cmd_fd, (char *)inbuf + inbufcount, readlen); 2103 # endif 2104 2105 if (len > 0 || got_int) 2106 break; 2107 /* 2108 * If reading stdin results in an error, continue reading stderr. 2109 * This helps when using "foo | xargs vim". 2110 */ 2111 if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0) 2112 { 2113 int m = cur_tmode; 2114 2115 /* We probably set the wrong file descriptor to raw mode. Switch 2116 * back to cooked mode, use another descriptor and set the mode to 2117 * what it was. */ 2118 settmode(TMODE_COOK); 2119 #ifdef HAVE_DUP 2120 /* Use stderr for stdin, also works for shell commands. */ 2121 close(0); 2122 vim_ignored = dup(2); 2123 #else 2124 read_cmd_fd = 2; /* read from stderr instead of stdin */ 2125 #endif 2126 settmode(m); 2127 } 2128 if (!exit_on_error) 2129 return; 2130 } 2131 # endif 2132 if (len <= 0 && !got_int) 2133 read_error_exit(); 2134 if (len > 0) 2135 did_read_something = TRUE; 2136 if (got_int) 2137 { 2138 /* Interrupted, pretend a CTRL-C was typed. */ 2139 inbuf[0] = 3; 2140 inbufcount = 1; 2141 } 2142 else 2143 { 2144 /* 2145 * May perform conversion on the input characters. 2146 * Include the unconverted rest of the previous call. 2147 * If there is an incomplete char at the end it is kept for the next 2148 * time, reading more bytes should make conversion possible. 2149 * Don't do this in the unlikely event that the input buffer is too 2150 * small ("rest" still contains more bytes). 2151 */ 2152 if (input_conv.vc_type != CONV_NONE) 2153 { 2154 inbufcount -= unconverted; 2155 len = convert_input_safe(inbuf + inbufcount, 2156 len + unconverted, INBUFLEN - inbufcount, 2157 rest == NULL ? &rest : NULL, &restlen); 2158 } 2159 while (len-- > 0) 2160 { 2161 /* 2162 * if a CTRL-C was typed, remove it from the buffer and set got_int 2163 */ 2164 if (inbuf[inbufcount] == 3 && ctrl_c_interrupts) 2165 { 2166 /* remove everything typed before the CTRL-C */ 2167 mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1)); 2168 inbufcount = 0; 2169 got_int = TRUE; 2170 } 2171 ++inbufcount; 2172 } 2173 } 2174 #endif /* UNIX or VMS*/ 2175 } 2176 #endif /* defined(UNIX) || defined(FEAT_GUI) || defined(VMS) */ 2177 2178 /* 2179 * Exit because of an input read error. 2180 */ 2181 void 2182 read_error_exit(void) 2183 { 2184 if (silent_mode) /* Normal way to exit for "ex -s" */ 2185 getout(0); 2186 STRCPY(IObuff, _("Vim: Error reading input, exiting...\n")); 2187 preserve_exit(); 2188 } 2189 2190 #if defined(CURSOR_SHAPE) || defined(PROTO) 2191 /* 2192 * May update the shape of the cursor. 2193 */ 2194 void 2195 ui_cursor_shape_forced(int forced) 2196 { 2197 # ifdef FEAT_GUI 2198 if (gui.in_use) 2199 gui_update_cursor_later(); 2200 else 2201 # endif 2202 term_cursor_mode(forced); 2203 2204 # ifdef MCH_CURSOR_SHAPE 2205 mch_update_cursor(); 2206 # endif 2207 2208 # ifdef FEAT_CONCEAL 2209 conceal_check_cursor_line(); 2210 # endif 2211 } 2212 2213 void 2214 ui_cursor_shape(void) 2215 { 2216 ui_cursor_shape_forced(FALSE); 2217 } 2218 #endif 2219 2220 /* 2221 * Check bounds for column number 2222 */ 2223 int 2224 check_col(int col) 2225 { 2226 if (col < 0) 2227 return 0; 2228 if (col >= (int)screen_Columns) 2229 return (int)screen_Columns - 1; 2230 return col; 2231 } 2232 2233 /* 2234 * Check bounds for row number 2235 */ 2236 int 2237 check_row(int row) 2238 { 2239 if (row < 0) 2240 return 0; 2241 if (row >= (int)screen_Rows) 2242 return (int)screen_Rows - 1; 2243 return row; 2244 } 2245 2246 /* 2247 * Stuff for the X clipboard. Shared between VMS and Unix. 2248 */ 2249 2250 #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO) 2251 # include <X11/Xatom.h> 2252 # include <X11/Intrinsic.h> 2253 2254 /* 2255 * Open the application context (if it hasn't been opened yet). 2256 * Used for Motif and Athena GUI and the xterm clipboard. 2257 */ 2258 void 2259 open_app_context(void) 2260 { 2261 if (app_context == NULL) 2262 { 2263 XtToolkitInitialize(); 2264 app_context = XtCreateApplicationContext(); 2265 } 2266 } 2267 2268 static Atom vim_atom; /* Vim's own special selection format */ 2269 static Atom vimenc_atom; /* Vim's extended selection format */ 2270 static Atom utf8_atom; 2271 static Atom compound_text_atom; 2272 static Atom text_atom; 2273 static Atom targets_atom; 2274 static Atom timestamp_atom; /* Used to get a timestamp */ 2275 2276 void 2277 x11_setup_atoms(Display *dpy) 2278 { 2279 vim_atom = XInternAtom(dpy, VIM_ATOM_NAME, False); 2280 vimenc_atom = XInternAtom(dpy, VIMENC_ATOM_NAME,False); 2281 utf8_atom = XInternAtom(dpy, "UTF8_STRING", False); 2282 compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False); 2283 text_atom = XInternAtom(dpy, "TEXT", False); 2284 targets_atom = XInternAtom(dpy, "TARGETS", False); 2285 clip_star.sel_atom = XA_PRIMARY; 2286 clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD", False); 2287 timestamp_atom = XInternAtom(dpy, "TIMESTAMP", False); 2288 } 2289 2290 /* 2291 * X Selection stuff, for cutting and pasting text to other windows. 2292 */ 2293 2294 static Boolean clip_x11_convert_selection_cb(Widget w, Atom *sel_atom, Atom *target, Atom *type, XtPointer *value, long_u *length, int *format); 2295 static void clip_x11_lose_ownership_cb(Widget w, Atom *sel_atom); 2296 static void clip_x11_notify_cb(Widget w, Atom *sel_atom, Atom *target); 2297 2298 /* 2299 * Property callback to get a timestamp for XtOwnSelection. 2300 */ 2301 static void 2302 clip_x11_timestamp_cb( 2303 Widget w, 2304 XtPointer n UNUSED, 2305 XEvent *event, 2306 Boolean *cont UNUSED) 2307 { 2308 Atom actual_type; 2309 int format; 2310 unsigned long nitems, bytes_after; 2311 unsigned char *prop=NULL; 2312 XPropertyEvent *xproperty=&event->xproperty; 2313 2314 /* Must be a property notify, state can't be Delete (True), has to be 2315 * one of the supported selection types. */ 2316 if (event->type != PropertyNotify || xproperty->state 2317 || (xproperty->atom != clip_star.sel_atom 2318 && xproperty->atom != clip_plus.sel_atom)) 2319 return; 2320 2321 if (XGetWindowProperty(xproperty->display, xproperty->window, 2322 xproperty->atom, 0, 0, False, timestamp_atom, &actual_type, &format, 2323 &nitems, &bytes_after, &prop)) 2324 return; 2325 2326 if (prop) 2327 XFree(prop); 2328 2329 /* Make sure the property type is "TIMESTAMP" and it's 32 bits. */ 2330 if (actual_type != timestamp_atom || format != 32) 2331 return; 2332 2333 /* Get the selection, using the event timestamp. */ 2334 if (XtOwnSelection(w, xproperty->atom, xproperty->time, 2335 clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, 2336 clip_x11_notify_cb) == OK) 2337 { 2338 /* Set the "owned" flag now, there may have been a call to 2339 * lose_ownership_cb in between. */ 2340 if (xproperty->atom == clip_plus.sel_atom) 2341 clip_plus.owned = TRUE; 2342 else 2343 clip_star.owned = TRUE; 2344 } 2345 } 2346 2347 void 2348 x11_setup_selection(Widget w) 2349 { 2350 XtAddEventHandler(w, PropertyChangeMask, False, 2351 /*(XtEventHandler)*/clip_x11_timestamp_cb, (XtPointer)NULL); 2352 } 2353 2354 static void 2355 clip_x11_request_selection_cb( 2356 Widget w UNUSED, 2357 XtPointer success, 2358 Atom *sel_atom, 2359 Atom *type, 2360 XtPointer value, 2361 long_u *length, 2362 int *format) 2363 { 2364 int motion_type = MAUTO; 2365 long_u len; 2366 char_u *p; 2367 char **text_list = NULL; 2368 VimClipboard *cbd; 2369 char_u *tmpbuf = NULL; 2370 2371 if (*sel_atom == clip_plus.sel_atom) 2372 cbd = &clip_plus; 2373 else 2374 cbd = &clip_star; 2375 2376 if (value == NULL || *length == 0) 2377 { 2378 clip_free_selection(cbd); /* nothing received, clear register */ 2379 *(int *)success = FALSE; 2380 return; 2381 } 2382 p = (char_u *)value; 2383 len = *length; 2384 if (*type == vim_atom) 2385 { 2386 motion_type = *p++; 2387 len--; 2388 } 2389 2390 else if (*type == vimenc_atom) 2391 { 2392 char_u *enc; 2393 vimconv_T conv; 2394 int convlen; 2395 2396 motion_type = *p++; 2397 --len; 2398 2399 enc = p; 2400 p += STRLEN(p) + 1; 2401 len -= p - enc; 2402 2403 /* If the encoding of the text is different from 'encoding', attempt 2404 * converting it. */ 2405 conv.vc_type = CONV_NONE; 2406 convert_setup(&conv, enc, p_enc); 2407 if (conv.vc_type != CONV_NONE) 2408 { 2409 convlen = len; /* Need to use an int here. */ 2410 tmpbuf = string_convert(&conv, p, &convlen); 2411 len = convlen; 2412 if (tmpbuf != NULL) 2413 p = tmpbuf; 2414 convert_setup(&conv, NULL, NULL); 2415 } 2416 } 2417 2418 else if (*type == compound_text_atom 2419 || *type == utf8_atom 2420 || (enc_dbcs != 0 && *type == text_atom)) 2421 { 2422 XTextProperty text_prop; 2423 int n_text = 0; 2424 int status; 2425 2426 text_prop.value = (unsigned char *)value; 2427 text_prop.encoding = *type; 2428 text_prop.format = *format; 2429 text_prop.nitems = len; 2430 #if defined(X_HAVE_UTF8_STRING) 2431 if (*type == utf8_atom) 2432 status = Xutf8TextPropertyToTextList(X_DISPLAY, &text_prop, 2433 &text_list, &n_text); 2434 else 2435 #endif 2436 status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop, 2437 &text_list, &n_text); 2438 if (status != Success || n_text < 1) 2439 { 2440 *(int *)success = FALSE; 2441 return; 2442 } 2443 p = (char_u *)text_list[0]; 2444 len = STRLEN(p); 2445 } 2446 clip_yank_selection(motion_type, p, (long)len, cbd); 2447 2448 if (text_list != NULL) 2449 XFreeStringList(text_list); 2450 vim_free(tmpbuf); 2451 XtFree((char *)value); 2452 *(int *)success = TRUE; 2453 } 2454 2455 void 2456 clip_x11_request_selection( 2457 Widget myShell, 2458 Display *dpy, 2459 VimClipboard *cbd) 2460 { 2461 XEvent event; 2462 Atom type; 2463 static int success; 2464 int i; 2465 time_t start_time; 2466 int timed_out = FALSE; 2467 2468 for (i = 0; i < 6; i++) 2469 { 2470 switch (i) 2471 { 2472 case 0: type = vimenc_atom; break; 2473 case 1: type = vim_atom; break; 2474 case 2: type = utf8_atom; break; 2475 case 3: type = compound_text_atom; break; 2476 case 4: type = text_atom; break; 2477 default: type = XA_STRING; 2478 } 2479 if (type == utf8_atom 2480 # if defined(X_HAVE_UTF8_STRING) 2481 && !enc_utf8 2482 # endif 2483 ) 2484 /* Only request utf-8 when 'encoding' is utf8 and 2485 * Xutf8TextPropertyToTextList is available. */ 2486 continue; 2487 success = MAYBE; 2488 XtGetSelectionValue(myShell, cbd->sel_atom, type, 2489 clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime); 2490 2491 /* Make sure the request for the selection goes out before waiting for 2492 * a response. */ 2493 XFlush(dpy); 2494 2495 /* 2496 * Wait for result of selection request, otherwise if we type more 2497 * characters, then they will appear before the one that requested the 2498 * paste! Don't worry, we will catch up with any other events later. 2499 */ 2500 start_time = time(NULL); 2501 while (success == MAYBE) 2502 { 2503 if (XCheckTypedEvent(dpy, PropertyNotify, &event) 2504 || XCheckTypedEvent(dpy, SelectionNotify, &event) 2505 || XCheckTypedEvent(dpy, SelectionRequest, &event)) 2506 { 2507 /* This is where clip_x11_request_selection_cb() should be 2508 * called. It may actually happen a bit later, so we loop 2509 * until "success" changes. 2510 * We may get a SelectionRequest here and if we don't handle 2511 * it we hang. KDE klipper does this, for example. 2512 * We need to handle a PropertyNotify for large selections. */ 2513 XtDispatchEvent(&event); 2514 continue; 2515 } 2516 2517 /* Time out after 2 to 3 seconds to avoid that we hang when the 2518 * other process doesn't respond. Note that the SelectionNotify 2519 * event may still come later when the selection owner comes back 2520 * to life and the text gets inserted unexpectedly. Don't know 2521 * why that happens or how to avoid that :-(. */ 2522 if (time(NULL) > start_time + 2) 2523 { 2524 timed_out = TRUE; 2525 break; 2526 } 2527 2528 /* Do we need this? Probably not. */ 2529 XSync(dpy, False); 2530 2531 /* Wait for 1 msec to avoid that we eat up all CPU time. */ 2532 ui_delay(1L, TRUE); 2533 } 2534 2535 if (success == TRUE) 2536 return; 2537 2538 /* don't do a retry with another type after timing out, otherwise we 2539 * hang for 15 seconds. */ 2540 if (timed_out) 2541 break; 2542 } 2543 2544 /* Final fallback position - use the X CUT_BUFFER0 store */ 2545 yank_cut_buffer0(dpy, cbd); 2546 } 2547 2548 static Boolean 2549 clip_x11_convert_selection_cb( 2550 Widget w UNUSED, 2551 Atom *sel_atom, 2552 Atom *target, 2553 Atom *type, 2554 XtPointer *value, 2555 long_u *length, 2556 int *format) 2557 { 2558 static char_u *save_result = NULL; 2559 static long_u save_length = 0; 2560 char_u *string; 2561 int motion_type; 2562 VimClipboard *cbd; 2563 int i; 2564 2565 if (*sel_atom == clip_plus.sel_atom) 2566 cbd = &clip_plus; 2567 else 2568 cbd = &clip_star; 2569 2570 if (!cbd->owned) 2571 return False; /* Shouldn't ever happen */ 2572 2573 /* requestor wants to know what target types we support */ 2574 if (*target == targets_atom) 2575 { 2576 static Atom array[7]; 2577 2578 *value = (XtPointer)array; 2579 i = 0; 2580 array[i++] = targets_atom; 2581 array[i++] = vimenc_atom; 2582 array[i++] = vim_atom; 2583 if (enc_utf8) 2584 array[i++] = utf8_atom; 2585 array[i++] = XA_STRING; 2586 array[i++] = text_atom; 2587 array[i++] = compound_text_atom; 2588 2589 *type = XA_ATOM; 2590 /* This used to be: *format = sizeof(Atom) * 8; but that caused 2591 * crashes on 64 bit machines. (Peter Derr) */ 2592 *format = 32; 2593 *length = i; 2594 return True; 2595 } 2596 2597 if ( *target != XA_STRING 2598 && *target != vimenc_atom 2599 && (*target != utf8_atom || !enc_utf8) 2600 && *target != vim_atom 2601 && *target != text_atom 2602 && *target != compound_text_atom) 2603 return False; 2604 2605 clip_get_selection(cbd); 2606 motion_type = clip_convert_selection(&string, length, cbd); 2607 if (motion_type < 0) 2608 return False; 2609 2610 /* For our own format, the first byte contains the motion type */ 2611 if (*target == vim_atom) 2612 (*length)++; 2613 2614 /* Our own format with encoding: motion 'encoding' NUL text */ 2615 if (*target == vimenc_atom) 2616 *length += STRLEN(p_enc) + 2; 2617 2618 if (save_length < *length || save_length / 2 >= *length) 2619 *value = XtRealloc((char *)save_result, (Cardinal)*length + 1); 2620 else 2621 *value = save_result; 2622 if (*value == NULL) 2623 { 2624 vim_free(string); 2625 return False; 2626 } 2627 save_result = (char_u *)*value; 2628 save_length = *length; 2629 2630 if (*target == XA_STRING || (*target == utf8_atom && enc_utf8)) 2631 { 2632 mch_memmove(save_result, string, (size_t)(*length)); 2633 *type = *target; 2634 } 2635 else if (*target == compound_text_atom || *target == text_atom) 2636 { 2637 XTextProperty text_prop; 2638 char *string_nt = (char *)save_result; 2639 int conv_result; 2640 2641 /* create NUL terminated string which XmbTextListToTextProperty wants */ 2642 mch_memmove(string_nt, string, (size_t)*length); 2643 string_nt[*length] = NUL; 2644 conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt, 2645 1, XCompoundTextStyle, &text_prop); 2646 if (conv_result != Success) 2647 { 2648 vim_free(string); 2649 return False; 2650 } 2651 *value = (XtPointer)(text_prop.value); /* from plain text */ 2652 *length = text_prop.nitems; 2653 *type = compound_text_atom; 2654 XtFree((char *)save_result); 2655 save_result = (char_u *)*value; 2656 save_length = *length; 2657 } 2658 else if (*target == vimenc_atom) 2659 { 2660 int l = STRLEN(p_enc); 2661 2662 save_result[0] = motion_type; 2663 STRCPY(save_result + 1, p_enc); 2664 mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2)); 2665 *type = vimenc_atom; 2666 } 2667 else 2668 { 2669 save_result[0] = motion_type; 2670 mch_memmove(save_result + 1, string, (size_t)(*length - 1)); 2671 *type = vim_atom; 2672 } 2673 *format = 8; /* 8 bits per char */ 2674 vim_free(string); 2675 return True; 2676 } 2677 2678 static void 2679 clip_x11_lose_ownership_cb(Widget w UNUSED, Atom *sel_atom) 2680 { 2681 if (*sel_atom == clip_plus.sel_atom) 2682 clip_lose_selection(&clip_plus); 2683 else 2684 clip_lose_selection(&clip_star); 2685 } 2686 2687 void 2688 clip_x11_lose_selection(Widget myShell, VimClipboard *cbd) 2689 { 2690 XtDisownSelection(myShell, cbd->sel_atom, 2691 XtLastTimestampProcessed(XtDisplay(myShell))); 2692 } 2693 2694 static void 2695 clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target UNUSED) 2696 { 2697 /* To prevent automatically freeing the selection value. */ 2698 } 2699 2700 int 2701 clip_x11_own_selection(Widget myShell, VimClipboard *cbd) 2702 { 2703 /* When using the GUI we have proper timestamps, use the one of the last 2704 * event. When in the console we don't get events (the terminal gets 2705 * them), Get the time by a zero-length append, clip_x11_timestamp_cb will 2706 * be called with the current timestamp. */ 2707 #ifdef FEAT_GUI 2708 if (gui.in_use) 2709 { 2710 if (XtOwnSelection(myShell, cbd->sel_atom, 2711 XtLastTimestampProcessed(XtDisplay(myShell)), 2712 clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, 2713 clip_x11_notify_cb) == False) 2714 return FAIL; 2715 } 2716 else 2717 #endif 2718 { 2719 if (!XChangeProperty(XtDisplay(myShell), XtWindow(myShell), 2720 cbd->sel_atom, timestamp_atom, 32, PropModeAppend, NULL, 0)) 2721 return FAIL; 2722 } 2723 /* Flush is required in a terminal as nothing else is doing it. */ 2724 XFlush(XtDisplay(myShell)); 2725 return OK; 2726 } 2727 2728 /* 2729 * Send the current selection to the clipboard. Do nothing for X because we 2730 * will fill in the selection only when requested by another app. 2731 */ 2732 void 2733 clip_x11_set_selection(VimClipboard *cbd UNUSED) 2734 { 2735 } 2736 2737 #if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) \ 2738 || defined(PROTO) 2739 int 2740 clip_x11_owner_exists(VimClipboard *cbd) 2741 { 2742 return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None; 2743 } 2744 #endif 2745 #endif 2746 2747 #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) \ 2748 || defined(FEAT_GUI_GTK) || defined(PROTO) 2749 /* 2750 * Get the contents of the X CUT_BUFFER0 and put it in "cbd". 2751 */ 2752 void 2753 yank_cut_buffer0(Display *dpy, VimClipboard *cbd) 2754 { 2755 int nbytes = 0; 2756 char_u *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0); 2757 2758 if (nbytes > 0) 2759 { 2760 int done = FALSE; 2761 2762 /* CUT_BUFFER0 is supposed to be always latin1. Convert to 'enc' when 2763 * using a multi-byte encoding. Conversion between two 8-bit 2764 * character sets usually fails and the text might actually be in 2765 * 'enc' anyway. */ 2766 if (has_mbyte) 2767 { 2768 char_u *conv_buf; 2769 vimconv_T vc; 2770 2771 vc.vc_type = CONV_NONE; 2772 if (convert_setup(&vc, (char_u *)"latin1", p_enc) == OK) 2773 { 2774 conv_buf = string_convert(&vc, buffer, &nbytes); 2775 if (conv_buf != NULL) 2776 { 2777 clip_yank_selection(MCHAR, conv_buf, (long)nbytes, cbd); 2778 vim_free(conv_buf); 2779 done = TRUE; 2780 } 2781 convert_setup(&vc, NULL, NULL); 2782 } 2783 } 2784 if (!done) /* use the text without conversion */ 2785 clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd); 2786 XFree((void *)buffer); 2787 if (p_verbose > 0) 2788 { 2789 verbose_enter(); 2790 verb_msg(_("Used CUT_BUFFER0 instead of empty selection")); 2791 verbose_leave(); 2792 } 2793 } 2794 } 2795 #endif 2796 2797 #if defined(FEAT_MOUSE) || defined(PROTO) 2798 2799 /* 2800 * Move the cursor to the specified row and column on the screen. 2801 * Change current window if necessary. Returns an integer with the 2802 * CURSOR_MOVED bit set if the cursor has moved or unset otherwise. 2803 * 2804 * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column. 2805 * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column. 2806 * 2807 * If flags has MOUSE_FOCUS, then the current window will not be changed, and 2808 * if the mouse is outside the window then the text will scroll, or if the 2809 * mouse was previously on a status line, then the status line may be dragged. 2810 * 2811 * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the 2812 * cursor is moved unless the cursor was on a status line. 2813 * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or 2814 * IN_SEP_LINE depending on where the cursor was clicked. 2815 * 2816 * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless 2817 * the mouse is on the status line of the same window. 2818 * 2819 * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since 2820 * the last call. 2821 * 2822 * If flags has MOUSE_SETPOS, nothing is done, only the current position is 2823 * remembered. 2824 */ 2825 int 2826 jump_to_mouse( 2827 int flags, 2828 int *inclusive, /* used for inclusive operator, can be NULL */ 2829 int which_button) /* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */ 2830 { 2831 static int on_status_line = 0; /* #lines below bottom of window */ 2832 static int on_sep_line = 0; /* on separator right of window */ 2833 #ifdef FEAT_MENU 2834 static int in_winbar = FALSE; 2835 #endif 2836 static int prev_row = -1; 2837 static int prev_col = -1; 2838 static win_T *dragwin = NULL; /* window being dragged */ 2839 static int did_drag = FALSE; /* drag was noticed */ 2840 2841 win_T *wp, *old_curwin; 2842 pos_T old_cursor; 2843 int count; 2844 int first; 2845 int row = mouse_row; 2846 int col = mouse_col; 2847 #ifdef FEAT_FOLDING 2848 int mouse_char; 2849 #endif 2850 2851 mouse_past_bottom = FALSE; 2852 mouse_past_eol = FALSE; 2853 2854 if (flags & MOUSE_RELEASED) 2855 { 2856 /* On button release we may change window focus if positioned on a 2857 * status line and no dragging happened. */ 2858 if (dragwin != NULL && !did_drag) 2859 flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE); 2860 dragwin = NULL; 2861 did_drag = FALSE; 2862 } 2863 2864 if ((flags & MOUSE_DID_MOVE) 2865 && prev_row == mouse_row 2866 && prev_col == mouse_col) 2867 { 2868 retnomove: 2869 /* before moving the cursor for a left click which is NOT in a status 2870 * line, stop Visual mode */ 2871 if (on_status_line) 2872 return IN_STATUS_LINE; 2873 if (on_sep_line) 2874 return IN_SEP_LINE; 2875 #ifdef FEAT_MENU 2876 if (in_winbar) 2877 { 2878 /* A quick second click may arrive as a double-click, but we use it 2879 * as a second click in the WinBar. */ 2880 if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED)) 2881 { 2882 wp = mouse_find_win(&row, &col); 2883 if (wp == NULL) 2884 return IN_UNKNOWN; 2885 winbar_click(wp, col); 2886 } 2887 return IN_OTHER_WIN | MOUSE_WINBAR; 2888 } 2889 #endif 2890 if (flags & MOUSE_MAY_STOP_VIS) 2891 { 2892 end_visual_mode(); 2893 redraw_curbuf_later(INVERTED); /* delete the inversion */ 2894 } 2895 #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD) 2896 /* Continue a modeless selection in another window. */ 2897 if (cmdwin_type != 0 && row < curwin->w_winrow) 2898 return IN_OTHER_WIN; 2899 #endif 2900 return IN_BUFFER; 2901 } 2902 2903 prev_row = mouse_row; 2904 prev_col = mouse_col; 2905 2906 if (flags & MOUSE_SETPOS) 2907 goto retnomove; /* ugly goto... */ 2908 2909 #ifdef FEAT_FOLDING 2910 /* Remember the character under the mouse, it might be a '-' or '+' in the 2911 * fold column. */ 2912 if (row >= 0 && row < Rows && col >= 0 && col <= Columns 2913 && ScreenLines != NULL) 2914 mouse_char = ScreenLines[LineOffset[row] + col]; 2915 else 2916 mouse_char = ' '; 2917 #endif 2918 2919 old_curwin = curwin; 2920 old_cursor = curwin->w_cursor; 2921 2922 if (!(flags & MOUSE_FOCUS)) 2923 { 2924 if (row < 0 || col < 0) /* check if it makes sense */ 2925 return IN_UNKNOWN; 2926 2927 /* find the window where the row is in */ 2928 wp = mouse_find_win(&row, &col); 2929 if (wp == NULL) 2930 return IN_UNKNOWN; 2931 dragwin = NULL; 2932 2933 #ifdef FEAT_MENU 2934 if (row == -1) 2935 { 2936 /* A click in the window toolbar does not enter another window or 2937 * change Visual highlighting. */ 2938 winbar_click(wp, col); 2939 in_winbar = TRUE; 2940 return IN_OTHER_WIN | MOUSE_WINBAR; 2941 } 2942 in_winbar = FALSE; 2943 #endif 2944 2945 /* 2946 * winpos and height may change in win_enter()! 2947 */ 2948 if (row >= wp->w_height) /* In (or below) status line */ 2949 { 2950 on_status_line = row - wp->w_height + 1; 2951 dragwin = wp; 2952 } 2953 else 2954 on_status_line = 0; 2955 if (col >= wp->w_width) /* In separator line */ 2956 { 2957 on_sep_line = col - wp->w_width + 1; 2958 dragwin = wp; 2959 } 2960 else 2961 on_sep_line = 0; 2962 2963 /* The rightmost character of the status line might be a vertical 2964 * separator character if there is no connecting window to the right. */ 2965 if (on_status_line && on_sep_line) 2966 { 2967 if (stl_connected(wp)) 2968 on_sep_line = 0; 2969 else 2970 on_status_line = 0; 2971 } 2972 2973 /* Before jumping to another buffer, or moving the cursor for a left 2974 * click, stop Visual mode. */ 2975 if (VIsual_active 2976 && (wp->w_buffer != curwin->w_buffer 2977 || (!on_status_line && !on_sep_line 2978 #ifdef FEAT_FOLDING 2979 && ( 2980 # ifdef FEAT_RIGHTLEFT 2981 wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc : 2982 # endif 2983 col >= wp->w_p_fdc 2984 # ifdef FEAT_CMDWIN 2985 + (cmdwin_type == 0 && wp == curwin ? 0 : 1) 2986 # endif 2987 ) 2988 #endif 2989 && (flags & MOUSE_MAY_STOP_VIS)))) 2990 { 2991 end_visual_mode(); 2992 redraw_curbuf_later(INVERTED); /* delete the inversion */ 2993 } 2994 #ifdef FEAT_CMDWIN 2995 if (cmdwin_type != 0 && wp != curwin) 2996 { 2997 /* A click outside the command-line window: Use modeless 2998 * selection if possible. Allow dragging the status lines. */ 2999 on_sep_line = 0; 3000 # ifdef FEAT_CLIPBOARD 3001 if (on_status_line) 3002 return IN_STATUS_LINE; 3003 return IN_OTHER_WIN; 3004 # else 3005 row = 0; 3006 col += wp->w_wincol; 3007 wp = curwin; 3008 # endif 3009 } 3010 #endif 3011 /* Only change window focus when not clicking on or dragging the 3012 * status line. Do change focus when releasing the mouse button 3013 * (MOUSE_FOCUS was set above if we dragged first). */ 3014 if (dragwin == NULL || (flags & MOUSE_RELEASED)) 3015 win_enter(wp, TRUE); /* can make wp invalid! */ 3016 3017 if (curwin != old_curwin) 3018 { 3019 #ifdef CHECK_DOUBLE_CLICK 3020 /* set topline, to be able to check for double click ourselves */ 3021 set_mouse_topline(curwin); 3022 #endif 3023 #ifdef FEAT_TERMINAL 3024 /* when entering a terminal window may change state */ 3025 term_win_entered(); 3026 #endif 3027 } 3028 if (on_status_line) /* In (or below) status line */ 3029 { 3030 /* Don't use start_arrow() if we're in the same window */ 3031 if (curwin == old_curwin) 3032 return IN_STATUS_LINE; 3033 else 3034 return IN_STATUS_LINE | CURSOR_MOVED; 3035 } 3036 if (on_sep_line) /* In (or below) status line */ 3037 { 3038 /* Don't use start_arrow() if we're in the same window */ 3039 if (curwin == old_curwin) 3040 return IN_SEP_LINE; 3041 else 3042 return IN_SEP_LINE | CURSOR_MOVED; 3043 } 3044 3045 curwin->w_cursor.lnum = curwin->w_topline; 3046 #ifdef FEAT_GUI 3047 /* remember topline, needed for double click */ 3048 gui_prev_topline = curwin->w_topline; 3049 # ifdef FEAT_DIFF 3050 gui_prev_topfill = curwin->w_topfill; 3051 # endif 3052 #endif 3053 } 3054 else if (on_status_line && which_button == MOUSE_LEFT) 3055 { 3056 if (dragwin != NULL) 3057 { 3058 /* Drag the status line */ 3059 count = row - dragwin->w_winrow - dragwin->w_height + 1 3060 - on_status_line; 3061 win_drag_status_line(dragwin, count); 3062 did_drag |= count; 3063 } 3064 return IN_STATUS_LINE; /* Cursor didn't move */ 3065 } 3066 else if (on_sep_line && which_button == MOUSE_LEFT) 3067 { 3068 if (dragwin != NULL) 3069 { 3070 /* Drag the separator column */ 3071 count = col - dragwin->w_wincol - dragwin->w_width + 1 3072 - on_sep_line; 3073 win_drag_vsep_line(dragwin, count); 3074 did_drag |= count; 3075 } 3076 return IN_SEP_LINE; /* Cursor didn't move */ 3077 } 3078 #ifdef FEAT_MENU 3079 else if (in_winbar) 3080 { 3081 /* After a click on the window toolbar don't start Visual mode. */ 3082 return IN_OTHER_WIN | MOUSE_WINBAR; 3083 } 3084 #endif 3085 else /* keep_window_focus must be TRUE */ 3086 { 3087 /* before moving the cursor for a left click, stop Visual mode */ 3088 if (flags & MOUSE_MAY_STOP_VIS) 3089 { 3090 end_visual_mode(); 3091 redraw_curbuf_later(INVERTED); /* delete the inversion */ 3092 } 3093 3094 #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD) 3095 /* Continue a modeless selection in another window. */ 3096 if (cmdwin_type != 0 && row < curwin->w_winrow) 3097 return IN_OTHER_WIN; 3098 #endif 3099 3100 row -= W_WINROW(curwin); 3101 col -= curwin->w_wincol; 3102 3103 /* 3104 * When clicking beyond the end of the window, scroll the screen. 3105 * Scroll by however many rows outside the window we are. 3106 */ 3107 if (row < 0) 3108 { 3109 count = 0; 3110 for (first = TRUE; curwin->w_topline > 1; ) 3111 { 3112 #ifdef FEAT_DIFF 3113 if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) 3114 ++count; 3115 else 3116 #endif 3117 count += plines(curwin->w_topline - 1); 3118 if (!first && count > -row) 3119 break; 3120 first = FALSE; 3121 #ifdef FEAT_FOLDING 3122 (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); 3123 #endif 3124 #ifdef FEAT_DIFF 3125 if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) 3126 ++curwin->w_topfill; 3127 else 3128 #endif 3129 { 3130 --curwin->w_topline; 3131 #ifdef FEAT_DIFF 3132 curwin->w_topfill = 0; 3133 #endif 3134 } 3135 } 3136 #ifdef FEAT_DIFF 3137 check_topfill(curwin, FALSE); 3138 #endif 3139 curwin->w_valid &= 3140 ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); 3141 redraw_later(VALID); 3142 row = 0; 3143 } 3144 else if (row >= curwin->w_height) 3145 { 3146 count = 0; 3147 for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; ) 3148 { 3149 #ifdef FEAT_DIFF 3150 if (curwin->w_topfill > 0) 3151 ++count; 3152 else 3153 #endif 3154 count += plines(curwin->w_topline); 3155 if (!first && count > row - curwin->w_height + 1) 3156 break; 3157 first = FALSE; 3158 #ifdef FEAT_FOLDING 3159 if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline) 3160 && curwin->w_topline == curbuf->b_ml.ml_line_count) 3161 break; 3162 #endif 3163 #ifdef FEAT_DIFF 3164 if (curwin->w_topfill > 0) 3165 --curwin->w_topfill; 3166 else 3167 #endif 3168 { 3169 ++curwin->w_topline; 3170 #ifdef FEAT_DIFF 3171 curwin->w_topfill = 3172 diff_check_fill(curwin, curwin->w_topline); 3173 #endif 3174 } 3175 } 3176 #ifdef FEAT_DIFF 3177 check_topfill(curwin, FALSE); 3178 #endif 3179 redraw_later(VALID); 3180 curwin->w_valid &= 3181 ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); 3182 row = curwin->w_height - 1; 3183 } 3184 else if (row == 0) 3185 { 3186 /* When dragging the mouse, while the text has been scrolled up as 3187 * far as it goes, moving the mouse in the top line should scroll 3188 * the text down (done later when recomputing w_topline). */ 3189 if (mouse_dragging > 0 3190 && curwin->w_cursor.lnum 3191 == curwin->w_buffer->b_ml.ml_line_count 3192 && curwin->w_cursor.lnum == curwin->w_topline) 3193 curwin->w_valid &= ~(VALID_TOPLINE); 3194 } 3195 } 3196 3197 #ifdef FEAT_FOLDING 3198 /* Check for position outside of the fold column. */ 3199 if ( 3200 # ifdef FEAT_RIGHTLEFT 3201 curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc : 3202 # endif 3203 col >= curwin->w_p_fdc 3204 # ifdef FEAT_CMDWIN 3205 + (cmdwin_type == 0 ? 0 : 1) 3206 # endif 3207 ) 3208 mouse_char = ' '; 3209 #endif 3210 3211 /* compute the position in the buffer line from the posn on the screen */ 3212 if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum)) 3213 mouse_past_bottom = TRUE; 3214 3215 /* Start Visual mode before coladvance(), for when 'sel' != "old" */ 3216 if ((flags & MOUSE_MAY_VIS) && !VIsual_active) 3217 { 3218 check_visual_highlight(); 3219 VIsual = old_cursor; 3220 VIsual_active = TRUE; 3221 VIsual_reselect = TRUE; 3222 /* if 'selectmode' contains "mouse", start Select mode */ 3223 may_start_select('o'); 3224 setmouse(); 3225 if (p_smd && msg_silent == 0) 3226 redraw_cmdline = TRUE; /* show visual mode later */ 3227 } 3228 3229 curwin->w_curswant = col; 3230 curwin->w_set_curswant = FALSE; /* May still have been TRUE */ 3231 if (coladvance(col) == FAIL) /* Mouse click beyond end of line */ 3232 { 3233 if (inclusive != NULL) 3234 *inclusive = TRUE; 3235 mouse_past_eol = TRUE; 3236 } 3237 else if (inclusive != NULL) 3238 *inclusive = FALSE; 3239 3240 count = IN_BUFFER; 3241 if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum 3242 || curwin->w_cursor.col != old_cursor.col) 3243 count |= CURSOR_MOVED; /* Cursor has moved */ 3244 3245 #ifdef FEAT_FOLDING 3246 if (mouse_char == '+') 3247 count |= MOUSE_FOLD_OPEN; 3248 else if (mouse_char != ' ') 3249 count |= MOUSE_FOLD_CLOSE; 3250 #endif 3251 3252 return count; 3253 } 3254 3255 /* 3256 * Compute the position in the buffer line from the posn on the screen in 3257 * window "win". 3258 * Returns TRUE if the position is below the last line. 3259 */ 3260 int 3261 mouse_comp_pos( 3262 win_T *win, 3263 int *rowp, 3264 int *colp, 3265 linenr_T *lnump) 3266 { 3267 int col = *colp; 3268 int row = *rowp; 3269 linenr_T lnum; 3270 int retval = FALSE; 3271 int off; 3272 int count; 3273 3274 #ifdef FEAT_RIGHTLEFT 3275 if (win->w_p_rl) 3276 col = win->w_width - 1 - col; 3277 #endif 3278 3279 lnum = win->w_topline; 3280 3281 while (row > 0) 3282 { 3283 #ifdef FEAT_DIFF 3284 /* Don't include filler lines in "count" */ 3285 if (win->w_p_diff 3286 # ifdef FEAT_FOLDING 3287 && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL) 3288 # endif 3289 ) 3290 { 3291 if (lnum == win->w_topline) 3292 row -= win->w_topfill; 3293 else 3294 row -= diff_check_fill(win, lnum); 3295 count = plines_win_nofill(win, lnum, TRUE); 3296 } 3297 else 3298 #endif 3299 count = plines_win(win, lnum, TRUE); 3300 if (count > row) 3301 break; /* Position is in this buffer line. */ 3302 #ifdef FEAT_FOLDING 3303 (void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL); 3304 #endif 3305 if (lnum == win->w_buffer->b_ml.ml_line_count) 3306 { 3307 retval = TRUE; 3308 break; /* past end of file */ 3309 } 3310 row -= count; 3311 ++lnum; 3312 } 3313 3314 if (!retval) 3315 { 3316 /* Compute the column without wrapping. */ 3317 off = win_col_off(win) - win_col_off2(win); 3318 if (col < off) 3319 col = off; 3320 col += row * (win->w_width - off); 3321 /* add skip column (for long wrapping line) */ 3322 col += win->w_skipcol; 3323 } 3324 3325 if (!win->w_p_wrap) 3326 col += win->w_leftcol; 3327 3328 /* skip line number and fold column in front of the line */ 3329 col -= win_col_off(win); 3330 if (col < 0) 3331 { 3332 #ifdef FEAT_NETBEANS_INTG 3333 netbeans_gutter_click(lnum); 3334 #endif 3335 col = 0; 3336 } 3337 3338 *colp = col; 3339 *rowp = row; 3340 *lnump = lnum; 3341 return retval; 3342 } 3343 3344 /* 3345 * Find the window at screen position "*rowp" and "*colp". The positions are 3346 * updated to become relative to the top-left of the window. 3347 * Returns NULL when something is wrong. 3348 */ 3349 win_T * 3350 mouse_find_win(int *rowp, int *colp UNUSED) 3351 { 3352 frame_T *fp; 3353 win_T *wp; 3354 3355 fp = topframe; 3356 *rowp -= firstwin->w_winrow; 3357 for (;;) 3358 { 3359 if (fp->fr_layout == FR_LEAF) 3360 break; 3361 if (fp->fr_layout == FR_ROW) 3362 { 3363 for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next) 3364 { 3365 if (*colp < fp->fr_width) 3366 break; 3367 *colp -= fp->fr_width; 3368 } 3369 } 3370 else /* fr_layout == FR_COL */ 3371 { 3372 for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next) 3373 { 3374 if (*rowp < fp->fr_height) 3375 break; 3376 *rowp -= fp->fr_height; 3377 } 3378 } 3379 } 3380 /* When using a timer that closes a window the window might not actually 3381 * exist. */ 3382 FOR_ALL_WINDOWS(wp) 3383 if (wp == fp->fr_win) 3384 { 3385 #ifdef FEAT_MENU 3386 *rowp -= wp->w_winbar_height; 3387 #endif 3388 return wp; 3389 } 3390 return NULL; 3391 } 3392 3393 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \ 3394 || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \ 3395 || defined(FEAT_GUI_PHOTON) || defined(FEAT_TERM_POPUP_MENU) \ 3396 || defined(PROTO) 3397 /* 3398 * Translate window coordinates to buffer position without any side effects 3399 */ 3400 int 3401 get_fpos_of_mouse(pos_T *mpos) 3402 { 3403 win_T *wp; 3404 int row = mouse_row; 3405 int col = mouse_col; 3406 3407 if (row < 0 || col < 0) /* check if it makes sense */ 3408 return IN_UNKNOWN; 3409 3410 /* find the window where the row is in */ 3411 wp = mouse_find_win(&row, &col); 3412 if (wp == NULL) 3413 return IN_UNKNOWN; 3414 /* 3415 * winpos and height may change in win_enter()! 3416 */ 3417 if (row >= wp->w_height) /* In (or below) status line */ 3418 return IN_STATUS_LINE; 3419 if (col >= wp->w_width) /* In vertical separator line */ 3420 return IN_SEP_LINE; 3421 3422 if (wp != curwin) 3423 return IN_UNKNOWN; 3424 3425 /* compute the position in the buffer line from the posn on the screen */ 3426 if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum)) 3427 return IN_STATUS_LINE; /* past bottom */ 3428 3429 mpos->col = vcol2col(wp, mpos->lnum, col); 3430 3431 if (mpos->col > 0) 3432 --mpos->col; 3433 mpos->coladd = 0; 3434 return IN_BUFFER; 3435 } 3436 #endif 3437 3438 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \ 3439 || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \ 3440 || defined(FEAT_GUI_PHOTON) || defined(FEAT_BEVAL) \ 3441 || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO) 3442 /* 3443 * Convert a virtual (screen) column to a character column. 3444 * The first column is one. 3445 */ 3446 int 3447 vcol2col(win_T *wp, linenr_T lnum, int vcol) 3448 { 3449 /* try to advance to the specified column */ 3450 int count = 0; 3451 char_u *ptr; 3452 char_u *line; 3453 3454 line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE); 3455 while (count < vcol && *ptr != NUL) 3456 { 3457 count += win_lbr_chartabsize(wp, line, ptr, count, NULL); 3458 MB_PTR_ADV(ptr); 3459 } 3460 return (int)(ptr - line); 3461 } 3462 #endif 3463 3464 #endif /* FEAT_MOUSE */ 3465 3466 #if defined(FEAT_GUI) || defined(MSWIN) || defined(PROTO) 3467 /* 3468 * Called when focus changed. Used for the GUI or for systems where this can 3469 * be done in the console (Win32). 3470 */ 3471 void 3472 ui_focus_change( 3473 int in_focus) /* TRUE if focus gained. */ 3474 { 3475 static time_t last_time = (time_t)0; 3476 int need_redraw = FALSE; 3477 3478 /* When activated: Check if any file was modified outside of Vim. 3479 * Only do this when not done within the last two seconds (could get 3480 * several events in a row). */ 3481 if (in_focus && last_time + 2 < time(NULL)) 3482 { 3483 need_redraw = check_timestamps( 3484 # ifdef FEAT_GUI 3485 gui.in_use 3486 # else 3487 FALSE 3488 # endif 3489 ); 3490 last_time = time(NULL); 3491 } 3492 3493 /* 3494 * Fire the focus gained/lost autocommand. 3495 */ 3496 need_redraw |= apply_autocmds(in_focus ? EVENT_FOCUSGAINED 3497 : EVENT_FOCUSLOST, NULL, NULL, FALSE, curbuf); 3498 3499 if (need_redraw) 3500 { 3501 /* Something was executed, make sure the cursor is put back where it 3502 * belongs. */ 3503 need_wait_return = FALSE; 3504 3505 if (State & CMDLINE) 3506 redrawcmdline(); 3507 else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE 3508 || State == EXTERNCMD || State == CONFIRM || exmode_active) 3509 repeat_message(); 3510 else if ((State & NORMAL) || (State & INSERT)) 3511 { 3512 if (must_redraw != 0) 3513 update_screen(0); 3514 setcursor(); 3515 } 3516 cursor_on(); /* redrawing may have switched it off */ 3517 out_flush_cursor(FALSE, TRUE); 3518 # ifdef FEAT_GUI 3519 if (gui.in_use) 3520 gui_update_scrollbars(FALSE); 3521 # endif 3522 } 3523 #ifdef FEAT_TITLE 3524 /* File may have been changed from 'readonly' to 'noreadonly' */ 3525 if (need_maketitle) 3526 maketitle(); 3527 #endif 3528 } 3529 #endif 3530 3531 #if defined(HAVE_INPUT_METHOD) || defined(PROTO) 3532 /* 3533 * Save current Input Method status to specified place. 3534 */ 3535 void 3536 im_save_status(long *psave) 3537 { 3538 /* Don't save when 'imdisable' is set or "xic" is NULL, IM is always 3539 * disabled then (but might start later). 3540 * Also don't save when inside a mapping, vgetc_im_active has not been set 3541 * then. 3542 * And don't save when the keys were stuffed (e.g., for a "." command). 3543 * And don't save when the GUI is running but our window doesn't have 3544 * input focus (e.g., when a find dialog is open). */ 3545 if (!p_imdisable && KeyTyped && !KeyStuffed 3546 # ifdef FEAT_XIM 3547 && xic != NULL 3548 # endif 3549 # ifdef FEAT_GUI 3550 && (!gui.in_use || gui.in_focus) 3551 # endif 3552 ) 3553 { 3554 /* Do save when IM is on, or IM is off and saved status is on. */ 3555 if (vgetc_im_active) 3556 *psave = B_IMODE_IM; 3557 else if (*psave == B_IMODE_IM) 3558 *psave = B_IMODE_NONE; 3559 } 3560 } 3561 #endif 3562