[LyX/master] Fix notifyCursorLeavesOrEnters with selections

Jean-Marc Lasgouttes <[email protected]> Fri, 26 Jun 2026 17:52:04 +0000
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit 4dd20ebe45f3f8b1e6880edcee7e49cde29d392f
Author: Jean-Marc Lasgouttes <[email protected]>
Date:   Tue Jun 16 17:15:54 2026 +0200

    Fix notifyCursorLeavesOrEnters with selections
    
    It may happen that cursor "old" points deeper inside an inset than the
    anchor when doing a selection. This can happens for example when
    selecting with the mouse, where BufferView::mouseEventDispatch() will
    first put the main DocIterator inside a nested inset and later will
    correct that to have a depth compatible with the anchor.
    
    When this happens, notifyCursorLeavesOrEnters could notify a `leave'
    to the selected insets, which is not desirable.
    
    This commit fixes the function so that, when selecting, it only
    considers slices that are compatible with the anchors of both old and
    new cursor.
    
    Fixes bug #13338 (see #13305 for a discussion).
---
 src/Cursor.cpp | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/Cursor.cpp b/src/Cursor.cpp
index 3141660515..2b713a80f5 100644
--- a/src/Cursor.cpp
+++ b/src/Cursor.cpp
@@ -2453,15 +2453,34 @@ void Cursor::sanitize()
 
 bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur)
 {
+	// handle selections: the real depth is the deepest element shared
+	// by cursor and anchor.
+	// First the new cursor...
+	size_type real_cur_depth = cur.depth();
+	if (cur.selection())
+		for (size_type i = 0 ; i < min(cur.depth(), cur.realAnchor().depth()) ; ++i)
+			if (&cur[i].inset() != &cur.realAnchor()[i].inset()) {
+				real_cur_depth = i;
+				break;
+			}
+	// ... and then the old one.
+	size_type real_old_depth = old.depth();
+	if (old.selection())
+		for (size_type i = 0 ; i < min(old.depth(), old.realAnchor().depth()) ; ++i)
+			if (&old[i].inset() != &old.realAnchor()[i].inset()) {
+				real_old_depth = i;
+				break;
+			}
+
 	// find inset in common
 	size_type i;
-	for (i = 0; i < old.depth() && i < cur.depth(); ++i) {
+	for (i = 0; i < real_old_depth && i < real_cur_depth; ++i) {
 		if (old[i].realInset() != cur[i].realInset())
 			break;
 	}
 
 	// update words if we just moved to another paragraph
-	if (i == old.depth() && i == cur.depth()
+	if (i == real_old_depth && i == real_cur_depth
 	    && !cur.buffer()->isClean()
 	    && cur.inTexted() && old.inTexted()
 	    && cur.pit() != old.pit()) {
@@ -2470,7 +2489,7 @@ bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur)
 
 	// notify everything on top of the common part in old cursor,
 	// but stop if the inset claims the cursor to be invalid now
-	for (size_type j = i; j < old.depth(); ++j) {
+	for (size_type j = i; j < real_old_depth; ++j) {
 		Cursor inset_pos = old;
 		inset_pos.resize(j + 1);
 		if (old[j].realInset()->notifyCursorLeaves(inset_pos, cur))
@@ -2479,7 +2498,7 @@ bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur)
 
 	// notify everything on top of the common part in new cursor,
 	// but stop if the inset claims the cursor to be invalid now
-	for (; i < cur.depth(); ++i) {
+	for (; i < real_cur_depth; ++i) {
 		if (cur[i].realInset()->notifyCursorEnters(old, cur))
 			return true;
 	}
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs