Analysis:

Previously, any selection action triggers saveSelection, which saves
selection and calls theSelection().haveSelection(cur.selection());.
Therefore, when selecting with page down, saveSelection will be called
many times, with larger and larger selected texts saving to the
selection buffer. This is of course slow.

Solution:

Instead of saveSelection when a selection is formed, this patch saves
a selection when it is cleared. This sounds strange so let me explain:

select, left button click, middle button click

previously triggers

select -> saveSelection, left button click -> clearSelection, middle
button click -> paste

and now

select -> nothing, left button click -> saveSelection, clearSelection,
middle button click -> paste

In the page down selection case, the entire selection will only be
copied to the selection buffer when the selection is pasted, or
cleared by left/right/up/down/home/end/buffer switch etc. Therefore,
bug 3877 is fixed.

Problem:

It is more difficult to catch 'selection clear' events than 'selection
creation' events. I have caught all keyboard up/down/home/end etc, and
BUFFER_SWITCH, but there is no WINDOW_SWITCH signal. That is to say, I
can not select in one window and paste in another one.

Note that selection in lyx, and paste outside of lyx is not affected.

Abdel: how to catch window enter/leave/switch events?

Patch:

Attached patch is long but easy to understand:

                case LFUN_BUFFER_SWITCH:
                        BOOST_ASSERT(lyx_view_);
+                       // save current selection to the selection buffer to 
allow
+                       // middle-button paste in another buffer
+                       cap::saveSelection(view()->cursor());
                        
lyx_view_->setBuffer(theBufferList().getBuffer(argument));
                        break;



saveSelection before buffer switch,


MANY cases like this:

        case LFUN_CHAR_FORWARD:
+               // save selection because char forward will clear selection
+               saveSelection(cur);
        case LFUN_CHAR_FORWARD_SELECT:
                //lyxerr << BOOST_CURRENT_FUNCTION
                //       << " LFUN_CHAR_FORWARD[SEL]:\n" << cur << endl;
@@ -488,11 +494,13 @@


Save selection with char-forward, backward, up, down, home, end etc.

@@ -575,44 +588,48 @@
                else {
                        cursorNext(cur);
                }
-               if (cur.selection())
-                       saveSelection(cur);
+               theSelection().haveSelection(cur.selection());
                break;

Remove saveSelection after selection is formed.

void saveSelection(Cursor & cur)
{
-       LYXERR(Debug::ACTION) << BOOST_CURRENT_FUNCTION << ": `"
-              << to_utf8(cur.selectionAsString(true)) << "'."
-              << endl;
+       // This function is called, not when a selection is formed, but when
+       // a selection is cleared. Therefore, multiple keyboard selection
+       // will not repeatively trigger this function (bug 3877).
+       // The problem with this approach is that it is difficult to catch
+       // all cases when this function should be called so a few minor bugs
+       // are expected.
+       if (cur.selection()) {
+               LYXERR(Debug::ACTION) << BOOST_CURRENT_FUNCTION << ": `"
+                          << to_utf8(cur.selectionAsString(true)) << "'."
+                          << endl;

-       // FIXME: The two lines below would allow middle-mouse
-       // pasting that preserves the LyX formatting when the selection
-       // is internal. They would also allow to use the feature on
-       // Windows and Mac. In the future, we may want to optionally enable
-       // this feature via a rc setting.
-       /*
-       if (cur.selection())
                copySelectionToStack(cur, selectionBuffer);
-       */
-
-       // tell X whether we now have a valid selection
-       theSelection().haveSelection(cur.selection());
+       }
}

The saveSelection function does not do theSelection()... now.


Conclusion: This is the best patch I can think of for BUG3877. Please
test and I will commit with two OKs.

Cheers,
Bo
Index: src/LyXFunc.cpp
===================================================================
--- src/LyXFunc.cpp	(revision 18980)
+++ src/LyXFunc.cpp	(working copy)
@@ -1184,6 +1184,9 @@
 		// --- buffers ----------------------------------------
 		case LFUN_BUFFER_SWITCH:
 			BOOST_ASSERT(lyx_view_);
