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