Patch 8.2.0443
Problem:    Clipboard code is spread out.
Solution:   Move clipboard code to its own file. (Yegappan Lakshmanan,
            closes #5827)
Files:      Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
            src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
            src/clipboard.c, src/ops.c, src/proto.h, src/proto/clipboard.pro,
            src/proto/ops.pro, src/proto/register.pro, src/proto/ui.pro,
            src/register.c, src/ui.c


*** ../vim-8.2.0442/Filelist    2020-02-26 16:15:31.056387006 +0100
--- Filelist    2020-03-24 21:07:55.522635118 +0100
***************
*** 29,34 ****
--- 29,35 ----
                src/channel.c \
                src/charset.c \
                src/cindent.c \
+               src/clipboard.c \
                src/cmdexpand.c \
                src/cmdhist.c \
                src/crypt.c \
***************
*** 200,205 ****
--- 201,207 ----
                src/proto/channel.pro \
                src/proto/charset.pro \
                src/proto/cindent.pro \
+               src/proto/clipboard.pro \
                src/proto/cmdexpand.pro \
                src/proto/cmdhist.pro \
                src/proto/crypt.pro \
*** ../vim-8.2.0442/src/Make_cyg_ming.mak       2020-02-14 13:21:55.642197064 
+0100
--- src/Make_cyg_ming.mak       2020-03-24 21:07:55.522635118 +0100
***************
*** 710,715 ****
--- 710,716 ----
        $(OUTDIR)/change.o \
        $(OUTDIR)/charset.o \
        $(OUTDIR)/cindent.o \
+       $(OUTDIR)/clipboard.o \
        $(OUTDIR)/cmdexpand.o \
        $(OUTDIR)/cmdhist.o \
        $(OUTDIR)/crypt.o \
*** ../vim-8.2.0442/src/Make_morph.mak  2020-02-14 13:21:55.642197064 +0100
--- src/Make_morph.mak  2020-03-24 21:07:55.526635106 +0100
***************
*** 33,38 ****
--- 33,39 ----
        change.c                                                \
        charset.c                                               \
        cindent.c                                               \
+       clipboard.c                                             \
        cmdexpand.c                                             \
        cmdhist.c                                               \
        crypt.c                                                 \
*** ../vim-8.2.0442/src/Make_mvc.mak    2020-03-19 13:36:52.701511604 +0100
--- src/Make_mvc.mak    2020-03-24 21:07:55.526635106 +0100
***************
*** 730,735 ****
--- 730,736 ----
        $(OUTDIR)\change.obj \
        $(OUTDIR)\charset.obj \
        $(OUTDIR)\cindent.obj \
+       $(OUTDIR)\clipboard.obj \
        $(OUTDIR)\cmdexpand.obj \
        $(OUTDIR)\cmdhist.obj \
        $(OUTDIR)\crypt.obj \
***************
*** 1515,1520 ****
--- 1516,1523 ----
  
  $(OUTDIR)/cindent.obj:        $(OUTDIR) cindent.c  $(INCL)
  
+ $(OUTDIR)/clipboard.obj:      $(OUTDIR) clipboard.c  $(INCL)
+ 
  $(OUTDIR)/cmdexpand.obj:      $(OUTDIR) cmdexpand.c  $(INCL)
  
  $(OUTDIR)/cmdhist.obj:        $(OUTDIR) cmdhist.c  $(INCL)
***************
*** 1862,1867 ****
--- 1865,1871 ----
        proto/change.pro \
        proto/charset.pro \
        proto/cindent.pro \
+       proto/clipboard.pro \
        proto/cmdexpand.pro \
        proto/cmdhist.pro \
        proto/crypt.pro \
*** ../vim-8.2.0442/src/Make_vms.mms    2020-02-14 13:21:55.642197064 +0100
--- src/Make_vms.mms    2020-03-24 21:07:55.526635106 +0100
***************
*** 306,311 ****
--- 306,312 ----
        change.c \
        charset.c \
        cindent.c \
+       clipboard.c \
        cmdexpand.c \
        cmdhist.c \
        crypt.c \
***************
*** 412,417 ****
--- 413,419 ----
        change.obj \
        charset.obj \
        cindent.obj \
+       clipboard.obj \
        cmdexpand.obj \
        cmdhist.obj \
        crypt.obj \
***************
*** 700,705 ****
--- 702,711 ----
   ascii.h keymap.h term.h macros.h structs.h regexp.h \
   gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
   globals.h
+ clipboard.obj : clipboard.c vim.h [.auto]config.h feature.h os_unix.h \
+  ascii.h keymap.h term.h macros.h structs.h regexp.h \
+  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+  globals.h
  cmdexpand.obj : cmdexpand.c vim.h [.auto]config.h feature.h os_unix.h \
   ascii.h keymap.h term.h macros.h structs.h regexp.h \
   gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
*** ../vim-8.2.0442/src/Makefile        2020-02-26 16:15:31.064386980 +0100
--- src/Makefile        2020-03-24 21:07:55.526635106 +0100
***************
*** 1599,1604 ****
--- 1599,1605 ----
        change.c \
        charset.c \
        cindent.c \
+       clipboard.c \
        cmdexpand.c \
        cmdhist.c \
        crypt.c \
***************
*** 1743,1748 ****
--- 1744,1750 ----
        objects/blob.o \
        objects/blowfish.o \
        objects/cindent.o \
+       objects/clipboard.o \
        objects/cmdexpand.o \
        objects/cmdhist.o \
        objects/crypt.o \
***************
*** 1903,1908 ****
--- 1905,1911 ----
        channel.pro \
        charset.pro \
        cindent.pro \
+       clipboard.pro \
        cmdexpand.pro \
        cmdhist.pro \
        crypt.pro \
***************
*** 3117,3122 ****
--- 3120,3128 ----
  objects/cindent.o: cindent.c
        $(CCC) -o $@ cindent.c
  
+ objects/clipboard.o: clipboard.c
+       $(CCC) -o $@ clipboard.c
+ 
  objects/cmdexpand.o: cmdexpand.c
        $(CCC) -o $@ cmdexpand.c
  
***************
*** 3734,3739 ****
--- 3740,3749 ----
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
   proto.h globals.h
+ objects/clipboard.o: clipboard.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
+  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+  proto.h globals.h
  objects/cmdexpand.o: cmdexpand.c vim.h protodef.h auto/config.h feature.h \
   os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
*** ../vim-8.2.0442/src/README.md       2020-02-14 13:21:55.642197064 +0100
--- src/README.md       2020-03-24 21:07:55.526635106 +0100
***************
*** 30,35 ****
--- 30,36 ----
  bufwrite.c    | writing a buffer to file
  change.c      | handling changes to text
  cindent.c     | C and Lisp indentation
+ clipboard.c   | handling the clipboard
  cmdexpand.c   | command-line completion
  cmdhist.c     | command-line history
  debugger.c    | vim script debugger
*** ../vim-8.2.0442/src/clipboard.c     2020-03-24 21:40:46.931709710 +0100
--- src/clipboard.c     2020-03-24 21:07:55.526635106 +0100
***************
*** 0 ****
--- 1,2212 ----
+ /* vi:set ts=8 sts=4 sw=4 noet:
+  *
+  * VIM - Vi IMproved  by Bram Moolenaar
+  *
+  * Do ":help uganda"  in Vim to read copying and usage conditions.
+  * Do ":help credits" in Vim to see a list of people who contributed.
+  * See README.txt for an overview of the Vim source code.
+  */
+ 
+ /*
+  * clipboard.c: Functions to handle the clipboard
+  */
+ 
+ #include "vim.h"
+ 
+ #ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
+ # define WIN32_LEAN_AND_MEAN
+ # include <windows.h>
+ # include "winclip.pro"
+ #endif
+ 
+ // Functions for copying and pasting text between applications.
+ // This is always included in a GUI version, but may also be included when the
+ // clipboard and mouse is available to a terminal version such as xterm.
+ // Note: there are some more functions in ops.c that handle selection stuff.
+ //
+ // Also note that the majority of functions here deal with the X 'primary'
+ // (visible - for Visual mode use) selection, and only that. There are no
+ // versions of these for the 'clipboard' selection, as Visual mode has no use
+ // for them.
+ 
+ #if defined(FEAT_CLIPBOARD) || defined(PROTO)
+ 
+ /*
+  * Selection stuff using Visual mode, for cutting and pasting text to other
+  * windows.
+  */
+ 
+ /*
+  * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
+  * is included, but the clipboard can not be used, or TRUE if the clipboard 
can
+  * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
+  * the GUI starts.
+  */
+     void
+ clip_init(int can_use)
+ {
+     Clipboard_T *cb;
+ 
+     cb = &clip_star;
+     for (;;)
+     {
+       cb->available  = can_use;
+       cb->owned      = FALSE;
+       cb->start.lnum = 0;
+       cb->start.col  = 0;
+       cb->end.lnum   = 0;
+       cb->end.col    = 0;
+       cb->state      = SELECT_CLEARED;
+ 
+       if (cb == &clip_plus)
+           break;
+       cb = &clip_plus;
+     }
+ }
+ 
+ /*
+  * Check whether the VIsual area has changed, and if so try to become the 
owner
+  * of the selection, and free any old converted selection we may still have
+  * lying around.  If the VIsual mode has ended, make a copy of what was
+  * selected so we can still give it to others.        Will probably have to 
make sure
+  * this is called whenever VIsual mode is ended.
+  */
+     void
+ clip_update_selection(Clipboard_T *clip)
+ {
+     pos_T         start, end;
+ 
+     // If visual mode is only due to a redo command ("."), then ignore it
+     if (!redo_VIsual_busy && VIsual_active && (State & NORMAL))
+     {
+       if (LT_POS(VIsual, curwin->w_cursor))
+       {
+           start = VIsual;
+           end = curwin->w_cursor;
+           if (has_mbyte)
+               end.col += (*mb_ptr2len)(ml_get_cursor()) - 1;
+       }
+       else
+       {
+           start = curwin->w_cursor;
+           end = VIsual;
+       }
+       if (!EQUAL_POS(clip->start, start)
+               || !EQUAL_POS(clip->end, end)
+               || clip->vmode != VIsual_mode)
+       {
+           clip_clear_selection(clip);
+           clip->start = start;
+           clip->end = end;
+           clip->vmode = VIsual_mode;
+           clip_free_selection(clip);
+           clip_own_selection(clip);
+           clip_gen_set_selection(clip);
+       }
+     }
+ }
+ 
+     static int
+ clip_gen_own_selection(Clipboard_T *cbd)
+ {
+ #ifdef FEAT_XCLIPBOARD
+ # ifdef FEAT_GUI
+     if (gui.in_use)
+       return clip_mch_own_selection(cbd);
+     else
+ # endif
+       return clip_xterm_own_selection(cbd);
+ #else
+     return clip_mch_own_selection(cbd);
+ #endif
+ }
+ 
+     void
+ clip_own_selection(Clipboard_T *cbd)
+ {
+     /*
+      * Also want to check somehow that we are reading from the keyboard rather
+      * than a mapping etc.
+      */
+ #ifdef FEAT_X11
+     // Always own the selection, we might have lost it without being
+     // notified, e.g. during a ":sh" command.
+     if (cbd->available)
+     {
+       int was_owned = cbd->owned;
+ 
+       cbd->owned = (clip_gen_own_selection(cbd) == OK);
+       if (!was_owned && (cbd == &clip_star || cbd == &clip_plus))
+       {
+           // May have to show a different kind of highlighting for the
+           // selected area.  There is no specific redraw command for this,
+           // just redraw all windows on the current buffer.
+           if (cbd->owned
+                   && (get_real_state() == VISUAL
+                                           || get_real_state() == SELECTMODE)
+                   && (cbd == &clip_star ? clip_isautosel_star()
+                                                     : clip_isautosel_plus())
+                   && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
+               redraw_curbuf_later(INVERTED_ALL);
+       }
+     }
+ #else
+     // Only own the clipboard when we didn't own it yet.
+     if (!cbd->owned && cbd->available)
+       cbd->owned = (clip_gen_own_selection(cbd) == OK);
+ #endif
+ }
+ 
+     static void
+ clip_gen_lose_selection(Clipboard_T *cbd)
+ {
+ #ifdef FEAT_XCLIPBOARD
+ # ifdef FEAT_GUI
+     if (gui.in_use)
+       clip_mch_lose_selection(cbd);
+     else
+ # endif
+       clip_xterm_lose_selection(cbd);
+ #else
+     clip_mch_lose_selection(cbd);
+ #endif
+ }
+ 
+     void
+ clip_lose_selection(Clipboard_T *cbd)
+ {
+ #ifdef FEAT_X11
+     int           was_owned = cbd->owned;
+ #endif
+     int     visual_selection = FALSE;
+ 
+     if (cbd == &clip_star || cbd == &clip_plus)
+       visual_selection = TRUE;
+ 
+     clip_free_selection(cbd);
+     cbd->owned = FALSE;
+     if (visual_selection)
+       clip_clear_selection(cbd);
+     clip_gen_lose_selection(cbd);
+ #ifdef FEAT_X11
+     if (visual_selection)
+     {
+       // May have to show a different kind of highlighting for the selected
+       // area.  There is no specific redraw command for this, just redraw all
+       // windows on the current buffer.
+       if (was_owned
+               && (get_real_state() == VISUAL
+                                           || get_real_state() == SELECTMODE)
+               && (cbd == &clip_star ?
+                               clip_isautosel_star() : clip_isautosel_plus())
+               && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
+       {
+           update_curbuf(INVERTED_ALL);
+           setcursor();
+           cursor_on();
+           out_flush_cursor(TRUE, FALSE);
+       }
+     }
+ #endif
+ }
+ 
+     static void
+ clip_copy_selection(Clipboard_T *clip)
+ {
+     if (VIsual_active && (State & NORMAL) && clip->available)
+     {
+       clip_update_selection(clip);
+       clip_free_selection(clip);
+       clip_own_selection(clip);
+       if (clip->owned)
+           clip_get_selection(clip);
+       clip_gen_set_selection(clip);
+     }
+ }
+ 
+ /*
+  * Save and restore clip_unnamed before doing possibly many changes. This
+  * prevents accessing the clipboard very often which might slow down Vim
+  * considerably.
+  */
+ static int global_change_count = 0; // if set, inside a start_global_changes
+ static int clipboard_needs_update = FALSE; // clipboard needs to be updated
+ static int clip_did_set_selection = TRUE;
+ 
+ /*
+  * Save clip_unnamed and reset it.
+  */
+     void
+ start_global_changes(void)
+ {
+     if (++global_change_count > 1)
+       return;
+     clip_unnamed_saved = clip_unnamed;
+     clipboard_needs_update = FALSE;
+ 
+     if (clip_did_set_selection)
+     {
+       clip_unnamed = 0;
+       clip_did_set_selection = FALSE;
+     }
+ }
+ 
+ /*
+  * Return TRUE if setting the clipboard was postponed, it already contains the
+  * right text.
+  */
+     static int
+ is_clipboard_needs_update()
+ {
+     return clipboard_needs_update;
+ }
+ 
+ /*
+  * Restore clip_unnamed and set the selection when needed.
+  */
+     void
+ end_global_changes(void)
+ {
+     if (--global_change_count > 0)
+       // recursive
+       return;
+     if (!clip_did_set_selection)
+     {
+       clip_did_set_selection = TRUE;
+       clip_unnamed = clip_unnamed_saved;
+       clip_unnamed_saved = 0;
+       if (clipboard_needs_update)
+       {
+           // only store something in the clipboard,
+           // if we have yanked anything to it
+           if (clip_unnamed & CLIP_UNNAMED)
+           {
+               clip_own_selection(&clip_star);
+               clip_gen_set_selection(&clip_star);
+           }
+           if (clip_unnamed & CLIP_UNNAMED_PLUS)
+           {
+               clip_own_selection(&clip_plus);
+               clip_gen_set_selection(&clip_plus);
+           }
+       }
+     }
+     clipboard_needs_update = FALSE;
+ }
+ 
+ /*
+  * Called when Visual mode is ended: update the selection.
+  */
+     void
+ clip_auto_select(void)
+ {
+     if (clip_isautosel_star())
+       clip_copy_selection(&clip_star);
+     if (clip_isautosel_plus())
+       clip_copy_selection(&clip_plus);
+ }
+ 
+ /*
+  * Return TRUE if automatic selection of Visual area is desired for the *
+  * register.
+  */
+     int
+ clip_isautosel_star(void)
+ {
+     return (
+ #ifdef FEAT_GUI
+           gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) :
+ #endif
+           clip_autoselect_star);
+ }
+ 
+ /*
+  * Return TRUE if automatic selection of Visual area is desired for the +
+  * register.
+  */
+     int
+ clip_isautosel_plus(void)
+ {
+     return (
+ #ifdef FEAT_GUI
+           gui.in_use ? (vim_strchr(p_go, GO_ASELPLUS) != NULL) :
+ #endif
+           clip_autoselect_plus);
+ }
+ 
+ 
+ /*
+  * Stuff for general mouse selection, without using Visual mode.
+  */
+ 
+ /*
+  * Compare two screen positions ala strcmp()
+  */
+     static int
+ clip_compare_pos(
+     int               row1,
+     int               col1,
+     int               row2,
+     int               col2)
+ {
+     if (row1 > row2) return(1);
+     if (row1 < row2) return(-1);
+     if (col1 > col2) return(1);
+     if (col1 < col2) return(-1);
+     return(0);
+ }
+ 
+ // "how" flags for clip_invert_area()
+ #define CLIP_CLEAR    1
+ #define CLIP_SET      2
+ #define CLIP_TOGGLE   3
+ 
+ /*
+  * Invert or un-invert a rectangle of the screen.
+  * "invert" is true if the result is inverted.
+  */
+     static void
+ clip_invert_rectangle(
+       Clipboard_T     *cbd UNUSED,
+       int             row_arg,
+       int             col_arg,
+       int             height_arg,
+       int             width_arg,
+       int             invert)
+ {
+     int               row = row_arg;
+     int               col = col_arg;
+     int               height = height_arg;
+     int               width = width_arg;
+ 
+ #ifdef FEAT_PROP_POPUP
+     // this goes on top of all popup windows
+     screen_zindex = CLIP_ZINDEX;
+ 
+     if (col < cbd->min_col)
+     {
+       width -= cbd->min_col - col;
+       col = cbd->min_col;
+     }
+     if (width > cbd->max_col - col)
+       width = cbd->max_col - col;
+     if (row < cbd->min_row)
+     {
+       height -= cbd->min_row - row;
+       row = cbd->min_row;
+     }
+     if (height > cbd->max_row - row + 1)
+       height = cbd->max_row - row + 1;
+ #endif
+ #ifdef FEAT_GUI
+     if (gui.in_use)
+       gui_mch_invert_rectangle(row, col, height, width);
+     else
+ #endif
+       screen_draw_rectangle(row, col, height, width, invert);
+ #ifdef FEAT_PROP_POPUP
+     screen_zindex = 0;
+ #endif
+ }
+ 
+ /*
+  * Invert a region of the display between a starting and ending row and column
+  * Values for "how":
+  * CLIP_CLEAR:  undo inversion
+  * CLIP_SET:    set inversion
+  * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise.
+  * 0: invert (GUI only).
+  */
+     static void
+ clip_invert_area(
+       Clipboard_T     *cbd,
+       int             row1,
+       int             col1,
+       int             row2,
+       int             col2,
+       int             how)
+ {
+     int               invert = FALSE;
+     int               max_col;
+ 
+ #ifdef FEAT_PROP_POPUP
+     max_col = cbd->max_col - 1;
+ #else
+     max_col = Columns - 1;
+ #endif
+ 
+     if (how == CLIP_SET)
+       invert = TRUE;
+ 
+     // Swap the from and to positions so the from is always before
+     if (clip_compare_pos(row1, col1, row2, col2) > 0)
+     {
+       int tmp_row, tmp_col;
+ 
+       tmp_row = row1;
+       tmp_col = col1;
+       row1    = row2;
+       col1    = col2;
+       row2    = tmp_row;
+       col2    = tmp_col;
+     }
+     else if (how == CLIP_TOGGLE)
+       invert = TRUE;
+ 
+     // If all on the same line, do it the easy way
+     if (row1 == row2)
+     {
+       clip_invert_rectangle(cbd, row1, col1, 1, col2 - col1, invert);
+     }
+     else
+     {
+       // Handle a piece of the first line
+       if (col1 > 0)
+       {
+           clip_invert_rectangle(cbd, row1, col1, 1,
+                                                 (int)Columns - col1, invert);
+           row1++;
+       }
+ 
+       // Handle a piece of the last line
+       if (col2 < max_col)
+       {
+           clip_invert_rectangle(cbd, row2, 0, 1, col2, invert);
+           row2--;
+       }
+ 
+       // Handle the rectangle that's left
+       if (row2 >= row1)
+           clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1,
+                                                        (int)Columns, invert);
+     }
+ }
+ 
+ /*
+  * Start, continue or end a modeless selection.  Used when editing the
+  * command-line, in the cmdline window and when the mouse is in a popup 
window.
+  */
+     void
+ clip_modeless(int button, int is_click, int is_drag)
+ {
+     int               repeat;
+ 
+     repeat = ((clip_star.mode == SELECT_MODE_CHAR
+               || clip_star.mode == SELECT_MODE_LINE)
+                                             && (mod_mask & MOD_MASK_2CLICK))
+           || (clip_star.mode == SELECT_MODE_WORD
+                                            && (mod_mask & MOD_MASK_3CLICK));
+     if (is_click && button == MOUSE_RIGHT)
+     {
+       // Right mouse button: If there was no selection, start one.
+       // Otherwise extend the existing selection.
+       if (clip_star.state == SELECT_CLEARED)
+           clip_start_selection(mouse_col, mouse_row, FALSE);
+       clip_process_selection(button, mouse_col, mouse_row, repeat);
+     }
+     else if (is_click)
+       clip_start_selection(mouse_col, mouse_row, repeat);
+     else if (is_drag)
+     {
+       // Don't try extending a selection if there isn't one.  Happens when
+       // button-down is in the cmdline and them moving mouse upwards.
+       if (clip_star.state != SELECT_CLEARED)
+           clip_process_selection(button, mouse_col, mouse_row, repeat);
+     }
+     else // release
+       clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE);
+ }
+ 
+ /*
+  * Update the currently selected region by adding and/or subtracting from the
+  * beginning or end and inverting the changed area(s).
+  */
+     static void
+ clip_update_modeless_selection(
+     Clipboard_T    *cb,
+     int                   row1,
+     int                   col1,
+     int                   row2,
+     int                   col2)
+ {
+     // See if we changed at the beginning of the selection
+     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
+     {
+       clip_invert_area(cb, row1, col1, (int)cb->start.lnum, cb->start.col,
+                                                                CLIP_TOGGLE);
+       cb->start.lnum = row1;
+       cb->start.col  = col1;
+     }
+ 
+     // See if we changed at the end of the selection
+     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
+     {
+       clip_invert_area(cb, (int)cb->end.lnum, cb->end.col, row2, col2,
+                                                                CLIP_TOGGLE);
+       cb->end.lnum = row2;
+       cb->end.col  = col2;
+     }
+ }
+ 
+ /*
+  * Find the starting and ending positions of the word at the given row and
+  * column.  Only white-separated words are recognized here.
+  */
+ #define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c))
+ 
+     static void
+ clip_get_word_boundaries(Clipboard_T *cb, int row, int col)
+ {
+     int               start_class;
+     int               temp_col;
+     char_u    *p;
+     int               mboff;
+ 
+     if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL)
+       return;
+ 
+     p = ScreenLines + LineOffset[row];
+     // Correct for starting in the right halve of a double-wide char
+     if (enc_dbcs != 0)
+       col -= dbcs_screen_head_off(p, p + col);
+     else if (enc_utf8 && p[col] == 0)
+       --col;
+     start_class = CHAR_CLASS(p[col]);
+ 
+     temp_col = col;
+     for ( ; temp_col > 0; temp_col--)
+       if (enc_dbcs != 0
+                  && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0)
+           temp_col -= mboff;
+       else if (CHAR_CLASS(p[temp_col - 1]) != start_class
+               && !(enc_utf8 && p[temp_col - 1] == 0))
+           break;
+     cb->word_start_col = temp_col;
+ 
+     temp_col = col;
+     for ( ; temp_col < screen_Columns; temp_col++)
+       if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2)
+           ++temp_col;
+       else if (CHAR_CLASS(p[temp_col]) != start_class
+               && !(enc_utf8 && p[temp_col] == 0))
+           break;
+     cb->word_end_col = temp_col;
+ }
+ 
+ /*
+  * Find the column position for the last non-whitespace character on the given
+  * line at or before start_col.
+  */
+     static int
+ clip_get_line_end(Clipboard_T *cbd UNUSED, int row)
+ {
+     int           i;
+ 
+     if (row >= screen_Rows || ScreenLines == NULL)
+       return 0;
+     for (i =
+ #ifdef FEAT_PROP_POPUP
+           cbd->max_col;
+ #else
+           screen_Columns;
+ #endif
+                           i > 0; i--)
+       if (ScreenLines[LineOffset[row] + i - 1] != ' ')
+           break;
+     return i;
+ }
+ 
+ /*
+  * Start the selection
+  */
+     void
+ clip_start_selection(int col, int row, int repeated_click)
+ {
+     Clipboard_T       *cb = &clip_star;
+ #ifdef FEAT_PROP_POPUP
+     win_T     *wp;
+     int               row_cp = row;
+     int               col_cp = col;
+ 
+     wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP);
+     if (wp != NULL && WIN_IS_POPUP(wp)
+                                 && popup_is_in_scrollbar(wp, row_cp, col_cp))
+       // click or double click in scrollbar does not start a selection
+       return;
+ #endif
+ 
+     if (cb->state == SELECT_DONE)
+       clip_clear_selection(cb);
+ 
+     row = check_row(row);
+     col = check_col(col);
+     col = mb_fix_col(col, row);
+ 
+     cb->start.lnum  = row;
+     cb->start.col   = col;
+     cb->end       = cb->start;
+     cb->origin_row  = (short_u)cb->start.lnum;
+     cb->state     = SELECT_IN_PROGRESS;
+ #ifdef FEAT_PROP_POPUP
+     if (wp != NULL && WIN_IS_POPUP(wp))
+     {
+       // Click in a popup window restricts selection to that window,
+       // excluding the border.
+       cb->min_col = wp->w_wincol + wp->w_popup_border[3];
+       cb->max_col = wp->w_wincol + popup_width(wp)
+                                - wp->w_popup_border[1] - wp->w_has_scrollbar;
+       if (cb->max_col > screen_Columns)
+           cb->max_col = screen_Columns;
+       cb->min_row = wp->w_winrow + wp->w_popup_border[0];
+       cb->max_row = wp->w_winrow + popup_height(wp) - 1
+                                                  - wp->w_popup_border[2];
+     }
+     else
+     {
+       cb->min_col = 0;
+       cb->max_col = screen_Columns;
+       cb->min_row = 0;
+       cb->max_row = screen_Rows;
+     }
+ #endif
+ 
+     if (repeated_click)
+     {
+       if (++cb->mode > SELECT_MODE_LINE)
+           cb->mode = SELECT_MODE_CHAR;
+     }
+     else
+       cb->mode = SELECT_MODE_CHAR;
+ 
+ #ifdef FEAT_GUI
+     // clear the cursor until the selection is made
+     if (gui.in_use)
+       gui_undraw_cursor();
+ #endif
+ 
+     switch (cb->mode)
+     {
+       case SELECT_MODE_CHAR:
+           cb->origin_start_col = cb->start.col;
+           cb->word_end_col = clip_get_line_end(cb, (int)cb->start.lnum);
+           break;
+ 
+       case SELECT_MODE_WORD:
+           clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
+           cb->origin_start_col = cb->word_start_col;
+           cb->origin_end_col   = cb->word_end_col;
+ 
+           clip_invert_area(cb, (int)cb->start.lnum, cb->word_start_col,
+                           (int)cb->end.lnum, cb->word_end_col, CLIP_SET);
+           cb->start.col = cb->word_start_col;
+           cb->end.col   = cb->word_end_col;
+           break;
+ 
+       case SELECT_MODE_LINE:
+           clip_invert_area(cb, (int)cb->start.lnum, 0, (int)cb->start.lnum,
+                           (int)Columns, CLIP_SET);
+           cb->start.col = 0;
+           cb->end.col   = Columns;
+           break;
+     }
+ 
+     cb->prev = cb->start;
+ 
+ #ifdef DEBUG_SELECTION
+     printf("Selection started at (%ld,%d)\n", cb->start.lnum, cb->start.col);
+ #endif
+ }
+ 
+ /*
+  * Continue processing the selection
+  */
+     void
+ clip_process_selection(
+     int               button,
+     int               col,
+     int               row,
+     int_u     repeated_click)
+ {
+     Clipboard_T       *cb = &clip_star;
+     int               diff;
+     int               slen = 1;       // cursor shape width
+ 
+     if (button == MOUSE_RELEASE)
+     {
+       if (cb->state != SELECT_IN_PROGRESS)
+           return;
+ 
+       // Check to make sure we have something selected
+       if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
+       {
+ #ifdef FEAT_GUI
+           if (gui.in_use)
+               gui_update_cursor(FALSE, FALSE);
+ #endif
+           cb->state = SELECT_CLEARED;
+           return;
+       }
+ 
+ #ifdef DEBUG_SELECTION
+       printf("Selection ended: (%ld,%d) to (%ld,%d)\n", cb->start.lnum,
+               cb->start.col, cb->end.lnum, cb->end.col);
+ #endif
+       if (clip_isautosel_star()
+               || (
+ #ifdef FEAT_GUI
+                   gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) :
+ #endif
+                   clip_autoselectml))
+           clip_copy_modeless_selection(FALSE);
+ #ifdef FEAT_GUI
+       if (gui.in_use)
+           gui_update_cursor(FALSE, FALSE);
+ #endif
+ 
+       cb->state = SELECT_DONE;
+       return;
+     }
+ 
+     row = check_row(row);
+     col = check_col(col);
+     col = mb_fix_col(col, row);
+ 
+     if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click)
+       return;
+ 
+     /*
+      * When extending the selection with the right mouse button, swap the
+      * start and end if the position is before half the selection
+      */
+     if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
+     {
+       /*
+        * If the click is before the start, or the click is inside the
+        * selection and the start is the closest side, set the origin to the
+        * end of the selection.
+        */
+       if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
+               || (clip_compare_pos(row, col,
+                                          (int)cb->end.lnum, cb->end.col) < 0
+                   && (((cb->start.lnum == cb->end.lnum
+                           && cb->end.col - col > col - cb->start.col))
+                       || ((diff = (cb->end.lnum - row) -
+                                                  (row - cb->start.lnum)) > 0
+                           || (diff == 0 && col < (int)(cb->start.col +
+                                                        cb->end.col) / 2)))))
+       {
+           cb->origin_row = (short_u)cb->end.lnum;
+           cb->origin_start_col = cb->end.col - 1;
+           cb->origin_end_col = cb->end.col;
+       }
+       else
+       {
+           cb->origin_row = (short_u)cb->start.lnum;
+           cb->origin_start_col = cb->start.col;
+           cb->origin_end_col = cb->start.col;
+       }
+       if (cb->mode == SELECT_MODE_WORD && !repeated_click)
+           cb->mode = SELECT_MODE_CHAR;
+     }
+ 
+     // set state, for when using the right mouse button
+     cb->state = SELECT_IN_PROGRESS;
+ 
+ #ifdef DEBUG_SELECTION
+     printf("Selection extending to (%d,%d)\n", row, col);
+ #endif
+ 
+     if (repeated_click && ++cb->mode > SELECT_MODE_LINE)
+       cb->mode = SELECT_MODE_CHAR;
+ 
+     switch (cb->mode)
+     {
+       case SELECT_MODE_CHAR:
+           // If we're on a different line, find where the line ends
+           if (row != cb->prev.lnum)
+               cb->word_end_col = clip_get_line_end(cb, row);
+ 
+           // See if we are before or after the origin of the selection
+           if (clip_compare_pos(row, col, cb->origin_row,
+                                                  cb->origin_start_col) >= 0)
+           {
+               if (col >= (int)cb->word_end_col)
+                   clip_update_modeless_selection(cb, cb->origin_row,
+                           cb->origin_start_col, row, (int)Columns);
+               else
+               {
+                   if (has_mbyte && mb_lefthalve(row, col))
+                       slen = 2;
+                   clip_update_modeless_selection(cb, cb->origin_row,
+                           cb->origin_start_col, row, col + slen);
+               }
+           }
+           else
+           {
+               if (has_mbyte
+                       && mb_lefthalve(cb->origin_row, cb->origin_start_col))
+                   slen = 2;
+               if (col >= (int)cb->word_end_col)
+                   clip_update_modeless_selection(cb, row, cb->word_end_col,
+                           cb->origin_row, cb->origin_start_col + slen);
+               else
+                   clip_update_modeless_selection(cb, row, col,
+                           cb->origin_row, cb->origin_start_col + slen);
+           }
+           break;
+ 
+       case SELECT_MODE_WORD:
+           // If we are still within the same word, do nothing
+           if (row == cb->prev.lnum && col >= (int)cb->word_start_col
+                   && col < (int)cb->word_end_col && !repeated_click)
+               return;
+ 
+           // Get new word boundaries
+           clip_get_word_boundaries(cb, row, col);
+ 
+           // Handle being after the origin point of selection
+           if (clip_compare_pos(row, col, cb->origin_row,
+                   cb->origin_start_col) >= 0)
+               clip_update_modeless_selection(cb, cb->origin_row,
+                       cb->origin_start_col, row, cb->word_end_col);
+           else
+               clip_update_modeless_selection(cb, row, cb->word_start_col,
+                       cb->origin_row, cb->origin_end_col);
+           break;
+ 
+       case SELECT_MODE_LINE:
+           if (row == cb->prev.lnum && !repeated_click)
+               return;
+ 
+           if (clip_compare_pos(row, col, cb->origin_row,
+                   cb->origin_start_col) >= 0)
+               clip_update_modeless_selection(cb, cb->origin_row, 0, row,
+                       (int)Columns);
+           else
+               clip_update_modeless_selection(cb, row, 0, cb->origin_row,
+                       (int)Columns);
+           break;
+     }
+ 
+     cb->prev.lnum = row;
+     cb->prev.col  = col;
+ 
+ #ifdef DEBUG_SELECTION
+       printf("Selection is: (%ld,%d) to (%ld,%d)\n", cb->start.lnum,
+               cb->start.col, cb->end.lnum, cb->end.col);
+ #endif
+ }
+ 
+ # if defined(FEAT_GUI) || defined(PROTO)
+ /*
+  * Redraw part of the selection if character at "row,col" is inside of it.
+  * Only used for the GUI.
+  */
+     void
+ clip_may_redraw_selection(int row, int col, int len)
+ {
+     int               start = col;
+     int               end = col + len;
+ 
+     if (clip_star.state != SELECT_CLEARED
+           && row >= clip_star.start.lnum
+           && row <= clip_star.end.lnum)
+     {
+       if (row == clip_star.start.lnum && start < (int)clip_star.start.col)
+           start = clip_star.start.col;
+       if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
+           end = clip_star.end.col;
+       if (end > start)
+           clip_invert_area(&clip_star, row, start, row, end, 0);
+     }
+ }
+ # endif
+ 
+ /*
+  * Called from outside to clear selected region from the display
+  */
+     void
+ clip_clear_selection(Clipboard_T *cbd)
+ {
+ 
+     if (cbd->state == SELECT_CLEARED)
+       return;
+ 
+     clip_invert_area(cbd, (int)cbd->start.lnum, cbd->start.col,
+                                (int)cbd->end.lnum, cbd->end.col, CLIP_CLEAR);
+     cbd->state = SELECT_CLEARED;
+ }
+ 
+ /*
+  * Clear the selection if any lines from "row1" to "row2" are inside of it.
+  */
+     void
+ clip_may_clear_selection(int row1, int row2)
+ {
+     if (clip_star.state == SELECT_DONE
+           && row2 >= clip_star.start.lnum
+           && row1 <= clip_star.end.lnum)
+       clip_clear_selection(&clip_star);
+ }
+ 
+ /*
+  * Called before the screen is scrolled up or down.  Adjusts the line numbers
+  * of the selection.  Call with big number when clearing the screen.
+  */
+     void
+ clip_scroll_selection(
+     int           rows)               // negative for scroll down
+ {
+     int           lnum;
+ 
+     if (clip_star.state == SELECT_CLEARED)
+       return;
+ 
+     lnum = clip_star.start.lnum - rows;
+     if (lnum <= 0)
+       clip_star.start.lnum = 0;
+     else if (lnum >= screen_Rows)     // scrolled off of the screen
+       clip_star.state = SELECT_CLEARED;
+     else
+       clip_star.start.lnum = lnum;
+ 
+     lnum = clip_star.end.lnum - rows;
+     if (lnum < 0)                     // scrolled off of the screen
+       clip_star.state = SELECT_CLEARED;
+     else if (lnum >= screen_Rows)
+       clip_star.end.lnum = screen_Rows - 1;
+     else
+       clip_star.end.lnum = lnum;
+ }
+ 
+ /*
+  * Copy the currently selected area into the '*' register so it will be
+  * available for pasting.
+  * When "both" is TRUE also copy to the '+' register.
+  */
+     void
+ clip_copy_modeless_selection(int both UNUSED)
+ {
+     char_u    *buffer;
+     char_u    *bufp;
+     int               row;
+     int               start_col;
+     int               end_col;
+     int               line_end_col;
+     int               add_newline_flag = FALSE;
+     int               len;
+     char_u    *p;
+     int               row1 = clip_star.start.lnum;
+     int               col1 = clip_star.start.col;
+     int               row2 = clip_star.end.lnum;
+     int               col2 = clip_star.end.col;
+ 
+     // Can't use ScreenLines unless initialized
+     if (ScreenLines == NULL)
+       return;
+ 
+     /*
+      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
+      */
+     if (row1 > row2)
+     {
+       row = row1; row1 = row2; row2 = row;
+       row = col1; col1 = col2; col2 = row;
+     }
+     else if (row1 == row2 && col1 > col2)
+     {
+       row = col1; col1 = col2; col2 = row;
+     }
+ #ifdef FEAT_PROP_POPUP
+     if (col1 < clip_star.min_col)
+       col1 = clip_star.min_col;
+     if (col2 > clip_star.max_col)
+       col2 = clip_star.max_col;
+     if (row1 > clip_star.max_row || row2 < clip_star.min_row)
+       return;
+     if (row1 < clip_star.min_row)
+       row1 = clip_star.min_row;
+     if (row2 > clip_star.max_row)
+       row2 = clip_star.max_row;
+ #endif
+     // correct starting point for being on right halve of double-wide char
+     p = ScreenLines + LineOffset[row1];
+     if (enc_dbcs != 0)
+       col1 -= (*mb_head_off)(p, p + col1);
+     else if (enc_utf8 && p[col1] == 0)
+       --col1;
+ 
+     // Create a temporary buffer for storing the text
+     len = (row2 - row1 + 1) * Columns + 1;
+     if (enc_dbcs != 0)
+       len *= 2;       // max. 2 bytes per display cell
+     else if (enc_utf8)
+       len *= MB_MAXBYTES;
+     buffer = alloc(len);
+     if (buffer == NULL)           // out of memory
+       return;
+ 
+     // Process each row in the selection
+     for (bufp = buffer, row = row1; row <= row2; row++)
+     {
+       if (row == row1)
+           start_col = col1;
+       else
+ #ifdef FEAT_PROP_POPUP
+           start_col = clip_star.min_col;
+ #else
+           start_col = 0;
+ #endif
+ 
+       if (row == row2)
+           end_col = col2;
+       else
+ #ifdef FEAT_PROP_POPUP
+           end_col = clip_star.max_col;
+ #else
+           end_col = Columns;
+ #endif
+ 
+       line_end_col = clip_get_line_end(&clip_star, row);
+ 
+       // See if we need to nuke some trailing whitespace
+       if (end_col >=
+ #ifdef FEAT_PROP_POPUP
+               clip_star.max_col
+ #else
+               Columns
+ #endif
+                   && (row < row2 || end_col > line_end_col))
+       {
+           // Get rid of trailing whitespace
+           end_col = line_end_col;
+           if (end_col < start_col)
+               end_col = start_col;
+ 
+           // If the last line extended to the end, add an extra newline
+           if (row == row2)
+               add_newline_flag = TRUE;
+       }
+ 
+       // If after the first row, we need to always add a newline
+       if (row > row1 && !LineWraps[row - 1])
+           *bufp++ = NL;
+ 
+       // Safetey check for in case resizing went wrong
+       if (row < screen_Rows && end_col <= screen_Columns)
+       {
+           if (enc_dbcs != 0)
+           {
+               int     i;
+ 
+               p = ScreenLines + LineOffset[row];
+               for (i = start_col; i < end_col; ++i)
+                   if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e)
+                   {
+                       // single-width double-byte char
+                       *bufp++ = 0x8e;
+                       *bufp++ = ScreenLines2[LineOffset[row] + i];
+                   }
+                   else
+                   {
+                       *bufp++ = p[i];
+                       if (MB_BYTE2LEN(p[i]) == 2)
+                           *bufp++ = p[++i];
+                   }
+           }
+           else if (enc_utf8)
+           {
+               int     off;
+               int     i;
+               int     ci;
+ 
+               off = LineOffset[row];
+               for (i = start_col; i < end_col; ++i)
+               {
+                   // The base character is either in ScreenLinesUC[] or
+                   // ScreenLines[].
+                   if (ScreenLinesUC[off + i] == 0)
+                       *bufp++ = ScreenLines[off + i];
+                   else
+                   {
+                       bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp);
+                       for (ci = 0; ci < Screen_mco; ++ci)
+                       {
+                           // Add a composing character.
+                           if (ScreenLinesC[ci][off + i] == 0)
+                               break;
+                           bufp += utf_char2bytes(ScreenLinesC[ci][off + i],
+                                                                       bufp);
+                       }
+                   }
+                   // Skip right halve of double-wide character.
+                   if (ScreenLines[off + i + 1] == 0)
+                       ++i;
+               }
+           }
+           else
+           {
+               STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col,
+                                                        end_col - start_col);
+               bufp += end_col - start_col;
+           }
+       }
+     }
+ 
+     // Add a newline at the end if the selection ended there
+     if (add_newline_flag)
+       *bufp++ = NL;
+ 
+     // First cleanup any old selection and become the owner.
+     clip_free_selection(&clip_star);
+     clip_own_selection(&clip_star);
+ 
+     // Yank the text into the '*' register.
+     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star);
+ 
+     // Make the register contents available to the outside world.
+     clip_gen_set_selection(&clip_star);
+ 
+ #ifdef FEAT_X11
+     if (both)
+     {
+       // Do the same for the '+' register.
+       clip_free_selection(&clip_plus);
+       clip_own_selection(&clip_plus);
+       clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus);
+       clip_gen_set_selection(&clip_plus);
+     }
+ #endif
+     vim_free(buffer);
+ }
+ 
+     void
+ clip_gen_set_selection(Clipboard_T *cbd)
+ {
+     if (!clip_did_set_selection)
+     {
+       // Updating postponed, so that accessing the system clipboard won't
+       // hang Vim when accessing it many times (e.g. on a :g command).
+       if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS))
+               || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED)))
+       {
+           clipboard_needs_update = TRUE;
+           return;
+       }
+     }
+ #ifdef FEAT_XCLIPBOARD
+ # ifdef FEAT_GUI
+     if (gui.in_use)
+       clip_mch_set_selection(cbd);
+     else
+ # endif
+       clip_xterm_set_selection(cbd);
+ #else
+     clip_mch_set_selection(cbd);
+ #endif
+ }
+ 
+     static void
+ clip_gen_request_selection(Clipboard_T *cbd)
+ {
+ #ifdef FEAT_XCLIPBOARD
+ # ifdef FEAT_GUI
+     if (gui.in_use)
+       clip_mch_request_selection(cbd);
+     else
+ # endif
+       clip_xterm_request_selection(cbd);
+ #else
+     clip_mch_request_selection(cbd);
+ #endif
+ }
+ 
+ #if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) \
+       || defined(PROTO)
+     static int
+ clip_x11_owner_exists(Clipboard_T *cbd)
+ {
+     return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None;
+ }
+ #endif
+ 
+ #if (defined(FEAT_X11) && defined(USE_SYSTEM)) || defined(PROTO)
+     int
+ clip_gen_owner_exists(Clipboard_T *cbd UNUSED)
+ {
+ #ifdef FEAT_XCLIPBOARD
+ # ifdef FEAT_GUI_GTK
+     if (gui.in_use)
+       return clip_gtk_owner_exists(cbd);
+     else
+ # endif
+       return clip_x11_owner_exists(cbd);
+ #else
+     return TRUE;
+ #endif
+ }
+ #endif
+ 
+ /*
+  * Extract the items in the 'clipboard' option and set global values.
+  * Return an error message or NULL for success.
+  */
+     char *
+ check_clipboard_option(void)
+ {
+     int               new_unnamed = 0;
+     int               new_autoselect_star = FALSE;
+     int               new_autoselect_plus = FALSE;
+     int               new_autoselectml = FALSE;
+     int               new_html = FALSE;
+     regprog_T *new_exclude_prog = NULL;
+     char      *errmsg = NULL;
+     char_u    *p;
+ 
+     for (p = p_cb; *p != NUL; )
+     {
+       if (STRNCMP(p, "unnamed", 7) == 0 && (p[7] == ',' || p[7] == NUL))
+       {
+           new_unnamed |= CLIP_UNNAMED;
+           p += 7;
+       }
+       else if (STRNCMP(p, "unnamedplus", 11) == 0
+                                           && (p[11] == ',' || p[11] == NUL))
+       {
+           new_unnamed |= CLIP_UNNAMED_PLUS;
+           p += 11;
+       }
+       else if (STRNCMP(p, "autoselect", 10) == 0
+                                           && (p[10] == ',' || p[10] == NUL))
+       {
+           new_autoselect_star = TRUE;
+           p += 10;
+       }
+       else if (STRNCMP(p, "autoselectplus", 14) == 0
+                                           && (p[14] == ',' || p[14] == NUL))
+       {
+           new_autoselect_plus = TRUE;
+           p += 14;
+       }
+       else if (STRNCMP(p, "autoselectml", 12) == 0
+                                           && (p[12] == ',' || p[12] == NUL))
+       {
+           new_autoselectml = TRUE;
+           p += 12;
+       }
+       else if (STRNCMP(p, "html", 4) == 0 && (p[4] == ',' || p[4] == NUL))
+       {
+           new_html = TRUE;
+           p += 4;
+       }
+       else if (STRNCMP(p, "exclude:", 8) == 0 && new_exclude_prog == NULL)
+       {
+           p += 8;
+           new_exclude_prog = vim_regcomp(p, RE_MAGIC);
+           if (new_exclude_prog == NULL)
+               errmsg = e_invarg;
+           break;
+       }
+       else
+       {
+           errmsg = e_invarg;
+           break;
+       }
+       if (*p == ',')
+           ++p;
+     }
+     if (errmsg == NULL)
+     {
+       clip_unnamed = new_unnamed;
+       clip_autoselect_star = new_autoselect_star;
+       clip_autoselect_plus = new_autoselect_plus;
+       clip_autoselectml = new_autoselectml;
+       clip_html = new_html;
+       vim_regfree(clip_exclude_prog);
+       clip_exclude_prog = new_exclude_prog;
+ #ifdef FEAT_GUI_GTK
+       if (gui.in_use)
+       {
+           gui_gtk_set_selection_targets();
+           gui_gtk_set_dnd_targets();
+       }
+ #endif
+     }
+     else
+       vim_regfree(new_exclude_prog);
+ 
+     return errmsg;
+ }
+ 
+ /*
+  * Stuff for the X clipboard.  Shared between VMS and Unix.
+  */
+ 
+ #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO)
+ # include <X11/Xatom.h>
+ # include <X11/Intrinsic.h>
+ 
+ /*
+  * Open the application context (if it hasn't been opened yet).
+  * Used for Motif and Athena GUI and the xterm clipboard.
+  */
+     void
+ open_app_context(void)
+ {
+     if (app_context == NULL)
+     {
+       XtToolkitInitialize();
+       app_context = XtCreateApplicationContext();
+     }
+ }
+ 
+ static Atom   vim_atom;       // Vim's own special selection format
+ static Atom   vimenc_atom;    // Vim's extended selection format
+ static Atom   utf8_atom;
+ static Atom   compound_text_atom;
+ static Atom   text_atom;
+ static Atom   targets_atom;
+ static Atom   timestamp_atom; // Used to get a timestamp
+ 
+     void
+ x11_setup_atoms(Display *dpy)
+ {
+     vim_atom         = XInternAtom(dpy, VIM_ATOM_NAME,   False);
+     vimenc_atom              = XInternAtom(dpy, VIMENC_ATOM_NAME,False);
+     utf8_atom        = XInternAtom(dpy, "UTF8_STRING",   False);
+     compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False);
+     text_atom        = XInternAtom(dpy, "TEXT",          False);
+     targets_atom       = XInternAtom(dpy, "TARGETS",     False);
+     clip_star.sel_atom = XA_PRIMARY;
+     clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD",           False);
+     timestamp_atom     = XInternAtom(dpy, "TIMESTAMP",           False);
+ }
+ 
+ /*
+  * X Selection stuff, for cutting and pasting text to other windows.
+  */
+ 
+     static Boolean
+ clip_x11_convert_selection_cb(
+     Widget    w UNUSED,
+     Atom      *sel_atom,
+     Atom      *target,
+     Atom      *type,
+     XtPointer *value,
+     long_u    *length,
+     int               *format)
+ {
+     static char_u   *save_result = NULL;
+     static long_u   save_length = 0;
+     char_u        *string;
+     int                   motion_type;
+     Clipboard_T    *cbd;
+     int                   i;
+ 
+     if (*sel_atom == clip_plus.sel_atom)
+       cbd = &clip_plus;
+     else
+       cbd = &clip_star;
+ 
+     if (!cbd->owned)
+       return False;       // Shouldn't ever happen
+ 
+     // requestor wants to know what target types we support
+     if (*target == targets_atom)
+     {
+       static Atom array[7];
+ 
+       *value = (XtPointer)array;
+       i = 0;
+       array[i++] = targets_atom;
+       array[i++] = vimenc_atom;
+       array[i++] = vim_atom;
+       if (enc_utf8)
+           array[i++] = utf8_atom;
+       array[i++] = XA_STRING;
+       array[i++] = text_atom;
+       array[i++] = compound_text_atom;
+ 
+       *type = XA_ATOM;
+       // This used to be: *format = sizeof(Atom) * 8; but that caused
+       // crashes on 64 bit machines. (Peter Derr)
+       *format = 32;
+       *length = i;
+       return True;
+     }
+ 
+     if (       *target != XA_STRING
+           && *target != vimenc_atom
+           && (*target != utf8_atom || !enc_utf8)
+           && *target != vim_atom
+           && *target != text_atom
+           && *target != compound_text_atom)
+       return False;
+ 
+     clip_get_selection(cbd);
+     motion_type = clip_convert_selection(&string, length, cbd);
+     if (motion_type < 0)
+       return False;
+ 
+     // For our own format, the first byte contains the motion type
+     if (*target == vim_atom)
+       (*length)++;
+ 
+     // Our own format with encoding: motion 'encoding' NUL text
+     if (*target == vimenc_atom)
+       *length += STRLEN(p_enc) + 2;
+ 
+     if (save_length < *length || save_length / 2 >= *length)
+       *value = XtRealloc((char *)save_result, (Cardinal)*length + 1);
+     else
+       *value = save_result;
+     if (*value == NULL)
+     {
+       vim_free(string);
+       return False;
+     }
+     save_result = (char_u *)*value;
+     save_length = *length;
+ 
+     if (*target == XA_STRING || (*target == utf8_atom && enc_utf8))
+     {
+       mch_memmove(save_result, string, (size_t)(*length));
+       *type = *target;
+     }
+     else if (*target == compound_text_atom || *target == text_atom)
+     {
+       XTextProperty   text_prop;
+       char            *string_nt = (char *)save_result;
+       int             conv_result;
+ 
+       // create NUL terminated string which XmbTextListToTextProperty wants
+       mch_memmove(string_nt, string, (size_t)*length);
+       string_nt[*length] = NUL;
+       conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt,
+                                          1, XCompoundTextStyle, &text_prop);
+       if (conv_result != Success)
+       {
+           vim_free(string);
+           return False;
+       }
+       *value = (XtPointer)(text_prop.value);  //    from plain text
+       *length = text_prop.nitems;
+       *type = compound_text_atom;
+       XtFree((char *)save_result);
+       save_result = (char_u *)*value;
+       save_length = *length;
+     }
+     else if (*target == vimenc_atom)
+     {
+       int l = STRLEN(p_enc);
+ 
+       save_result[0] = motion_type;
+       STRCPY(save_result + 1, p_enc);
+       mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2));
+       *type = vimenc_atom;
+     }
+     else
+     {
+       save_result[0] = motion_type;
+       mch_memmove(save_result + 1, string, (size_t)(*length - 1));
+       *type = vim_atom;
+     }
+     *format = 8;          // 8 bits per char
+     vim_free(string);
+     return True;
+ }
+ 
+     static void
+ clip_x11_lose_ownership_cb(Widget w UNUSED, Atom *sel_atom)
+ {
+     if (*sel_atom == clip_plus.sel_atom)
+       clip_lose_selection(&clip_plus);
+     else
+       clip_lose_selection(&clip_star);
+ }
+ 
+     static void
+ clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target 
UNUSED)
+ {
+     // To prevent automatically freeing the selection value.
+ }
+ 
+ /*
+  * Property callback to get a timestamp for XtOwnSelection.
+  */
+     static void
+ clip_x11_timestamp_cb(
+     Widget    w,
+     XtPointer n UNUSED,
+     XEvent    *event,
+     Boolean   *cont UNUSED)
+ {
+     Atom          actual_type;
+     int                   format;
+     unsigned  long  nitems, bytes_after;
+     unsigned char   *prop=NULL;
+     XPropertyEvent  *xproperty=&event->xproperty;
+ 
+     // Must be a property notify, state can't be Delete (True), has to be
+     // one of the supported selection types.
+     if (event->type != PropertyNotify || xproperty->state
+           || (xproperty->atom != clip_star.sel_atom
+                                   && xproperty->atom != clip_plus.sel_atom))
+       return;
+ 
+     if (XGetWindowProperty(xproperty->display, xproperty->window,
+         xproperty->atom, 0, 0, False, timestamp_atom, &actual_type, &format,
+                                               &nitems, &bytes_after, &prop))
+       return;
+ 
+     if (prop)
+       XFree(prop);
+ 
+     // Make sure the property type is "TIMESTAMP" and it's 32 bits.
+     if (actual_type != timestamp_atom || format != 32)
+       return;
+ 
+     // Get the selection, using the event timestamp.
+     if (XtOwnSelection(w, xproperty->atom, xproperty->time,
+           clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
+           clip_x11_notify_cb) == OK)
+     {
+       // Set the "owned" flag now, there may have been a call to
+       // lose_ownership_cb in between.
+       if (xproperty->atom == clip_plus.sel_atom)
+           clip_plus.owned = TRUE;
+       else
+           clip_star.owned = TRUE;
+     }
+ }
+ 
+     void
+ x11_setup_selection(Widget w)
+ {
+     XtAddEventHandler(w, PropertyChangeMask, False,
+           /*(XtEventHandler)*/clip_x11_timestamp_cb, (XtPointer)NULL);
+ }
+ 
+     static void
+ clip_x11_request_selection_cb(
+     Widget    w UNUSED,
+     XtPointer success,
+     Atom      *sel_atom,
+     Atom      *type,
+     XtPointer value,
+     long_u    *length,
+     int               *format)
+ {
+     int               motion_type = MAUTO;
+     long_u    len;
+     char_u    *p;
+     char      **text_list = NULL;
+     Clipboard_T       *cbd;
+     char_u    *tmpbuf = NULL;
+ 
+     if (*sel_atom == clip_plus.sel_atom)
+       cbd = &clip_plus;
+     else
+       cbd = &clip_star;
+ 
+     if (value == NULL || *length == 0)
+     {
+       clip_free_selection(cbd);       // nothing received, clear register
+       *(int *)success = FALSE;
+       return;
+     }
+     p = (char_u *)value;
+     len = *length;
+     if (*type == vim_atom)
+     {
+       motion_type = *p++;
+       len--;
+     }
+ 
+     else if (*type == vimenc_atom)
+     {
+       char_u          *enc;
+       vimconv_T       conv;
+       int             convlen;
+ 
+       motion_type = *p++;
+       --len;
+ 
+       enc = p;
+       p += STRLEN(p) + 1;
+       len -= p - enc;
+ 
+       // If the encoding of the text is different from 'encoding', attempt
+       // converting it.
+       conv.vc_type = CONV_NONE;
+       convert_setup(&conv, enc, p_enc);
+       if (conv.vc_type != CONV_NONE)
+       {
+           convlen = len;      // Need to use an int here.
+           tmpbuf = string_convert(&conv, p, &convlen);
+           len = convlen;
+           if (tmpbuf != NULL)
+               p = tmpbuf;
+           convert_setup(&conv, NULL, NULL);
+       }
+     }
+ 
+     else if (*type == compound_text_atom
+           || *type == utf8_atom
+           || (enc_dbcs != 0 && *type == text_atom))
+     {
+       XTextProperty   text_prop;
+       int             n_text = 0;
+       int             status;
+ 
+       text_prop.value = (unsigned char *)value;
+       text_prop.encoding = *type;
+       text_prop.format = *format;
+       text_prop.nitems = len;
+ #if defined(X_HAVE_UTF8_STRING)
+       if (*type == utf8_atom)
+           status = Xutf8TextPropertyToTextList(X_DISPLAY, &text_prop,
+                                                        &text_list, &n_text);
+       else
+ #endif
+           status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop,
+                                                        &text_list, &n_text);
+       if (status != Success || n_text < 1)
+       {
+           *(int *)success = FALSE;
+           return;
+       }
+       p = (char_u *)text_list[0];
+       len = STRLEN(p);
+     }
+     clip_yank_selection(motion_type, p, (long)len, cbd);
+ 
+     if (text_list != NULL)
+       XFreeStringList(text_list);
+     vim_free(tmpbuf);
+     XtFree((char *)value);
+     *(int *)success = TRUE;
+ }
+ 
+     void
+ clip_x11_request_selection(
+     Widget    myShell,
+     Display   *dpy,
+     Clipboard_T       *cbd)
+ {
+     XEvent    event;
+     Atom      type;
+     static int        success;
+     int               i;
+     time_t    start_time;
+     int               timed_out = FALSE;
+ 
+     for (i = 0; i < 6; i++)
+     {
+       switch (i)
+       {
+           case 0:  type = vimenc_atom;        break;
+           case 1:  type = vim_atom;           break;
+           case 2:  type = utf8_atom;          break;
+           case 3:  type = compound_text_atom; break;
+           case 4:  type = text_atom;          break;
+           default: type = XA_STRING;
+       }
+       if (type == utf8_atom
+ # if defined(X_HAVE_UTF8_STRING)
+               && !enc_utf8
+ # endif
+               )
+           // Only request utf-8 when 'encoding' is utf8 and
+           // Xutf8TextPropertyToTextList is available.
+           continue;
+       success = MAYBE;
+       XtGetSelectionValue(myShell, cbd->sel_atom, type,
+           clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime);
+ 
+       // Make sure the request for the selection goes out before waiting for
+       // a response.
+       XFlush(dpy);
+ 
+       /*
+        * Wait for result of selection request, otherwise if we type more
+        * characters, then they will appear before the one that requested the
+        * paste!  Don't worry, we will catch up with any other events later.
+        */
+       start_time = time(NULL);
+       while (success == MAYBE)
+       {
+           if (XCheckTypedEvent(dpy, PropertyNotify, &event)
+                   || XCheckTypedEvent(dpy, SelectionNotify, &event)
+                   || XCheckTypedEvent(dpy, SelectionRequest, &event))
+           {
+               // This is where clip_x11_request_selection_cb() should be
+               // called.  It may actually happen a bit later, so we loop
+               // until "success" changes.
+               // We may get a SelectionRequest here and if we don't handle
+               // it we hang.  KDE klipper does this, for example.
+               // We need to handle a PropertyNotify for large selections.
+               XtDispatchEvent(&event);
+               continue;
+           }
+ 
+           // Time out after 2 to 3 seconds to avoid that we hang when the
+           // other process doesn't respond.  Note that the SelectionNotify
+           // event may still come later when the selection owner comes back
+           // to life and the text gets inserted unexpectedly.  Don't know
+           // why that happens or how to avoid that :-(.
+           if (time(NULL) > start_time + 2)
+           {
+               timed_out = TRUE;
+               break;
+           }
+ 
+           // Do we need this?  Probably not.
+           XSync(dpy, False);
+ 
+           // Wait for 1 msec to avoid that we eat up all CPU time.
+           ui_delay(1L, TRUE);
+       }
+ 
+       if (success == TRUE)
+           return;
+ 
+       // don't do a retry with another type after timing out, otherwise we
+       // hang for 15 seconds.
+       if (timed_out)
+           break;
+     }
+ 
+     // Final fallback position - use the X CUT_BUFFER0 store
+     yank_cut_buffer0(dpy, cbd);
+ }
+ 
+     void
+ clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd)
+ {
+     XtDisownSelection(myShell, cbd->sel_atom,
+                               XtLastTimestampProcessed(XtDisplay(myShell)));
+ }
+ 
+     int
+ clip_x11_own_selection(Widget myShell, Clipboard_T *cbd)
+ {
+     // When using the GUI we have proper timestamps, use the one of the last
+     // event.  When in the console we don't get events (the terminal gets
+     // them), Get the time by a zero-length append, clip_x11_timestamp_cb will
+     // be called with the current timestamp.
+ #ifdef FEAT_GUI
+     if (gui.in_use)
+     {
+       if (XtOwnSelection(myShell, cbd->sel_atom,
+              XtLastTimestampProcessed(XtDisplay(myShell)),
+              clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
+              clip_x11_notify_cb) == False)
+           return FAIL;
+     }
+     else
+ #endif
+     {
+       if (!XChangeProperty(XtDisplay(myShell), XtWindow(myShell),
+                 cbd->sel_atom, timestamp_atom, 32, PropModeAppend, NULL, 0))
+           return FAIL;
+     }
+     // Flush is required in a terminal as nothing else is doing it.
+     XFlush(XtDisplay(myShell));
+     return OK;
+ }
+ 
+ /*
+  * Send the current selection to the clipboard.  Do nothing for X because we
+  * will fill in the selection only when requested by another app.
+  */
+     void
+ clip_x11_set_selection(Clipboard_T *cbd UNUSED)
+ {
+ }
+ 
+ #endif
+ 
+ #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) \
+     || defined(FEAT_GUI_GTK) || defined(PROTO)
+ /*
+  * Get the contents of the X CUT_BUFFER0 and put it in "cbd".
+  */
+     void
+ yank_cut_buffer0(Display *dpy, Clipboard_T *cbd)
+ {
+     int               nbytes = 0;
+     char_u    *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0);
+ 
+     if (nbytes > 0)
+     {
+       int  done = FALSE;
+ 
+       // CUT_BUFFER0 is supposed to be always latin1.  Convert to 'enc' when
+       // using a multi-byte encoding.  Conversion between two 8-bit
+       // character sets usually fails and the text might actually be in
+       // 'enc' anyway.
+       if (has_mbyte)
+       {
+           char_u      *conv_buf;
+           vimconv_T   vc;
+ 
+           vc.vc_type = CONV_NONE;
+           if (convert_setup(&vc, (char_u *)"latin1", p_enc) == OK)
+           {
+               conv_buf = string_convert(&vc, buffer, &nbytes);
+               if (conv_buf != NULL)
+               {
+                   clip_yank_selection(MCHAR, conv_buf, (long)nbytes, cbd);
+                   vim_free(conv_buf);
+                   done = TRUE;
+               }
+               convert_setup(&vc, NULL, NULL);
+           }
+       }
+       if (!done)  // use the text without conversion
+           clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd);
+       XFree((void *)buffer);
+       if (p_verbose > 0)
+       {
+           verbose_enter();
+           verb_msg(_("Used CUT_BUFFER0 instead of empty selection"));
+           verbose_leave();
+       }
+     }
+ }
+ #endif
+ 
+ /*
+  * SELECTION / PRIMARY ('*')
+  *
+  * Text selection stuff that uses the GUI selection register '*'.  When using 
a
+  * GUI this may be text from another window, otherwise it is the last text we
+  * had highlighted with VIsual mode.  With mouse support, clicking the middle
+  * button performs the paste, otherwise you will need to do <"*p>. "
+  * If not under X, it is synonymous with the clipboard register '+'.
+  *
+  * X CLIPBOARD ('+')
+  *
+  * Text selection stuff that uses the GUI clipboard register '+'.
+  * Under X, this matches the standard cut/paste buffer CLIPBOARD selection.
+  * It will be used for unnamed cut/pasting is 'clipboard' contains "unnamed",
+  * otherwise you will need to do <"+p>. "
+  * If not under X, it is synonymous with the selection register '*'.
+  */
+ 
+ /*
+  * Routine to export any final X selection we had to the environment
+  * so that the text is still available after Vim has exited. X selections
+  * only exist while the owning application exists, so we write to the
+  * permanent (while X runs) store CUT_BUFFER0.
+  * Dump the CLIPBOARD selection if we own it (it's logically the more
+  * 'permanent' of the two), otherwise the PRIMARY one.
+  * For now, use a hard-coded sanity limit of 1Mb of data.
+  */
+ #if (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
+     void
+ x11_export_final_selection(void)
+ {
+     Display   *dpy;
+     char_u    *str = NULL;
+     long_u    len = 0;
+     int               motion_type = -1;
+ 
+ # ifdef FEAT_GUI
+     if (gui.in_use)
+       dpy = X_DISPLAY;
+     else
+ # endif
+ # ifdef FEAT_XCLIPBOARD
+       dpy = xterm_dpy;
+ # else
+       return;
+ # endif
+ 
+     // Get selection to export
+     if (clip_plus.owned)
+       motion_type = clip_convert_selection(&str, &len, &clip_plus);
+     else if (clip_star.owned)
+       motion_type = clip_convert_selection(&str, &len, &clip_star);
+ 
+     // Check it's OK
+     if (dpy != NULL && str != NULL && motion_type >= 0
+                                              && len < 1024*1024 && len > 0)
+     {
+       int ok = TRUE;
+ 
+       // The CUT_BUFFER0 is supposed to always contain latin1.  Convert from
+       // 'enc' when it is a multi-byte encoding.  When 'enc' is an 8-bit
+       // encoding conversion usually doesn't work, so keep the text as-is.
+       if (has_mbyte)
+       {
+           vimconv_T   vc;
+ 
+           vc.vc_type = CONV_NONE;
+           if (convert_setup(&vc, p_enc, (char_u *)"latin1") == OK)
+           {
+               int     intlen = len;
+               char_u  *conv_str;
+ 
+               vc.vc_fail = TRUE;
+               conv_str = string_convert(&vc, str, &intlen);
+               len = intlen;
+               if (conv_str != NULL)
+               {
+                   vim_free(str);
+                   str = conv_str;
+               }
+               else
+               {
+                   ok = FALSE;
+               }
+               convert_setup(&vc, NULL, NULL);
+           }
+           else
+           {
+               ok = FALSE;
+           }
+       }
+ 
+       // Do not store the string if conversion failed.  Better to use any
+       // other selection than garbled text.
+       if (ok)
+       {
+           XStoreBuffer(dpy, (char *)str, (int)len, 0);
+           XFlush(dpy);
+       }
+     }
+ 
+     vim_free(str);
+ }
+ #endif
+ 
+     void
+ clip_free_selection(Clipboard_T *cbd)
+ {
+     yankreg_T *y_ptr = get_y_current();
+ 
+     if (cbd == &clip_plus)
+       set_y_current(get_y_register(PLUS_REGISTER));
+     else
+       set_y_current(get_y_register(STAR_REGISTER));
+     free_yank_all();
+     get_y_current()->y_size = 0;
+     set_y_current(y_ptr);
+ }
+ 
+ /*
+  * Get the selected text and put it in register '*' or '+'.
+  */
+     void
+ clip_get_selection(Clipboard_T *cbd)
+ {
+     yankreg_T *old_y_previous, *old_y_current;
+     pos_T     old_cursor;
+     pos_T     old_visual;
+     int               old_visual_mode;
+     colnr_T   old_curswant;
+     int               old_set_curswant;
+     pos_T     old_op_start, old_op_end;
+     oparg_T   oa;
+     cmdarg_T  ca;
+ 
+     if (cbd->owned)
+     {
+       if ((cbd == &clip_plus
+               && get_y_register(PLUS_REGISTER)->y_array != NULL)
+               || (cbd == &clip_star
+                   && get_y_register(STAR_REGISTER)->y_array != NULL))
+           return;
+ 
+       // Get the text between clip_star.start & clip_star.end
+       old_y_previous = get_y_previous();
+       old_y_current = get_y_current();
+       old_cursor = curwin->w_cursor;
+       old_curswant = curwin->w_curswant;
+       old_set_curswant = curwin->w_set_curswant;
+       old_op_start = curbuf->b_op_start;
+       old_op_end = curbuf->b_op_end;
+       old_visual = VIsual;
+       old_visual_mode = VIsual_mode;
+       clear_oparg(&oa);
+       oa.regname = (cbd == &clip_plus ? '+' : '*');
+       oa.op_type = OP_YANK;
+       vim_memset(&ca, 0, sizeof(ca));
+       ca.oap = &oa;
+       ca.cmdchar = 'y';
+       ca.count1 = 1;
+       ca.retval = CA_NO_ADJ_OP_END;
+       do_pending_operator(&ca, 0, TRUE);
+       set_y_previous(old_y_previous);
+       set_y_current(old_y_current);
+       curwin->w_cursor = old_cursor;
+       changed_cline_bef_curs();   // need to update w_virtcol et al
+       curwin->w_curswant = old_curswant;
+       curwin->w_set_curswant = old_set_curswant;
+       curbuf->b_op_start = old_op_start;
+       curbuf->b_op_end = old_op_end;
+       VIsual = old_visual;
+       VIsual_mode = old_visual_mode;
+     }
+     else if (!is_clipboard_needs_update())
+     {
+       clip_free_selection(cbd);
+ 
+       // Try to get selected text from another window
+       clip_gen_request_selection(cbd);
+     }
+ }
+ 
+ /*
+  * Convert from the GUI selection string into the '*'/'+' register.
+  */
+     void
+ clip_yank_selection(
+     int               type,
+     char_u    *str,
+     long      len,
+     Clipboard_T *cbd)
+ {
+     yankreg_T *y_ptr;
+ 
+     if (cbd == &clip_plus)
+       y_ptr = get_y_register(PLUS_REGISTER);
+     else
+       y_ptr = get_y_register(STAR_REGISTER);
+ 
+     clip_free_selection(cbd);
+ 
+     str_to_reg(y_ptr, type, str, len, 0L, FALSE);
+ }
+ 
+ /*
+  * Convert the '*'/'+' register into a GUI selection string returned in *str
+  * with length *len.
+  * Returns the motion type, or -1 for failure.
+  */
+     int
+ clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd)
+ {
+     char_u    *p;
+     int               lnum;
+     int               i, j;
+     int_u     eolsize;
+     yankreg_T *y_ptr;
+ 
+     if (cbd == &clip_plus)
+       y_ptr = get_y_register(PLUS_REGISTER);
+     else
+       y_ptr = get_y_register(STAR_REGISTER);
+ 
+ # ifdef USE_CRNL
+     eolsize = 2;
+ # else
+     eolsize = 1;
+ # endif
+ 
+     *str = NULL;
+     *len = 0;
+     if (y_ptr->y_array == NULL)
+       return -1;
+ 
+     for (i = 0; i < y_ptr->y_size; i++)
+       *len += (long_u)STRLEN(y_ptr->y_array[i]) + eolsize;
+ 
+     // Don't want newline character at end of last line if we're in MCHAR 
mode.
+     if (y_ptr->y_type == MCHAR && *len >= eolsize)
+       *len -= eolsize;
+ 
+     p = *str = alloc(*len + 1);       // add one to avoid zero
+     if (p == NULL)
+       return -1;
+     lnum = 0;
+     for (i = 0, j = 0; i < (int)*len; i++, j++)
+     {
+       if (y_ptr->y_array[lnum][j] == '\n')
+           p[i] = NUL;
+       else if (y_ptr->y_array[lnum][j] == NUL)
+       {
+ # ifdef USE_CRNL
+           p[i++] = '\r';
+ # endif
+           p[i] = '\n';
+           lnum++;
+           j = -1;
+       }
+       else
+           p[i] = y_ptr->y_array[lnum][j];
+     }
+     return y_ptr->y_type;
+ }
+ 
+ /*
+  * When "regname" is a clipboard register, obtain the selection.  If it's not
+  * available return zero, otherwise return "regname".
+  */
+     int
+ may_get_selection(int regname)
+ {
+     if (regname == '*')
+     {
+       if (!clip_star.available)
+           regname = 0;
+       else
+           clip_get_selection(&clip_star);
+     }
+     else if (regname == '+')
+     {
+       if (!clip_plus.available)
+           regname = 0;
+       else
+           clip_get_selection(&clip_plus);
+     }
+     return regname;
+ }
+ 
+ /*
+  * If we have written to a clipboard register, send the text to the clipboard.
+  */
+     void
+ may_set_selection(void)
+ {
+     if ((get_y_current() == get_y_register(STAR_REGISTER))
+           && clip_star.available)
+     {
+       clip_own_selection(&clip_star);
+       clip_gen_set_selection(&clip_star);
+     }
+     else if ((get_y_current() == get_y_register(PLUS_REGISTER))
+           && clip_plus.available)
+     {
+       clip_own_selection(&clip_plus);
+       clip_gen_set_selection(&clip_plus);
+     }
+ }
+ 
+ /*
+  * Adjust the register name pointed to with "rp" for the clipboard being
+  * used always and the clipboard being available.
+  */
+     void
+ adjust_clip_reg(int *rp)
+ {
+     // If no reg. specified, and "unnamed" or "unnamedplus" is in 'clipboard',
+     // use '*' or '+' reg, respectively. "unnamedplus" prevails.
+     if (*rp == 0 && (clip_unnamed != 0 || clip_unnamed_saved != 0))
+     {
+       if (clip_unnamed != 0)
+           *rp = ((clip_unnamed & CLIP_UNNAMED_PLUS) && clip_plus.available)
+                                                                 ? '+' : '*';
+       else
+           *rp = ((clip_unnamed_saved & CLIP_UNNAMED_PLUS)
+                                          && clip_plus.available) ? '+' : '*';
+     }
+     if (!clip_star.available && *rp == '*')
+       *rp = 0;
+     if (!clip_plus.available && *rp == '+')
+       *rp = 0;
+ }
+ 
+ #endif // FEAT_CLIPBOARD
*** ../vim-8.2.0442/src/ops.c   2020-03-23 22:12:15.496961030 +0100
--- src/ops.c   2020-03-24 21:07:55.526635106 +0100
***************
*** 3409,3521 ****
      return did_change;
  }
  
- #if defined(FEAT_CLIPBOARD) || defined(PROTO)
- /*
-  * SELECTION / PRIMARY ('*')
-  *
-  * Text selection stuff that uses the GUI selection register '*'.  When using 
a
-  * GUI this may be text from another window, otherwise it is the last text we
-  * had highlighted with VIsual mode.  With mouse support, clicking the middle
-  * button performs the paste, otherwise you will need to do <"*p>. "
-  * If not under X, it is synonymous with the clipboard register '+'.
-  *
-  * X CLIPBOARD ('+')
-  *
-  * Text selection stuff that uses the GUI clipboard register '+'.
-  * Under X, this matches the standard cut/paste buffer CLIPBOARD selection.
-  * It will be used for unnamed cut/pasting is 'clipboard' contains "unnamed",
-  * otherwise you will need to do <"+p>. "
-  * If not under X, it is synonymous with the selection register '*'.
-  */
- 
- /*
-  * Routine to export any final X selection we had to the environment
-  * so that the text is still available after Vim has exited. X selections
-  * only exist while the owning application exists, so we write to the
-  * permanent (while X runs) store CUT_BUFFER0.
-  * Dump the CLIPBOARD selection if we own it (it's logically the more
-  * 'permanent' of the two), otherwise the PRIMARY one.
-  * For now, use a hard-coded sanity limit of 1Mb of data.
-  */
- #if (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
-     void
- x11_export_final_selection(void)
- {
-     Display   *dpy;
-     char_u    *str = NULL;
-     long_u    len = 0;
-     int               motion_type = -1;
- 
- # ifdef FEAT_GUI
-     if (gui.in_use)
-       dpy = X_DISPLAY;
-     else
- # endif
- # ifdef FEAT_XCLIPBOARD
-       dpy = xterm_dpy;
- # else
-       return;
- # endif
- 
-     // Get selection to export
-     if (clip_plus.owned)
-       motion_type = clip_convert_selection(&str, &len, &clip_plus);
-     else if (clip_star.owned)
-       motion_type = clip_convert_selection(&str, &len, &clip_star);
- 
-     // Check it's OK
-     if (dpy != NULL && str != NULL && motion_type >= 0
-                                              && len < 1024*1024 && len > 0)
-     {
-       int ok = TRUE;
- 
-       // The CUT_BUFFER0 is supposed to always contain latin1.  Convert from
-       // 'enc' when it is a multi-byte encoding.  When 'enc' is an 8-bit
-       // encoding conversion usually doesn't work, so keep the text as-is.
-       if (has_mbyte)
-       {
-           vimconv_T   vc;
- 
-           vc.vc_type = CONV_NONE;
-           if (convert_setup(&vc, p_enc, (char_u *)"latin1") == OK)
-           {
-               int     intlen = len;
-               char_u  *conv_str;
- 
-               vc.vc_fail = TRUE;
-               conv_str = string_convert(&vc, str, &intlen);
-               len = intlen;
-               if (conv_str != NULL)
-               {
-                   vim_free(str);
-                   str = conv_str;
-               }
-               else
-               {
-                   ok = FALSE;
-               }
-               convert_setup(&vc, NULL, NULL);
-           }
-           else
-           {
-               ok = FALSE;
-           }
-       }
- 
-       // Do not store the string if conversion failed.  Better to use any
-       // other selection than garbled text.
-       if (ok)
-       {
-           XStoreBuffer(dpy, (char *)str, (int)len, 0);
-           XFlush(dpy);
-       }
-     }
- 
-     vim_free(str);
- }
- #endif
- #endif // FEAT_CLIPBOARD || PROTO
- 
      void
  clear_oparg(oparg_T *oap)
  {
--- 3409,3414 ----
*** ../vim-8.2.0442/src/proto.h 2020-03-23 22:12:15.492961050 +0100
--- src/proto.h 2020-03-24 21:07:55.526635106 +0100
***************
*** 68,73 ****
--- 68,74 ----
  # include "change.pro"
  # include "charset.pro"
  # include "cindent.pro"
+ # include "clipboard.pro"
  # include "cmdexpand.pro"
  # include "cmdhist.pro"
  # include "if_cscope.pro"
*** ../vim-8.2.0442/src/proto/clipboard.pro     2020-03-24 21:40:46.947709654 
+0100
--- src/proto/clipboard.pro     2020-03-24 21:07:55.530635092 +0100
***************
*** 0 ****
--- 1,38 ----
+ /* clipboard.c */
+ void clip_init(int can_use);
+ void clip_update_selection(Clipboard_T *clip);
+ void clip_own_selection(Clipboard_T *cbd);
+ void clip_lose_selection(Clipboard_T *cbd);
+ void start_global_changes(void);
+ void end_global_changes(void);
+ void clip_auto_select(void);
+ int clip_isautosel_star(void);
+ int clip_isautosel_plus(void);
+ void clip_modeless(int button, int is_click, int is_drag);
+ void clip_start_selection(int col, int row, int repeated_click);
+ void clip_process_selection(int button, int col, int row, int_u 
repeated_click);
+ void clip_may_redraw_selection(int row, int col, int len);
+ void clip_clear_selection(Clipboard_T *cbd);
+ void clip_may_clear_selection(int row1, int row2);
+ void clip_scroll_selection(int rows);
+ void clip_copy_modeless_selection(int both);
+ void clip_gen_set_selection(Clipboard_T *cbd);
+ int clip_gen_owner_exists(Clipboard_T *cbd);
+ char *check_clipboard_option(void);
+ void open_app_context(void);
+ void x11_setup_atoms(Display *dpy);
+ void x11_setup_selection(Widget w);
+ void clip_x11_request_selection(Widget myShell, Display *dpy, Clipboard_T 
*cbd);
+ void clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd);
+ int clip_x11_own_selection(Widget myShell, Clipboard_T *cbd);
+ void clip_x11_set_selection(Clipboard_T *cbd);
+ void yank_cut_buffer0(Display *dpy, Clipboard_T *cbd);
+ void x11_export_final_selection(void);
+ void clip_free_selection(Clipboard_T *cbd);
+ void clip_get_selection(Clipboard_T *cbd);
+ void clip_yank_selection(int type, char_u *str, long len, Clipboard_T *cbd);
+ int clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd);
+ int may_get_selection(int regname);
+ void may_set_selection(void);
+ void adjust_clip_reg(int *rp);
+ /* vim: set ft=c : */
*** ../vim-8.2.0442/src/proto/ops.pro   2019-12-12 12:55:29.000000000 +0100
--- src/proto/ops.pro   2020-03-24 21:07:55.530635092 +0100
***************
*** 19,25 ****
  int paragraph_start(linenr_T lnum);
  void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int 
