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