]> git.lyx.org Git - features.git/commitdiff
Persistent-selection (and fix bug 3162)
authorBo Peng <bpeng@lyx.org>
Fri, 2 Feb 2007 03:10:15 +0000 (03:10 +0000)
committerBo Peng <bpeng@lyx.org>
Fri, 2 Feb 2007 03:10:15 +0000 (03:10 +0000)
* src/CutAndPaste.h/C: add selectionBuffer to save selected text
* src/text3.C: proper handling of paste
* src/lyxfind.C: save selection
* src/BufferView.C: save selection
* src/text.C: save selection
* src/cursor.C: save selection
* src/insets/insettabular.C: save selection
* src/mathed/InsetMathGrid.C: save selection
* src/mathed/InsetMathHull.C: save selection
* src/mathed/InsetMathNest.C: save selection

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@17022 a592a061-630c-0410-9148-cb99ea01b6c8

12 files changed:
src/BufferView.C
src/CutAndPaste.C
src/CutAndPaste.h
src/cursor.C
src/insets/insettabular.C
src/insets/insettabular.h
src/lyxfind.C
src/mathed/InsetMathGrid.C
src/mathed/InsetMathHull.C
src/mathed/InsetMathNest.C
src/text.C
src/text3.C

index 8771f0d2e5315188481bf5d7d8ec964dd636496b..a0da8a82d86ffa9b903ce3a424a6a275c6a3a930 100644 (file)
@@ -63,7 +63,6 @@
 #include "frontends/Alert.h"
 #include "frontends/FileDialog.h"
 #include "frontends/FontMetrics.h"
-#include "frontends/Selection.h"
 
 #include "graphics/Previews.h"
 
@@ -209,7 +208,8 @@ void BufferView::setBuffer(Buffer * b)
                        cursor_.resetAnchor();
                        cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset())));
                        cursor_.setSelection();
-                       theSelection().haveSelection(cursor_.selection());
+                       // do not set selection to the new buffer because we
+                       // only paste recent selection.
                }
        }
 
@@ -1054,6 +1054,10 @@ void BufferView::clearSelection()
 {
        if (buffer_) {
                cursor_.clearSelection();
+               // Clear the selection buffer. Otherwise a subsequent
+               // middle-mouse-button paste would use the selection buffer,
+               // not the more current external selection.
+               cap::clearSelection();
                xsel_cache_.set = false;
                // The buffer did not really change, but this causes the
                // redraw we need because we cleared the selection above.
@@ -1342,7 +1346,7 @@ void BufferView::putSelectionAt(DocIterator const & cur,
                        cursor_.setSelection(cursor_, -length);
                } else
                        cursor_.setSelection(cursor_, length);
-               theSelection().haveSelection(cursor_.selection());
+               cap::saveSelection(cursor_);
        }
 }
 
index ee7b2d24959e30172a621631293272b33f87e76c..dcab51805b5c0e64971a5a47966d6c5df2d42060 100644 (file)
@@ -73,6 +73,8 @@ typedef std::pair<pit_type, int> PitPosPair;
 typedef limited_stack<pair<ParagraphList, textclass_type> > CutStack;
 
 CutStack theCuts(10);
+// persistent selection, cleared until the next selection
+CutStack selectionBuffer(1);
 
 // store whether the tabular stack is newer than the normal copy stack
 // FIXME: this is a workaround for bug 1919. Should be removed for 1.5,
@@ -343,7 +345,7 @@ void putClipboard(ParagraphList const & paragraphs, textclass_type textclass,
 
 void copySelectionHelper(Buffer const & buf, ParagraphList & pars,
        pit_type startpit, pit_type endpit,
-       int start, int end, textclass_type tc)
+       int start, int end, textclass_type tc, CutStack & cutstack)
 {
        BOOST_ASSERT(0 <= start && start <= pars[startpit].size());
        BOOST_ASSERT(0 <= end && end <= pars[endpit].size());
@@ -377,7 +379,7 @@ void copySelectionHelper(Buffer const & buf, ParagraphList & pars,
        // again, do not track deletion
        front.eraseChars(0, start, false);
 
-       theCuts.push(make_pair(paragraphs, tc));
+       cutstack.push(make_pair(paragraphs, tc));
 }
 
 } // namespace anon
@@ -524,7 +526,7 @@ void cutSelection(LCursor & cur, bool doclear, bool realcut)
                                text->paragraphs(),
                                begpit, endpit,
                                cur.selBegin().pos(), endpos,
