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