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 <dndevdis.hxx>
21 #include <dndlcon.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
36 DNDEventDispatcher::DNDEventDispatcher( vcl::Window
* pTopWindow
):
37 m_pTopWindow( pTopWindow
),
38 m_pCurrentWindow( NULL
)
42 // DNDEventDispatcher::~DNDEventDispatcher
43 DNDEventDispatcher::~DNDEventDispatcher()
45 designate_currentwindow(NULL
);
48 vcl::Window
* DNDEventDispatcher::findTopLevelWindow(Point location
)
50 SolarMutexGuard aSolarGuard
;
52 // find the window that is toplevel for this coordinates
53 // because those coordinates come from outside, they must be mirrored if RTL layout is active
54 if( AllSettings::GetLayoutRTL() )
55 m_pTopWindow
->ImplMirrorFramePos( location
);
56 vcl::Window
* pChildWindow
= m_pTopWindow
->ImplFindWindow( location
);
58 if( NULL
== pChildWindow
)
59 pChildWindow
= m_pTopWindow
;
61 while( pChildWindow
->ImplGetClientWindow() )
62 pChildWindow
= pChildWindow
->ImplGetClientWindow();
64 if( pChildWindow
->ImplIsAntiparallel() )
66 const OutputDevice
*pChildWinOutDev
= pChildWindow
->GetOutDev();
67 pChildWinOutDev
->ReMirror( location
);
73 IMPL_LINK(DNDEventDispatcher
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
75 if (pEvent
&& pEvent
->GetId() == VCLEVENT_OBJECT_DYING
)
77 designate_currentwindow(NULL
);
82 void DNDEventDispatcher::designate_currentwindow(vcl::Window
*pWindow
)
85 m_pCurrentWindow
->RemoveEventListener(LINK(this, DNDEventDispatcher
, WindowEventListener
));
86 m_pCurrentWindow
= pWindow
;
88 m_pCurrentWindow
->AddEventListener(LINK(this, DNDEventDispatcher
, WindowEventListener
));
91 // DNDEventDispatcher::drop
92 void SAL_CALL
DNDEventDispatcher::drop( const DropTargetDropEvent
& dtde
)
93 throw(RuntimeException
, std::exception
)
95 osl::MutexGuard
aImplGuard( m_aMutex
);
97 Point
location( dtde
.LocationX
, dtde
.LocationY
);
99 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
101 // handle the case that drop is in an other vcl window than the last dragOver
102 if( pChildWindow
!= m_pCurrentWindow
.get() )
104 // fire dragExit on listeners of previous window
105 fireDragExitEvent( m_pCurrentWindow
);
107 fireDragEnterEvent( pChildWindow
, static_cast < XDropTargetDragContext
* > (this),
108 dtde
.DropAction
, location
, dtde
.SourceActions
, m_aDataFlavorList
);
111 sal_Int32 nListeners
= 0;
113 // send drop event to the child window
114 nListeners
= fireDropEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
,
115 location
, dtde
.SourceActions
, dtde
.Transferable
);
117 // reject drop if no listeners found
118 if( nListeners
== 0 ) {
119 OSL_TRACE( "rejecting drop due to missing listeners." );
120 dtde
.Context
->rejectDrop();
123 // this is a drop -> no further drag overs
124 designate_currentwindow(NULL
);
125 m_aDataFlavorList
.realloc( 0 );
128 // DNDEventDispatcher::dragEnter
130 void SAL_CALL
DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent
& dtdee
)
131 throw(RuntimeException
, std::exception
)
133 osl::MutexGuard
aImplGuard( m_aMutex
);
134 Point
location( dtdee
.LocationX
, dtdee
.LocationY
);
136 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
138 // assume pointer write operation to be atomic
139 designate_currentwindow(pChildWindow
);
140 m_aDataFlavorList
= dtdee
.SupportedDataFlavors
;
142 // fire dragEnter on listeners of current window
143 sal_Int32 nListeners
= fireDragEnterEvent( pChildWindow
, dtdee
.Context
, dtdee
.DropAction
, location
,
144 dtdee
.SourceActions
, dtdee
.SupportedDataFlavors
);
146 // reject drag if no listener found
147 if( nListeners
== 0 ) {
148 OSL_TRACE( "rejecting drag enter due to missing listeners." );
149 dtdee
.Context
->rejectDrag();
154 // DNDEventDispatcher::dragExit
156 void SAL_CALL
DNDEventDispatcher::dragExit( const DropTargetEvent
& /*dte*/ )
157 throw(RuntimeException
, std::exception
)
159 osl::MutexGuard
aImplGuard( m_aMutex
);
161 fireDragExitEvent( m_pCurrentWindow
);
163 // reset member values
164 designate_currentwindow(NULL
);
165 m_aDataFlavorList
.realloc( 0 );
168 // DNDEventDispatcher::dragOver
170 void SAL_CALL
DNDEventDispatcher::dragOver( const DropTargetDragEvent
& dtde
)
171 throw(RuntimeException
, std::exception
)
173 osl::MutexGuard
aImplGuard( m_aMutex
);
175 Point
location( dtde
.LocationX
, dtde
.LocationY
);
176 sal_Int32 nListeners
;
178 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
180 if( pChildWindow
!= m_pCurrentWindow
.get() )
182 // fire dragExit on listeners of previous window
183 fireDragExitEvent( m_pCurrentWindow
);
185 // remember new window
186 designate_currentwindow(pChildWindow
);
188 // fire dragEnter on listeners of current window
189 nListeners
= fireDragEnterEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
190 dtde
.SourceActions
, m_aDataFlavorList
);
194 // fire dragOver on listeners of current window
195 nListeners
= fireDragOverEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
196 dtde
.SourceActions
);
199 // reject drag if no listener found
200 if( nListeners
== 0 )
202 OSL_TRACE( "rejecting drag over due to missing listeners." );
203 dtde
.Context
->rejectDrag();
207 // DNDEventDispatcher::dropActionChanged
208 void SAL_CALL
DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent
& dtde
)
209 throw(RuntimeException
, std::exception
)
211 osl::MutexGuard
aImplGuard( m_aMutex
);
213 Point
location( dtde
.LocationX
, dtde
.LocationY
);
214 sal_Int32 nListeners
;
216 vcl::Window
* pChildWindow
= findTopLevelWindow(location
);
218 if( pChildWindow
!= m_pCurrentWindow
.get() )
220 // fire dragExit on listeners of previous window
221 fireDragExitEvent( m_pCurrentWindow
);
223 // remember new window
224 designate_currentwindow(pChildWindow
);
226 // fire dragEnter on listeners of current window
227 nListeners
= fireDragEnterEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
228 dtde
.SourceActions
, m_aDataFlavorList
);
232 // fire dropActionChanged on listeners of current window
233 nListeners
= fireDropActionChangedEvent( pChildWindow
, dtde
.Context
, dtde
.DropAction
, location
,
234 dtde
.SourceActions
);
237 // reject drag if no listener found
238 if( nListeners
== 0 )
240 OSL_TRACE( "rejecting dropActionChanged due to missing listeners." );
241 dtde
.Context
->rejectDrag();
245 // DNDEventDispatcher::dragGestureRecognized
247 void SAL_CALL
DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent
& dge
)
248 throw(RuntimeException
, std::exception
)
250 osl::MutexGuard
aImplGuard( m_aMutex
);
252 Point
origin( dge
.DragOriginX
, dge
.DragOriginY
);
254 vcl::Window
* pChildWindow
= findTopLevelWindow(origin
);
256 fireDragGestureEvent( pChildWindow
, dge
.DragSource
, dge
.Event
, origin
, dge
.DragAction
);
259 // DNDEventDispatcher::disposing
261 void SAL_CALL
DNDEventDispatcher::disposing( const EventObject
& )
262 throw(RuntimeException
, std::exception
)
266 // DNDEventDispatcher::acceptDrag
268 void SAL_CALL
DNDEventDispatcher::acceptDrag( sal_Int8
/*dropAction*/ ) throw(RuntimeException
, std::exception
)
272 // DNDEventDispatcher::rejectDrag
274 void SAL_CALL
DNDEventDispatcher::rejectDrag() throw(RuntimeException
, std::exception
)
278 // DNDEventDispatcher::fireDragEnterEvent
280 sal_Int32
DNDEventDispatcher::fireDragEnterEvent( vcl::Window
*pWindow
,
281 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
282 const Point
& rLocation
, const sal_Int8 nSourceActions
, const Sequence
< DataFlavor
>& aFlavorList
284 throw(RuntimeException
)
288 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
290 SolarMutexClearableGuard aSolarGuard
;
293 pWindow
->IncrementLockCount();
295 // query DropTarget from window
296 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
298 if( xDropTarget
.is() )
300 // retrieve relative mouse position
301 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
304 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragEnterEvent(
305 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
, aFlavorList
);
312 // DNDEventDispatcher::fireDragOverEvent
314 sal_Int32
DNDEventDispatcher::fireDragOverEvent( vcl::Window
*pWindow
,
315 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
316 const Point
& rLocation
, const sal_Int8 nSourceActions
318 throw(RuntimeException
)
322 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
324 SolarMutexClearableGuard aSolarGuard
;
326 // query DropTarget from window
327 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
329 if( xDropTarget
.is() )
331 // retrieve relative mouse position
332 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
335 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragOverEvent(
336 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
);
343 // DNDEventDispatcher::fireDragExitEvent
345 sal_Int32
DNDEventDispatcher::fireDragExitEvent( vcl::Window
*pWindow
) throw(RuntimeException
)
349 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
351 SolarMutexClearableGuard aGuard
;
353 // query DropTarget from window
354 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
358 if( xDropTarget
.is() )
359 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDragExitEvent();
362 pWindow
->DecrementLockCount();
368 // DNDEventDispatcher::fireDropActionChangedEvent
370 sal_Int32
DNDEventDispatcher::fireDropActionChangedEvent( vcl::Window
*pWindow
,
371 const Reference
< XDropTargetDragContext
>& xContext
, const sal_Int8 nDropAction
,
372 const Point
& rLocation
, const sal_Int8 nSourceActions
374 throw(RuntimeException
)
378 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
380 SolarMutexClearableGuard aGuard
;
382 // query DropTarget from window
383 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
385 if( xDropTarget
.is() )
387 // retrieve relative mouse position
388 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
391 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDropActionChangedEvent(
392 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
);
399 // DNDEventDispatcher::fireDropEvent
401 sal_Int32
DNDEventDispatcher::fireDropEvent( vcl::Window
*pWindow
,
402 const Reference
< XDropTargetDropContext
>& xContext
, const sal_Int8 nDropAction
, const Point
& rLocation
,
403 const sal_Int8 nSourceActions
, const Reference
< XTransferable
>& xTransferable
405 throw(RuntimeException
)
409 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
411 SolarMutexClearableGuard aGuard
;
413 // query DropTarget from window
414 Reference
< XDropTarget
> xDropTarget
= pWindow
->GetDropTarget();
416 // window may be destroyed in drop event handler
417 ImplDelData aDelData
;
418 pWindow
->ImplAddDel( &aDelData
);
420 if( xDropTarget
.is() )
422 // retrieve relative mouse position
423 Point relLoc
= pWindow
->ImplFrameToOutput( rLocation
);
426 n
= static_cast < DNDListenerContainer
* > ( xDropTarget
.get() )->fireDropEvent(
427 xContext
, nDropAction
, relLoc
.X(), relLoc
.Y(), nSourceActions
, xTransferable
);
430 if ( !aDelData
.IsDead() )
432 pWindow
->ImplRemoveDel( &aDelData
);
434 pWindow
->DecrementLockCount();
442 // DNDEventDispatcher::fireDragGestureRecognized
444 sal_Int32
DNDEventDispatcher::fireDragGestureEvent( vcl::Window
*pWindow
,
445 const Reference
< XDragSource
>& xSource
, const Any
& event
,
446 const Point
& rOrigin
, const sal_Int8 nDragAction
448 throw(::com::sun::star::uno::RuntimeException
)
452 if( pWindow
&& pWindow
->IsInputEnabled() && ! pWindow
->IsInModalMode() )
454 SolarMutexClearableGuard aGuard
;
456 // query DropTarget from window
457 Reference
< XDragGestureRecognizer
> xDragGestureRecognizer
= pWindow
->GetDragGestureRecognizer();
459 if( xDragGestureRecognizer
.is() )
461 // retrieve relative mouse position
462 Point relLoc
= pWindow
->ImplFrameToOutput( rOrigin
);
465 n
= static_cast < DNDListenerContainer
* > ( xDragGestureRecognizer
.get() )->fireDragGestureEvent(
466 nDragAction
, relLoc
.X(), relLoc
.Y(), xSource
, event
);
470 pWindow
->DecrementLockCount();
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */