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

New commits:
commit 2173a79c691f793a6a6f55353d406e6c71c41e09
Author:     Samuel Mehrbrodt <[email protected]>
AuthorDate: Mon Jan 12 14:52:42 2026 +0100
Commit:     Samuel Mehrbrodt <[email protected]>
CommitDate: Tue Jan 13 21:38:04 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

diff --git a/include/vcl/dndlistenercontainer.hxx 
b/include/vcl/dndlistenercontainer.hxx
index 2d2c6a80d954..d8f5897389ce 100644
--- a/include/vcl/dndlistenercontainer.hxx
+++ b/include/vcl/dndlistenercontainer.hxx
@@ -80,6 +80,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/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/source/window/dndlistenercontainer.cxx 
b/vcl/source/window/dndlistenercontainer.cxx
index f3f5b6cda0e5..1970bfcb524f 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..05a5859bdbda 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 <vcl/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 = pWin->GetDropTarget();
+    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