Line data Source code
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 :
20 : #include <dndevdis.hxx>
21 : #include <dndlcon.hxx>
22 : #include <window.h>
23 : #include <svdata.hxx>
24 :
25 : #include <osl/mutex.hxx>
26 : #include <vcl/svapp.hxx>
27 : #include <vcl/settings.hxx>
28 :
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;
34 :
35 : // DNDEventDispatcher::DNDEventDispatcher
36 1897 : DNDEventDispatcher::DNDEventDispatcher( vcl::Window * pTopWindow ):
37 : m_pTopWindow( pTopWindow ),
38 1897 : m_pCurrentWindow( NULL )
39 : {
40 1897 : }
41 :
42 : // DNDEventDispatcher::~DNDEventDispatcher
43 5679 : DNDEventDispatcher::~DNDEventDispatcher()
44 : {
45 1893 : designate_currentwindow(NULL);
46 3786 : }
47 :
48 0 : vcl::Window* DNDEventDispatcher::findTopLevelWindow(Point location)
49 : {
50 0 : SolarMutexGuard aSolarGuard;
51 :
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 0 : if( AllSettings::GetLayoutRTL() )
55 0 : m_pTopWindow->ImplMirrorFramePos( location );
56 0 : vcl::Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
57 :
58 0 : if( NULL == pChildWindow )
59 0 : pChildWindow = m_pTopWindow;
60 :
61 0 : while( pChildWindow->ImplGetClientWindow() )
62 0 : pChildWindow = pChildWindow->ImplGetClientWindow();
63 :
64 0 : if( pChildWindow->ImplIsAntiparallel() )
65 : {
66 0 : const OutputDevice *pChildWinOutDev = pChildWindow->GetOutDev();
67 0 : pChildWinOutDev->ReMirror( location );
68 : }
69 :
70 0 : return pChildWindow;
71 : }
72 :
73 0 : IMPL_LINK(DNDEventDispatcher, WindowEventListener, VclSimpleEvent*, pEvent)
74 : {
75 0 : if (pEvent && pEvent->GetId() == VCLEVENT_OBJECT_DYING)
76 : {
77 0 : designate_currentwindow(NULL);
78 : }
79 0 : return 0;
80 : }
81 :
82 1893 : void DNDEventDispatcher::designate_currentwindow(vcl::Window *pWindow)
83 : {
84 1893 : if (m_pCurrentWindow)
85 0 : m_pCurrentWindow->RemoveEventListener(LINK(this, DNDEventDispatcher, WindowEventListener));
86 1893 : m_pCurrentWindow = pWindow;
87 1893 : if (m_pCurrentWindow)
88 0 : m_pCurrentWindow->AddEventListener(LINK(this, DNDEventDispatcher, WindowEventListener));
89 1893 : }
90 :
91 : // DNDEventDispatcher::drop
92 0 : void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde )
93 : throw(RuntimeException, std::exception)
94 : {
95 0 : osl::MutexGuard aImplGuard( m_aMutex );
96 :
97 0 : Point location( dtde.LocationX, dtde.LocationY );
98 :
99 0 : vcl::Window* pChildWindow = findTopLevelWindow(location);
100 :
101 : // handle the case that drop is in an other vcl window than the last dragOver
102 0 : if( pChildWindow != m_pCurrentWindow.get() )
103 : {
104 : // fire dragExit on listeners of previous window
105 0 : fireDragExitEvent( m_pCurrentWindow );
106 :
107 : fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this),
108 0 : dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList );
109 : }
110 :
111 0 : sal_Int32 nListeners = 0;
112 :
113 : // send drop event to the child window
114 : nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction,
115 0 : location, dtde.SourceActions, dtde.Transferable );
116 :
117 : // reject drop if no listeners found
118 0 : if( nListeners == 0 ) {
119 : OSL_TRACE( "rejecting drop due to missing listeners." );
120 0 : dtde.Context->rejectDrop();
121 : }
122 :
123 : // this is a drop -> no further drag overs
124 0 : designate_currentwindow(NULL);
125 0 : m_aDataFlavorList.realloc( 0 );
126 0 : }
127 :
128 : // DNDEventDispatcher::dragEnter
129 :
130 0 : void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee )
131 : throw(RuntimeException, std::exception)
132 : {
133 0 : osl::MutexGuard aImplGuard( m_aMutex );
134 0 : Point location( dtdee.LocationX, dtdee.LocationY );
135 :
136 0 : vcl::Window * pChildWindow = findTopLevelWindow(location);
137 :
138 : // assume pointer write operation to be atomic
139 0 : designate_currentwindow(pChildWindow);
140 0 : m_aDataFlavorList = dtdee.SupportedDataFlavors;
141 :
142 : // fire dragEnter on listeners of current window
143 : sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location,
144 0 : dtdee.SourceActions, dtdee.SupportedDataFlavors );
145 :
146 : // reject drag if no listener found
147 0 : if( nListeners == 0 ) {
148 : OSL_TRACE( "rejecting drag enter due to missing listeners." );
149 0 : dtdee.Context->rejectDrag();
150 0 : }
151 :
152 0 : }
153 :
154 : // DNDEventDispatcher::dragExit
155 :
156 0 : void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ )
157 : throw(RuntimeException, std::exception)
158 : {
159 0 : osl::MutexGuard aImplGuard( m_aMutex );
160 :
161 0 : fireDragExitEvent( m_pCurrentWindow );
162 :
163 : // reset member values
164 0 : designate_currentwindow(NULL);
165 0 : m_aDataFlavorList.realloc( 0 );
166 0 : }
167 :
168 : // DNDEventDispatcher::dragOver
169 :
170 0 : void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde )
171 : throw(RuntimeException, std::exception)
172 : {
173 0 : osl::MutexGuard aImplGuard( m_aMutex );
174 :
175 0 : Point location( dtde.LocationX, dtde.LocationY );
176 : sal_Int32 nListeners;
177 :
178 0 : vcl::Window * pChildWindow = findTopLevelWindow(location);
179 :
180 0 : if( pChildWindow != m_pCurrentWindow.get() )
181 : {
182 : // fire dragExit on listeners of previous window
183 0 : fireDragExitEvent( m_pCurrentWindow );
184 :
185 : // remember new window
186 0 : designate_currentwindow(pChildWindow);
187 :
188 : // fire dragEnter on listeners of current window
189 : nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
190 0 : dtde.SourceActions, m_aDataFlavorList );
191 : }
192 : else
193 : {
194 : // fire dragOver on listeners of current window
195 : nListeners = fireDragOverEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
196 0 : dtde.SourceActions );
197 : }
198 :
199 : // reject drag if no listener found
200 0 : if( nListeners == 0 )
201 : {
202 : OSL_TRACE( "rejecting drag over due to missing listeners." );
203 0 : dtde.Context->rejectDrag();
204 0 : }
205 0 : }
206 :
207 : // DNDEventDispatcher::dropActionChanged
208 0 : void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde )
209 : throw(RuntimeException, std::exception)
210 : {
211 0 : osl::MutexGuard aImplGuard( m_aMutex );
212 :
213 0 : Point location( dtde.LocationX, dtde.LocationY );
214 : sal_Int32 nListeners;
215 :
216 0 : vcl::Window* pChildWindow = findTopLevelWindow(location);
217 :
218 0 : if( pChildWindow != m_pCurrentWindow.get() )
219 : {
220 : // fire dragExit on listeners of previous window
221 0 : fireDragExitEvent( m_pCurrentWindow );
222 :
223 : // remember new window
224 0 : designate_currentwindow(pChildWindow);
225 :
226 : // fire dragEnter on listeners of current window
227 : nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
228 0 : dtde.SourceActions, m_aDataFlavorList );
229 : }
230 : else
231 : {
232 : // fire dropActionChanged on listeners of current window
233 : nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
234 0 : dtde.SourceActions );
235 : }
236 :
237 : // reject drag if no listener found
238 0 : if( nListeners == 0 )
239 : {
240 : OSL_TRACE( "rejecting dropActionChanged due to missing listeners." );
241 0 : dtde.Context->rejectDrag();
242 0 : }
243 0 : }
244 :
245 : // DNDEventDispatcher::dragGestureRecognized
246 :
247 0 : void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge )
248 : throw(RuntimeException, std::exception)
249 : {
250 0 : osl::MutexGuard aImplGuard( m_aMutex );
251 :
252 0 : Point origin( dge.DragOriginX, dge.DragOriginY );
253 :
254 0 : vcl::Window* pChildWindow = findTopLevelWindow(origin);
255 :
256 0 : fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction );
257 0 : }
258 :
259 : // DNDEventDispatcher::disposing
260 :
261 1250 : void SAL_CALL DNDEventDispatcher::disposing( const EventObject& )
262 : throw(RuntimeException, std::exception)
263 : {
264 1250 : }
265 :
266 : // DNDEventDispatcher::acceptDrag
267 :
268 0 : void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ ) throw(RuntimeException, std::exception)
269 : {
270 0 : }
271 :
272 : // DNDEventDispatcher::rejectDrag
273 :
274 0 : void SAL_CALL DNDEventDispatcher::rejectDrag() throw(RuntimeException, std::exception)
275 : {
276 0 : }
277 :
278 : // DNDEventDispatcher::fireDragEnterEvent
279 :
280 0 : 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
283 : )
284 : throw(RuntimeException)
285 : {
286 0 : sal_Int32 n = 0;
287 :
288 0 : if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
289 : {
290 0 : SolarMutexClearableGuard aSolarGuard;
291 :
292 : // set an UI lock
293 0 : pWindow->IncrementLockCount();
294 :
295 : // query DropTarget from window
296 0 : Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
297 :
298 0 : if( xDropTarget.is() )
299 : {
300 : // retrieve relative mouse position
301 0 : Point relLoc = pWindow->ImplFrameToOutput( rLocation );
302 0 : aSolarGuard.clear();
303 :
304 0 : n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent(
305 0 : xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList );
306 0 : }
307 : }
308 :
309 0 : return n;
310 : }
311 :
312 : // DNDEventDispatcher::fireDragOverEvent
313 :
314 0 : sal_Int32 DNDEventDispatcher::fireDragOverEvent( vcl::Window *pWindow,
315 : const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
316 : const Point& rLocation, const sal_Int8 nSourceActions
317 : )
318 : throw(RuntimeException)
319 : {
320 0 : sal_Int32 n = 0;
321 :
322 0 : if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
323 : {
324 0 : SolarMutexClearableGuard aSolarGuard;
325 :
326 : // query DropTarget from window
327 0 : Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
328 :
329 0 : if( xDropTarget.is() )
330 : {
331 : // retrieve relative mouse position
332 0 : Point relLoc = pWindow->ImplFrameToOutput( rLocation );
333 0 : aSolarGuard.clear();
334 :
335 0 : n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent(
336 0 : xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
337 0 : }
338 : }
339 :
340 0 : return n;
341 : }
342 :
343 : // DNDEventDispatcher::fireDragExitEvent
344 :
345 0 : sal_Int32 DNDEventDispatcher::fireDragExitEvent( vcl::Window *pWindow ) throw(RuntimeException)
346 : {
347 0 : sal_Int32 n = 0;
348 :
349 0 : if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
350 : {
351 0 : SolarMutexClearableGuard aGuard;
352 :
353 : // query DropTarget from window
354 0 : Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
355 :
356 0 : aGuard.clear();
357 :
358 0 : if( xDropTarget.is() )
359 0 : n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent();
360 :
361 : // release UI lock
362 0 : pWindow->DecrementLockCount();
363 : }
364 :
365 0 : return n;
366 : }
367 :
368 : // DNDEventDispatcher::fireDropActionChangedEvent
369 :
370 0 : sal_Int32 DNDEventDispatcher::fireDropActionChangedEvent( vcl::Window *pWindow,
371 : const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
372 : const Point& rLocation, const sal_Int8 nSourceActions
373 : )
374 : throw(RuntimeException)
375 : {
376 0 : sal_Int32 n = 0;
377 :
378 0 : if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
379 : {
380 0 : SolarMutexClearableGuard aGuard;
381 :
382 : // query DropTarget from window
383 0 : Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
384 :
385 0 : if( xDropTarget.is() )
386 : {
387 : // retrieve relative mouse position
388 0 : Point relLoc = pWindow->ImplFrameToOutput( rLocation );
389 0 : aGuard.clear();
390 :
391 0 : n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent(
392 0 : xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
393 0 : }
394 : }
395 :
396 0 : return n;
397 : }
398 :
399 : // DNDEventDispatcher::fireDropEvent
400 :
401 0 : 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
404 : )
405 : throw(RuntimeException)
406 : {
407 0 : sal_Int32 n = 0;
408 :
409 0 : if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
410 : {
411 0 : SolarMutexClearableGuard aGuard;
412 :
413 : // query DropTarget from window
414 0 : Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
415 :
416 : // window may be destroyed in drop event handler
417 0 : ImplDelData aDelData;
418 0 : pWindow->ImplAddDel( &aDelData );
419 :
420 0 : if( xDropTarget.is() )
421 : {
422 : // retrieve relative mouse position
423 0 : Point relLoc = pWindow->ImplFrameToOutput( rLocation );
424 0 : aGuard.clear();
425 :
426 0 : n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent(
427 0 : xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable );
428 : }
429 :
430 0 : if ( !aDelData.IsDead() )
431 : {
432 0 : pWindow->ImplRemoveDel( &aDelData );
433 : // release UI lock
434 0 : pWindow->DecrementLockCount();
435 0 : }
436 :
437 : }
438 :
439 0 : return n;
440 : }
441 :
442 : // DNDEventDispatcher::fireDragGestureRecognized
443 :
444 0 : sal_Int32 DNDEventDispatcher::fireDragGestureEvent( vcl::Window *pWindow,
445 : const Reference< XDragSource >& xSource, const Any& event,
446 : const Point& rOrigin, const sal_Int8 nDragAction
447 : )
448 : throw(::com::sun::star::uno::RuntimeException)
449 : {
450 0 : sal_Int32 n = 0;
451 :
452 0 : if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
453 : {
454 0 : SolarMutexClearableGuard aGuard;
455 :
456 : // query DropTarget from window
457 0 : Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer();
458 :
459 0 : if( xDragGestureRecognizer.is() )
460 : {
461 : // retrieve relative mouse position
462 0 : Point relLoc = pWindow->ImplFrameToOutput( rOrigin );
463 0 : aGuard.clear();
464 :
465 0 : n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent(
466 0 : nDragAction, relLoc.X(), relLoc.Y(), xSource, event );
467 : }
468 :
469 : // release UI lock
470 0 : pWindow->DecrementLockCount();
471 : }
472 :
473 0 : return n;
474 : }
475 :
476 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|