-                               bp.textclass);
+                               bp.textclass, theCuts);
                        // Stuff what we got on the clipboard.
                        // Even if there is no selection.
                        putClipboard(theCuts[0].first, theCuts[0].second,
@@ -580,16 +582,9 @@ void copySelection(LCursor & cur)
 }
 
 
-void copySelection(LCursor & cur, docstring const & plaintext)
-{
-       copySelectionToStack(cur);
-
-       // stuff the selection onto the X clipboard, from an explicit copy request
-       putClipboard(theCuts[0].first, theCuts[0].second, plaintext);
-}
-
+namespace {
 
-void copySelectionToStack(LCursor & cur)
+void copySelectionToStack(LCursor & cur, CutStack & cutstack)
 {
        // this doesn't make sense, if there is no selection
        if (!cur.selection())
@@ -611,7 +606,7 @@ void copySelectionToStack(LCursor & cur)
                        ++pos;
 
                copySelectionHelper(cur.buffer(), pars, par, cur.selEnd().pit(),
-                       pos, cur.selEnd().pos(), cur.buffer().params().textclass);
+                       pos, cur.selEnd().pos(), cur.buffer().params().textclass, cutstack);
        }
 
        if (cur.inMathed()) {
@@ -622,10 +617,50 @@ void copySelectionToStack(LCursor & cur)
                par.layout(bp.getLyXTextClass().defaultLayout());
                par.insert(0, grabSelection(cur), LyXFont(), Change(Change::UNCHANGED));
                pars.push_back(par);
-               theCuts.push(make_pair(pars, bp.textclass));
+               cutstack.push(make_pair(pars, bp.textclass));
        }
-       // tell tabular that a recent copy happened
-       dirtyTabularStack(false);
+}
+
+}
+
+
+void copySelectionToStack()
+{
+       if (!selectionBuffer.empty())
+               theCuts.push(selectionBuffer[0]);
+}
+
+
+void copySelection(LCursor & cur, docstring const & plaintext)
+{
+       copySelectionToStack(cur, theCuts);
+
+       // stuff the selection onto the X clipboard, from an explicit copy request
+       putClipboard(theCuts[0].first, theCuts[0].second, plaintext);
+}
+
+
+void saveSelection(LCursor & cur)
+{
+       lyxerr[Debug::ACTION] << "cap::saveSelection: `"
+              << to_utf8(cur.selectionAsString(true)) << "'." << endl;
+       
+       if (cur.selection())
+               copySelectionToStack(cur, selectionBuffer);
+       // tell X whether we now have a valid selection
+       theSelection().haveSelection(cur.selection());
+}
+
+
+bool selection()
+{
+       return !selectionBuffer.empty();
+}
+
+
+void clearSelection()
+{
+       selectionBuffer.clear();
 }
 
 
@@ -660,11 +695,25 @@ void pasteParagraphList(LCursor & cur, ParagraphList const & parlist,
 }
 
 
+void pasteFromStack(LCursor & cur, ErrorList & errorList, size_t sel_index)
+{
+       // this does not make sense, if there is nothing to paste
+       if (!checkPastePossible(sel_index))
+               return;
+
+       recordUndo(cur);
+       pasteParagraphList(cur, theCuts[sel_index].first,
+                          theCuts[sel_index].second, errorList);
+       cur.setSelection();
+       saveSelection(cur);
+}
+
+
 void pasteClipboard(LCursor & cur, ErrorList & errorList, bool asParagraphs)
 {
        // Use internal clipboard if it is the most recent one
        if (theClipboard().isInternal()) {
-               pasteSelection(cur, errorList, 0);
+               pasteClipboard(cur, errorList, 0);
                return;
        }
 
@@ -696,15 +745,13 @@ void pasteClipboard(LCursor & cur, ErrorList & errorList, bool asParagraphs)
 }
 
 
-void pasteSelection(LCursor & cur, ErrorList & errorList, size_t sel_index)
+void pasteSelection(LCursor & cur, ErrorList & errorList)
 {
-       // this does not make sense, if there is nothing to paste
-       if (!checkPastePossible(sel_index))
+       if (selectionBuffer.empty())
                return;
-
        recordUndo(cur);
-       pasteParagraphList(cur, theCuts[sel_index].first,
-                          theCuts[sel_index].second, errorList);
+       pasteParagraphList(cur, selectionBuffer[0].first,
+                          selectionBuffer[0].second, errorList);
        cur.setSelection();
 }
 