is_del);
  void op_addsub(oparg_T *oap, linenr_T Prenum1, int g_cmd);
- void x11_export_final_selection(void);
  void clear_oparg(oparg_T *oap);
  void cursor_pos_info(dict_T *dict);
  void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank);
--- 19,24 ----
*** ../vim-8.2.0442/src/proto/register.pro      2019-12-12 12:55:31.000000000 
+0100
--- src/proto/register.pro      2020-03-24 21:07:55.530635092 +0100
***************
*** 1,14 ****
  /* register.c */
  yankreg_T *get_y_regs(void);
  yankreg_T *get_y_current(void);
  yankreg_T *get_y_previous(void);
  void set_y_previous(yankreg_T *yreg);
  int get_expr_register(void);
  void set_expr_line(char_u *new_line);
  char_u *get_expr_line(void);
  int valid_yank_reg(int regname, int writing);
  int get_yank_register(int regname, int writing);
- int may_get_selection(int regname);
  void *get_register(int name, int copy);
  void put_register(int name, void *reg);
  void free_register(void *reg);
--- 1,15 ----
  /* register.c */
  yankreg_T *get_y_regs(void);
+ yankreg_T *get_y_register(int reg);
  yankreg_T *get_y_current(void);
  yankreg_T *get_y_previous(void);
+ void set_y_current(yankreg_T *yreg);
  void set_y_previous(yankreg_T *yreg);
  int get_expr_register(void);
  void set_expr_line(char_u *new_line);
  char_u *get_expr_line(void);
  int valid_yank_reg(int regname, int writing);
  int get_yank_register(int regname, int writing);
  void *get_register(int name, int copy);
  void put_register(int name, void *reg);
  void free_register(void *reg);
***************
*** 20,42 ****
  int insert_reg(int regname, int literally_arg);
  int get_spec_reg(int regname, char_u **argp, int *allocated, int errmsg);
  int cmdline_paste_reg(int regname, int literally_arg, int remcr);
- void adjust_clip_reg(int *rp);
  void shift_delete_registers(void);
  void yank_do_autocmd(oparg_T *oap, yankreg_T *reg);
  void init_yank(void);
  void clear_registers(void);
  int op_yank(oparg_T *oap, int deleting, int mess);
  void do_put(int regname, int dir, long count, int flags);
  int get_register_name(int num);
  void ex_display(exarg_T *eap);
- void clip_free_selection(Clipboard_T *cbd);
- void clip_get_selection(Clipboard_T *cbd);
- void clip_yank_selection(int type, char_u *str, long len, Clipboard_T *cbd);
- int clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd);
  void dnd_yank_drag_data(char_u *str, long len);
  char_u get_reg_type(int regname, long *reglen);
  char_u *get_reg_contents(int regname, int flags);
  void write_reg_contents(int name, char_u *str, int maxlen, int must_append);
  void write_reg_contents_lst(int name, char_u **strings, int maxlen, int 
must_append, int yank_type, long block_len);
  void write_reg_contents_ex(int name, char_u *str, int maxlen, int 
must_append, int yank_type, long block_len);
  /* vim: set ft=c : */
