update dev300-m58
[ooovba.git] / dtrans / source / win32 / dnd / source.cxx
blob14d5f51754016d5ab2fb5dcf12b917b9b883ff0c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: source.cxx,v $
10 * $Revision: 1.23 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dtrans.hxx"
33 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
34 #include <com/sun/star/datatransfer/XTransferable.hpp>
35 #include <com/sun/star/awt/MouseButton.hpp>
36 #include <com/sun/star/awt/MouseEvent.hpp>
37 #include <rtl/unload.h>
39 #include <process.h>
40 #include <memory>
42 #include "source.hxx"
43 #include "globals.hxx"
44 #include "sourcecontext.hxx"
45 #include "../../inc/DtObjFactory.hxx"
46 #include <rtl/ustring.h>
47 #include <process.h>
48 #include <winuser.h>
49 #include <stdio.h>
51 #ifdef __MINGW32__
52 #define __uuidof(I) IID_##I
53 #endif
55 using namespace rtl;
56 using namespace cppu;
57 using namespace osl;
58 using namespace com::sun::star::datatransfer;
59 using namespace com::sun::star::datatransfer::dnd;
60 using namespace com::sun::star::datatransfer::dnd::DNDConstants;
61 using namespace com::sun::star::uno;
62 using namespace com::sun::star::awt::MouseButton;
63 using namespace com::sun::star::awt;
64 using namespace com::sun::star::lang;
66 extern rtl_StandardModuleCount g_moduleCount;
68 //--> TRA
70 extern Reference< XTransferable > g_XTransferable;
72 //<-- TRA
74 unsigned __stdcall DndOleSTAFunc(LPVOID pParams);
76 //----------------------------------------------------
77 /** Ctor
79 DragSource::DragSource( const Reference<XMultiServiceFactory>& sf):
80 m_serviceFactory( sf),
81 WeakComponentImplHelper3< XDragSource, XInitialization, XServiceInfo >(m_mutex),
82 // m_pcurrentContext_impl(0),
83 m_hAppWindow(0),
84 m_MouseButton(0),
85 m_RunningDndOperationCount(0)
87 g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
90 //----------------------------------------------------
91 /** Dtor
93 DragSource::~DragSource()
95 g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
98 //----------------------------------------------------
99 /** First start a new drag and drop thread if
100 the last one has finished
102 ????
103 Do we really need a separate thread for
104 every Dnd opeartion or only if the source
105 thread is an MTA thread
106 ????
108 void DragSource::StartDragImpl(
109 const DragGestureEvent& trigger,
110 sal_Int8 sourceActions,
111 sal_Int32 /*cursor*/,
112 sal_Int32 /*image*/,
113 const Reference<XTransferable >& trans,
114 const Reference<XDragSourceListener >& listener )
116 // The actions supported by the drag source
117 m_sourceActions= sourceActions;
118 // We need to know which mouse button triggered the operation.
119 // If it was the left one, then the drop occurs when that button
120 // has been released and if it was the right one then the drop
121 // occurs when the right button has been released. If the event is not
122 // set then we assume that the left button is pressed.
123 MouseEvent evtMouse;
124 trigger.Event >>= evtMouse;
125 m_MouseButton= evtMouse.Buttons;
127 // The SourceContext class administers the XDragSourceListener s and
128 // fires events to them. An instance only exists in the scope of this
129 // functions. However, the drag and drop operation causes callbacks
130 // to the IDropSource interface implemented in this class (but only
131 // while this function executes). The source context is also used
132 // in DragSource::QueryContinueDrag.
133 m_currentContext= static_cast<XDragSourceContext*>( new SourceContext(
134 static_cast<DragSource*>(this), listener ) );
136 // Convert the XTransferable data object into an IDataObject object;
138 //--> TRA
139 g_XTransferable = trans;
140 //<-- TRA
142 m_spDataObject= m_aDataConverter.createDataObjFromTransferable(
143 m_serviceFactory, trans);
145 // Obtain the id of the thread that created the window
146 DWORD processId;
147 m_threadIdWindow= GetWindowThreadProcessId( m_hAppWindow, &processId);
149 // hold the instance for the DnD thread, it's to late
150 // to acquire at the start of the thread procedure
151 // the thread procedure is responsible for the release
152 acquire();
154 // The thread acccesses members of this instance but does not call acquire.
155 // Hopefully this instance is not destroyed before the thread has terminated.
156 unsigned threadId;
157 HANDLE hThread= reinterpret_cast<HANDLE>(_beginthreadex(
158 0, 0, DndOleSTAFunc, reinterpret_cast<void*>(this), 0, &threadId));
160 // detach from thread
161 CloseHandle(hThread);
164 // XInitialization
166 //----------------------------------------------------
167 /** aArguments contains a machine id
169 void SAL_CALL DragSource::initialize( const Sequence< Any >& aArguments )
170 throw(Exception, RuntimeException)
172 if( aArguments.getLength() >=2)
173 m_hAppWindow= *(HWND*)aArguments[1].getValue();
174 OSL_ASSERT( IsWindow( m_hAppWindow) );
177 //----------------------------------------------------
178 /** XDragSource
180 sal_Bool SAL_CALL DragSource::isDragImageSupported( )
181 throw(RuntimeException)
183 return 0;
186 //----------------------------------------------------
189 sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
190 throw( IllegalArgumentException, RuntimeException)
192 return 0;
195 //----------------------------------------------------
196 /** Notifies the XDragSourceListener by
197 calling dragDropEnd
199 void SAL_CALL DragSource::startDrag(
200 const DragGestureEvent& trigger,
201 sal_Int8 sourceActions,
202 sal_Int32 cursor,
203 sal_Int32 image,
204 const Reference<XTransferable >& trans,
205 const Reference<XDragSourceListener >& listener ) throw( RuntimeException)
207 // Allow only one running dnd operation at a time,
208 // see XDragSource documentation
210 long cnt = InterlockedIncrement(&m_RunningDndOperationCount);
212 if (1 == cnt)
214 StartDragImpl(trigger, sourceActions, cursor, image, trans, listener);
216 else
218 //OSL_ENSURE(false, "Overlapping Drag&Drop operation rejected!");
220 cnt = InterlockedDecrement(&m_RunningDndOperationCount);
222 DragSourceDropEvent dsde;
224 dsde.DropAction = ACTION_NONE;
225 dsde.DropSuccess = false;
229 listener->dragDropEnd(dsde);
231 catch(RuntimeException&)
233 OSL_ENSURE(false, "Runtime exception during event dispatching");
238 //----------------------------------------------------
239 /**IDropTarget
241 HRESULT STDMETHODCALLTYPE DragSource::QueryInterface( REFIID riid, void **ppvObject)
243 if( !ppvObject)
244 return E_POINTER;
245 *ppvObject= NULL;
247 if( riid == __uuidof( IUnknown) )
248 *ppvObject= static_cast<IUnknown*>( this);
249 else if ( riid == __uuidof( IDropSource) )
250 *ppvObject= static_cast<IDropSource*>( this);
252 if(*ppvObject)
254 AddRef();
255 return S_OK;
257 else
258 return E_NOINTERFACE;
262 //----------------------------------------------------
265 ULONG STDMETHODCALLTYPE DragSource::AddRef( void)
267 acquire();
268 return (ULONG) m_refCount;
271 //----------------------------------------------------
274 ULONG STDMETHODCALLTYPE DragSource::Release( void)
276 ULONG ref= m_refCount;
277 release();
278 return --ref;
281 //----------------------------------------------------
282 /** IDropSource
284 HRESULT STDMETHODCALLTYPE DragSource::QueryContinueDrag(
285 /* [in] */ BOOL fEscapePressed,
286 /* [in] */ DWORD grfKeyState)
288 #if defined DBG_CONSOLE_OUT
289 printf("\nDragSource::QueryContinueDrag");
290 #endif
292 HRESULT retVal= S_OK; // default continue DnD
294 if (fEscapePressed)
296 retVal= DRAGDROP_S_CANCEL;
298 else
300 if( ( m_MouseButton == MouseButton::RIGHT && !(grfKeyState & MK_RBUTTON) ) ||
301 ( m_MouseButton == MouseButton::MIDDLE && !(grfKeyState & MK_MBUTTON) ) ||
302 ( m_MouseButton == MouseButton::LEFT && !(grfKeyState & MK_LBUTTON) ) ||
303 ( m_MouseButton == 0 && !(grfKeyState & MK_LBUTTON) ) )
305 retVal= DRAGDROP_S_DROP;
309 // fire dropActionChanged event.
310 // this is actually done by the context, which also detects whether the action
311 // changed at all
312 sal_Int8 dropAction= fEscapePressed ? ACTION_NONE :
313 dndOleKeysToAction( grfKeyState, m_sourceActions);
315 sal_Int8 userAction= fEscapePressed ? ACTION_NONE :
316 dndOleKeysToAction( grfKeyState, -1 );
318 static_cast<SourceContext*>(m_currentContext.get())->fire_dropActionChanged(
319 dropAction, userAction);
321 return retVal;
324 //----------------------------------------------------
327 HRESULT STDMETHODCALLTYPE DragSource::GiveFeedback(
328 /* [in] */ DWORD
329 #if defined DBG_CONSOLE_OUT
330 dwEffect
331 #endif
334 #if defined DBG_CONSOLE_OUT
335 printf("\nDragSource::GiveFeedback %d", dwEffect);
336 #endif
338 return DRAGDROP_S_USEDEFAULTCURSORS;
341 // XServiceInfo
342 OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException)
344 return OUString(RTL_CONSTASCII_USTRINGPARAM(DNDSOURCE_IMPL_NAME));;
346 // XServiceInfo
347 sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException)
349 if( ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(DNDSOURCE_SERVICE_NAME ))))
350 return sal_True;
351 return sal_False;
354 Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames( ) throw (RuntimeException)
356 OUString names[1]= {OUString(RTL_CONSTASCII_USTRINGPARAM(DNDSOURCE_SERVICE_NAME))};
358 return Sequence<OUString>(names, 1);
361 //----------------------------------------------------
362 /**This function is called as extra thread from
363 DragSource::executeDrag. The function
364 carries out a drag and drop operation by calling
365 DoDragDrop. The thread also notifies all
366 XSourceListener.
368 unsigned __stdcall DndOleSTAFunc(LPVOID pParams)
370 // The structure contains all arguments for DoDragDrop and other
371 DragSource *pSource= (DragSource*)pParams;
373 // Drag and drop only works in a thread in which OleInitialize is called.
374 HRESULT hr= OleInitialize( NULL);
376 if(SUCCEEDED(hr))
378 // We force the creation of a thread message queue. This is necessary
379 // for a later call to AttachThreadInput
380 MSG msgtemp;
381 PeekMessage( &msgtemp, NULL, WM_USER, WM_USER, PM_NOREMOVE);
383 DWORD threadId= GetCurrentThreadId();
385 // This thread is attached to the thread that created the window. Hence
386 // this thread also receives all mouse and keyboard messages which are
387 // needed by DoDragDrop
388 AttachThreadInput( threadId , pSource->m_threadIdWindow, TRUE );
390 DWORD dwEffect= 0;
391 hr= DoDragDrop(
392 pSource->m_spDataObject.get(),
393 static_cast<IDropSource*>(pSource),
394 dndActionsToDropEffects( pSource->m_sourceActions),
395 &dwEffect);
397 // #105428 detach my message queue from the other threads
398 // message queue before calling fire_dragDropEnd else
399 // the office may appear to hang sometimes
400 AttachThreadInput( threadId, pSource->m_threadIdWindow, FALSE);
402 //--> TRA
403 // clear the global transferable again
404 g_XTransferable = Reference< XTransferable >( );
405 //<-- TRA
407 OSL_ENSURE( hr != E_INVALIDARG, "IDataObject impl does not contain valid data");
409 //Fire event
410 sal_Int8 action= hr == DRAGDROP_S_DROP ? dndOleDropEffectsToActions( dwEffect) : ACTION_NONE;
412 static_cast<SourceContext*>(pSource->m_currentContext.get())->fire_dragDropEnd(
413 hr == DRAGDROP_S_DROP ? sal_True : sal_False, action);
415 // Destroy SourceContextslkfgj
416 pSource->m_currentContext= 0;
417 // Destroy the XTransferable wrapper
418 pSource->m_spDataObject=0;
420 OleUninitialize();
423 InterlockedDecrement(&pSource->m_RunningDndOperationCount);
425 // the DragSource was manually acquired by
426 // thread starting method DelayedStartDrag
427 pSource->release();
429 return 0;