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_dtrans.hxx" 26 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> 27 #include <com/sun/star/datatransfer/XTransferable.hpp> 28 #include <com/sun/star/awt/MouseButton.hpp> 29 #include <com/sun/star/awt/MouseEvent.hpp> 30 #include <rtl/unload.h> 31 32 #include <process.h> 33 #include <memory> 34 35 #include "source.hxx" 36 #include "globals.hxx" 37 #include "sourcecontext.hxx" 38 #include "../../inc/DtObjFactory.hxx" 39 #include <rtl/ustring.h> 40 #include <process.h> 41 #include <winuser.h> 42 #include <stdio.h> 43 44 #ifdef __MINGW32__ 45 #define __uuidof(I) IID_##I 46 #endif 47 48 using namespace rtl; 49 using namespace cppu; 50 using namespace osl; 51 using namespace com::sun::star::datatransfer; 52 using namespace com::sun::star::datatransfer::dnd; 53 using namespace com::sun::star::datatransfer::dnd::DNDConstants; 54 using namespace com::sun::star::uno; 55 using namespace com::sun::star::awt::MouseButton; 56 using namespace com::sun::star::awt; 57 using namespace com::sun::star::lang; 58 59 extern rtl_StandardModuleCount g_moduleCount; 60 61 //--> TRA 62 63 extern Reference< XTransferable > g_XTransferable; 64 65 //<-- TRA 66 67 unsigned __stdcall DndOleSTAFunc(LPVOID pParams); 68 69 //---------------------------------------------------- 70 /** Ctor 71 */ 72 DragSource::DragSource( const Reference<XMultiServiceFactory>& sf): 73 m_serviceFactory( sf), 74 WeakComponentImplHelper3< XDragSource, XInitialization, XServiceInfo >(m_mutex), 75 // m_pcurrentContext_impl(0), 76 m_hAppWindow(0), 77 m_MouseButton(0), 78 m_RunningDndOperationCount(0) 79 { 80 g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt ); 81 } 82 83 //---------------------------------------------------- 84 /** Dtor 85 */ 86 DragSource::~DragSource() 87 { 88 g_moduleCount.modCnt.release( &g_moduleCount.modCnt ); 89 } 90 91 //---------------------------------------------------- 92 /** First start a new drag and drop thread if 93 the last one has finished 94 95 ???? 96 Do we really need a separate thread for 97 every Dnd opeartion or only if the source 98 thread is an MTA thread 99 ???? 100 */ 101 void DragSource::StartDragImpl( 102 const DragGestureEvent& trigger, 103 sal_Int8 sourceActions, 104 sal_Int32 /*cursor*/, 105 sal_Int32 /*image*/, 106 const Reference<XTransferable >& trans, 107 const Reference<XDragSourceListener >& listener ) 108 { 109 // The actions supported by the drag source 110 m_sourceActions= sourceActions; 111 // We need to know which mouse button triggered the operation. 112 // If it was the left one, then the drop occurs when that button 113 // has been released and if it was the right one then the drop 114 // occurs when the right button has been released. If the event is not 115 // set then we assume that the left button is pressed. 116 MouseEvent evtMouse; 117 trigger.Event >>= evtMouse; 118 m_MouseButton= evtMouse.Buttons; 119 120 // The SourceContext class administers the XDragSourceListener s and 121 // fires events to them. An instance only exists in the scope of this 122 // functions. However, the drag and drop operation causes callbacks 123 // to the IDropSource interface implemented in this class (but only 124 // while this function executes). The source context is also used 125 // in DragSource::QueryContinueDrag. 126 m_currentContext= static_cast<XDragSourceContext*>( new SourceContext( 127 static_cast<DragSource*>(this), listener ) ); 128 129 // Convert the XTransferable data object into an IDataObject object; 130 131 //--> TRA 132 g_XTransferable = trans; 133 //<-- TRA 134 135 m_spDataObject= m_aDataConverter.createDataObjFromTransferable( 136 m_serviceFactory, trans); 137 138 // Obtain the id of the thread that created the window 139 DWORD processId; 140 m_threadIdWindow= GetWindowThreadProcessId( m_hAppWindow, &processId); 141 142 // hold the instance for the DnD thread, it's to late 143 // to acquire at the start of the thread procedure 144 // the thread procedure is responsible for the release 145 acquire(); 146 147 // The thread acccesses members of this instance but does not call acquire. 148 // Hopefully this instance is not destroyed before the thread has terminated. 149 unsigned threadId; 150 HANDLE hThread= reinterpret_cast<HANDLE>(_beginthreadex( 151 0, 0, DndOleSTAFunc, reinterpret_cast<void*>(this), 0, &threadId)); 152 153 // detach from thread 154 CloseHandle(hThread); 155 } 156 157 // XInitialization 158 159 //---------------------------------------------------- 160 /** aArguments contains a machine id 161 */ 162 void SAL_CALL DragSource::initialize( const Sequence< Any >& aArguments ) 163 throw(Exception, RuntimeException) 164 { 165 if( aArguments.getLength() >=2) 166 m_hAppWindow= *(HWND*)aArguments[1].getValue(); 167 OSL_ASSERT( IsWindow( m_hAppWindow) ); 168 } 169 170 //---------------------------------------------------- 171 /** XDragSource 172 */ 173 sal_Bool SAL_CALL DragSource::isDragImageSupported( ) 174 throw(RuntimeException) 175 { 176 return 0; 177 } 178 179 //---------------------------------------------------- 180 /** 181 */ 182 sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ ) 183 throw( IllegalArgumentException, RuntimeException) 184 { 185 return 0; 186 } 187 188 //---------------------------------------------------- 189 /** Notifies the XDragSourceListener by 190 calling dragDropEnd 191 */ 192 void SAL_CALL DragSource::startDrag( 193 const DragGestureEvent& trigger, 194 sal_Int8 sourceActions, 195 sal_Int32 cursor, 196 sal_Int32 image, 197 const Reference<XTransferable >& trans, 198 const Reference<XDragSourceListener >& listener ) throw( RuntimeException) 199 { 200 // Allow only one running dnd operation at a time, 201 // see XDragSource documentation 202 203 long cnt = InterlockedIncrement(&m_RunningDndOperationCount); 204 205 if (1 == cnt) 206 { 207 StartDragImpl(trigger, sourceActions, cursor, image, trans, listener); 208 } 209 else 210 { 211 //OSL_ENSURE(false, "Overlapping Drag&Drop operation rejected!"); 212 213 cnt = InterlockedDecrement(&m_RunningDndOperationCount); 214 215 DragSourceDropEvent dsde; 216 217 dsde.DropAction = ACTION_NONE; 218 dsde.DropSuccess = false; 219 220 try 221 { 222 listener->dragDropEnd(dsde); 223 } 224 catch(RuntimeException&) 225 { 226 OSL_ENSURE(false, "Runtime exception during event dispatching"); 227 } 228 } 229 } 230 231 //---------------------------------------------------- 232 /**IDropTarget 233 */ 234 HRESULT STDMETHODCALLTYPE DragSource::QueryInterface( REFIID riid, void **ppvObject) 235 { 236 if( !ppvObject) 237 return E_POINTER; 238 *ppvObject= NULL; 239 240 if( riid == __uuidof( IUnknown) ) 241 *ppvObject= static_cast<IUnknown*>( this); 242 else if ( riid == __uuidof( IDropSource) ) 243 *ppvObject= static_cast<IDropSource*>( this); 244 245 if(*ppvObject) 246 { 247 AddRef(); 248 return S_OK; 249 } 250 else 251 return E_NOINTERFACE; 252 253 } 254 255 //---------------------------------------------------- 256 /** 257 */ 258 ULONG STDMETHODCALLTYPE DragSource::AddRef( void) 259 { 260 acquire(); 261 return (ULONG) m_refCount; 262 } 263 264 //---------------------------------------------------- 265 /** 266 */ 267 ULONG STDMETHODCALLTYPE DragSource::Release( void) 268 { 269 ULONG ref= m_refCount; 270 release(); 271 return --ref; 272 } 273 274 //---------------------------------------------------- 275 /** IDropSource 276 */ 277 HRESULT STDMETHODCALLTYPE DragSource::QueryContinueDrag( 278 /* [in] */ BOOL fEscapePressed, 279 /* [in] */ DWORD grfKeyState) 280 { 281 #if defined DBG_CONSOLE_OUT 282 printf("\nDragSource::QueryContinueDrag"); 283 #endif 284 285 HRESULT retVal= S_OK; // default continue DnD 286 287 if (fEscapePressed) 288 { 289 retVal= DRAGDROP_S_CANCEL; 290 } 291 else 292 { 293 if( ( m_MouseButton == MouseButton::RIGHT && !(grfKeyState & MK_RBUTTON) ) || 294 ( m_MouseButton == MouseButton::MIDDLE && !(grfKeyState & MK_MBUTTON) ) || 295 ( m_MouseButton == MouseButton::LEFT && !(grfKeyState & MK_LBUTTON) ) || 296 ( m_MouseButton == 0 && !(grfKeyState & MK_LBUTTON) ) ) 297 { 298 retVal= DRAGDROP_S_DROP; 299 } 300 } 301 302 // fire dropActionChanged event. 303 // this is actually done by the context, which also detects whether the action 304 // changed at all 305 sal_Int8 dropAction= fEscapePressed ? ACTION_NONE : 306 dndOleKeysToAction( grfKeyState, m_sourceActions); 307 308 sal_Int8 userAction= fEscapePressed ? ACTION_NONE : 309 dndOleKeysToAction( grfKeyState, -1 ); 310 311 static_cast<SourceContext*>(m_currentContext.get())->fire_dropActionChanged( 312 dropAction, userAction); 313 314 return retVal; 315 } 316 317 //---------------------------------------------------- 318 /** 319 */ 320 HRESULT STDMETHODCALLTYPE DragSource::GiveFeedback( 321 /* [in] */ DWORD 322 #if defined DBG_CONSOLE_OUT 323 dwEffect 324 #endif 325 ) 326 { 327 #if defined DBG_CONSOLE_OUT 328 printf("\nDragSource::GiveFeedback %d", dwEffect); 329 #endif 330 331 return DRAGDROP_S_USEDEFAULTCURSORS; 332 } 333 334 // XServiceInfo 335 OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException) 336 { 337 return OUString(RTL_CONSTASCII_USTRINGPARAM(DNDSOURCE_IMPL_NAME));; 338 } 339 // XServiceInfo 340 sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException) 341 { 342 if( ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(DNDSOURCE_SERVICE_NAME )))) 343 return sal_True; 344 return sal_False; 345 } 346 347 Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames( ) throw (RuntimeException) 348 { 349 OUString names[1]= {OUString(RTL_CONSTASCII_USTRINGPARAM(DNDSOURCE_SERVICE_NAME))}; 350 351 return Sequence<OUString>(names, 1); 352 } 353 354 //---------------------------------------------------- 355 /**This function is called as extra thread from 356 DragSource::executeDrag. The function 357 carries out a drag and drop operation by calling 358 DoDragDrop. The thread also notifies all 359 XSourceListener. 360 */ 361 unsigned __stdcall DndOleSTAFunc(LPVOID pParams) 362 { 363 // The structure contains all arguments for DoDragDrop and other 364 DragSource *pSource= (DragSource*)pParams; 365 366 // Drag and drop only works in a thread in which OleInitialize is called. 367 HRESULT hr= OleInitialize( NULL); 368 369 if(SUCCEEDED(hr)) 370 { 371 // We force the creation of a thread message queue. This is necessary 372 // for a later call to AttachThreadInput 373 MSG msgtemp; 374 PeekMessage( &msgtemp, NULL, WM_USER, WM_USER, PM_NOREMOVE); 375 376 DWORD threadId= GetCurrentThreadId(); 377 378 // This thread is attached to the thread that created the window. Hence 379 // this thread also receives all mouse and keyboard messages which are 380 // needed by DoDragDrop 381 AttachThreadInput( threadId , pSource->m_threadIdWindow, TRUE ); 382 383 DWORD dwEffect= 0; 384 hr= DoDragDrop( 385 pSource->m_spDataObject.get(), 386 static_cast<IDropSource*>(pSource), 387 dndActionsToDropEffects( pSource->m_sourceActions), 388 &dwEffect); 389 390 // #105428 detach my message queue from the other threads 391 // message queue before calling fire_dragDropEnd else 392 // the office may appear to hang sometimes 393 AttachThreadInput( threadId, pSource->m_threadIdWindow, FALSE); 394 395 //--> TRA 396 // clear the global transferable again 397 g_XTransferable = Reference< XTransferable >( ); 398 //<-- TRA 399 400 OSL_ENSURE( hr != E_INVALIDARG, "IDataObject impl does not contain valid data"); 401 402 //Fire event 403 sal_Int8 action= hr == DRAGDROP_S_DROP ? dndOleDropEffectsToActions( dwEffect) : ACTION_NONE; 404 405 static_cast<SourceContext*>(pSource->m_currentContext.get())->fire_dragDropEnd( 406 hr == DRAGDROP_S_DROP ? sal_True : sal_False, action); 407 408 // Destroy SourceContextslkfgj 409 pSource->m_currentContext= 0; 410 // Destroy the XTransferable wrapper 411 pSource->m_spDataObject=0; 412 413 OleUninitialize(); 414 } 415 416 InterlockedDecrement(&pSource->m_RunningDndOperationCount); 417 418 // the DragSource was manually acquired by 419 // thread starting method DelayedStartDrag 420 pSource->release(); 421 422 return 0; 423 } 424 425 426 427 428