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() ) )