--- 21,40 ----
  int insert_reg(int regname, int literally_arg);
  int get_spec_reg(int regname, char_u **argp, int *allocated, int errmsg);
  int cmdline_paste_reg(int regname, int literally_arg, int remcr);
  void shift_delete_registers(void);
  void yank_do_autocmd(oparg_T *oap, yankreg_T *reg);
  void init_yank(void);
  void clear_registers(void);
+ void free_yank_all(void);
  int op_yank(oparg_T *oap, int deleting, int mess);
  void do_put(int regname, int dir, long count, int flags);
  int get_register_name(int num);
  void ex_display(exarg_T *eap);
  void dnd_yank_drag_data(char_u *str, long len);
  char_u get_reg_type(int regname, long *reglen);
  char_u *get_reg_contents(int regname, int flags);
  void write_reg_contents(int name, char_u *str, int maxlen, int must_append);
  void write_reg_contents_lst(int name, char_u **strings, int maxlen, int 
must_append, int yank_type, long block_len);
  void write_reg_contents_ex(int name, char_u *str, int maxlen, int 
must_append, int yank_type, long block_len);
+ void str_to_reg(yankreg_T *y_ptr, int yank_type, char_u *str, long len, long 
blocklen, int str_list);
  /* vim: set ft=c : */
*** ../vim-8.2.0442/src/proto/ui.pro    2019-12-12 12:55:36.000000000 +0100
--- src/proto/ui.pro    2020-03-24 21:07:55.530635092 +0100
***************
*** 14,41 ****
  int ui_get_winpos(int *x, int *y, varnumber_T timeout);
  void ui_breakcheck(void);
  void ui_breakcheck_force(int force);
- void clip_init(int can_use);
- void clip_update_selection(Clipboard_T *clip);
- void clip_own_selection(Clipboard_T *cbd);
- void clip_lose_selection(Clipboard_T *cbd);
- void start_global_changes(void);
- int is_clipboard_needs_update(void);
- void end_global_changes(void);
- void clip_auto_select(void);
- int clip_isautosel_star(void);
- int clip_isautosel_plus(void);
- void clip_modeless(int button, int is_click, int is_drag);
- void clip_start_selection(int col, int row, int repeated_click);
- void clip_process_selection(int button, int col, int row, int_u 
repeated_click);
- void clip_may_redraw_selection(int row, int col, int len);
- void clip_clear_selection(Clipboard_T *cbd);
- void clip_may_clear_selection(int row1, int row2);
- void clip_scroll_selection(int rows);
- void clip_copy_modeless_selection(int both);
- void clip_gen_set_selection(Clipboard_T *cbd);
- void clip_gen_request_selection(Clipboard_T *cbd);
- int clip_gen_owner_exists(Clipboard_T *cbd);
- char *check_clipboard_option(void);
  int vim_is_input_buf_full(void);
  int vim_is_input_buf_empty(void);
  int vim_free_in_input_buf(void);
--- 14,19 ----
***************
*** 52,65 ****
  void ui_cursor_shape(void);
  int check_col(int col);
  int check_row(int row);
- void open_app_context(void);
- void x11_setup_atoms(Display *dpy);
- void x11_setup_selection(Widget w);
- void clip_x11_request_selection(Widget myShell, Display *dpy, Clipboard_T 
*cbd);
- void clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd);
- int clip_x11_own_selection(Widget myShell, Clipboard_T *cbd);
- void clip_x11_set_selection(Clipboard_T *cbd);
- void yank_cut_buffer0(Display *dpy, Clipboard_T *cbd);
  void ui_focus_change(int in_focus);
  void im_save_status(long *psave);
  /* vim: set ft=c : */
--- 30,35 ----
*** ../vim-8.2.0442/src/register.c      2020-02-26 13:43:48.646089639 +0100
--- src/register.c      2020-03-24 21:07:55.530635092 +0100
***************
*** 32,47 ****
  static void   put_reedit_in_typebuf(int silent);
  static int    put_in_typebuf(char_u *s, int esc, int colon,
                                                                 int silent);
- static void   free_yank_all(void);
  static int    yank_copy_line(struct block_def *bd, long y_idx);
  #ifdef FEAT_CLIPBOARD
  static void   copy_yank_reg(yankreg_T *reg);
- static void   may_set_selection(void);
  #endif
  static void   dis_msg(char_u *p, int skip_esc);
- #if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
- static void   str_to_reg(yankreg_T *y_ptr, int yank_type, char_u *str, long 
len, long blocklen, int str_list);
- #endif
  
      yankreg_T *
  get_y_regs(void)
--- 32,42 ----
***************
*** 50,55 ****
--- 45,56 ----
  }
  
      yankreg_T *
+ get_y_register(int reg)
+ {
+     return &y_regs[reg];
+ }
+ 
+     yankreg_T *
  get_y_current(void)
  {
      return y_current;
***************
*** 62,67 ****
--- 63,74 ----
  }
  
      void
+ set_y_current(yankreg_T *yreg)
+ {
+     y_current = yreg;
+ }
+ 
+     void
  set_y_previous(yankreg_T *yreg)
  {
      y_previous = yreg;
***************
*** 241,272 ****
      return ret;
  }
  
- #if defined(FEAT_CLIPBOARD) || defined(PROTO)
- /*
-  * When "regname" is a clipboard register, obtain the selection.  If it's not
-  * available return zero, otherwise return "regname".
-  */
-     int
- may_get_selection(int regname)
- {
-     if (regname == '*')
-     {
-       if (!clip_star.available)
-           regname = 0;
-       else
-           clip_get_selection(&clip_star);
-     }
-     else if (regname == '+')
-     {
-       if (!clip_plus.available)
-           regname = 0;
-       else
-           clip_get_selection(&clip_plus);
-     }
-     return regname;
- }
- #endif
- 
  /*
   * Obtain the contents of a "normal" register. The register is made empty.
   * The returned pointer has allocated memory, use put_register() later.
--- 248,253 ----
***************
*** 883,914 ****
      return OK;
  }
  
- #if defined(FEAT_CLIPBOARD) || defined(PROTO)
- /*
-  * Adjust the register name pointed to with "rp" for the clipboard being
-  * used always and the clipboard being available.
-  */
-     void
- adjust_clip_reg(int *rp)
- {
-     // If no reg. specified, and "unnamed" or "unnamedplus" is in 'clipboard',
-     // use '*' or '+' reg, respectively. "unnamedplus" prevails.
-     if (*rp == 0 && (clip_unnamed != 0 || clip_unnamed_saved != 0))
-     {
-       if (clip_unnamed != 0)
-           *rp = ((clip_unnamed & CLIP_UNNAMED_PLUS) && clip_plus.available)
-                                                                 ? '+' : '*';
-       else
-           *rp = ((clip_unnamed_saved & CLIP_UNNAMED_PLUS)
-                                          && clip_plus.available) ? '+' : '*';
-     }
-     if (!clip_star.available && *rp == '*')
-       *rp = 0;
-     if (!clip_plus.available && *rp == '+')
-       *rp = 0;
- }
- #endif
- 
  /*
   * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
   */
--- 864,869 ----
***************
*** 1050,1056 ****
      }
  }
  
!     static void
  free_yank_all(void)
  {
      free_yank(y_current->y_size);
--- 1005,1011 ----
      }
  }
  
!     void
  free_yank_all(void)
  {
      free_yank(y_current->y_size);
***************
*** 2348,2533 ****
      ui_breakcheck();
  }
  
- #if defined(FEAT_CLIPBOARD) || defined(PROTO)
-     void
- clip_free_selection(Clipboard_T *cbd)
- {
-     yankreg_T *y_ptr = y_current;
- 
-     if (cbd == &clip_plus)
-       y_current = &y_regs[PLUS_REGISTER];
-     else
-       y_current = &y_regs[STAR_REGISTER];
-     free_yank_all();
-     y_current->y_size = 0;
-     y_current = y_ptr;
- }
- 
- /*
-  * Get the selected text and put it in register '*' or '+'.
-  */
-     void
- clip_get_selection(Clipboard_T *cbd)
- {
-     yankreg_T *old_y_previous, *old_y_current;
-     pos_T     old_cursor;
-     pos_T     old_visual;
-     int               old_visual_mode;
-     colnr_T   old_curswant;
-     int               old_set_curswant;
-     pos_T     old_op_start, old_op_end;
-     oparg_T   oa;
-     cmdarg_T  ca;
- 
-     if (cbd->owned)
-     {
-       if ((cbd == &clip_plus && y_regs[PLUS_REGISTER].y_array != NULL)
-               || (cbd == &clip_star && y_regs[STAR_REGISTER].y_array != NULL))
-           return;
- 
-       // Get the text between clip_star.start & clip_star.end
-       old_y_previous = y_previous;
-       old_y_current = y_current;
-       old_cursor = curwin->w_cursor;
-       old_curswant = curwin->w_curswant;
-       old_set_curswant = curwin->w_set_curswant;
-       old_op_start = curbuf->b_op_start;
-       old_op_end = curbuf->b_op_end;
-       old_visual = VIsual;
-       old_visual_mode = VIsual_mode;
-       clear_oparg(&oa);
-       oa.regname = (cbd == &clip_plus ? '+' : '*');
-       oa.op_type = OP_YANK;
-       vim_memset(&ca, 0, sizeof(ca));
-       ca.oap = &oa;
-       ca.cmdchar = 'y';
-       ca.count1 = 1;
-       ca.retval = CA_NO_ADJ_OP_END;
-       do_pending_operator(&ca, 0, TRUE);
-       y_previous = old_y_previous;
-       y_current = old_y_current;
-       curwin->w_cursor = old_cursor;
-       changed_cline_bef_curs();   // need to update w_virtcol et al
-       curwin->w_curswant = old_curswant;
-       curwin->w_set_curswant = old_set_curswant;
-       curbuf->b_op_start = old_op_start;
-       curbuf->b_op_end = old_op_end;
-       VIsual = old_visual;
-       VIsual_mode = old_visual_mode;
-     }
-     else if (!is_clipboard_needs_update())
-     {
-       clip_free_selection(cbd);
- 
-       // Try to get selected text from another window
-       clip_gen_request_selection(cbd);
-     }
- }
- 
- /*
-  * Convert from the GUI selection string into the '*'/'+' register.
-  */
-     void
- clip_yank_selection(
-     int               type,
-     char_u    *str,
-     long      len,
-     Clipboard_T *cbd)
- {
-     yankreg_T *y_ptr;
- 
-     if (cbd == &clip_plus)
-       y_ptr = &y_regs[PLUS_REGISTER];
-     else
-       y_ptr = &y_regs[STAR_REGISTER];
- 
-     clip_free_selection(cbd);
- 
-     str_to_reg(y_ptr, type, str, len, 0L, FALSE);
- }
- 
- /*
-  * Convert the '*'/'+' register into a GUI selection string returned in *str
-  * with length *len.
-  * Returns the motion type, or -1 for failure.
-  */
-     int
- clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd)
- {
-     char_u    *p;
-     int               lnum;
-     int               i, j;
-     int_u     eolsize;
-     yankreg_T *y_ptr;
- 
-     if (cbd == &clip_plus)
-       y_ptr = &y_regs[PLUS_REGISTER];
-     else
-       y_ptr = &y_regs[STAR_REGISTER];
- 
- # ifdef USE_CRNL
-     eolsize = 2;
- # else
-     eolsize = 1;
- # endif
- 
-     *str = NULL;
-     *len = 0;
-     if (y_ptr->y_array == NULL)
-       return -1;
- 
-     for (i = 0; i < y_ptr->y_size; i++)
-       *len += (long_u)STRLEN(y_ptr->y_array[i]) + eolsize;
- 
-     // Don't want newline character at end of last line if we're in MCHAR 
mode.
-     if (y_ptr->y_type == MCHAR && *len >= eolsize)
-       *len -= eolsize;
- 
-     p = *str = alloc(*len + 1);       // add one to avoid zero
-     if (p == NULL)
-       return -1;
-     lnum = 0;
-     for (i = 0, j = 0; i < (int)*len; i++, j++)
-     {
-       if (y_ptr->y_array[lnum][j] == '\n')
-           p[i] = NUL;
-       else if (y_ptr->y_array[lnum][j] == NUL)
-       {
- # ifdef USE_CRNL
-           p[i++] = '\r';
- # endif
-           p[i] = '\n';
-           lnum++;
-           j = -1;
-       }
-       else
-           p[i] = y_ptr->y_array[lnum][j];
-     }
-     return y_ptr->y_type;
- }
- 
- 
- /*
-  * If we have written to a clipboard register, send the text to the clipboard.
-  */
-     static void
- may_set_selection(void)
- {
-     if (y_current == &(y_regs[STAR_REGISTER]) && clip_star.available)
-     {
-       clip_own_selection(&clip_star);
-       clip_gen_set_selection(&clip_star);
-     }
-     else if (y_current == &(y_regs[PLUS_REGISTER]) && clip_plus.available)
-     {
-       clip_own_selection(&clip_plus);
-       clip_gen_set_selection(&clip_plus);
-     }
- }
- 
- #endif // FEAT_CLIPBOARD || PROTO
- 
- 
  #if defined(FEAT_DND) || defined(PROTO)
  /*
   * Replace the contents of the '~' register with str.
--- 2303,2308 ----
***************
*** 2900,2906 ****
   * Put a string into a register.  When the register is not empty, the string
   * is appended.
   */
!     static void
  str_to_reg(
      yankreg_T *y_ptr,         // pointer to yank register
      int               yank_type,      // MCHAR, MLINE, MBLOCK, MAUTO
--- 2675,2681 ----
   * Put a string into a register.  When the register is not empty, the string
   * is appended.
   */
!     void
  str_to_reg(
      yankreg_T *y_ptr,         // pointer to yank register
      int               yank_type,      // MCHAR, MLINE, MBLOCK, MAUTO
*** ../vim-8.2.0442/src/ui.c    2020-03-23 19:17:25.877431605 +0100
--- src/ui.c    2020-03-24 21:07:55.530635092 +0100
***************
*** 12,29 ****
   * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
   *    before the machine specific stuff (mch_*) so that we can call the GUI
   *    stuff instead if the GUI is running.
!  * 2. Clipboard stuff.
!  * 3. Input buffer stuff.
   */
  
  #include "vim.h"
  
- #ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
- # define WIN32_LEAN_AND_MEAN
- # include <windows.h>
- # include "winclip.pro"
- #endif
- 
      void
  ui_write(char_u *s, int len)
  {
--- 12,22 ----
   * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
   *    before the machine specific stuff (mch_*) so that we can call the GUI
   *    stuff instead if the GUI is running.
!  * 2. Input buffer stuff.
   */
  
  #include "vim.h"
  
      void
  ui_write(char_u *s, int len)
  {
***************
*** 712,2042 ****
  }
  
  //////////////////////////////////////////////////////////////////////////////
- // Functions for copying and pasting text between applications.
- // This is always included in a GUI version, but may also be included when the
- // clipboard and mouse is available to a terminal version such as xterm.
- // Note: there are some more functions in ops.c that handle selection stuff.
- //
- // Also note that the majority of functions here deal with the X 'primary'
- // (visible - for Visual mode use) selection, and only that. There are no
- // versions of these for the 'clipboard' selection, as Visual mode has no use
- // for them.
- 
- #if defined(FEAT_CLIPBOARD) || defined(PROTO)
- 
- static void clip_gen_lose_selection(Clipboard_T *cbd);
- static int clip_gen_own_selection(Clipboard_T *cbd);
- #if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)
- static int clip_x11_owner_exists(Clipboard_T *cbd);
- #endif
- 
- /*
-  * Selection stuff using Visual mode, for cutting and pasting text to other
-  * windows.
-  */
- 
- /*
-  * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
-  * is included, but the clipboard can not be used, or TRUE if the clipboard 
can
-  * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
-  * the GUI starts.
-  */
-     void
- clip_init(int can_use)
- {
-     Clipboard_T *cb;
- 
-     cb = &clip_star;
-     for (;;)
-     {
-       cb->available  = can_use;
-       cb->owned      = FALSE;
-       cb->start.lnum = 0;
-       cb->start.col  = 0;
-       cb->end.lnum   = 0;
-       cb->end.col    = 0;
-       cb->state      = SELECT_CLEARED;
- 
-       if (cb == &clip_plus)
-           break;
-       cb = &clip_plus;
-     }
- }
- 
- /*
-  * Check whether the VIsual area has changed, and if so try to become the 
owner
-  * of the selection, and free any old converted selection we may still have
-  * lying around.  If the VIsual mode has ended, make a copy of what was
-  * selected so we can still give it to others.        Will probably have to 
make sure
-  * this is called whenever VIsual mode is ended.
-  */
-     void
- clip_update_selection(Clipboard_T *clip)
- {
-     pos_T         start, end;
- 
-     // If visual mode is only due to a redo command ("."), then ignore it
-     if (!redo_VIsual_busy && VIsual_active && (State & NORMAL))
-     {
-       if (LT_POS(VIsual, curwin->w_cursor))
-       {
-           start = VIsual;
-           end = curwin->w_cursor;
-           if (has_mbyte)
-               end.col += (*mb_ptr2len)(ml_get_cursor()) - 1;
-       }
-       else
-       {
-           start = curwin->w_cursor;
-           end = VIsual;
-       }
-       if (!EQUAL_POS(clip->start, start)
-               || !EQUAL_POS(clip->end, end)
-               || clip->vmode != VIsual_mode)
-       {
-           clip_clear_selection(clip);
-           clip->start = start;
-           clip->end = end;
-           clip->vmode = VIsual_mode;
-           clip_free_selection(clip);
-           clip_own_selection(clip);
-           clip_gen_set_selection(clip);
-       }
-     }
- }
- 
-     void
- clip_own_selection(Clipboard_T *cbd)
- {
-     /*
-      * Also want to check somehow that we are reading from the keyboard rather
-      * than a mapping etc.
-      */
- #ifdef FEAT_X11
-     // Always own the selection, we might have lost it without being
-     // notified, e.g. during a ":sh" command.
-     if (cbd->available)
-     {
-       int was_owned = cbd->owned;
- 
-       cbd->owned = (clip_gen_own_selection(cbd) == OK);
-       if (!was_owned && (cbd == &clip_star || cbd == &clip_plus))
-       {
-           // May have to show a different kind of highlighting for the
-           // selected area.  There is no specific redraw command for this,
-           // just redraw all windows on the current buffer.
-           if (cbd->owned
-                   && (get_real_state() == VISUAL
-                                           || get_real_state() == SELECTMODE)
-                   && (cbd == &clip_star ? clip_isautosel_star()
-                                                     : clip_isautosel_plus())
-                   && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
-               redraw_curbuf_later(INVERTED_ALL);
-       }
-     }
- #else
-     // Only own the clipboard when we didn't own it yet.
-     if (!cbd->owned && cbd->available)
-       cbd->owned = (clip_gen_own_selection(cbd) == OK);
- #endif
- }
- 
-     void
- clip_lose_selection(Clipboard_T *cbd)
- {
- #ifdef FEAT_X11
-     int           was_owned = cbd->owned;
- #endif
-     int     visual_selection = FALSE;
- 
-     if (cbd == &clip_star || cbd == &clip_plus)
-       visual_selection = TRUE;
- 
-     clip_free_selection(cbd);
-     cbd->owned = FALSE;
-     if (visual_selection)
-       clip_clear_selection(cbd);
-     clip_gen_lose_selection(cbd);
- #ifdef FEAT_X11
-     if (visual_selection)
-     {
-       // May have to show a different kind of highlighting for the selected
-       // area.  There is no specific redraw command for this, just redraw all
-       // windows on the current buffer.
-       if (was_owned
-               && (get_real_state() == VISUAL
-                                           || get_real_state() == SELECTMODE)
-               && (cbd == &clip_star ?
-                               clip_isautosel_star() : clip_isautosel_plus())
-               && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
-       {
-           update_curbuf(INVERTED_ALL);
-           setcursor();
-           cursor_on();
-           out_flush_cursor(TRUE, FALSE);
-       }
-     }
- #endif
- }
- 
-     static void
- clip_copy_selection(Clipboard_T *clip)
- {
-     if (VIsual_active && (State & NORMAL) && clip->available)
-     {
-       clip_update_selection(clip);
-       clip_free_selection(clip);
-       clip_own_selection(clip);
-       if (clip->owned)
-           clip_get_selection(clip);
-       clip_gen_set_selection(clip);
-     }
- }
- 
- /*
-  * Save and restore clip_unnamed before doing possibly many changes. This
-  * prevents accessing the clipboard very often which might slow down Vim
-  * considerably.
-  */
- static int global_change_count = 0; // if set, inside a start_global_changes
- static int clipboard_needs_update = FALSE; // clipboard needs to be updated
- static int clip_did_set_selection = TRUE;
- 
- /*
-  * Save clip_unnamed and reset it.
-  */
-     void
- start_global_changes(void)
- {
-     if (++global_change_count > 1)
-       return;
-     clip_unnamed_saved = clip_unnamed;
-     clipboard_needs_update = FALSE;
- 
-     if (clip_did_set_selection)
-     {
-       clip_unnamed = 0;
-       clip_did_set_selection = FALSE;
-     }
- }
- 
- /*
-  * Return TRUE if setting the clipboard was postponed, it already contains the
-  * right text.
-  */
-     int
- is_clipboard_needs_update()
- {
-     return clipboard_needs_update;
- }
- 
- /*
-  * Restore clip_unnamed and set the selection when needed.
-  */
-     void
- end_global_changes(void)
- {
-     if (--global_change_count > 0)
-       // recursive
-       return;
-     if (!clip_did_set_selection)
-     {
-       clip_did_set_selection = TRUE;
-       clip_unnamed = clip_unnamed_saved;
-       clip_unnamed_saved = 0;
-       if (clipboard_needs_update)
-       {
-           // only store something in the clipboard,
-           // if we have yanked anything to it
-           if (clip_unnamed & CLIP_UNNAMED)
-           {
-               clip_own_selection(&clip_star);
-               clip_gen_set_selection(&clip_star);
-           }
-           if (clip_unnamed & CLIP_UNNAMED_PLUS)
-           {
-               clip_own_selection(&clip_plus);
-               clip_gen_set_selection(&clip_plus);
-           }
-       }
-     }
-     clipboard_needs_update = FALSE;
- }
- 
- /*
-  * Called when Visual mode is ended: update the selection.
-  */
-     void
- clip_auto_select(void)
- {
-     if (clip_isautosel_star())
-       clip_copy_selection(&clip_star);
-     if (clip_isautosel_plus())
-       clip_copy_selection(&clip_plus);
- }
- 
- /*
-  * Return TRUE if automatic selection of Visual area is desired for the *
-  * register.
-  */
-     int
- clip_isautosel_star(void)
- {
-     return (
- #ifdef FEAT_GUI
-           gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) :
- #endif
-           clip_autoselect_star);
- }
- 
- /*
-  * Return TRUE if automatic selection of Visual area is desired for the +
-  * register.
-  */
-     int
- clip_isautosel_plus(void)
- {
-     return (
- #ifdef FEAT_GUI
-           gui.in_use ? (vim_strchr(p_go, GO_ASELPLUS) != NULL) :
- #endif
-           clip_autoselect_plus);
- }
- 
- 
- /*
-  * Stuff for general mouse selection, without using Visual mode.
-  */
- 
- static void clip_invert_area(Clipboard_T *, int, int, int, int, int how);
- static void clip_invert_rectangle(Clipboard_T *, int row, int col, int 
height, int width, int invert);
- static void clip_get_word_boundaries(Clipboard_T *, int, int);
- static int  clip_get_line_end(Clipboard_T *, int);
- static void clip_update_modeless_selection(Clipboard_T *, int, int, int, int);
- 
- // "how" flags for clip_invert_area()
- #define CLIP_CLEAR    1
- #define CLIP_SET      2
- #define CLIP_TOGGLE   3
- 
- /*
-  * Start, continue or end a modeless selection.  Used when editing the
-  * command-line, in the cmdline window and when the mouse is in a popup 
window.
-  */
-     void
- clip_modeless(int button, int is_click, int is_drag)
- {
-     int               repeat;
- 
-     repeat = ((clip_star.mode == SELECT_MODE_CHAR
-               || clip_star.mode == SELECT_MODE_LINE)
-                                             && (mod_mask & MOD_MASK_2CLICK))
-           || (clip_star.mode == SELECT_MODE_WORD
-                                            && (mod_mask & MOD_MASK_3CLICK));
-     if (is_click && button == MOUSE_RIGHT)
-     {
-       // Right mouse button: If there was no selection, start one.
-       // Otherwise extend the existing selection.
-       if (clip_star.state == SELECT_CLEARED)
-           clip_start_selection(mouse_col, mouse_row, FALSE);
-       clip_process_selection(button, mouse_col, mouse_row, repeat);
-     }
-     else if (is_click)
-       clip_start_selection(mouse_col, mouse_row, repeat);
-     else if (is_drag)
-     {
-       // Don't try extending a selection if there isn't one.  Happens when
-       // button-down is in the cmdline and then moving mouse upwards.
-       if (clip_star.state != SELECT_CLEARED)
-           clip_process_selection(button, mouse_col, mouse_row, repeat);
-     }
-     else // release
-       clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE);
- }
- 
- /*
-  * Compare two screen positions ala strcmp()
-  */
-     static int
- clip_compare_pos(
-     int               row1,
-     int               col1,
-     int               row2,
-     int               col2)
- {
-     if (row1 > row2) return(1);
-     if (row1 < row2) return(-1);
-     if (col1 > col2) return(1);
-     if (col1 < col2) return(-1);
-     return(0);
- }
- 
- /*
-  * Start the selection
-  */
-     void
- clip_start_selection(int col, int row, int repeated_click)
- {
-     Clipboard_T       *cb = &clip_star;
- #ifdef FEAT_PROP_POPUP
-     win_T     *wp;
-     int               row_cp = row;
-     int               col_cp = col;
- 
-     wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP);
-     if (wp != NULL && WIN_IS_POPUP(wp)
-                                 && popup_is_in_scrollbar(wp, row_cp, col_cp))
-       // click or double click in scrollbar does not start a selection
-       return;
- #endif
- 
-     if (cb->state == SELECT_DONE)
-       clip_clear_selection(cb);
- 
-     row = check_row(row);
-     col = check_col(col);
-     col = mb_fix_col(col, row);
- 
-     cb->start.lnum  = row;
-     cb->start.col   = col;
-     cb->end       = cb->start;
-     cb->origin_row  = (short_u)cb->start.lnum;
-     cb->state     = SELECT_IN_PROGRESS;
- #ifdef FEAT_PROP_POPUP
-     if (wp != NULL && WIN_IS_POPUP(wp))
-     {
-       // Click in a popup window restricts selection to that window,
-       // excluding the border.
-       cb->min_col = wp->w_wincol + wp->w_popup_border[3];
-       cb->max_col = wp->w_wincol + popup_width(wp)
-                                - wp->w_popup_border[1] - wp->w_has_scrollbar;
-       if (cb->max_col > screen_Columns)
-           cb->max_col = screen_Columns;
-       cb->min_row = wp->w_winrow + wp->w_popup_border[0];
-       cb->max_row = wp->w_winrow + popup_height(wp) - 1
-                                                  - wp->w_popup_border[2];
-     }
-     else
-     {
-       cb->min_col = 0;
-       cb->max_col = screen_Columns;
-       cb->min_row = 0;
-       cb->max_row = screen_Rows;
-     }
- #endif
- 
-     if (repeated_click)
-     {
-       if (++cb->mode > SELECT_MODE_LINE)
-           cb->mode = SELECT_MODE_CHAR;
-     }
-     else
-       cb->mode = SELECT_MODE_CHAR;
- 
- #ifdef FEAT_GUI
-     // clear the cursor until the selection is made
-     if (gui.in_use)
-       gui_undraw_cursor();
- #endif
- 
-     switch (cb->mode)
-     {
-       case SELECT_MODE_CHAR:
-           cb->origin_start_col = cb->start.col;
-           cb->word_end_col = clip_get_line_end(cb, (int)cb->start.lnum);
-           break;
- 
-       case SELECT_MODE_WORD:
-           clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
-           cb->origin_start_col = cb->word_start_col;
-           cb->origin_end_col   = cb->word_end_col;
- 
-           clip_invert_area(cb, (int)cb->start.lnum, cb->word_start_col,
-                           (int)cb->end.lnum, cb->word_end_col, CLIP_SET);
-           cb->start.col = cb->word_start_col;
-           cb->end.col   = cb->word_end_col;
-           break;
- 
-       case SELECT_MODE_LINE:
-           clip_invert_area(cb, (int)cb->start.lnum, 0, (int)cb->start.lnum,
-                           (int)Columns, CLIP_SET);
-           cb->start.col = 0;
-           cb->end.col   = Columns;
-           break;
-     }
- 
-     cb->prev = cb->start;
- 
- #ifdef DEBUG_SELECTION
-     printf("Selection started at (%ld,%d)\n", cb->start.lnum, cb->start.col);
- #endif
- }
- 
- /*
-  * Continue processing the selection
-  */
-     void
- clip_process_selection(
-     int               button,
-     int               col,
-     int               row,
-     int_u     repeated_click)
- {
-     Clipboard_T       *cb = &clip_star;
-     int               diff;
-     int               slen = 1;       // cursor shape width
- 
-     if (button == MOUSE_RELEASE)
-     {
-       if (cb->state != SELECT_IN_PROGRESS)
-           return;
- 
-       // Check to make sure we have something selected
-       if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
-       {
- #ifdef FEAT_GUI
-           if (gui.in_use)
-               gui_update_cursor(FALSE, FALSE);
- #endif
-           cb->state = SELECT_CLEARED;
-           return;
-       }
- 
- #ifdef DEBUG_SELECTION
-       printf("Selection ended: (%ld,%d) to (%ld,%d)\n", cb->start.lnum,
-               cb->start.col, cb->end.lnum, cb->end.col);
- #endif
-       if (clip_isautosel_star()
-               || (
- #ifdef FEAT_GUI
-                   gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) :
- #endif
-                   clip_autoselectml))
-           clip_copy_modeless_selection(FALSE);
- #ifdef FEAT_GUI
-       if (gui.in_use)
-           gui_update_cursor(FALSE, FALSE);
- #endif
- 
-       cb->state = SELECT_DONE;
-       return;
-     }
- 
-     row = check_row(row);
-     col = check_col(col);
-     col = mb_fix_col(col, row);
- 
-     if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click)
-       return;
- 
-     /*
-      * When extending the selection with the right mouse button, swap the
-      * start and end if the position is before half the selection
-      */
-     if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
-     {
-       /*
-        * If the click is before the start, or the click is inside the
-        * selection and the start is the closest side, set the origin to the
-        * end of the selection.
-        */
-       if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
-               || (clip_compare_pos(row, col,
-                                          (int)cb->end.lnum, cb->end.col) < 0
-                   && (((cb->start.lnum == cb->end.lnum
-                           && cb->end.col - col > col - cb->start.col))
-                       || ((diff = (cb->end.lnum - row) -
-                                                  (row - cb->start.lnum)) > 0
-                           || (diff == 0 && col < (int)(cb->start.col +
-                                                        cb->end.col) / 2)))))
-       {
-           cb->origin_row = (short_u)cb->end.lnum;
-           cb->origin_start_col = cb->end.col - 1;
-           cb->origin_end_col = cb->end.col;
-       }
-       else
-       {
-           cb->origin_row = (short_u)cb->start.lnum;
-           cb->origin_start_col = cb->start.col;
-           cb->origin_end_col = cb->start.col;
-       }
-       if (cb->mode == SELECT_MODE_WORD && !repeated_click)
-           cb->mode = SELECT_MODE_CHAR;
-     }
- 
-     // set state, for when using the right mouse button
-     cb->state = SELECT_IN_PROGRESS;
- 
- #ifdef DEBUG_SELECTION
-     printf("Selection extending to (%d,%d)\n", row, col);
- #endif
- 
-     if (repeated_click && ++cb->mode > SELECT_MODE_LINE)
-       cb->mode = SELECT_MODE_CHAR;
- 
-     switch (cb->mode)
-     {
-       case SELECT_MODE_CHAR:
-           // If we're on a different line, find where the line ends
-           if (row != cb->prev.lnum)
-               cb->word_end_col = clip_get_line_end(cb, row);
- 
-           // See if we are before or after the origin of the selection
-           if (clip_compare_pos(row, col, cb->origin_row,
-                                                  cb->origin_start_col) >= 0)
-           {
-               if (col >= (int)cb->word_end_col)
-                   clip_update_modeless_selection(cb, cb->origin_row,
-                           cb->origin_start_col, row, (int)Columns);
-               else
-               {
-                   if (has_mbyte && mb_lefthalve(row, col))
-                       slen = 2;
-                   clip_update_modeless_selection(cb, cb->origin_row,
-                           cb->origin_start_col, row, col + slen);
-               }
-           }
-           else
-           {
-               if (has_mbyte
-                       && mb_lefthalve(cb->origin_row, cb->origin_start_col))
-                   slen = 2;
-               if (col >= (int)cb->word_end_col)
-                   clip_update_modeless_selection(cb, row, cb->word_end_col,
-                           cb->origin_row, cb->origin_start_col + slen);
-               else
-                   clip_update_modeless_selection(cb, row, col,
-                           cb->origin_row, cb->origin_start_col + slen);
-           }
-           break;
- 
-       case SELECT_MODE_WORD:
-           // If we are still within the same word, do nothing
-           if (row == cb->prev.lnum && col >= (int)cb->word_start_col
-                   && col < (int)cb->word_end_col && !repeated_click)
-               return;
- 
-           // Get new word boundaries
-           clip_get_word_boundaries(cb, row, col);
- 
-           // Handle being after the origin point of selection
-           if (clip_compare_pos(row, col, cb->origin_row,
-                   cb->origin_start_col) >= 0)
-               clip_update_modeless_selection(cb, cb->origin_row,
-                       cb->origin_start_col, row, cb->word_end_col);
-           else
-               clip_update_modeless_selection(cb, row, cb->word_start_col,
-                       cb->origin_row, cb->origin_end_col);
-           break;
- 
-       case SELECT_MODE_LINE:
-           if (row == cb->prev.lnum && !repeated_click)
-               return;
- 
-           if (clip_compare_pos(row, col, cb->origin_row,
-                   cb->origin_start_col) >= 0)
-               clip_update_modeless_selection(cb, cb->origin_row, 0, row,
-                       (int)Columns);
-           else
-               clip_update_modeless_selection(cb, row, 0, cb->origin_row,
-                       (int)Columns);
-           break;
-     }
- 
-     cb->prev.lnum = row;
-     cb->prev.col  = col;
- 
- #ifdef DEBUG_SELECTION
-       printf("Selection is: (%ld,%d) to (%ld,%d)\n", cb->start.lnum,
-               cb->start.col, cb->end.lnum, cb->end.col);
- #endif
- }
- 
- # if defined(FEAT_GUI) || defined(PROTO)
- /*
-  * Redraw part of the selection if character at "row,col" is inside of it.
-  * Only used for the GUI.
-  */
-     void
- clip_may_redraw_selection(int row, int col, int len)
- {
-     int               start = col;
-     int               end = col + len;
- 
-     if (clip_star.state != SELECT_CLEARED
-           && row >= clip_star.start.lnum
-           && row <= clip_star.end.lnum)
-     {
-       if (row == clip_star.start.lnum && start < (int)clip_star.start.col)
-           start = clip_star.start.col;
-       if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
-           end = clip_star.end.col;
-       if (end > start)
-           clip_invert_area(&clip_star, row, start, row, end, 0);
-     }
- }
- # endif
- 
- /*
-  * Called from outside to clear selected region from the display
-  */
-     void
- clip_clear_selection(Clipboard_T *cbd)
- {
- 
-     if (cbd->state == SELECT_CLEARED)
-       return;
- 
-     clip_invert_area(cbd, (int)cbd->start.lnum, cbd->start.col,
-                                (int)cbd->end.lnum, cbd->end.col, CLIP_CLEAR);
-     cbd->state = SELECT_CLEARED;
- }
- 
- /*
-  * Clear the selection if any lines from "row1" to "row2" are inside of it.
-  */
-     void
- clip_may_clear_selection(int row1, int row2)
- {
-     if (clip_star.state == SELECT_DONE
-           && row2 >= clip_star.start.lnum
-           && row1 <= clip_star.end.lnum)
-       clip_clear_selection(&clip_star);
- }
- 
- /*
-  * Called before the screen is scrolled up or down.  Adjusts the line numbers
-  * of the selection.  Call with big number when clearing the screen.
-  */
-     void
- clip_scroll_selection(
-     int           rows)               // negative for scroll down
- {
-     int           lnum;
- 
-     if (clip_star.state == SELECT_CLEARED)
-       return;
- 
-     lnum = clip_star.start.lnum - rows;
-     if (lnum <= 0)
-       clip_star.start.lnum = 0;
-     else if (lnum >= screen_Rows)     // scrolled off of the screen
-       clip_star.state = SELECT_CLEARED;
-     else
-       clip_star.start.lnum = lnum;
- 
-     lnum = clip_star.end.lnum - rows;
-     if (lnum < 0)                     // scrolled off of the screen
-       clip_star.state = SELECT_CLEARED;
-     else if (lnum >= screen_Rows)
-       clip_star.end.lnum = screen_Rows - 1;
-     else
-       clip_star.end.lnum = lnum;
- }
- 
- /*
-  * Invert a region of the display between a starting and ending row and column
-  * Values for "how":
-  * CLIP_CLEAR:  undo inversion
-  * CLIP_SET:    set inversion
-  * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise.
-  * 0: invert (GUI only).
-  */
-     static void
- clip_invert_area(
-       Clipboard_T     *cbd,
-       int             row1,
-       int             col1,
-       int             row2,
-       int             col2,
-       int             how)
- {
-     int               invert = FALSE;
-     int               max_col;
- 
- #ifdef FEAT_PROP_POPUP
-     max_col = cbd->max_col - 1;
- #else
-     max_col = Columns - 1;
- #endif
- 
-     if (how == CLIP_SET)
-       invert = TRUE;
- 
-     // Swap the from and to positions so the from is always before
-     if (clip_compare_pos(row1, col1, row2, col2) > 0)
-     {
-       int tmp_row, tmp_col;
- 
-       tmp_row = row1;
-       tmp_col = col1;
-       row1    = row2;
-       col1    = col2;
-       row2    = tmp_row;
-       col2    = tmp_col;
-     }
-     else if (how == CLIP_TOGGLE)
-       invert = TRUE;
- 
-     // If all on the same line, do it the easy way
-     if (row1 == row2)
-     {
-       clip_invert_rectangle(cbd, row1, col1, 1, col2 - col1, invert);
-     }
-     else
-     {
-       // Handle a piece of the first line
-       if (col1 > 0)
-       {
-           clip_invert_rectangle(cbd, row1, col1, 1,
-                                                 (int)Columns - col1, invert);
-           row1++;
-       }
- 
-       // Handle a piece of the last line
-       if (col2 < max_col)
-       {
-           clip_invert_rectangle(cbd, row2, 0, 1, col2, invert);
-           row2--;
-       }
- 
-       // Handle the rectangle that's left
-       if (row2 >= row1)
-           clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1,
-                                                        (int)Columns, invert);
-     }
- }
- 
- /*
-  * Invert or un-invert a rectangle of the screen.
-  * "invert" is true if the result is inverted.
-  */
-     static void
- clip_invert_rectangle(
-       Clipboard_T     *cbd UNUSED,
-       int             row_arg,
-       int             col_arg,
-       int             height_arg,
-       int             width_arg,
-       int             invert)
- {
-     int               row = row_arg;
-     int               col = col_arg;
-     int               height = height_arg;
-     int               width = width_arg;
- 
- #ifdef FEAT_PROP_POPUP
-     // this goes on top of all popup windows
-     screen_zindex = CLIP_ZINDEX;
- 
-     if (col < cbd->min_col)
-     {
-       width -= cbd->min_col - col;
-       col = cbd->min_col;
-     }
-     if (width > cbd->max_col - col)
-       width = cbd->max_col - col;
-     if (row < cbd->min_row)
-     {
-       height -= cbd->min_row - row;
-       row = cbd->min_row;
-     }
-     if (height > cbd->max_row - row + 1)
-       height = cbd->max_row - row + 1;
- #endif
- #ifdef FEAT_GUI
-     if (gui.in_use)
-       gui_mch_invert_rectangle(row, col, height, width);
-     else
- #endif
-       screen_draw_rectangle(row, col, height, width, invert);
- #ifdef FEAT_PROP_POPUP
-     screen_zindex = 0;
- #endif
- }
- 
- /*
-  * Copy the currently selected area into the '*' register so it will be
-  * available for pasting.
-  * When "both" is TRUE also copy to the '+' register.
-  */
-     void
- clip_copy_modeless_selection(int both UNUSED)
- {
-     char_u    *buffer;
-     char_u    *bufp;
-     int               row;
-     int               start_col;
-     int               end_col;
-     int               line_end_col;
-     int               add_newline_flag = FALSE;
-     int               len;
-     char_u    *p;
-     int               row1 = clip_star.start.lnum;
-     int               col1 = clip_star.start.col;
-     int               row2 = clip_star.end.lnum;
-     int               col2 = clip_star.end.col;
- 
-     // Can't use ScreenLines unless initialized
-     if (ScreenLines == NULL)
-       return;
- 
-     /*
-      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
-      */
-     if (row1 > row2)
-     {
-       row = row1; row1 = row2; row2 = row;
-       row = col1; col1 = col2; col2 = row;
-     }
-     else if (row1 == row2 && col1 > col2)
-     {
-       row = col1; col1 = col2; col2 = row;
-     }
- #ifdef FEAT_PROP_POPUP
-     if (col1 < clip_star.min_col)
-       col1 = clip_star.min_col;
-     if (col2 > clip_star.max_col)
-       col2 = clip_star.max_col;
-     if (row1 > clip_star.max_row || row2 < clip_star.min_row)
-       return;
-     if (row1 < clip_star.min_row)
-       row1 = clip_star.min_row;
-     if (row2 > clip_star.max_row)
-       row2 = clip_star.max_row;
- #endif
-     // correct starting point for being on right halve of double-wide char
-     p = ScreenLines + LineOffset[row1];
-     if (enc_dbcs != 0)
-       col1 -= (*mb_head_off)(p, p + col1);
-     else if (enc_utf8 && p[col1] == 0)
-       --col1;
- 
-     // Create a temporary buffer for storing the text
-     len = (row2 - row1 + 1) * Columns + 1;
-     if (enc_dbcs != 0)
-       len *= 2;       // max. 2 bytes per display cell
-     else if (enc_utf8)
-       len *= MB_MAXBYTES;
-     buffer = alloc(len);
-     if (buffer == NULL)           // out of memory
-       return;
- 
-     // Process each row in the selection
-     for (bufp = buffer, row = row1; row <= row2; row++)
-     {
-       if (row == row1)
-           start_col = col1;
-       else
- #ifdef FEAT_PROP_POPUP
-           start_col = clip_star.min_col;
- #else
-           start_col = 0;
- #endif
- 
-       if (row == row2)
-           end_col = col2;
-       else
- #ifdef FEAT_PROP_POPUP
-           end_col = clip_star.max_col;
- #else
-           end_col = Columns;
- #endif
- 
-       line_end_col = clip_get_line_end(&clip_star, row);
- 
-       // See if we need to nuke some trailing whitespace
-       if (end_col >=
- #ifdef FEAT_PROP_POPUP
-               clip_star.max_col
- #else
-               Columns
- #endif
-                   && (row < row2 || end_col > line_end_col))
-       {
-           // Get rid of trailing whitespace
-           end_col = line_end_col;
-           if (end_col < start_col)
-               end_col = start_col;
- 
-           // If the last line extended to the end, add an extra newline
-           if (row == row2)
-               add_newline_flag = TRUE;
-       }
- 
-       // If after the first row, we need to always add a newline
-       if (row > row1 && !LineWraps[row - 1])
-           *bufp++ = NL;
- 
-       // Safetey check for in case resizing went wrong
-       if (row < screen_Rows && end_col <= screen_Columns)
-       {
-           if (enc_dbcs != 0)
-           {
-               int     i;
- 
-               p = ScreenLines + LineOffset[row];
-               for (i = start_col; i < end_col; ++i)
-                   if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e)
-                   {
-                       // single-width double-byte char
-                       *bufp++ = 0x8e;
-                       *bufp++ = ScreenLines2[LineOffset[row] + i];
-                   }
-                   else
-                   {
-                       *bufp++ = p[i];
-                       if (MB_BYTE2LEN(p[i]) == 2)
-                           *bufp++ = p[++i];
-                   }
-           }
-           else if (enc_utf8)
-           {
-               int     off;
-               int     i;
-               int     ci;
- 
-               off = LineOffset[row];
-               for (i = start_col; i < end_col; ++i)
-               {
-                   // The base character is either in ScreenLinesUC[] or
-                   // ScreenLines[].
-                   if (ScreenLinesUC[off + i] == 0)
-                       *bufp++ = ScreenLines[off + i];
-                   else
-                   {
-                       bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp);
-                       for (ci = 0; ci < Screen_mco; ++ci)
-                       {
-                           // Add a composing character.
-                           if (ScreenLinesC[ci][off + i] == 0)
-                               break;
-                           bufp += utf_char2bytes(ScreenLinesC[ci][off + i],
-                                                                       bufp);
-                       }
-                   }
-                   // Skip right halve of double-wide character.
-                   if (ScreenLines[off + i + 1] == 0)
-                       ++i;
-               }
-           }
-           else
-           {
-               STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col,
-                                                        end_col - start_col);
-               bufp += end_col - start_col;
-           }
-       }
-     }
- 
-     // Add a newline at the end if the selection ended there
-     if (add_newline_flag)
-       *bufp++ = NL;
- 
-     // First cleanup any old selection and become the owner.
-     clip_free_selection(&clip_star);
-     clip_own_selection(&clip_star);
- 
-     // Yank the text into the '*' register.
-     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star);
- 
-     // Make the register contents available to the outside world.
-     clip_gen_set_selection(&clip_star);
- 
- #ifdef FEAT_X11
-     if (both)
-     {
-       // Do the same for the '+' register.
-       clip_free_selection(&clip_plus);
-       clip_own_selection(&clip_plus);
-       clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus);
-       clip_gen_set_selection(&clip_plus);
-     }
- #endif
-     vim_free(buffer);
- }
- 
- /*
-  * Find the starting and ending positions of the word at the given row and
-  * column.  Only white-separated words are recognized here.
-  */
- #define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c))
- 
-     static void
- clip_get_word_boundaries(Clipboard_T *cb, int row, int col)
- {
-     int               start_class;
-     int               temp_col;
-     char_u    *p;
-     int               mboff;
- 
-     if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL)
-       return;
- 
-     p = ScreenLines + LineOffset[row];
-     // Correct for starting in the right halve of a double-wide char
-     if (enc_dbcs != 0)
-       col -= dbcs_screen_head_off(p, p + col);
-     else if (enc_utf8 && p[col] == 0)
-       --col;
-     start_class = CHAR_CLASS(p[col]);
- 
-     temp_col = col;
-     for ( ; temp_col > 0; temp_col--)
-       if (enc_dbcs != 0
-                  && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0)
-           temp_col -= mboff;
-       else if (CHAR_CLASS(p[temp_col - 1]) != start_class
-               && !(enc_utf8 && p[temp_col - 1] == 0))
-           break;
-     cb->word_start_col = temp_col;
- 
-     temp_col = col;
-     for ( ; temp_col < screen_Columns; temp_col++)
-       if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2)
-           ++temp_col;
-       else if (CHAR_CLASS(p[temp_col]) != start_class
-               && !(enc_utf8 && p[temp_col] == 0))
-           break;
-     cb->word_end_col = temp_col;
- }
- 
- /*
-  * Find the column position for the last non-whitespace character on the given
-  * line at or before start_col.
-  */
-     static int
- clip_get_line_end(Clipboard_T *cbd UNUSED, int row)
- {
-     int           i;
- 
-     if (row >= screen_Rows || ScreenLines == NULL)
-       return 0;
-     for (i =
- #ifdef FEAT_PROP_POPUP
-           cbd->max_col;
- #else
-           screen_Columns;
- #endif
-                           i > 0; i--)
-       if (ScreenLines[LineOffset[row] + i - 1] != ' ')
-           break;
-     return i;
- }
- 
- /*
-  * Update the currently selected region by adding and/or subtracting from the
-  * beginning or end and inverting the changed area(s).
-  */
-     static void
- clip_update_modeless_selection(
-     Clipboard_T    *cb,
-     int                   row1,
-     int                   col1,
-     int                   row2,
-     int                   col2)
- {
-     // See if we changed at the beginning of the selection
-     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
-     {
-       clip_invert_area(cb, row1, col1, (int)cb->start.lnum, cb->start.col,
-                                                                CLIP_TOGGLE);
-       cb->start.lnum = row1;
-       cb->start.col  = col1;
-     }
- 
-     // See if we changed at the end of the selection
-     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
-     {
-       clip_invert_area(cb, (int)cb->end.lnum, cb->end.col, row2, col2,
-                                                                CLIP_TOGGLE);
-       cb->end.lnum = row2;
-       cb->end.col  = col2;
-     }
- }
- 
-     static int
- clip_gen_own_selection(Clipboard_T *cbd)
- {
- #ifdef FEAT_XCLIPBOARD
- # ifdef FEAT_GUI
-     if (gui.in_use)
-       return clip_mch_own_selection(cbd);
-     else
- # endif
-       return clip_xterm_own_selection(cbd);
- #else
-     return clip_mch_own_selection(cbd);
- #endif
- }
- 
-     static void
- clip_gen_lose_selection(Clipboard_T *cbd)
- {
- #ifdef FEAT_XCLIPBOARD
- # ifdef FEAT_GUI
-     if (gui.in_use)
-       clip_mch_lose_selection(cbd);
-     else
- # endif
-       clip_xterm_lose_selection(cbd);
- #else
-     clip_mch_lose_selection(cbd);
- #endif
- }
- 
-     void
- clip_gen_set_selection(Clipboard_T *cbd)
- {
-     if (!clip_did_set_selection)
-     {
-       // Updating postponed, so that accessing the system clipboard won't
-       // hang Vim when accessing it many times (e.g. on a :g command).
-       if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS))
-               || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED)))
-       {
-           clipboard_needs_update = TRUE;
-           return;
-       }
-     }
- #ifdef FEAT_XCLIPBOARD
- # ifdef FEAT_GUI
-     if (gui.in_use)
-       clip_mch_set_selection(cbd);
-     else
- # endif
-       clip_xterm_set_selection(cbd);
- #else
-     clip_mch_set_selection(cbd);
- #endif
- }
- 
-     void
- clip_gen_request_selection(Clipboard_T *cbd)
- {
- #ifdef FEAT_XCLIPBOARD
- # ifdef FEAT_GUI
-     if (gui.in_use)
-       clip_mch_request_selection(cbd);
-     else
- # endif
-       clip_xterm_request_selection(cbd);
- #else
-     clip_mch_request_selection(cbd);
- #endif
- }
- 
- #if (defined(FEAT_X11) && defined(USE_SYSTEM)) || defined(PROTO)
-     int
- clip_gen_owner_exists(Clipboard_T *cbd UNUSED)
- {
- #ifdef FEAT_XCLIPBOARD
- # ifdef FEAT_GUI_GTK
-     if (gui.in_use)
-       return clip_gtk_owner_exists(cbd);
-     else
- # endif
-       return clip_x11_owner_exists(cbd);
- #else
-     return TRUE;
- #endif
- }
- #endif
- 
- /*
-  * Extract the items in the 'clipboard' option and set global values.
-  * Return an error message or NULL for success.
-  */
-     char *
- check_clipboard_option(void)
- {
-     int               new_unnamed = 0;
-     int               new_autoselect_star = FALSE;
-     int               new_autoselect_plus = FALSE;
-     int               new_autoselectml = FALSE;
-     int               new_html = FALSE;
-     regprog_T *new_exclude_prog = NULL;
-     char      *errmsg = NULL;
-     char_u    *p;
- 
-     for (p = p_cb; *p != NUL; )
-     {
-       if (STRNCMP(p, "unnamed", 7) == 0 && (p[7] == ',' || p[7] == NUL))
-       {
-           new_unnamed |= CLIP_UNNAMED;
-           p += 7;
-       }
-       else if (STRNCMP(p, "unnamedplus", 11) == 0
-                                           && (p[11] == ',' || p[11] == NUL))
-       {
-           new_unnamed |= CLIP_UNNAMED_PLUS;
-           p += 11;
-       }
-       else if (STRNCMP(p, "autoselect", 10) == 0
-                                           && (p[10] == ',' || p[10] == NUL))
-       {
-           new_autoselect_star = TRUE;
-           p += 10;
-       }
-       else if (STRNCMP(p, "autoselectplus", 14) == 0
-                                           && (p[14] == ',' || p[14] == NUL))
-       {
-           new_autoselect_plus = TRUE;
-           p += 14;
-       }
-       else if (STRNCMP(p, "autoselectml", 12) == 0
-                                           && (p[12] == ',' || p[12] == NUL))
-       {
-           new_autoselectml = TRUE;
-           p += 12;
-       }
-       else if (STRNCMP(p, "html", 4) == 0 && (p[4] == ',' || p[4] == NUL))
-       {
-           new_html = TRUE;
-           p += 4;
-       }
-       else if (STRNCMP(p, "exclude:", 8) == 0 && new_exclude_prog == NULL)
-       {
-           p += 8;
-           new_exclude_prog = vim_regcomp(p, RE_MAGIC);
-           if (new_exclude_prog == NULL)
-               errmsg = e_invarg;
-           break;
-       }
-       else
-       {
-           errmsg = e_invarg;
-           break;
-       }
-       if (*p == ',')
-           ++p;
-     }
-     if (errmsg == NULL)
-     {
-       clip_unnamed = new_unnamed;
-       clip_autoselect_star = new_autoselect_star;
-       clip_autoselect_plus = new_autoselect_plus;
-       clip_autoselectml = new_autoselectml;
-       clip_html = new_html;
-       vim_regfree(clip_exclude_prog);
-       clip_exclude_prog = new_exclude_prog;
- #ifdef FEAT_GUI_GTK
-       if (gui.in_use)
-       {
-           gui_gtk_set_selection_targets();
-           gui_gtk_set_dnd_targets();
-       }
- #endif
-     }
-     else
-       vim_regfree(new_exclude_prog);
- 
-     return errmsg;
- }
- 
- #endif // FEAT_CLIPBOARD
- 
- //////////////////////////////////////////////////////////////////////////////
  // Functions that handle the input buffer.
  // This is used for any GUI version, and the unix terminal version.
  //
--- 705,710 ----
***************
*** 2431,2987 ****
      return row;
  }
  
- /*
-  * Stuff for the X clipboard.  Shared between VMS and Unix.
-  */
- 
- #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO)
- # include <X11/Xatom.h>
- # include <X11/Intrinsic.h>
- 
- /*
-  * Open the application context (if it hasn't been opened yet).
-  * Used for Motif and Athena GUI and the xterm clipboard.
-  */
-     void
- open_app_context(void)
- {
-     if (app_context == NULL)
-     {
-       XtToolkitInitialize();
-       app_context = XtCreateApplicationContext();
-     }
- }
- 
- static Atom   vim_atom;       // Vim's own special selection format
- static Atom   vimenc_atom;    // Vim's extended selection format
- static Atom   utf8_atom;
- static Atom   compound_text_atom;
- static Atom   text_atom;
- static Atom   targets_atom;
- static Atom   timestamp_atom; // Used to get a timestamp
- 
-     void
- x11_setup_atoms(Display *dpy)
- {
-     vim_atom         = XInternAtom(dpy, VIM_ATOM_NAME,   False);
-     vimenc_atom              = XInternAtom(dpy, VIMENC_ATOM_NAME,False);
-     utf8_atom        = XInternAtom(dpy, "UTF8_STRING",   False);
-     compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False);
-     text_atom        = XInternAtom(dpy, "TEXT",          False);
-     targets_atom       = XInternAtom(dpy, "TARGETS",     False);
-     clip_star.sel_atom = XA_PRIMARY;
-     clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD",           False);
-     timestamp_atom     = XInternAtom(dpy, "TIMESTAMP",           False);
- }
- 
- /*
-  * X Selection stuff, for cutting and pasting text to other windows.
-  */
- 
- static Boolean        clip_x11_convert_selection_cb(Widget w, Atom *sel_atom, 
Atom *target, Atom *type, XtPointer *value, long_u *length, int *format);
- static void clip_x11_lose_ownership_cb(Widget w, Atom *sel_atom);
- static void clip_x11_notify_cb(Widget w, Atom *sel_atom, Atom *target);
- 
- /*
-  * Property callback to get a timestamp for XtOwnSelection.
-  */
-     static void
- clip_x11_timestamp_cb(
-     Widget    w,
-     XtPointer n UNUSED,
-     XEvent    *event,
-     Boolean   *cont UNUSED)
- {
-     Atom          actual_type;
-     int                   format;
-     unsigned  long  nitems, bytes_after;
-     unsigned char   *prop=NULL;
-     XPropertyEvent  *xproperty=&event->xproperty;
- 
-     // Must be a property notify, state can't be Delete (True), has to be
-     // one of the supported selection types.
-     if (event->type != PropertyNotify || xproperty->state
-           || (xproperty->atom != clip_star.sel_atom
-                                   && xproperty->atom != clip_plus.sel_atom))
-       return;
- 
-     if (XGetWindowProperty(xproperty->display, xproperty->window,
-         xproperty->atom, 0, 0, False, timestamp_atom, &actual_type, &format,
-                                               &nitems, &bytes_after, &prop))
-       return;
- 
-     if (prop)
-       XFree(prop);
- 
-     // Make sure the property type is "TIMESTAMP" and it's 32 bits.
-     if (actual_type != timestamp_atom || format != 32)
-       return;
- 
-     // Get the selection, using the event timestamp.
-     if (XtOwnSelection(w, xproperty->atom, xproperty->time,
-           clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
-           clip_x11_notify_cb) == OK)
-     {
-       // Set the "owned" flag now, there may have been a call to
-       // lose_ownership_cb in between.
-       if (xproperty->atom == clip_plus.sel_atom)
-           clip_plus.owned = TRUE;
-       else
-           clip_star.owned = TRUE;
-     }
- }
- 
-     void
- x11_setup_selection(Widget w)
- {
-     XtAddEventHandler(w, PropertyChangeMask, False,
-           /*(XtEventHandler)*/clip_x11_timestamp_cb, (XtPointer)NULL);
- }
- 
-     static void
- clip_x11_request_selection_cb(
-     Widget    w UNUSED,
-     XtPointer success,
-     Atom      *sel_atom,
-     Atom      *type,
-     XtPointer value,
-     long_u    *length,
-     int               *format)
- {
-     int               motion_type = MAUTO;
-     long_u    len;
-     char_u    *p;
-     char      **text_list = NULL;
-     Clipboard_T       *cbd;
-     char_u    *tmpbuf = NULL;
- 
-     if (*sel_atom == clip_plus.sel_atom)
-       cbd = &clip_plus;
-     else
-       cbd = &clip_star;
- 
-     if (value == NULL || *length == 0)
-     {
-       clip_free_selection(cbd);       // nothing received, clear register
-       *(int *)success = FALSE;
-       return;
-     }
-     p = (char_u *)value;
-     len = *length;
-     if (*type == vim_atom)
-     {
-       motion_type = *p++;
-       len--;
-     }
- 
-     else if (*type == vimenc_atom)
-     {
-       char_u          *enc;
-       vimconv_T       conv;
-       int             convlen;
- 
-       motion_type = *p++;
-       --len;
- 
-       enc = p;
-       p += STRLEN(p) + 1;
-       len -= p - enc;
- 
-       // If the encoding of the text is different from 'encoding', attempt
-       // converting it.
-       conv.vc_type = CONV_NONE;
-       convert_setup(&conv, enc, p_enc);
-       if (conv.vc_type != CONV_NONE)
-       {
-           convlen = len;      // Need to use an int here.
-           tmpbuf = string_convert(&conv, p, &convlen);
-           len = convlen;
-           if (tmpbuf != NULL)
-               p = tmpbuf;
-           convert_setup(&conv, NULL, NULL);
-       }
-     }
- 
-     else if (*type == compound_text_atom
-           || *type == utf8_atom
-           || (enc_dbcs != 0 && *type == text_atom))
-     {
-       XTextProperty   text_prop;
-       int             n_text = 0;
-       int             status;
- 
-       text_prop.value = (unsigned char *)value;
-       text_prop.encoding = *type;
-       text_prop.format = *format;
-       text_prop.nitems = len;
- #if defined(X_HAVE_UTF8_STRING)
-       if (*type == utf8_atom)
-           status = Xutf8TextPropertyToTextList(X_DISPLAY, &text_prop,
-                                                        &text_list, &n_text);
-       else
- #endif
-           status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop,
-                                                        &text_list, &n_text);
-       if (status != Success || n_text < 1)
-       {
-           *(int *)success = FALSE;
-           return;
-       }
-       p = (char_u *)text_list[0];
-       len = STRLEN(p);
-     }
-     clip_yank_selection(motion_type, p, (long)len, cbd);
- 
-     if (text_list != NULL)
-       XFreeStringList(text_list);
-     vim_free(tmpbuf);
-     XtFree((char *)value);
-     *(int *)success = TRUE;
- }
- 
-     void
- clip_x11_request_selection(
-     Widget    myShell,
-     Display   *dpy,
-     Clipboard_T       *cbd)
- {
-     XEvent    event;
-     Atom      type;
-     static int        success;
-     int               i;
-     time_t    start_time;
-     int               timed_out = FALSE;
- 
-     for (i = 0; i < 6; i++)
-     {
-       switch (i)
-       {
-           case 0:  type = vimenc_atom;        break;
-           case 1:  type = vim_atom;           break;
-           case 2:  type = utf8_atom;          break;
-           case 3:  type = compound_text_atom; break;
-           case 4:  type = text_atom;          break;
-           default: type = XA_STRING;
-       }
-       if (type == utf8_atom
- # if defined(X_HAVE_UTF8_STRING)
-               && !enc_utf8
- # endif
-               )
-           // Only request utf-8 when 'encoding' is utf8 and
-           // Xutf8TextPropertyToTextList is available.
-           continue;
-       success = MAYBE;
-       XtGetSelectionValue(myShell, cbd->sel_atom, type,
-           clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime);
- 
-       // Make sure the request for the selection goes out before waiting for
-       // a response.
-       XFlush(dpy);
- 
-       /*
-        * Wait for result of selection request, otherwise if we type more
-        * characters, then they will appear before the one that requested the
-        * paste!  Don't worry, we will catch up with any other events later.
-        */
-       start_time = time(NULL);
-       while (success == MAYBE)
-       {
-           if (XCheckTypedEvent(dpy, PropertyNotify, &event)
-                   || XCheckTypedEvent(dpy, SelectionNotify, &event)
-                   || XCheckTypedEvent(dpy, SelectionRequest, &event))
-           {
-               // This is where clip_x11_request_selection_cb() should be
-               // called.  It may actually happen a bit later, so we loop
-               // until "success" changes.
-               // We may get a SelectionRequest here and if we don't handle
-               // it we hang.  KDE klipper does this, for example.
-               // We need to handle a PropertyNotify for large selections.
-               XtDispatchEvent(&event);
-               continue;
-           }
- 
-           // Time out after 2 to 3 seconds to avoid that we hang when the
-           // other process doesn't respond.  Note that the SelectionNotify
-           // event may still come later when the selection owner comes back
-           // to life and the text gets inserted unexpectedly.  Don't know
-           // why that happens or how to avoid that :-(.
-           if (time(NULL) > start_time + 2)
-           {
-               timed_out = TRUE;
-               break;
-           }
- 
-           // Do we need this?  Probably not.
-           XSync(dpy, False);
- 
-           // Wait for 1 msec to avoid that we eat up all CPU time.
-           ui_delay(1L, TRUE);
-       }
- 
-       if (success == TRUE)
-           return;
- 
-       // don't do a retry with another type after timing out, otherwise we
-       // hang for 15 seconds.
-       if (timed_out)
-           break;
-     }
- 
-     // Final fallback position - use the X CUT_BUFFER0 store
-     yank_cut_buffer0(dpy, cbd);
- }
- 
-     static Boolean
- clip_x11_convert_selection_cb(
-     Widget    w UNUSED,
-     Atom      *sel_atom,
-     Atom      *target,
-     Atom      *type,
-     XtPointer *value,
-     long_u    *length,
-     int               *format)
- {
-     static char_u   *save_result = NULL;
-     static long_u   save_length = 0;
-     char_u        *string;
-     int                   motion_type;
-     Clipboard_T    *cbd;
-     int                   i;
- 
-     if (*sel_atom == clip_plus.sel_atom)
-       cbd = &clip_plus;
-     else
-       cbd = &clip_star;
- 
-     if (!cbd->owned)
-       return False;       // Shouldn't ever happen
- 
-     // requestor wants to know what target types we support
-     if (*target == targets_atom)
-     {
-       static Atom array[7];
- 
-       *value = (XtPointer)array;
-       i = 0;
-       array[i++] = targets_atom;
-       array[i++] = vimenc_atom;
-       array[i++] = vim_atom;
-       if (enc_utf8)
-           array[i++] = utf8_atom;
-       array[i++] = XA_STRING;
-       array[i++] = text_atom;
-       array[i++] = compound_text_atom;
- 
-       *type = XA_ATOM;
-       // This used to be: *format = sizeof(Atom) * 8; but that caused
-       // crashes on 64 bit machines. (Peter Derr)
-       *format = 32;
-       *length = i;
-       return True;
-     }
- 
-     if (       *target != XA_STRING
-           && *target != vimenc_atom
-           && (*target != utf8_atom || !enc_utf8)
-           && *target != vim_atom
-           && *target != text_atom
-           && *target != compound_text_atom)
-       return False;
- 
-     clip_get_selection(cbd);
-     motion_type = clip_convert_selection(&string, length, cbd);
-     if (motion_type < 0)
-       return False;
- 
-     // For our own format, the first byte contains the motion type
-     if (*target == vim_atom)
-       (*length)++;
- 
-     // Our own format with encoding: motion 'encoding' NUL text
-     if (*target == vimenc_atom)
-       *length += STRLEN(p_enc) + 2;
- 
-     if (save_length < *length || save_length / 2 >= *length)
-       *value = XtRealloc((char *)save_result, (Cardinal)*length + 1);
-     else
-       *value = save_result;
-     if (*value == NULL)
-     {
-       vim_free(string);
-       return False;
-     }
-     save_result = (char_u *)*value;
-     save_length = *length;
- 
-     if (*target == XA_STRING || (*target == utf8_atom && enc_utf8))
-     {
-       mch_memmove(save_result, string, (size_t)(*length));
-       *type = *target;
-     }
-     else if (*target == compound_text_atom || *target == text_atom)
-     {
-       XTextProperty   text_prop;
-       char            *string_nt = (char *)save_result;
-       int             conv_result;
- 
-       // create NUL terminated string which XmbTextListToTextProperty wants
-       mch_memmove(string_nt, string, (size_t)*length);
-       string_nt[*length] = NUL;
-       conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt,
-                                          1, XCompoundTextStyle, &text_prop);
-       if (conv_result != Success)
-       {
-           vim_free(string);
-           return False;
-       }
-       *value = (XtPointer)(text_prop.value);  //    from plain text
-       *length = text_prop.nitems;
-       *type = compound_text_atom;
-       XtFree((char *)save_result);
-       save_result = (char_u *)*value;
-       save_length = *length;
-     }
-     else if (*target == vimenc_atom)
-     {
-       int l = STRLEN(p_enc);
- 
-       save_result[0] = motion_type;
-       STRCPY(save_result + 1, p_enc);
-       mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2));
-       *type = vimenc_atom;
-     }
-     else
-     {
-       save_result[0] = motion_type;
-       mch_memmove(save_result + 1, string, (size_t)(*length - 1));
-       *type = vim_atom;
-     }
-     *format = 8;          // 8 bits per char
-     vim_free(string);
-     return True;
- }
- 
-     static void
- clip_x11_lose_ownership_cb(Widget w UNUSED, Atom *sel_atom)
- {
-     if (*sel_atom == clip_plus.sel_atom)
-       clip_lose_selection(&clip_plus);
-     else
-       clip_lose_selection(&clip_star);
- }
- 
-     void
- clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd)
- {
-     XtDisownSelection(myShell, cbd->sel_atom,
-                               XtLastTimestampProcessed(XtDisplay(myShell)));
- }
- 
-     static void
- clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target 
UNUSED)
- {
-     // To prevent automatically freeing the selection value.
- }
- 
-     int
- clip_x11_own_selection(Widget myShell, Clipboard_T *cbd)
- {
-     // When using the GUI we have proper timestamps, use the one of the last
-     // event.  When in the console we don't get events (the terminal gets
-     // them), Get the time by a zero-length append, clip_x11_timestamp_cb will
-     // be called with the current timestamp.
- #ifdef FEAT_GUI
-     if (gui.in_use)
-     {
-       if (XtOwnSelection(myShell, cbd->sel_atom,
-              XtLastTimestampProcessed(XtDisplay(myShell)),
-              clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
-              clip_x11_notify_cb) == False)
-           return FAIL;
-     }
-     else
- #endif
-     {
-       if (!XChangeProperty(XtDisplay(myShell), XtWindow(myShell),
-                 cbd->sel_atom, timestamp_atom, 32, PropModeAppend, NULL, 0))
-           return FAIL;
-     }
-     // Flush is required in a terminal as nothing else is doing it.
-     XFlush(XtDisplay(myShell));
-     return OK;
- }
- 
- /*
-  * Send the current selection to the clipboard.  Do nothing for X because we
-  * will fill in the selection only when requested by another app.
-  */
-     void
- clip_x11_set_selection(Clipboard_T *cbd UNUSED)
- {
- }
- 
- #if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) \
-       || defined(PROTO)
-     static int
- clip_x11_owner_exists(Clipboard_T *cbd)
- {
-     return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None;
- }
- #endif
- #endif
- 
- #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) \
-     || defined(FEAT_GUI_GTK) || defined(PROTO)
- /*
-  * Get the contents of the X CUT_BUFFER0 and put it in "cbd".
-  */
-     void
- yank_cut_buffer0(Display *dpy, Clipboard_T *cbd)
- {
-     int               nbytes = 0;
-     char_u    *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0);
- 
-     if (nbytes > 0)
-     {
-       int  done = FALSE;
- 
-       // CUT_BUFFER0 is supposed to be always latin1.  Convert to 'enc' when
-       // using a multi-byte encoding.  Conversion between two 8-bit
-       // character sets usually fails and the text might actually be in
-       // 'enc' anyway.
-       if (has_mbyte)
-       {
-           char_u      *conv_buf;
-           vimconv_T   vc;
- 
-           vc.vc_type = CONV_NONE;
-           if (convert_setup(&vc, (char_u *)"latin1", p_enc) == OK)
-           {
-               conv_buf = string_convert(&vc, buffer, &nbytes);
-               if (conv_buf != NULL)
-               {
-                   clip_yank_selection(MCHAR, conv_buf, (long)nbytes, cbd);
-                   vim_free(conv_buf);
-                   done = TRUE;
-               }
-               convert_setup(&vc, NULL, NULL);
-           }
-       }
-       if (!done)  // use the text without conversion
-           clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd);
-       XFree((void *)buffer);
-       if (p_verbose > 0)
-       {
-           verbose_enter();
-           verb_msg(_("Used CUT_BUFFER0 instead of empty selection"));
-           verbose_leave();
-       }
-     }
- }
- #endif
- 
  #if defined(FEAT_GUI) || defined(MSWIN) || defined(PROTO)
  /*
   * Called when focus changed.  Used for the GUI or for systems where this can
--- 1099,1104 ----
*** ../vim-8.2.0442/src/version.c       2020-03-24 20:35:14.741080390 +0100
--- src/version.c       2020-03-24 21:40:29.123770574 +0100
***************
*** 740,741 ****
--- 740,743 ----
  {   /* Add new patch number below this line */
+ /**/
+     443,
  /**/

-- 
ARTHUR:  Well, I can't just call you `Man'.
DENNIS:  Well, you could say `Dennis'.
ARTHUR:  Well, I didn't know you were called `Dennis.'
DENNIS:  Well, you didn't bother to find out, did you?
                                  The Quest for the Holy Grail (Monty Python)

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202003242043.02OKhHvS000820%40masaka.moolenaar.net.

Raspunde prin e-mail lui