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