@@ -735,6 +782,7 @@ void replaceSelectionWithString(LCursor & cur, docstring const & str, bool backw
                cur.setSelection(selbeg, -int(str.length()));
        } else
                cur.setSelection(selbeg, str.length());
+       saveSelection(cur);
 }
 
 
index a07d04c11810967fe104e34c2e258c87076b3c38..329c2e72b50f9e289dd5b30200635905b87cf171 100644 (file)
@@ -68,15 +68,24 @@ void copySelection(LCursor & cur);
  *        clipboard
  */
 void copySelection(LCursor & cur, docstring const & plaintext);
-/// Push the current selection to the cut buffer.
-void copySelectionToStack(LCursor & cur);
+/// Push the selection buffer to the cut buffer.
+void copySelectionToStack();
+/// Store the current selection in the internal selection buffer
+void saveSelection(LCursor & cur);
+/// Is a selection available in our selection buffer?
+bool selection();
+/// Clear our selection buffer
+void clearSelection();
+/// Paste the current selection at \p cur
+/// Does handle undo. Does only work in text, not mathed.
+void pasteSelection(LCursor & cur, ErrorList &);
 /// Replace the current selection with the clipboard contents (internal or
 /// external: which is newer)
 /// Does handle undo. Does only work in text, not mathed.
 void pasteClipboard(LCursor & cur, ErrorList & errorList, bool asParagraphs = true);
 /// Replace the current selection with cut buffer \c sel_index
 /// Does handle undo. Does only work in text, not mathed.
-void pasteSelection(LCursor & cur, ErrorList &, size_t sel_index = 0);
+void pasteFromStack(LCursor & cur, ErrorList & errorList, size_t sel_index);
 
 /// Paste the paragraph list \p parlist at the position given by \p cur.
 /// Does not handle undo. Does only work in text, not mathed.
index e9c4d753494781bc4ac1c11b5bdc5942eb3c74b9..ad749e3aaa35cdb5a14ae7a7ae0f84dc798cd96d 100644 (file)
@@ -41,8 +41,6 @@
 #include "mathed/InsetMathScript.h"
 #include "mathed/MathMacroTable.h"
 
-#include "frontends/Selection.h"
-
 #include "support/limited_stack.h"
 
 #include <boost/assert.hpp>
@@ -560,7 +558,7 @@ bool LCursor::selHandle(bool sel)
 
        resetAnchor();
        selection() = sel;
-       theSelection().haveSelection(sel);
+       cap::saveSelection(*this);
        return true;
 }
 
index eeda178a56a286efacf6a39cf4dee5504593ff7a..9443fc17ef88928229c302915f3128deb7e0f622 100644 (file)
@@ -50,6 +50,7 @@ namespace lyx {
 
 using cap::dirtyTabularStack;
 using cap::tabularStackDirty;
+using cap::saveSelection;
 
 using graphics::PreviewLoader;
 
@@ -501,12 +502,12 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
                }
 
                if (cmd.button() == mouse_button::button2) {
-                       if (bvcur.selection()) {
+                       if (cap::selection()) {
                                // See comment in LyXText::dispatch why we
                                // do this
                                // FIXME This does not use paste_tabular,
                                // another reason why paste_tabular should go.
-                               cap::copySelectionToStack(bvcur);
+                               cap::copySelectionToStack();
                                cmd = FuncRequest(LFUN_PASTE, "0");
                        } else {
                                cmd = FuncRequest(LFUN_PRIMARY_SELECTION_PASTE,
@@ -537,7 +538,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
                //lyxerr << "# InsetTabular::MouseRelease\n" << bvcur << endl;
                if (cmd.button() == mouse_button::button1) {
                        if (bvcur.selection())
-                               theSelection().haveSelection(true);
+                               saveSelection(bvcur);// theSelection().haveSelection(true);
                } else if (cmd.button() == mouse_button::button3)
                        InsetTabularMailer(*this).showDialog(&cur.bv());
                break;
@@ -545,11 +546,13 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_CELL_BACKWARD:
                movePrevCell(cur);
                cur.selection() = false;
+               saveSelection(cur);
                break;
 
        case LFUN_CELL_FORWARD:
                moveNextCell(cur);
                cur.selection() = false;
+               saveSelection(cur);
                break;
 
        case LFUN_CHAR_FORWARD_SELECT:
@@ -558,7 +561,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
                if (!cur.result().dispatched()) {
                        isRightToLeft(cur) ? movePrevCell(cur) : moveNextCell(cur);
                        if (cmd.action == LFUN_CHAR_FORWARD_SELECT)
-                               theSelection().haveSelection(cur.selection());
+                               saveSelection(cur);
                        if (sl == cur.top())
                                cmd = FuncRequest(LFUN_FINISHED_RIGHT);
                        else
@@ -572,7 +575,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
                if (!cur.result().dispatched()) {
                        isRightToLeft(cur) ? moveNextCell(cur) : movePrevCell(cur);
                        if (cmd.action == LFUN_CHAR_BACKWARD_SELECT)
-                               theSelection().haveSelection(cur.selection());
+                               saveSelection(cur);
                        if (sl == cur.top())
                                cmd = FuncRequest(LFUN_FINISHED_LEFT);
                        else
@@ -595,7 +598,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
                                        cur.bv().textMetrics(cell(cur.idx())->getText(0));
                                cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX());
                                if (cmd.action == LFUN_DOWN_SELECT)
-                                       theSelection().haveSelection(cur.selection());
+                                       saveSelection(cur);
                        }
                if (sl == cur.top()) {
                        // we trick it to go to the RIGHT after leaving the
@@ -622,7 +625,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
                                        tm.parMetrics(cur.lastpit());
                                cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, cur.targetX());
                                if (cmd.action == LFUN_UP_SELECT)
-                                       theSelection().haveSelection(cur.selection());
+                                       saveSelection(cur);
                        }
                if (sl == cur.top()) {
                        cmd = FuncRequest(LFUN_FINISHED_UP);
@@ -746,7 +749,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_PASTE:
                if (tabularStackDirty() && theClipboard().isInternal()) {
                        recordUndoInset(cur, Undo::INSERT);
-                       pasteSelection(cur);
+                       pasteClipboard(cur);
                        break;
                }
                cell(cur.idx())->dispatch(cur, cmd);
@@ -1823,7 +1826,7 @@ bool InsetTabular::copySelection(LCursor & cur)
 }
 
 
-bool InsetTabular::pasteSelection(LCursor & cur)
+bool InsetTabular::pasteClipboard(LCursor & cur)
 {
        if (!paste_tabular)
                return false;
index c9e5c5c68d3f46ef1ace66407f742741bc596b0a..2ab5d2f327f0f31d671bed6b263defe60030e1a2 100644 (file)
@@ -179,7 +179,7 @@ private:
        ///
        bool copySelection(LCursor & cur);
        ///
-       bool pasteSelection(LCursor & cur);
+       bool pasteClipboard(LCursor & cur);
        ///
        void cutSelection(LCursor & cur);
        ///
index c223c65b377c7a542c03a231aef9c6f5782cfa44..932cbec30e0a31df48b9cd37ab980a076802070f 100644 (file)
@@ -29,7 +29,6 @@
 #include "undo.h"
 
 #include "frontends/Alert.h"
-#include "frontends/Selection.h"
 
 #include "support/convert.h"
 #include "support/docstream.h"
@@ -366,7 +365,6 @@ bool findNextChange(BufferView * bv)
        // Now put cursor to end of selection:
        bv->cursor().setCursor(cur);
        bv->cursor().setSelection();
-       theSelection().haveSelection(bv->cursor().selection());
 
        return true;
 }
index 9d0a5ddd3c9cf409870b0916413ad06506441ca1..aac42634d77c75934b84af8982620182d99a815b 100644 (file)
@@ -50,7 +50,6 @@ using std::istream;
 using std::istringstream;
 using std::vector;
 
-
 class GridInsetMailer : public MailInset {
 public:
        GridInsetMailer(InsetMathGrid & inset) : inset_(inset) {}
index 55a51dc0ffcc8ad0cb1c544ab8c47ae5e0adbc21..09ac010b2748288b781d01f683ee120797862303 100644 (file)
@@ -1400,7 +1400,6 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str,
                MathArray const & a = top.asInsetMath()->cell(top.idx_);
                if (a.matchpart(ar, top.pos_)) {
                        bv->cursor().setSelection(it, ar.size());
-                       theSelection().haveSelection(bv->cursor().selection());
                        current = it;
                        top.pos_ += ar.size();
                        bv->update();
index 40dae7ee177e33457d019a8eb6cbd03e4e50a420..84883636161e650fb5e3f0bc8df5c288af326fd9 100644 (file)
@@ -580,7 +580,7 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                cur.selection() = true;
                cur.pos() = cur.lastpos();
                cur.idx() = cur.lastidx();
-               theSelection().haveSelection(true);
+               cap::saveSelection(cur);
                break;
 
        case LFUN_PARAGRAPH_UP:
@@ -1151,10 +1151,11 @@ void InsetMathNest::lfunMousePress(LCursor & cur, FuncRequest & cmd)
                cur.updateFlags(Update::Decoration | Update::FitCursor);
        } else if (cmd.button() == mouse_button::button2) {
                MathArray ar;
-               if (cur.selection()) {
+               if (cap::selection()) {
                        // See comment in LyXText::dispatch why we do this
-                       cap::copySelectionToStack(bv.cursor());
-                       asArray(bv.cursor().selectionAsString(false), ar);
+                       cap::copySelectionToStack();
+                       cmd = FuncRequest(LFUN_PASTE, "0");
+                       doDispatch(cur, cmd);
                } else
                        asArray(theSelection().get(), ar);
 
@@ -1185,10 +1186,13 @@ void InsetMathNest::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
        //lyxerr << "## lfunMouseRelease: buttons: " << cmd.button() << endl;
 
        if (cmd.button() == mouse_button::button1) {
-               if (cur.bv().cursor().selection())
-                       theSelection().haveSelection(true);
                if (!cur.selection())
                        cur.noUpdate();
+               else {
+                       LCursor & bvcur = cur.bv().cursor();
+                       bvcur.selection() = true;
+                       cap::saveSelection(bvcur);
+               }
                return;
        }
 
index ce9e710fa8c34f8743c5cdc0c4a07155e4d17f79..d30bdeb20f17b81d8344b2ea24f843ddfea03308 100644 (file)
@@ -53,7 +53,6 @@
 
 #include "frontends/FontMetrics.h"
 #include "frontends/Painter.h"
-#include "frontends/Selection.h"
 
 #include "insets/insettext.h"
 #include "insets/insetbibitem.h"
@@ -829,7 +828,7 @@ void LyXText::selectWord(LCursor & cur, word_location loc)
        cur.resetAnchor();
        setCursor(cur, to.pit(), to.pos());
        cur.setSelection();
-       theSelection().haveSelection(cur.selection());
+       cap::saveSelection(cur);
 }
 
 
index a6103ec59c6bc49f890c3ac29b05f1b4c81c4f90..fe9c9cd7846c6d43c9ed1cb73ff1369c32640d7e 100644 (file)
@@ -76,9 +76,10 @@ namespace lyx {
 
 using cap::copySelection;
 using cap::cutSelection;
+using cap::pasteFromStack;
 using cap::pasteClipboard;
-using cap::pasteSelection;
 using cap::replaceSelection;
+using cap::saveSelection;
 
 using support::isStrUnsignedInt;
 using support::token;
@@ -122,7 +123,7 @@ namespace {
        {
                if (selecting || cur.mark())
                        cur.setSelection();
-               theSelection().haveSelection(cur.selection());
+               saveSelection(cur);
                cur.bv().switchKeyMap();
        }
 
@@ -138,7 +139,6 @@ namespace {
        {
                recordUndo(cur);
                docstring sel = cur.selectionAsString(false);
-               //lyxerr << "selection is: '" << sel << "'" << endl;
 
                // It may happen that sel is empty but there is a selection
                replaceSelection(cur);
@@ -434,6 +434,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_RIGHT);
                }
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_CHAR_BACKWARD:
@@ -450,6 +452,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_LEFT);
                }
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_UP:
@@ -464,6 +468,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_UP);
                }
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_DOWN:
@@ -478,18 +484,24 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_DOWN);
                }
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_PARAGRAPH_UP:
        case LFUN_PARAGRAPH_UP_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_PARAGRAPH_UP_SELECT);
                needsUpdate |= cursorUpParagraph(cur);
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_PARAGRAPH_DOWN:
        case LFUN_PARAGRAPH_DOWN_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_PARAGRAPH_DOWN_SELECT);
                needsUpdate |= cursorDownParagraph(cur);
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_SCREEN_UP:
@@ -501,6 +513,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                } else {
                        cursorPrevious(cur);
                }
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_SCREEN_DOWN:
@@ -513,6 +527,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                } else {
                        cursorNext(cur);
                }
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_LINE_BEGIN:
@@ -525,6 +541,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_LINE_END_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_LINE_END_SELECT);
                needsUpdate |= cursorEnd(cur);
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_WORD_FORWARD:
@@ -534,6 +552,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        needsUpdate |= cursorLeftOneWord(cur);
                else
                        needsUpdate |= cursorRightOneWord(cur);
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_WORD_BACKWARD:
@@ -543,6 +563,8 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        needsUpdate |= cursorRightOneWord(cur);
                else
                        needsUpdate |= cursorLeftOneWord(cur);
