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 47 DNDEventDispatcher::DNDEventDispatcher( Window * pTopWindow ): 48 m_pTopWindow( pTopWindow ), 49 m_pCurrentWindow( NULL ) 50 { 51 } 52 53 //================================================================================================== 54 // DNDEventDispatcher::~DNDEventDispatcher 55 //================================================================================================== 56 57 DNDEventDispatcher::~DNDEventDispatcher() 58 { 59 } 60 61 //================================================================================================== 62 // DNDEventDispatcher::drop 63 //================================================================================================== 64 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 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 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 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 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 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 332 void SAL_CALL DNDEventDispatcher::disposing( const EventObject& ) 333 throw(RuntimeException) 334 { 335 } 336 337 //================================================================================================== 338 // DNDEventDispatcher::acceptDrag 339 //================================================================================================== 340 341 void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ ) throw(RuntimeException) 342 { 343 } 344 345 //================================================================================================== 346 // DNDEventDispatcher::rejectDrag 347 //================================================================================================== 348 349 void SAL_CALL DNDEventDispatcher::rejectDrag() throw(RuntimeException) 350 { 351 } 352 353 //================================================================================================== 354 // DNDEventDispatcher::fireDragEnterEvent 355 //================================================================================================== 356 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 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 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 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 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 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