changeset 19774:00a1b89256ea v8.2.0443

patch 8.2.0443: clipboard code is spread out Commit: https://github.com/vim/vim/commit/45fffdf10b7cb6e59794e76e9b8a2930fcb4b192 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Mar 24 21:42:01 2020 +0100 patch 8.2.0443: clipboard code is spread out Problem: Clipboard code is spread out. Solution: Move clipboard code to its own file. (Yegappan Lakshmanan, closes #5827)
author Bram Moolenaar <Bram@vim.org>
date Tue, 24 Mar 2020 21:45:04 +0100
parents c8242fe426a7
children 56dca79644a9
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 src/version.c
diffstat 17 files changed, 2297 insertions(+), 2267 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -29,6 +29,7 @@ SRC_ALL =	\
 		src/channel.c \
 		src/charset.c \
 		src/cindent.c \
+		src/clipboard.c \
 		src/cmdexpand.c \
 		src/cmdhist.c \
 		src/crypt.c \
@@ -200,6 +201,7 @@ SRC_ALL =	\
 		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 \
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -710,6 +710,7 @@ OBJ = \
 	$(OUTDIR)/change.o \
 	$(OUTDIR)/charset.o \
 	$(OUTDIR)/cindent.o \
+	$(OUTDIR)/clipboard.o \
 	$(OUTDIR)/cmdexpand.o \
 	$(OUTDIR)/cmdhist.o \
 	$(OUTDIR)/crypt.o \
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -33,6 +33,7 @@ SRC =	arabic.c						\
 	change.c						\
 	charset.c						\
 	cindent.c						\
+	clipboard.c						\
 	cmdexpand.c						\
 	cmdhist.c						\
 	crypt.c							\
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -730,6 +730,7 @@ OBJ = \
 	$(OUTDIR)\change.obj \
 	$(OUTDIR)\charset.obj \
 	$(OUTDIR)\cindent.obj \
+	$(OUTDIR)\clipboard.obj \
 	$(OUTDIR)\cmdexpand.obj \
 	$(OUTDIR)\cmdhist.obj \
 	$(OUTDIR)\crypt.obj \
@@ -1515,6 +1516,8 @@ testclean:
 
 $(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,6 +1865,7 @@ proto.h: \
 	proto/change.pro \
 	proto/charset.pro \
 	proto/cindent.pro \
+	proto/clipboard.pro \
 	proto/cmdexpand.pro \
 	proto/cmdhist.pro \
 	proto/crypt.pro \
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -306,6 +306,7 @@ SRC = \
 	change.c \
 	charset.c \
 	cindent.c \
+	clipboard.c \
 	cmdexpand.c \
 	cmdhist.c \
 	crypt.c \
@@ -412,6 +413,7 @@ OBJ = \
 	change.obj \
 	charset.obj \
 	cindent.obj \
+	clipboard.obj \
 	cmdexpand.obj \
 	cmdhist.obj \
 	crypt.obj \
@@ -700,6 +702,10 @@ cindent.obj : cindent.c vim.h [.auto]con
  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 \
--- a/src/Makefile
+++ b/src/Makefile
@@ -1599,6 +1599,7 @@ BASIC_SRC = \
 	change.c \
 	charset.c \
 	cindent.c \
+	clipboard.c \
 	cmdexpand.c \
 	cmdhist.c \
 	crypt.c \
@@ -1743,6 +1744,7 @@ OBJ_COMMON = \
 	objects/blob.o \
 	objects/blowfish.o \
 	objects/cindent.o \
+	objects/clipboard.o \
 	objects/cmdexpand.o \
 	objects/cmdhist.o \
 	objects/crypt.o \
@@ -1903,6 +1905,7 @@ PRO_AUTO = \
 	channel.pro \
 	charset.pro \
 	cindent.pro \
+	clipboard.pro \
 	cmdexpand.pro \
 	cmdhist.pro \
 	crypt.pro \
@@ -3117,6 +3120,9 @@ objects/charset.o: charset.c
 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,6 +3740,10 @@ objects/cindent.o: cindent.c vim.h proto
  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 \
--- a/src/README.md
+++ b/src/README.md
@@ -30,6 +30,7 @@ buffer.c	| manipulating buffers (loaded 
 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
new file mode 100644
--- /dev/null
+++ b/src/clipboard.c
@@ -0,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
--- a/src/ops.c
+++ b/src/ops.c
@@ -3409,113 +3409,6 @@ theend:
     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)
 {
--- a/src/proto.h
+++ b/src/proto.h
@@ -68,6 +68,7 @@ extern int _stricoll(char *a, char *b);
 # include "change.pro"
 # include "charset.pro"
 # include "cindent.pro"
+# include "clipboard.pro"
 # include "cmdexpand.pro"
 # include "cmdhist.pro"
 # include "if_cscope.pro"
new file mode 100644
--- /dev/null
+++ b/src/proto/clipboard.pro
@@ -0,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 : */
--- a/src/proto/ops.pro
+++ b/src/proto/ops.pro
@@ -19,7 +19,6 @@ void format_lines(linenr_T line_count, i
 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);
--- a/src/proto/register.pro
+++ b/src/proto/register.pro
@@ -1,14 +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);
-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);
@@ -20,23 +21,20 @@ int do_execreg(int regname, int colon, i
 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);
+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 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);
+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 : */
--- a/src/proto/ui.pro
+++ b/src/proto/ui.pro
@@ -14,28 +14,6 @@ void ui_new_shellsize(void);
 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);
@@ -52,14 +30,6 @@ void ui_cursor_shape_forced(int forced);
 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 : */
--- a/src/register.c
+++ b/src/register.c
@@ -32,16 +32,11 @@ static int	stuff_yank(int, char_u *);
 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)
@@ -50,6 +45,12 @@ get_y_regs(void)
 }
 
     yankreg_T *
+get_y_register(int reg)
+{
+    return &y_regs[reg];
+}
+
+    yankreg_T *
 get_y_current(void)
 {
     return y_current;
@@ -62,6 +63,12 @@ get_y_previous(void)
 }
 
     void
+set_y_current(yankreg_T *yreg)
+{
+    y_current = yreg;
+}
+
+    void
 set_y_previous(yankreg_T *yreg)
 {
     y_previous = yreg;
@@ -241,32 +248,6 @@ get_yank_register(int regname, int writi
     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.
@@ -883,32 +864,6 @@ cmdline_paste_reg(
     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.
  */
@@ -1050,7 +1005,7 @@ free_yank(long n)
     }
 }
 
-    static void
+    void
 free_yank_all(void)
 {
     free_yank(y_current->y_size);
@@ -2348,186 +2303,6 @@ dis_msg(
     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.
@@ -2900,7 +2675,7 @@ write_reg_contents_ex(
  * Put a string into a register.  When the register is not empty, the string
  * is appended.
  */
-    static void
+    void
 str_to_reg(
     yankreg_T	*y_ptr,		// pointer to yank register
     int		yank_type,	// MCHAR, MLINE, MBLOCK, MAUTO
--- a/src/ui.c
+++ b/src/ui.c
@@ -12,18 +12,11 @@
  * 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.
+ * 2. 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)
 {
@@ -712,1331 +705,6 @@ ui_breakcheck_force(int force)
 }
 
 //////////////////////////////////////////////////////////////////////////////
-// 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.
 //
@@ -2431,557 +1099,6 @@ check_row(int row)
     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
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    443,
+/**/
     442,
 /**/
     441,