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"
25 #include <osl/mutex.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/settings.hxx>
29 using namespace ::cppu
;
30 using namespace ::com::sun::star::uno
;
31 using namespace ::com::sun::star::lang
;
32 using namespace ::com::sun::star::datatransfer
;
33 using namespace ::com::sun::star::datatransfer::dnd
;
35 DNDEventDispatcher::DNDEventDispatcher( vcl::Window
* pTopWindow
):
36 m_pTopWindow( pTopWindow
),
37 m_pCurrentWindow( nullptr )
41 DNDEventDispatcher::~DNDEventDispatcher()
43 designate_currentwindow(nullptr);
46 vcl::Window
* DNDEventDispatcher::findTopLevelWindow(Point location
)
48 SolarMutexGuard aSolarGuard
;
50 // find the window that is toplevel for this coordinates
51 // because those coordinates come from outside, they must be mirrored if RTL layout is active
52 if( AllSettings::GetLayoutRTL() )
53 m_pTopWindow
->ImplMirrorFramePos( location
);
54 vcl::Window
* pChildWindow
= m_pTopWindow
->ImplFindWindow( location
);
56 if( nullptr == pChildWindow
)
57 pChildWindow
= m_pTopWindow
;
59 while( pChildWindow
->ImplGetClientWindow() )
60 pChildWindow
= pChildWindow
->ImplGetClientWindow();
62 if( pChildWindow
->ImplIsAntiparallel() )
64 const OutputDevice
*pChildWinOutDev
= pChildWindow
->GetOutDev();
65 pChildWinOutDev
->ReMirror( location
);
71 IMPL_LINK(DNDEventDispatcher
, WindowEventListener
, VclWindowEvent
&, rEvent
, void)
73 if (rEvent
.GetId() == VCLEVENT_OBJECT_DYING
)
75 designate_currentwindow(nullptr);
79 void DNDEventDispatcher::designate_currentwindow(vcl::Window
*pWindow
)
82 m_pCurrentWindow
->RemoveEventListener(LINK(this, DNDEventDispatcher
, WindowEventListener
));
83 m_pCurrentWindow
= pWindow
;
85 m_pCurrentWindow
->AddEventListener(LINK(this, DNDEventDispatcher
, WindowEventListener
));
88 void SAL_CALL
DNDEventDispatcher::drop( const DropTargetDropEvent
& dtde
)
89 throw(RuntimeException
, std::exception
)
91 osl::MutexGuard
aImplGuard( m_aMutex
);
93 Point
location( dtde
.LocationX
, dtde
.LocationY
);
95 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
97 // handle the case that drop is in an other vcl window than the last dragOver
98 if( pChildWindow
!= m_pCurrentWindow
.get() )
100 // fire dragExit on listeners of previous window
101 fireDragExitEvent( m_pCurrentWindow
);
103 fireDragEnterEvent( pChildWindow
, static_cast < XDropTargetDragContext
* > (this),
104 dtde
.DropAction
, location
, dtde
.SourceActions
, m_aDataFlavorList
);
107 sal_Int32 nListeners
= 0;
109 // send drop event to the child window
110 nListeners
= fireDropEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
,
111 location
, dtde
.SourceActions
, dtde
.Transferable
);
113 // reject drop if no listeners found
114 if( nListeners
== 0 ) {
115 OSL_TRACE( "rejecting drop due to missing listeners." );
116 dtde
.Context
->rejectDrop();
119 // this is a drop -> no further drag overs
120 designate_currentwindow(nullptr);
121 m_aDataFlavorList
.realloc( 0 );
124 void SAL_CALL
DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent
& dtdee
)
125 throw(RuntimeException
, std::exception
)
127 osl::MutexGuard
aImplGuard( m_aMutex
);
128 Point
location( dtdee
.LocationX
, dtdee
.LocationY
);
130 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
132 // assume pointer write operation to be atomic
133 designate_currentwindow(pChildWindow
);
134 m_aDataFlavorList
= dtdee
.SupportedDataFlavors
;
136 // fire dragEnter on listeners of current window
137 sal_Int32 nListeners
= fireDragEnterEvent( pChildWindow
, dtdee
.Context
, dtdee
.DropAction
, location
,
138 dtdee
.SourceActions
, dtdee
.SupportedDataFlavors
);
140 // reject drag if no listener found
141 if( nListeners
== 0 ) {
142 OSL_TRACE( "rejecting drag enter due to missing listeners." );
143 dtdee
.Context
->rejectDrag();
148 void SAL_CALL
DNDEventDispatcher::dragExit( const DropTargetEvent
& /*dte*/ )
149 throw(RuntimeException
, std::exception
)
151 osl::MutexGuard
aImplGuard( m_aMutex
);
153 fireDragExitEvent( m_pCurrentWindow
);
155 // reset member values
156 designate_currentwindow(nullptr);
157 m_aDataFlavorList
.realloc( 0 );
160 void SAL_CALL
DNDEventDispatcher::dragOver( const DropTargetDragEvent
& dtde
)
161 throw(RuntimeException
, std::exception
)
163 osl::MutexGuard
aImplGuard( m_aMutex
);
165 Point
location( dtde
.LocationX
, dtde
.LocationY
);
166 sal_Int32 nListeners
;
168 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
170 if( pChildWindow
!= m_pCurrentWindow
.get() )
172 // fire dragExit on listeners of previous window
173 fireDragExitEvent( m_pCurrentWindow
);
175 // remember new window
176 designate_currentwindow(pChildWindow
);
178 // fire dragEnter on listeners of current window
179 nListeners
= fireDragEnterEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
180 dtde
.SourceActions
, m_aDataFlavorList
);
184 // fire dragOver on listeners of current window
185 nListeners
= fireDragOverEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
186 dtde
.SourceActions
);
189 // reject drag if no listener found
190 if( nListeners
== 0 )
192 OSL_TRACE( "rejecting drag over due to missing listeners." );
193 dtde
.Context
->rejectDrag();
197 void SAL_CALL
DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent
& dtde
)
198 throw(RuntimeException
, std::exception
)
200 osl::MutexGuard
aImplGuard( m_aMutex
);
202 Point
location( dtde
.LocationX
, dtde
.LocationY
);
203 sal_Int32 nListeners
;
205 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
207 if( pChildWindow
!= m_pCurrentWindow
.get() )
209 // fire dragExit on listeners of previous window
210 fireDragExitEvent( m_pCurrentWindow
);
212 // remember new window
213 designate_currentwindow(pChildWindow
);
215 // fire dragEnter on listeners of current window
216 nListeners
= fireDragEnterEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
217 dtde
.SourceActions
, m_aDataFlavorList
);
221 // fire dropActionChanged on listeners of current window
222 nListeners
= fireDropActionChangedEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
223 dtde
.SourceActions
);
226 // reject drag if no listener found
227 if( nListeners
== 0 )
229 OSL_TRACE( "rejecting dropActionChanged due to missing listeners." );
230 dtde
.Context
->rejectDrag();
234 void SAL_CALL
DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent
& dge
)
235 throw(RuntimeException
, std::exception
)
237 osl::MutexGuard
aImplGuard( m_aMutex
);
239 Point
origin( dge
.DragOriginX
, dge
.DragOriginY
);
241 vcl::Window
* pChildWindow
= findTopLevelWindow(origin
);
243 fireDragGestureEvent( pChildWindow
, dge
.DragSource
, dge
.Event
, origin
, dge
.DragAction
);
246 void SAL_CALL
DNDEventDispatcher::disposing( const EventObject
& )
247 throw(RuntimeException
, std::exception
)
251 void SAL_CALL
DNDEventDispatcher::acceptDrag( sal_Int8
/*dropAction*/ ) throw(RuntimeException
, std::exception
)
255 void SAL_CALL
DNDEventDispatcher::rejectDrag() throw(RuntimeException
, std::exception
)
259 sal_Int32
DNDEventDispatcher::fireDragEnterEvent( vcl::Window
*pWindow
,
260 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
261 const Point
& rLocation
, const sal_Int8 nSourceActions
, const Sequence
< DataFlavor
>& aFlavorList
263 throw(RuntimeException
)
267 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
269 SolarMutexClearableGuard aSolarGuard
;
272 pWindow
->IncrementLockCount();
274 // query DropTarget from window
275 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
277 if( xDropTarget
.is() )
279 // retrieve relative mouse position
280 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
283 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragEnterEvent(
284 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
, aFlavorList
);
291 sal_Int32
DNDEventDispatcher::fireDragOverEvent( vcl::Window
*pWindow
,
292 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
293 const Point
& rLocation
, const sal_Int8 nSourceActions
295 throw(RuntimeException
)
299 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
301 SolarMutexClearableGuard aSolarGuard
;
303 // query DropTarget from window
304 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
306 if( xDropTarget
.is() )
308 // retrieve relative mouse position
309 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
312 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragOverEvent(
313 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
);
320 sal_Int32
DNDEventDispatcher::fireDragExitEvent( vcl::Window
*pWindow
) throw(RuntimeException
)
324 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
326 SolarMutexClearableGuard aGuard
;
328 // query DropTarget from window
329 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
333 if( xDropTarget
.is() )
334 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragExitEvent();
337 pWindow
->DecrementLockCount();
343 sal_Int32
DNDEventDispatcher::fireDropActionChangedEvent( vcl::Window
*pWindow
,
344 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
345 const Point
& rLocation
, const sal_Int8 nSourceActions
347 throw(RuntimeException
)
351 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
353 SolarMutexClearableGuard aGuard
;
355 // query DropTarget from window
356 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
358 if( xDropTarget
.is() )
360 // retrieve relative mouse position
361 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
364 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDropActionChangedEvent(
365 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
);
372 sal_Int32
DNDEventDispatcher::fireDropEvent( vcl::Window
*pWindow
,
373 const Reference
< XDropTargetDropContext
>& xContext
, const sal_Int8 nDropAction
, const Point
& rLocation
,
374 const sal_Int8 nSourceActions
, const Reference
< XTransferable
>& xTransferable
376 throw(RuntimeException
)
380 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
382 SolarMutexClearableGuard aGuard
;
384 // query DropTarget from window
385 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
387 // window may be destroyed in drop event handler
388 VclPtr
<vcl::Window
> xWindow
= pWindow
;
390 if( xDropTarget
.is() )
392 // retrieve relative mouse position
393 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
396 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDropEvent(
397 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
, xTransferable
);
400 if ( !xWindow
->IsDisposed() )
403 pWindow
->DecrementLockCount();
411 sal_Int32
DNDEventDispatcher::fireDragGestureEvent( vcl::Window
*pWindow
,
412 const Reference
< XDragSource
>& xSource
, const Any
& event
,
413 const Point
& rOrigin
, const sal_Int8 nDragAction
415 throw(css::uno::RuntimeException
)
419 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
421 SolarMutexClearableGuard aGuard
;
423 // query DropTarget from window
424 Reference
< XDragGestureRecognizer
> xDragGestureRecognizer
= pWindow
->GetDragGestureRecognizer();
426 if( xDragGestureRecognizer
.is() )
428 // retrieve relative mouse position
429 Point relLoc
= pWindow
->ImplFrameToOutput( rOrigin
);
432 n
= static_cast < DNDListenerContainer
* > ( xDragGestureRecognizer
.get() )->fireDragGestureEvent(
433 nDragAction
, relLoc
.X(), relLoc
.Y(), xSource
, event
);
437 pWindow
->DecrementLockCount();
443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */