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