+               if (cur.selection())
+                       saveSelection(cur);
                break;
 
        case LFUN_WORD_SELECT: {
@@ -781,7 +803,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        pasteClipboard(cur, bv->buffer()->errorList("Paste"));
                else {
                        string const arg(to_utf8(cmd.argument()));
-                       pasteSelection(cur, bv->buffer()->errorList("Paste"),
+                       pasteFromStack(cur, bv->buffer()->errorList("Paste"),
                                        isStrUnsignedInt(arg) ?
                                                convert<unsigned int>(arg) :
                                                0);
@@ -960,7 +982,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                        cursorEnd(cur);
                        cur.setSelection();
                        bv->cursor() = cur;
-                       theSelection().haveSelection(cur.selection());
+                       saveSelection(cur);
                }
                break;
 
@@ -968,7 +990,6 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                if (cmd.button() == mouse_button::button1) {
                        selectWord(cur, WHOLE_WORD_STRICT);
                        bv->cursor() = cur;
-                       theSelection().haveSelection(cur.selection());
                }
                break;
 
@@ -983,15 +1004,11 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                // it could get cleared on the unlocking of the inset so
                // we have to check this first
                bool paste_internally = false;
-               if (cmd.button() == mouse_button::button2 && cur.selection()) {
-                       // Copy the selection to the clipboard stack. This
-                       // is done for two reasons:
-                       // - We want it to appear in the "Edit->Paste recent"
-                       //   menu.
-                       // - We can then use the normal copy/paste machinery
-                       //   instead of theSelection().get() to preserve
-                       //   formatting of the pasted stuff.
-                       cap::copySelectionToStack(cur.bv().cursor());
+               if (cmd.button() == mouse_button::button2 && cap::selection()) {
+                       // Copy the selection buffer to the clipboard
+                       // stack, because we want it to appear in the
+                       // "Edit->Paste recent" menu.
+                       cap::copySelectionToStack();
                        paste_internally = true;
                }
 
@@ -1002,9 +1019,13 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                // if there is a local selection in the current buffer,
                // insert this
                if (cmd.button() == mouse_button::button2) {
-                       if (paste_internally)
-                               lyx::dispatch(FuncRequest(LFUN_PASTE, "0"));
-                       else
+                       if (paste_internally) {
+                               cap::pasteSelection(cur, bv->buffer()->errorList("Paste"));
+                               bv->buffer()->errors("Paste");
+                               cur.clearSelection(); // bug 393
+                               bv->switchKeyMap();
+                               finishUndo();
+                       } else
                                lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
                }
 
@@ -1061,10 +1082,18 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                if (cmd.button() == mouse_button::button2)
                        break;
 
-               // finish selection
                if (cmd.button() == mouse_button::button1) {
-                       if (cur.selection())
-                               theSelection().haveSelection(true);
+                       // if there is new selection, update persistent
+                       // selection, otherwise, single click does not
+                       // clear persistent selection buffer
+                       if (cur.selection()) {
+                               // finish selection
+                               // if double click, cur is moved to the end of word by selectWord
+                               // but bvcur is current mouse position
+                               LCursor & bvcur = cur.bv().cursor();
+                               bvcur.selection() = true;
+                               saveSelection(bvcur);
+                       }
                        needsUpdate = false;
                        cur.noUpdate();
                }
@@ -1083,13 +1112,9 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
                // "auto_region_delete", which defaults to
                // true (on).
 
-               if (lyxrc.auto_region_delete) {
+               if (lyxrc.auto_region_delete)
                        if (cur.selection())
                                cutSelection(cur, false, false);
-                               // cutSelection clears the X selection.
-                       else
-                               theSelection().haveSelection(false);
-               }
 
                cur.clearSelection();
                LyXFont const old_font = real_current_font;
@@ -1508,6 +1533,7 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_ESCAPE:
                if (cur.selection()) {
                        cur.selection() = false;
+                       saveSelection(cur);
                } else {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_RIGHT);