LibreOffice Module vcl (master) 1
dndeventdispatcher.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
22#include <sal/log.hxx>
23
24#include <osl/mutex.hxx>
25#include <vcl/svapp.hxx>
26#include <vcl/settings.hxx>
27
28using namespace ::cppu;
29using namespace ::com::sun::star::uno;
30using namespace ::com::sun::star::lang;
31using namespace ::com::sun::star::datatransfer;
32using namespace ::com::sun::star::datatransfer::dnd;
33
35 m_pTopWindow( pTopWindow ),
36 m_pCurrentWindow( nullptr )
37{
38}
39
41{
43}
44
46{
47 SolarMutexGuard aSolarGuard;
48
49 // find the window that is toplevel for this coordinates
50 // because those coordinates come from outside, they must be mirrored if RTL layout is active
53 vcl::Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
54
55 if( nullptr == pChildWindow )
56 pChildWindow = m_pTopWindow;
57
58 while( pChildWindow->ImplGetClientWindow() )
59 pChildWindow = pChildWindow->ImplGetClientWindow();
60
61 if( pChildWindow->GetOutDev()->ImplIsAntiparallel() )
62 {
63 const OutputDevice *pChildWinOutDev = pChildWindow->GetOutDev();
64 pChildWinOutDev->ReMirror( location );
65 }
66
67 return pChildWindow;
68}
69
70IMPL_LINK(DNDEventDispatcher, WindowEventListener, VclWindowEvent&, rEvent, void)
71{
72 if (rEvent.GetId() == VclEventId::ObjectDying)
73 {
74 designate_currentwindow(nullptr);
75 }
76}
77
79{
81 m_pCurrentWindow->RemoveEventListener(LINK(this, DNDEventDispatcher, WindowEventListener));
82 m_pCurrentWindow = pWindow;
84 m_pCurrentWindow->AddEventListener(LINK(this, DNDEventDispatcher, WindowEventListener));
85}
86
87void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde )
88{
89 std::scoped_lock aImplGuard( m_aMutex );
90
91 Point location( dtde.LocationX, dtde.LocationY );
92
93 vcl::Window* pChildWindow = findTopLevelWindow(location);
94
95 // handle the case that drop is in another vcl window than the last dragOver
96 if( pChildWindow != m_pCurrentWindow.get() )
97 {
98 // fire dragExit on listeners of previous window
100
101 fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this),
102 dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList );
103 }
104
105 // send drop event to the child window
106 sal_Int32 nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction,
107 location, dtde.SourceActions, dtde.Transferable );
108
109 // reject drop if no listeners found
110 if( nListeners == 0 ) {
111 SAL_WARN( "vcl", "rejecting drop due to missing listeners." );
112 dtde.Context->rejectDrop();
113 }
114
115 // this is a drop -> no further drag overs
117 m_aDataFlavorList.realloc( 0 );
118}
119
120void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee )
121{
122 std::scoped_lock aImplGuard( m_aMutex );
123 Point location( dtdee.LocationX, dtdee.LocationY );
124
125 vcl::Window * pChildWindow = findTopLevelWindow(location);
126
127 // assume pointer write operation to be atomic
128 designate_currentwindow(pChildWindow);
129 m_aDataFlavorList = dtdee.SupportedDataFlavors;
130
131 // fire dragEnter on listeners of current window
132 sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location,
133 dtdee.SourceActions, dtdee.SupportedDataFlavors );
134
135 // reject drag if no listener found
136 if( nListeners == 0 ) {
137 SAL_WARN( "vcl", "rejecting drag enter due to missing listeners." );
138 dtdee.Context->rejectDrag();
139 }
140
141}
142
143void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ )
144{
145 std::scoped_lock aImplGuard( m_aMutex );
146
148
149 // reset member values
151 m_aDataFlavorList.realloc( 0 );
152}
153
154void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde )
155{
156 std::scoped_lock aImplGuard( m_aMutex );
157
158 Point location( dtde.LocationX, dtde.LocationY );
159 sal_Int32 nListeners;
160
161 vcl::Window * pChildWindow = findTopLevelWindow(location);
162
163 if( pChildWindow != m_pCurrentWindow.get() )
164 {
165 // fire dragExit on listeners of previous window
167
168 // remember new window
169 designate_currentwindow(pChildWindow);
170
171 // fire dragEnter on listeners of current window
172 nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
173 dtde.SourceActions, m_aDataFlavorList );
174 }
175 else
176 {
177 // fire dragOver on listeners of current window
178 nListeners = fireDragOverEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
179 dtde.SourceActions );
180 }
181
182 // reject drag if no listener found
183 if( nListeners == 0 )
184 {
185 SAL_WARN( "vcl", "rejecting drag over due to missing listeners." );
186 dtde.Context->rejectDrag();
187 }
188}
189
190void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde )
191{
192 std::scoped_lock aImplGuard( m_aMutex );
193
194 Point location( dtde.LocationX, dtde.LocationY );
195 sal_Int32 nListeners;
196
197 vcl::Window* pChildWindow = findTopLevelWindow(location);
198
199 if( pChildWindow != m_pCurrentWindow.get() )
200 {
201 // fire dragExit on listeners of previous window
203
204 // remember new window
205 designate_currentwindow(pChildWindow);
206
207 // fire dragEnter on listeners of current window
208 nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
209 dtde.SourceActions, m_aDataFlavorList );
210 }
211 else
212 {
213 // fire dropActionChanged on listeners of current window
214 nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
215 dtde.SourceActions );
216 }
217
218 // reject drag if no listener found
219 if( nListeners == 0 )
220 {
221 SAL_WARN( "vcl", "rejecting dropActionChanged due to missing listeners." );
222 dtde.Context->rejectDrag();
223 }
224}
225
226void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge )
227{
228 std::scoped_lock aImplGuard( m_aMutex );
229
230 Point origin( dge.DragOriginX, dge.DragOriginY );
231
232 vcl::Window* pChildWindow = findTopLevelWindow(origin);
233
234 fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction );
235}
236
237void SAL_CALL DNDEventDispatcher::disposing( const EventObject& )
238{
239}
240
241void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ )
242{
243}
244
246{
247}
248
250 const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
251 const Point& rLocation, const sal_Int8 nSourceActions, const Sequence< DataFlavor >& aFlavorList
252)
253{
254 sal_Int32 n = 0;
255
256 if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
257 {
258 SolarMutexClearableGuard aSolarGuard;
259
260 // query DropTarget from window
261 Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
262
263 if( xDropTarget.is() )
264 {
265 // retrieve relative mouse position
266 Point relLoc = pWindow->ScreenToOutputPixel( rLocation );
267 aSolarGuard.clear();
268
269 n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent(
270 xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList );
271 }
272 }
273
274 return n;
275}
276
278 const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
279 const Point& rLocation, const sal_Int8 nSourceActions
280)
281{
282 sal_Int32 n = 0;
283
284 if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
285 {
286 SolarMutexClearableGuard aSolarGuard;
287
288 // query DropTarget from window
289 Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
290
291 if( xDropTarget.is() )
292 {
293 // retrieve relative mouse position
294 Point relLoc = pWindow->ScreenToOutputPixel( rLocation );
295 aSolarGuard.clear();
296
297 n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent(
298 xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
299 }
300 }
301
302 return n;
303}
304
306{
307 sal_Int32 n = 0;
308
309 if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
310 {
312
313 // query DropTarget from window
314 Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
315
316 aGuard.clear();
317
318 if( xDropTarget.is() )
319 n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent();
320 }
321
322 return n;
323}
324
326 const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
327 const Point& rLocation, const sal_Int8 nSourceActions
328)
329{
330 sal_Int32 n = 0;
331
332 if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
333 {
335
336 // query DropTarget from window
337 Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
338
339 if( xDropTarget.is() )
340 {
341 // retrieve relative mouse position
342 Point relLoc = pWindow->ScreenToOutputPixel( rLocation );
343 aGuard.clear();
344
345 n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent(
346 xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
347 }
348 }
349
350 return n;
351}
352
354 const Reference< XDropTargetDropContext >& xContext, const sal_Int8 nDropAction, const Point& rLocation,
355 const sal_Int8 nSourceActions, const Reference< XTransferable >& xTransferable
356)
357{
358 sal_Int32 n = 0;
359
360 if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
361 {
363
364 // query DropTarget from window
365 Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
366
367 // window may be destroyed in drop event handler
368 VclPtr<vcl::Window> xPreventDelete = pWindow;
369
370 if( xDropTarget.is() )
371 {
372 // retrieve relative mouse position
373 Point relLoc = pWindow->ScreenToOutputPixel( rLocation );
374 aGuard.clear();
375
376 n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent(
377 xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable );
378 }
379 }
380
381 return n;
382}
383
385 const Reference< XDragSource >& xSource, const Any& event,
386 const Point& rOrigin, const sal_Int8 nDragAction
387)
388{
389 sal_Int32 n = 0;
390
391 if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
392 {
394
395 // query DropTarget from window
396 Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer();
397
398 if( xDragGestureRecognizer.is() )
399 {
400 // retrieve relative mouse position
401 Point relLoc = pWindow->ScreenToOutputPixel( rOrigin );
402 aGuard.clear();
403
404 n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent(
405 nDragAction, relLoc.X(), relLoc.Y(), xSource, event );
406 }
407 }
408
409 return n;
410}
411
412/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool GetLayoutRTL()
virtual void SAL_CALL drop(const css::datatransfer::dnd::DropTargetDropEvent &dtde) override
static sal_Int32 fireDragGestureEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDragSource > &xSource, const css::uno::Any &event, const Point &rOrigin, const sal_Int8 nDragAction)
virtual void SAL_CALL dragGestureRecognized(const css::datatransfer::dnd::DragGestureEvent &dge) override
virtual void SAL_CALL disposing(const css::lang::EventObject &eo) override
static sal_Int32 fireDragOverEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction)
static sal_Int32 fireDropActionChangedEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction)
void designate_currentwindow(vcl::Window *pWindow)
virtual void SAL_CALL dropActionChanged(const css::datatransfer::dnd::DropTargetDragEvent &dtde) override
virtual void SAL_CALL acceptDrag(sal_Int8 dropAction) override
static sal_Int32 fireDropEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDropContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction, const css::uno::Reference< css::datatransfer::XTransferable > &xTransferable)
VclPtr< vcl::Window > m_pTopWindow
static sal_Int32 fireDragExitEvent(vcl::Window *pWindow)
VclPtr< vcl::Window > m_pCurrentWindow
static sal_Int32 fireDragEnterEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction, const css::uno::Sequence< css::datatransfer::DataFlavor > &aFlavorList)
virtual void SAL_CALL rejectDrag() override
css::uno::Sequence< css::datatransfer::DataFlavor > m_aDataFlavorList
vcl::Window * findTopLevelWindow(Point &location)
virtual void SAL_CALL dragExit(const css::datatransfer::dnd::DropTargetEvent &dte) override
virtual ~DNDEventDispatcher() override
virtual void SAL_CALL dragOver(const css::datatransfer::dnd::DropTargetDragEvent &dtde) override
DNDEventDispatcher(vcl::Window *pTopWindow)
std::recursive_mutex m_aMutex
virtual void SAL_CALL dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent &dtdee) override
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:170
SAL_DLLPRIVATE bool ImplIsAntiparallel() const
Definition: outdev.cxx:655
SAL_DLLPRIVATE void ReMirror(Point &rPoint) const
Definition: outdev.cxx:671
constexpr tools::Long Y() const
constexpr tools::Long X() const
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
SAL_DLLPRIVATE vcl::Window * ImplFindWindow(const Point &rFramePos)
Definition: stacking.cxx:629
bool IsInputEnabled() const
Definition: window2.cxx:1153
void RemoveEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:312
::OutputDevice const * GetOutDev() const
Definition: window.cxx:567
bool IsInModalMode() const
A window is in modal mode if one of its children or subchildren is a running modal window (a modal di...
Definition: window.cxx:3597
void AddEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:307
SAL_DLLPRIVATE void ImplMirrorFramePos(Point &pt) const
Definition: window.cxx:3591
css::uno::Reference< css::datatransfer::dnd::XDropTarget > GetDropTarget()
Definition: mouse.cxx:651
Point ScreenToOutputPixel(const Point &rPos) const
Definition: window.cxx:2812
css::uno::Reference< css::datatransfer::dnd::XDragGestureRecognizer > GetDragGestureRecognizer()
Definition: mouse.cxx:737
SAL_DLLPRIVATE vcl::Window * ImplGetClientWindow() const
Definition: window2.cxx:901
IMPL_LINK(DNDEventDispatcher, WindowEventListener, VclWindowEvent &, rEvent, void)
sal_Int64 n
#define SAL_WARN(area, stream)
signed char sal_Int8