+			// save current selection to the selection buffer to allow
+			// middle-button paste in another buffer
+			cap::saveSelection(view()->cursor());
 			lyx_view_->setBuffer(theBufferList().getBuffer(argument));
 			break;
 
Index: src/CutAndPaste.cpp
===================================================================
--- src/CutAndPaste.cpp	(revision 18980)
+++ src/CutAndPaste.cpp	(working copy)
@@ -672,22 +672,19 @@
 
 void saveSelection(Cursor & cur)
 {
-	LYXERR(Debug::ACTION) << BOOST_CURRENT_FUNCTION << ": `"
-	       << to_utf8(cur.selectionAsString(true)) << "'."
-	       << endl;
+	// This function is called, not when a selection is formed, but when
+	// a selection is cleared. Therefore, multiple keyboard selection
+	// will not repeatively trigger this function (bug 3877).
+	// The problem with this approach is that it is difficult to catch 
+	// all cases when this function should be called so a few minor bugs 
+	// are expected.
+	if (cur.selection()) {
+		LYXERR(Debug::ACTION) << BOOST_CURRENT_FUNCTION << ": `"
+			   << to_utf8(cur.selectionAsString(true)) << "'."
+			   << endl;
 
-	// FIXME: The two lines below would allow middle-mouse 
-	// pasting that preserves the LyX formatting when the selection
-	// is internal. They would also allow to use the feature on
-	// Windows and Mac. In the future, we may want to optionally enable
-	// this feature via a rc setting.
-	/*
-	if (cur.selection())
 		copySelectionToStack(cur, selectionBuffer);
-	*/
-
-	// tell X whether we now have a valid selection
-	theSelection().haveSelection(cur.selection());
+	}
 }
 
 
Index: src/Text3.cpp
===================================================================
--- src/Text3.cpp	(revision 18980)
+++ src/Text3.cpp	(working copy)
@@ -119,7 +119,7 @@
 	{
 		if (selecting || cur.mark())
 			cur.setSelection();
-		saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 	}
 
 
@@ -455,6 +455,8 @@
 		break;
 
 	case LFUN_BUFFER_BEGIN:
+		// save selection because buffer begin will clear selection
+		saveSelection(cur);
 	case LFUN_BUFFER_BEGIN_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_BUFFER_BEGIN_SELECT);
 		if (cur.depth() == 1) {
@@ -465,6 +467,8 @@
 		break;
 
 	case LFUN_BUFFER_END:
+		// save selection because buffer end will clear selection
+		saveSelection(cur);
 	case LFUN_BUFFER_END_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_BUFFER_END_SELECT);
 		if (cur.depth() == 1) {
@@ -475,6 +479,8 @@
 		break;
 
 	case LFUN_CHAR_FORWARD:
+		// save selection because char forward will clear selection
+		saveSelection(cur);
 	case LFUN_CHAR_FORWARD_SELECT:
 		//lyxerr << BOOST_CURRENT_FUNCTION
 		//       << " LFUN_CHAR_FORWARD[SEL]:\n" << cur << endl;
@@ -488,11 +494,13 @@
 				&& cur.boundary() == oldBoundary) {
 			cur.undispatched();
 			cmd = FuncRequest(LFUN_FINISHED_RIGHT);
-		} else if (cur.selection())
-			saveSelection(cur);
+		}
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_CHAR_BACKWARD:
+		// save selection because char backward will clear selection
+		saveSelection(cur);
 	case LFUN_CHAR_BACKWARD_SELECT:
 		//lyxerr << "handle LFUN_CHAR_BACKWARD[_SELECT]:\n" << cur << endl;
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_BACKWARD_SELECT);
@@ -506,14 +514,16 @@
 			cur.undispatched();
 			cmd = FuncRequest(LFUN_FINISHED_LEFT);
 		}
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
+	case LFUN_UP:
+	case LFUN_DOWN: 
+		// save selection because cursor up/down will clear selection
+		saveSelection(cur);
 	case LFUN_UP_SELECT:
 	case LFUN_DOWN_SELECT:
-	case LFUN_UP:
-	case LFUN_DOWN: {
+	{
 		// stop/start the selection
 		bool select = cmd.action == LFUN_DOWN_SELECT ||
 			cmd.action == LFUN_UP_SELECT;
@@ -532,29 +542,31 @@
 		} else
 			cur.undispatched();
 		
-		// save new selection
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 	}
 
 	case LFUN_PARAGRAPH_UP:
