1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <dndeventdispatcher.hxx>
21 #include <dndlistenercontainer.hxx>
22 #include <sal/log.hxx>
24 #include <osl/mutex.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/settings.hxx>
28 using namespace ::cppu
;
29 using namespace ::com::sun::star::uno
;
30 using namespace ::com::sun::star::lang
;
31 using namespace ::com::sun::star::datatransfer
;
32 using namespace ::com::sun::star::datatransfer::dnd
;
34 DNDEventDispatcher::DNDEventDispatcher( vcl::Window
* pTopWindow
):
35 m_pTopWindow( pTopWindow
),
36 m_pCurrentWindow( nullptr )
40 DNDEventDispatcher::~DNDEventDispatcher()
42 designate_currentwindow(nullptr);
45 vcl::Window
* DNDEventDispatcher::findTopLevelWindow(Point location
)
47 SolarMutexGuard aSolarGuard
;
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
51 if( AllSettings::GetLayoutRTL() )
52 m_pTopWindow
->ImplMirrorFramePos( location
);
53 vcl::Window
* pChildWindow
= m_pTopWindow
->ImplFindWindow( location
);
55 if( nullptr == pChildWindow
)
56 pChildWindow
= m_pTopWindow
;
58 while( pChildWindow
->ImplGetClientWindow() )
59 pChildWindow
= pChildWindow
->ImplGetClientWindow();
61 if( pChildWindow
->ImplIsAntiparallel() )
63 const OutputDevice
*pChildWinOutDev
= pChildWindow
->GetOutDev();
64 pChildWinOutDev
->ReMirror( location
);
70 IMPL_LINK(DNDEventDispatcher
, WindowEventListener
, VclWindowEvent
&, rEvent
, void)
72 if (rEvent
.GetId() == VclEventId::ObjectDying
)
74 designate_currentwindow(nullptr);
78 void DNDEventDispatcher::designate_currentwindow(vcl::Window
*pWindow
)
81 m_pCurrentWindow
->RemoveEventListener(LINK(this, DNDEventDispatcher
, WindowEventListener
));
82 m_pCurrentWindow
= pWindow
;
84 m_pCurrentWindow
->AddEventListener(LINK(this, DNDEventDispatcher
, WindowEventListener
));
87 void SAL_CALL
DNDEventDispatcher::drop( const DropTargetDropEvent
& dtde
)
89 osl::MutexGuard
aImplGuard( m_aMutex
);
91 Point
location( dtde
.LocationX
, dtde
.LocationY
);
93 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
95 // handle the case that drop is in another vcl window than the last dragOver
96 if( pChildWindow
!= m_pCurrentWindow
.get() )
98 // fire dragExit on listeners of previous window
99 fireDragExitEvent( m_pCurrentWindow
);
101 fireDragEnterEvent( pChildWindow
, static_cast < XDropTargetDragContext
* > (this),
102 dtde
.DropAction
, location
, dtde
.SourceActions
, m_aDataFlavorList
);
105 // send drop event to the child window
106 sal_Int32 nListeners
= fireDropEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
,
107 location
, dtde
.SourceActions
, dtde
.Transferable
);
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();
115 // this is a drop -> no further drag overs
116 designate_currentwindow(nullptr);
117 m_aDataFlavorList
.realloc( 0 );
120 void SAL_CALL
DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent
& dtdee
)
122 osl::MutexGuard
aImplGuard( m_aMutex
);
123 Point
location( dtdee
.LocationX
, dtdee
.LocationY
);
125 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
127 // assume pointer write operation to be atomic
128 designate_currentwindow(pChildWindow
);
129 m_aDataFlavorList
= dtdee
.SupportedDataFlavors
;
131 // fire dragEnter on listeners of current window
132 sal_Int32 nListeners
= fireDragEnterEvent( pChildWindow
, dtdee
.Context
, dtdee
.DropAction
, location
,
133 dtdee
.SourceActions
, dtdee
.SupportedDataFlavors
);
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();
143 void SAL_CALL
DNDEventDispatcher::dragExit( const DropTargetEvent
& /*dte*/ )
145 osl::MutexGuard
aImplGuard( m_aMutex
);
147 fireDragExitEvent( m_pCurrentWindow
);
149 // reset member values
150 designate_currentwindow(nullptr);
151 m_aDataFlavorList
.realloc( 0 );
154 void SAL_CALL
DNDEventDispatcher::dragOver( const DropTargetDragEvent
& dtde
)
156 osl::MutexGuard
aImplGuard( m_aMutex
);
158 Point
location( dtde
.LocationX
, dtde
.LocationY
);
159 sal_Int32 nListeners
;
161 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
163 if( pChildWindow
!= m_pCurrentWindow
.get() )
165 // fire dragExit on listeners of previous window
166 fireDragExitEvent( m_pCurrentWindow
);
168 // remember new window
169 designate_currentwindow(pChildWindow
);
171 // fire dragEnter on listeners of current window
172 nListeners
= fireDragEnterEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
173 dtde
.SourceActions
, m_aDataFlavorList
);
177 // fire dragOver on listeners of current window
178 nListeners
= fireDragOverEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
179 dtde
.SourceActions
);
182 // reject drag if no listener found
183 if( nListeners
== 0 )
185 SAL_WARN( "vcl", "rejecting drag over due to missing listeners." );
186 dtde
.Context
->rejectDrag();
190 void SAL_CALL
DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent
& dtde
)
192 osl::MutexGuard
aImplGuard( m_aMutex
);
194 Point
location( dtde
.LocationX
, dtde
.LocationY
);
195 sal_Int32 nListeners
;
197 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
199 if( pChildWindow
!= m_pCurrentWindow
.get() )
201 // fire dragExit on listeners of previous window
202 fireDragExitEvent( m_pCurrentWindow
);
204 // remember new window
205 designate_currentwindow(pChildWindow
);
207 // fire dragEnter on listeners of current window
208 nListeners
= fireDragEnterEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
209 dtde
.SourceActions
, m_aDataFlavorList
);
213 // fire dropActionChanged on listeners of current window
214 nListeners
= fireDropActionChangedEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
215 dtde
.SourceActions
);
218 // reject drag if no listener found
219 if( nListeners
== 0 )
221 SAL_WARN( "vcl", "rejecting dropActionChanged due to missing listeners." );
222 dtde
.Context
->rejectDrag();
226 void SAL_CALL
DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent
& dge
)
228 osl::MutexGuard
aImplGuard( m_aMutex
);
230 Point
origin( dge
.DragOriginX
, dge
.DragOriginY
);
232 vcl::Window
* pChildWindow
= findTopLevelWindow(origin
);
234 fireDragGestureEvent( pChildWindow
, dge
.DragSource
, dge
.Event
, origin
, dge
.DragAction
);
237 void SAL_CALL
DNDEventDispatcher::disposing( const EventObject
& )
241 void SAL_CALL
DNDEventDispatcher::acceptDrag( sal_Int8
/*dropAction*/ )
245 void SAL_CALL
DNDEventDispatcher::rejectDrag()
249 sal_Int32
DNDEventDispatcher::fireDragEnterEvent( vcl::Window
*pWindow
,
250 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
251 const Point
& rLocation
, const sal_Int8 nSourceActions
, const Sequence
< DataFlavor
>& aFlavorList
256 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
258 SolarMutexClearableGuard aSolarGuard
;
260 // query DropTarget from window
261 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
263 if( xDropTarget
.is() )
265 // retrieve relative mouse position
266 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
269 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragEnterEvent(
270 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
, aFlavorList
);
277 sal_Int32
DNDEventDispatcher::fireDragOverEvent( vcl::Window
*pWindow
,
278 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
279 const Point
& rLocation
, const sal_Int8 nSourceActions
284 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
286 SolarMutexClearableGuard aSolarGuard
;
288 // query DropTarget from window
289 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
291 if( xDropTarget
.is() )
293 // retrieve relative mouse position
294 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
297 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragOverEvent(
298 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
);
305 sal_Int32
DNDEventDispatcher::fireDragExitEvent( vcl::Window
*pWindow
)
309 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
311 SolarMutexClearableGuard aGuard
;
313 // query DropTarget from window
314 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
318 if( xDropTarget
.is() )
319 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragExitEvent();
325 sal_Int32
DNDEventDispatcher::fireDropActionChangedEvent( vcl::Window
*pWindow
,
326 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
327 const Point
& rLocation
, const sal_Int8 nSourceActions
332 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
334 SolarMutexClearableGuard aGuard
;
336 // query DropTarget from window
337 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
339 if( xDropTarget
.is() )
341 // retrieve relative mouse position
342 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
345 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDropActionChangedEvent(
346 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
);
353 sal_Int32
DNDEventDispatcher::fireDropEvent( vcl::Window
*pWindow
,
354 const Reference
< XDropTargetDropContext
>& xContext
, const sal_Int8 nDropAction
, const Point
& rLocation
,
355 const sal_Int8 nSourceActions
, const Reference
< XTransferable
>& xTransferable
360 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
362 SolarMutexClearableGuard aGuard
;
364 // query DropTarget from window
365 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
367 // window may be destroyed in drop event handler
368 VclPtr
<vcl::Window
> xWindow
= pWindow
;
370 if( xDropTarget
.is() )
372 // retrieve relative mouse position
373 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
376 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDropEvent(
377 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
, xTransferable
);
384 sal_Int32
DNDEventDispatcher::fireDragGestureEvent( vcl::Window
*pWindow
,
385 const Reference
< XDragSource
>& xSource
, const Any
& event
,
386 const Point
& rOrigin
, const sal_Int8 nDragAction
391 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
393 SolarMutexClearableGuard aGuard
;
395 // query DropTarget from window
396 Reference
< XDragGestureRecognizer
> xDragGestureRecognizer
= pWindow
->GetDragGestureRecognizer();
398 if( xDragGestureRecognizer
.is() )
400 // retrieve relative mouse position
401 Point relLoc
= pWindow
->ImplFrameToOutput( rOrigin
);
404 n
= static_cast < DNDListenerContainer
* > ( xDragGestureRecognizer
.get() )->fireDragGestureEvent(
405 nDragAction
, relLoc
.X(), relLoc
.Y(), xSource
, event
);
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */