xref: /trunk/main/vcl/source/window/dndevdis.cxx (revision 9f62ea84)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <dndevdis.hxx>
28 #include <dndlcon.hxx>
29 #include <window.h>
30 #include <svdata.hxx>
31 
32 #include <vos/mutex.hxx>
33 #include <vcl/svapp.hxx>
34 
35 using namespace ::osl;
36 using namespace ::vos;
37 using namespace ::cppu;
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::lang;
40 using namespace ::com::sun::star::datatransfer;
41 using namespace ::com::sun::star::datatransfer::dnd;
42 
43 //==================================================================================================
44 // DNDEventDispatcher::DNDEventDispatcher
45 //==================================================================================================
46 
DNDEventDispatcher(Window * pTopWindow)47 DNDEventDispatcher::DNDEventDispatcher( Window * pTopWindow ):
48 	m_pTopWindow( pTopWindow ),
49 	m_pCurrentWindow( NULL )
50 {
51 }
52 
53 //==================================================================================================
54 // DNDEventDispatcher::~DNDEventDispatcher
55 //==================================================================================================
56 
~DNDEventDispatcher()57 DNDEventDispatcher::~DNDEventDispatcher()
58 {
59 }
60 
61 //==================================================================================================
62 // DNDEventDispatcher::drop
63 //==================================================================================================
64 
drop(const DropTargetDropEvent & dtde)65 void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde )
66 	throw(RuntimeException)
67 {
68 	MutexGuard aImplGuard( m_aMutex );
69 
70 	Point location( dtde.LocationX, dtde.LocationY );
71 
72 	// find the window that is toplevel for this coordinates
73 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
74 
75     // because those coordinates come from outside, they must be mirrored if RTL layout is active
76     if( Application::GetSettings().GetLayoutRTL() )
77         m_pTopWindow->ImplMirrorFramePos( location );
78     Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
79 
80 	if( NULL == pChildWindow )
81         pChildWindow = m_pTopWindow;
82 
83     while( pChildWindow->ImplGetClientWindow() )
84         pChildWindow = pChildWindow->ImplGetClientWindow();
85 
86     if( pChildWindow->ImplIsAntiparallel() )
87         pChildWindow->ImplReMirror( location );
88 
89 	aSolarGuard.clear();
90 
91 	// handle the case that drop is in an other vcl window than the last dragOver
92 	if( pChildWindow != m_pCurrentWindow )
93 	{
94 		// fire dragExit on listeners of previous window
95 		fireDragExitEvent( m_pCurrentWindow );
96 
97 		fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this),
98 			dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList );
99 	}
100 
101 	sal_Int32 nListeners = 0;
102 
103 	// send drop event to the child window
104 	nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction,
105 		location, dtde.SourceActions, dtde.Transferable );
106 
107 	// reject drop if no listeners found
108 	if( nListeners == 0 ) {
109 		OSL_TRACE( "rejecting drop due to missing listeners." );
110 		dtde.Context->rejectDrop();
111 	}
112 
113 	// this is a drop -> no further drag overs
114 	m_pCurrentWindow = NULL;
115 	m_aDataFlavorList.realloc( 0 );
116 }
117 
118 //==================================================================================================
119 // DNDEventDispatcher::dragEnter
120 //==================================================================================================
121 
dragEnter(const DropTargetDragEnterEvent & dtdee)122 void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee )
123 	throw(RuntimeException)
124 {
125 	MutexGuard aImplGuard( m_aMutex );
126 	Point location( dtdee.LocationX, dtdee.LocationY );
127 
128 	// find the window that is toplevel for this coordinates
129 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
130 
131     // because those coordinates come from outside, they must be mirrored if RTL layout is active
132     if( Application::GetSettings().GetLayoutRTL() )
133         m_pTopWindow->ImplMirrorFramePos( location );
134 	Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
135 
136 	if( NULL == pChildWindow )
137         pChildWindow = m_pTopWindow;
138 
139     while( pChildWindow->ImplGetClientWindow() )
140         pChildWindow = pChildWindow->ImplGetClientWindow();
141 
142     if( pChildWindow->ImplIsAntiparallel() )
143         pChildWindow->ImplReMirror( location );
144 
145 	aSolarGuard.clear();
146 
147 	// assume pointer write operation to be atomic
148 	m_pCurrentWindow = pChildWindow;
149 	m_aDataFlavorList = dtdee.SupportedDataFlavors;
150 
151 	// fire dragEnter on listeners of current window
152 	sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location,
153 		dtdee.SourceActions, dtdee.SupportedDataFlavors );
154 
155 	// reject drag if no listener found
156 	if( nListeners == 0 ) {
157 		OSL_TRACE( "rejecting drag enter due to missing listeners." );
158 		dtdee.Context->rejectDrag();
159 	}
160 
161 }
162 
163 //==================================================================================================
164 // DNDEventDispatcher::dragExit
165 //==================================================================================================
166 
dragExit(const DropTargetEvent &)167 void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ )
168 	throw(RuntimeException)
169 {
170 	MutexGuard aImplGuard( m_aMutex );
171 
172 	fireDragExitEvent( m_pCurrentWindow );
173 
174 	// reset member values
175 	m_pCurrentWindow = NULL;
176 	m_aDataFlavorList.realloc( 0 );
177 }
178 
179 //==================================================================================================
180 // DNDEventDispatcher::dragOver
181 //==================================================================================================
182 
dragOver(const DropTargetDragEvent & dtde)183 void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde )
184 	throw(RuntimeException)
185 {
186 	MutexGuard aImplGuard( m_aMutex );
187 
188 	Point location( dtde.LocationX, dtde.LocationY );
189 	sal_Int32 nListeners;
190 
191 	// find the window that is toplevel for this coordinates
192 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
193 
194     // because those coordinates come from outside, they must be mirrored if RTL layout is active
195     if( Application::GetSettings().GetLayoutRTL() )
196         m_pTopWindow->ImplMirrorFramePos( location );
197 	Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
198 
199 	if( NULL == pChildWindow )
200         pChildWindow = m_pTopWindow;
201 
202     while( pChildWindow->ImplGetClientWindow() )
203         pChildWindow = pChildWindow->ImplGetClientWindow();
204 
205     if( pChildWindow->ImplIsAntiparallel() )
206         pChildWindow->ImplReMirror( location );
207 
208 	aSolarGuard.clear();
209 
210 	if( pChildWindow != m_pCurrentWindow )
211 	{
212 		// fire dragExit on listeners of previous window
213 		fireDragExitEvent( m_pCurrentWindow );
214 
215 		// remember new window
216 		m_pCurrentWindow = pChildWindow;
217 
218 		// fire dragEnter on listeners of current window
219 		nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
220 			dtde.SourceActions, m_aDataFlavorList );
221 	}
222 	else
223 	{
224 		// fire dragOver on listeners of current window
225 		nListeners = fireDragOverEvent( pChildWindow, dtde.Context,	dtde.DropAction, location,
226 			dtde.SourceActions );
227 	}
228 
229 	// reject drag if no listener found
230 	if( nListeners == 0 )
231 	{
232 		OSL_TRACE( "rejecting drag over due to missing listeners." );
233 		dtde.Context->rejectDrag();
234 	}
235 }
236 
237 //==================================================================================================
238 // DNDEventDispatcher::dropActionChanged
239 //==================================================================================================
240 
dropActionChanged(const DropTargetDragEvent & dtde)241 void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde )
242 	throw(RuntimeException)
243 {
244 	MutexGuard aImplGuard( m_aMutex );
245 
246 	Point location( dtde.LocationX, dtde.LocationY );
247 	sal_Int32 nListeners;
248 
249 	// find the window that is toplevel for this coordinates
250 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
251 
252     // because those coordinates come from outside, they must be mirrored if RTL layout is active
253     if( Application::GetSettings().GetLayoutRTL() )
254         m_pTopWindow->ImplMirrorFramePos( location );
255 	Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
256 
257 	if( NULL == pChildWindow )
258         pChildWindow = m_pTopWindow;
259 
260     while( pChildWindow->ImplGetClientWindow() )
261         pChildWindow = pChildWindow->ImplGetClientWindow();
262 
263     if( pChildWindow->ImplIsAntiparallel() )
264         pChildWindow->ImplReMirror( location );
265 
266 	aSolarGuard.clear();
267 
268 	if( pChildWindow != m_pCurrentWindow )
269 	{
270 		// fire dragExit on listeners of previous window
271 		fireDragExitEvent( m_pCurrentWindow );
272 
273 		// remember new window
274 		m_pCurrentWindow = pChildWindow;
275 
276 		// fire dragEnter on listeners of current window
277 		nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
278 			dtde.SourceActions, m_aDataFlavorList );
279 	}
280 	else
281 	{
282 		// fire dropActionChanged on listeners of current window
283 		nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
284 			dtde.SourceActions );
285 	}
286 
287 	// reject drag if no listener found
288 	if( nListeners == 0 )
289 	{
290 		OSL_TRACE( "rejecting dropActionChanged due to missing listeners." );
291 		dtde.Context->rejectDrag();
292 	}
293 }
294 
295 
296 //==================================================================================================
297 // DNDEventDispatcher::dragGestureRecognized
298 //==================================================================================================
299 
dragGestureRecognized(const DragGestureEvent & dge)300 void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge )
301     throw(RuntimeException)
302 {	MutexGuard aImplGuard( m_aMutex );
303 
304 	Point origin( dge.DragOriginX, dge.DragOriginY );
305 
306 	// find the window that is toplevel for this coordinates
307 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
308 
309     // because those coordinates come from outside, they must be mirrored if RTL layout is active
310     if( Application::GetSettings().GetLayoutRTL() )
311         m_pTopWindow->ImplMirrorFramePos( origin );
312     Window * pChildWindow = m_pTopWindow->ImplFindWindow( origin );
313 
314 	if( NULL == pChildWindow )
315         pChildWindow = m_pTopWindow;
316 
317     while( pChildWindow->ImplGetClientWindow() )
318         pChildWindow = pChildWindow->ImplGetClientWindow();
319 
320     if( pChildWindow->ImplIsAntiparallel() )
321         pChildWindow->ImplReMirror( origin );
322 
323 	aSolarGuard.clear();
324 
325     fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction );
326 }
327 
328 //==================================================================================================
329 // DNDEventDispatcher::disposing
330 //==================================================================================================
331 
disposing(const EventObject &)332 void SAL_CALL DNDEventDispatcher::disposing( const EventObject& )
333 	throw(RuntimeException)
334 {
335 }
336 
337 //==================================================================================================
338 // DNDEventDispatcher::acceptDrag
339 //==================================================================================================
340 
acceptDrag(sal_Int8)341 void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ ) throw(RuntimeException)
342 {
343 }
344 
345 //==================================================================================================
346 // DNDEventDispatcher::rejectDrag
347 //==================================================================================================
348 
rejectDrag()349 void SAL_CALL DNDEventDispatcher::rejectDrag() throw(RuntimeException)
350 {
351 }
352 
353 //==================================================================================================
354 // DNDEventDispatcher::fireDragEnterEvent
355 //==================================================================================================
356 
fireDragEnterEvent(Window * pWindow,const Reference<XDropTargetDragContext> & xContext,const sal_Int8 nDropAction,const Point & rLocation,const sal_Int8 nSourceActions,const Sequence<DataFlavor> & aFlavorList)357 sal_Int32 DNDEventDispatcher::fireDragEnterEvent( Window *pWindow,
358 	const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
359 	const Point& rLocation, const sal_Int8 nSourceActions, const Sequence< DataFlavor >& aFlavorList
360 )
361 	throw(RuntimeException)
362 {
363 	sal_Int32 n = 0;
364 
365 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
366 	{
367 		OClearableGuard aGuard( Application::GetSolarMutex() );
368 
369         // set an UI lock
370         pWindow->IncrementLockCount();
371 
372 		// query DropTarget from window
373 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
374 
375 		if( xDropTarget.is() )
376 		{
377 			// retrieve relative mouse position
378 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
379 			aGuard.clear();
380 
381 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent(
382 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList );
383 		}
384 	}
385 
386 	return n;
387 }
388 
389 //==================================================================================================
390 // DNDEventDispatcher::fireDragOverEvent
391 //==================================================================================================
392 
fireDragOverEvent(Window * pWindow,const Reference<XDropTargetDragContext> & xContext,const sal_Int8 nDropAction,const Point & rLocation,const sal_Int8 nSourceActions)393 sal_Int32 DNDEventDispatcher::fireDragOverEvent( Window *pWindow,
394 	const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
395 	const Point& rLocation, const sal_Int8 nSourceActions
396 )
397 	throw(RuntimeException)
398 {
399 	sal_Int32 n = 0;
400 
401 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
402 	{
403 		OClearableGuard aGuard( Application::GetSolarMutex() );
404 
405 		// query DropTarget from window
406 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
407 
408 		if( xDropTarget.is() )
409 		{
410 			// retrieve relative mouse position
411 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
412 			aGuard.clear();
413 
414 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent(
415 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
416 		}
417 	}
418 
419 	return n;
420 }
421 
422 //==================================================================================================
423 // DNDEventDispatcher::fireDragExitEvent
424 //==================================================================================================
425 
fireDragExitEvent(Window * pWindow)426 sal_Int32 DNDEventDispatcher::fireDragExitEvent( Window *pWindow ) throw(RuntimeException)
427 {
428 	sal_Int32 n = 0;
429 
430 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
431 	{
432 		OClearableGuard aGuard( Application::GetSolarMutex() );
433 
434 		// query DropTarget from window
435 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
436 
437 		aGuard.clear();
438 
439 		if( xDropTarget.is() )
440 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent();
441 
442         // release UI lock
443         pWindow->DecrementLockCount();
444 	}
445 
446 	return n;
447 }
448 
449 //==================================================================================================
450 // DNDEventDispatcher::fireDropActionChangedEvent
451 //==================================================================================================
452 
fireDropActionChangedEvent(Window * pWindow,const Reference<XDropTargetDragContext> & xContext,const sal_Int8 nDropAction,const Point & rLocation,const sal_Int8 nSourceActions)453 sal_Int32 DNDEventDispatcher::fireDropActionChangedEvent( Window *pWindow,
454 	const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
455 	const Point& rLocation, const sal_Int8 nSourceActions
456 )
457 	throw(RuntimeException)
458 {
459 	sal_Int32 n = 0;
460 
461 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
462 	{
463 		OClearableGuard aGuard( Application::GetSolarMutex() );
464 
465 		// query DropTarget from window
466 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
467 
468 		if( xDropTarget.is() )
469 		{
470 			// retrieve relative mouse position
471 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
472 			aGuard.clear();
473 
474 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent(
475 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
476 		}
477 	}
478 
479 	return n;
480 }
481 
482 //==================================================================================================
483 // DNDEventDispatcher::fireDropEvent
484 //==================================================================================================
485 
fireDropEvent(Window * pWindow,const Reference<XDropTargetDropContext> & xContext,const sal_Int8 nDropAction,const Point & rLocation,const sal_Int8 nSourceActions,const Reference<XTransferable> & xTransferable)486 sal_Int32 DNDEventDispatcher::fireDropEvent( Window *pWindow,
487 	const Reference< XDropTargetDropContext >& xContext, const sal_Int8 nDropAction, const Point& rLocation,
488 	const sal_Int8 nSourceActions, const Reference< XTransferable >& xTransferable
489 )
490 	throw(RuntimeException)
491 {
492 	sal_Int32 n = 0;
493 
494 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
495 	{
496 		OClearableGuard aGuard( Application::GetSolarMutex() );
497 
498 		// query DropTarget from window
499 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
500 
501         // window may be destroyed in drop event handler
502         ImplDelData         aDelData;
503         pWindow->ImplAddDel( &aDelData );
504 
505 		if( xDropTarget.is() )
506 		{
507 			// retrieve relative mouse position
508 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
509 			aGuard.clear();
510 
511 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent(
512 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable );
513 		}
514 
515         if ( !aDelData.IsDelete() )
516         {
517             pWindow->ImplRemoveDel( &aDelData );
518             // release UI lock
519             pWindow->DecrementLockCount();
520         }
521 
522 	}
523 
524 	return n;
525 }
526 
527 //==================================================================================================
528 // DNDEventDispatcher::fireDragGestureRecognized
529 //==================================================================================================
530 
fireDragGestureEvent(Window * pWindow,const Reference<XDragSource> & xSource,const Any event,const Point & rOrigin,const sal_Int8 nDragAction)531 sal_Int32 DNDEventDispatcher::fireDragGestureEvent( Window *pWindow,
532     const Reference< XDragSource >& xSource, const Any event,
533     const Point& rOrigin, const sal_Int8 nDragAction
534 )
535     throw(::com::sun::star::uno::RuntimeException)
536 {
537 	sal_Int32 n = 0;
538 
539 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
540 	{
541 		OClearableGuard aGuard( Application::GetSolarMutex() );
542 
543 		// query DropTarget from window
544 		Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer();
545 
546 		if( xDragGestureRecognizer.is() )
547 		{
548 			// retrieve relative mouse position
549 			Point relLoc = pWindow->ImplFrameToOutput( rOrigin );
550 			aGuard.clear();
551 
552 			n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent(
553 				nDragAction, relLoc.X(), relLoc.Y(), xSource, event );
554 		}
555 
556         // release UI lock
557         pWindow->DecrementLockCount();
558 	}
559 
560 	return n;
561 }
562