+		// save selection because paragraph up will clear selection
+		saveSelection(cur);
 	case LFUN_PARAGRAPH_UP_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_PARAGRAPH_UP_SELECT);
 		needsUpdate |= cursorUpParagraph(cur);
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_PARAGRAPH_DOWN:
+		// save selection because paragraph down will clear selection
+		saveSelection(cur);
 	case LFUN_PARAGRAPH_DOWN_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_PARAGRAPH_DOWN_SELECT);
 		needsUpdate |= cursorDownParagraph(cur);
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_SCREEN_UP:
+		// save selection because screen up will clear selection
+		saveSelection(cur);
 	case LFUN_SCREEN_UP_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_SCREEN_UP_SELECT);
 		if (cur.pit() == 0 && cur.textRow().pos() == 0)
@@ -562,11 +574,12 @@
 		else {
 			cursorPrevious(cur);
 		}
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_SCREEN_DOWN:
+		// save selection because screen down will clear selection
+		saveSelection(cur);
 	case LFUN_SCREEN_DOWN_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_SCREEN_DOWN_SELECT);
 		if (cur.pit() == cur.lastpit()
@@ -575,44 +588,48 @@
 		else {
 			cursorNext(cur);
 		}
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_LINE_BEGIN:
+		// save selection because line begin will clear selection
+		saveSelection(cur);
 	case LFUN_LINE_BEGIN_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_LINE_BEGIN_SELECT);
 		needsUpdate |= cursorHome(cur);
 		break;
 
 	case LFUN_LINE_END:
+		// save selection because line end will clear selection
+		saveSelection(cur);
 	case LFUN_LINE_END_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_LINE_END_SELECT);
 		needsUpdate |= cursorEnd(cur);
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_WORD_FORWARD:
+		// save selection because word forward will clear selection
+		saveSelection(cur);
 	case LFUN_WORD_FORWARD_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT);
 		if (reverseDirectionNeeded(cur))
 			needsUpdate |= cursorLeftOneWord(cur);
 		else
 			needsUpdate |= cursorRightOneWord(cur);
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_WORD_BACKWARD:
+		// save selection because word backward will clear selection
+		saveSelection(cur);
 	case LFUN_WORD_BACKWARD_SELECT:
 		needsUpdate |= cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT);
 		if (reverseDirectionNeeded(cur))
 			needsUpdate |= cursorRightOneWord(cur);
 		else
 			needsUpdate |= cursorLeftOneWord(cur);
-		if (cur.selection())
-			saveSelection(cur);
+		theSelection().haveSelection(cur.selection());
 		break;
 
 	case LFUN_WORD_SELECT: {
@@ -1033,7 +1050,7 @@
 			cursorEnd(cur);
 			cur.setSelection();
 			bv->cursor() = cur;
-			saveSelection(cur);
+			theSelection().haveSelection(cur.selection());
 		}
 		break;
 
@@ -1046,6 +1063,9 @@
 
 	// Single-click on work area
 	case LFUN_MOUSE_PRESS: {
+		// previous selection is going to be cleared, so we
+		// save it to selection buffer (for persistent selection)
+		saveSelection(cur.bv().cursor());
 		// Right click on a footnote flag opens float menu
 		if (cmd.button() == mouse_button::button3)
 			cur.clearSelection();
@@ -1145,7 +1165,7 @@
 				// but bvcur is current mouse position
 				Cursor & bvcur = cur.bv().cursor();
 				bvcur.selection() = true;
-				saveSelection(bvcur);
+				theSelection().haveSelection(true);
 			}
 			needsUpdate = false;
 			cur.noUpdate();
@@ -1589,7 +1609,7 @@
 	case LFUN_ESCAPE:
 		if (cur.selection()) {
 			cur.selection() = false;
-			saveSelection(cur);
+			theSelection().haveSelection(cur.selection());
 		} else {
 			cur.undispatched();
 			cmd = FuncRequest(LFUN_FINISHED_RIGHT);

Reply via email to