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