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