include/vcl/seleng.hxx                     |    2 ++
 vcl/inc/dndlistenercontainer.hxx           |    3 +++
 vcl/source/window/dndlistenercontainer.cxx |    6 ++++++
 vcl/source/window/seleng.cxx               |   24 +++++++++++++++++++++---
 4 files changed, 32 insertions(+), 3 deletions(-)

New commits:
commit 4d128e84db906ed45b2975f8e1d649dad44e9ec2
Author:     Samuel Mehrbrodt <[email protected]>
AuthorDate: Mon Jan 12 14:52:42 2026 +0100
Commit:     Samuel Mehrbrodt <[email protected]>
CommitDate: Mon Jan 19 07:46:08 2026 +0100

    Fix drag&drop with multiselection from extensions
    
    When registering drag gesture listeners via an extension,
    the selection handling code did not recognize that as "drag mode" being set.
    Dragging multiple elements did not work consequently.
    
    Change this and consider registered drag gesture listeners also as
    "drag mode" being set.
    
    Change-Id: I37de30ad3c385001f08988d462f6e7dfb3f0183c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197117
    Reviewed-by: Stephan Bergmann <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit 2173a79c691f793a6a6f55353d406e6c71c41e09)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197221
    Tested-by: allotropia jenkins <[email protected]>

diff --git a/include/vcl/seleng.hxx b/include/vcl/seleng.hxx
index a0f069e04c1e..5f5498a6caec 100644
--- a/include/vcl/seleng.hxx
+++ b/include/vcl/seleng.hxx
@@ -91,6 +91,8 @@ private:
 
     inline bool         ShouldDeselect( bool bModifierKey1 ) const;
                                 // determines to deselect or not when Ctrl-key 
is pressed on CursorPosChanging
+    bool                IsDragEnabled() const;
+                                // checks if dragging is enabled via flag or 
drag gesture listeners
 public:
 
                         SelectionEngine( vcl::Window* pWindow,
diff --git a/vcl/inc/dndlistenercontainer.hxx b/vcl/inc/dndlistenercontainer.hxx
index bc4109d5e42c..11e16dfaac15 100644
--- a/vcl/inc/dndlistenercontainer.hxx
+++ b/vcl/inc/dndlistenercontainer.hxx
@@ -103,6 +103,9 @@ public:
     virtual void SAL_CALL removeDragGestureListener( const 
css::uno::Reference< css::datatransfer::dnd::XDragGestureListener >& dgl ) 
override;
     virtual void SAL_CALL resetRecognizer(  ) override;
 
+    // Helper method to check if there are any drag gesture listeners 
registered
+    bool hasDragGestureListeners() const;
+
        /*
      * XDropTargetDragContext
      */
diff --git a/vcl/source/window/dndlistenercontainer.cxx 
b/vcl/source/window/dndlistenercontainer.cxx
index 9ff128c808bb..b037cf89bd9b 100644
--- a/vcl/source/window/dndlistenercontainer.cxx
+++ b/vcl/source/window/dndlistenercontainer.cxx
@@ -50,6 +50,12 @@ void SAL_CALL DNDListenerContainer::resetRecognizer(  )
 {
 }
 
+bool DNDListenerContainer::hasDragGestureListeners() const
+{
+    std::unique_lock g(m_aMutex);
+    return maDragGestureListeners.getLength(g) > 0;
+}
+
 void SAL_CALL DNDListenerContainer::addDropTargetListener( const Reference< 
XDropTargetListener >& dtl )
 {
     std::unique_lock g(m_aMutex);
diff --git a/vcl/source/window/seleng.cxx b/vcl/source/window/seleng.cxx
index a22ecaa7c5dd..516926c8f627 100644
--- a/vcl/source/window/seleng.cxx
+++ b/vcl/source/window/seleng.cxx
@@ -20,6 +20,7 @@
 #include <vcl/commandevent.hxx>
 #include <vcl/window.hxx>
 #include <vcl/seleng.hxx>
+#include <dndlistenercontainer.hxx>
 #include <comphelper/lok.hxx>
 #include <sal/log.hxx>
 
@@ -32,6 +33,22 @@ inline bool SelectionEngine::ShouldDeselect( bool 
bModifierKey1 ) const
     return eSelMode != SelectionMode::Multiple || !bModifierKey1;
 }
 
+bool SelectionEngine::IsDragEnabled() const
+{
+    // Check if drag is enabled via flag
+    if (nFlags & SelectionEngineFlags::DRG_ENAB)
+        return true;
+
+    // Extensions might have registered drag gesture listeners
+    // while the drag flag is not set - in this case we also
+    // want to allow drag operations. Otherwise D&D from
+    // extensions would not work properly (esp. with multiple selection).
+    if (!pWin)
+        return false;
+    rtl::Reference<DNDListenerContainer> rDropTarget = 
dynamic_cast<DNDListenerContainer *>(pWin->GetDropTarget().get());
+    return rDropTarget.is() && rDropTarget->hasDragGestureListeners();
+}
+
 // TODO: throw out FunctionSet::SelectAtPoint
 
 SelectionEngine::SelectionEngine( vcl::Window* pWindow, FunctionSet* pFuncSet 
) :
@@ -153,8 +170,9 @@ bool SelectionEngine::SelMouseButtonDown( const MouseEvent& 
rMEvt )
         case 0:     // KEY_NO_KEY
         {
             bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
+            bool bDragEnabled = IsDragEnabled();
             nFlags &= ~SelectionEngineFlags::IN_ADD;
-            if ( (nFlags & SelectionEngineFlags::DRG_ENAB) && bSelAtPoint )
+            if ( bDragEnabled && bSelAtPoint )
             {
                 nFlags |= SelectionEngineFlags::WAIT_UPEVT;
                 nFlags &= ~SelectionEngineFlags::IN_SEL;
@@ -171,7 +189,7 @@ bool SelectionEngine::SelMouseButtonDown( const MouseEvent& 
rMEvt )
             }
             pFunctionSet->SetCursorAtPoint( aPos );
             // special case Single-Selection, to enable simple Select+Drag
-            if (eSelMode == SelectionMode::Single && (nFlags & 
SelectionEngineFlags::DRG_ENAB))
+            if (eSelMode == SelectionMode::Single && bDragEnabled)
                 nFlags |= SelectionEngineFlags::WAIT_UPEVT;
             return true;
         }
@@ -375,7 +393,7 @@ bool SelectionEngine::Command( const CommandEvent& rCEvt )
         return false;
 
     nFlags |= SelectionEngineFlags::CMDEVT;
-    if ( nFlags & SelectionEngineFlags::DRG_ENAB )
+    if ( IsDragEnabled() )
     {
         SAL_WARN_IF( !rCEvt.IsMouseEvent(), "vcl", "STARTDRAG: Not a 
MouseEvent" );
         if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )

Reply via email to