diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /dtrans/source/win32/dnd | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | dtrans/source/win32/dnd/dndentry.cxx | 88 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/globals.cxx | 130 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/globals.hxx | 81 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/idroptarget.cxx | 96 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/idroptarget.hxx | 67 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/source.cxx | 365 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/source.hxx | 127 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/sourcecontext.cxx | 134 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/sourcecontext.hxx | 70 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/target.cxx | 628 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/target.hxx | 177 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/targetdragcontext.cxx | 43 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/targetdragcontext.hxx | 52 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/targetdropcontext.cxx | 53 | ||||
-rw-r--r-- | dtrans/source/win32/dnd/targetdropcontext.hxx | 54 |
15 files changed, 2165 insertions, 0 deletions
diff --git a/dtrans/source/win32/dnd/dndentry.cxx b/dtrans/source/win32/dnd/dndentry.cxx new file mode 100644 index 000000000..0a44283e5 --- /dev/null +++ b/dtrans/source/win32/dnd/dndentry.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppuhelper/factory.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include "source.hxx" +#include "target.hxx" + +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::registry ; +using namespace ::cppu ; +using namespace ::com::sun::star::lang; + +static Reference< XInterface > createDragSource( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + DragSource* pSource= new DragSource( comphelper::getComponentContext(rServiceManager) ); + return Reference<XInterface>( static_cast<XInitialization*>(pSource), UNO_QUERY); +} + +static Reference< XInterface > createDropTarget( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + DropTarget* pTarget= new DropTarget( comphelper::getComponentContext(rServiceManager) ); + return Reference<XInterface>( static_cast<XInitialization*>(pTarget), UNO_QUERY); +} + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void* +dnd_component_getFactory( const char* pImplName, void* pSrvManager, void* /*pRegistryKey*/ ) +{ + void* pRet = nullptr; + Reference< XSingleServiceFactory > xFactory; + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, DNDSOURCE_IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS { DNDSOURCE_SERVICE_NAME }; + + xFactory= createSingleFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createDragSource, + aSNS); + + } + else if( pSrvManager && ( 0 == rtl_str_compare( pImplName, DNDTARGET_IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS { DNDTARGET_SERVICE_NAME }; + + xFactory= createSingleFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createDropTarget, + aSNS); + + } + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/globals.cxx b/dtrans/source/win32/dnd/globals.cxx new file mode 100644 index 000000000..fcddef22e --- /dev/null +++ b/dtrans/source/win32/dnd/globals.cxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include "globals.hxx" + +//--> TRA +#include <com/sun/star/datatransfer/XTransferable.hpp> + +// used as shortcut when drag-source and drop-target are the same +css::uno::Reference< css::datatransfer::XTransferable > g_XTransferable; + +//<-- TRA + +using namespace com::sun::star::datatransfer::dnd::DNDConstants; + +sal_Int8 dndOleKeysToAction( DWORD grfKeyState, sal_Int8 nSourceActions) +{ + sal_Int8 ret= 0; + + // no MK_ALT, MK_CONTROL, MK_SHIFT + if( !(grfKeyState & MK_CONTROL) && + !(grfKeyState & MK_ALT) && + !(grfKeyState & MK_RBUTTON) && + !(grfKeyState & MK_SHIFT)) + { + if( nSourceActions & ACTION_MOVE ) + { + ret= ACTION_DEFAULT | ACTION_MOVE; + } + + else if( nSourceActions & ACTION_COPY ) + { + ret= ACTION_COPY; + } + + else if( nSourceActions & ACTION_LINK ) + { + ret= ACTION_LINK; + } + + else + ret = 0; + } + else if( grfKeyState & MK_SHIFT && + !(grfKeyState & MK_CONTROL)) + { + ret= ACTION_MOVE; + } + else if ( grfKeyState & MK_CONTROL && + !(grfKeyState & MK_SHIFT) ) + { + ret= ACTION_COPY; + } + else if ( grfKeyState & MK_CONTROL && + grfKeyState & MK_SHIFT) + { + ret= ACTION_LINK; + } + else if ( grfKeyState & MK_RBUTTON || + grfKeyState & MK_ALT) + { + ret= ACTION_COPY_OR_MOVE | ACTION_LINK; + } + return ret; +} + +sal_Int8 dndOleDropEffectsToActions( DWORD dwEffect) +{ + sal_Int8 ret= ACTION_NONE; + if( dwEffect & DROPEFFECT_COPY) + ret |= ACTION_COPY; + if( dwEffect & DROPEFFECT_MOVE) + ret |= ACTION_MOVE; + if( dwEffect & DROPEFFECT_LINK) + ret |= ACTION_LINK; + + return ret; +} + +DWORD dndActionsToDropEffects( sal_Int8 actions) +{ + DWORD ret= DROPEFFECT_NONE; + if( actions & ACTION_MOVE) + ret |= DROPEFFECT_MOVE; + if( actions & ACTION_COPY) + ret |= DROPEFFECT_COPY; + if( actions & ACTION_LINK) + ret |= DROPEFFECT_LINK; + if( actions & ACTION_DEFAULT) + ret |= DROPEFFECT_COPY; + return ret; +} + +DWORD dndActionsToSingleDropEffect( sal_Int8 actions) +{ + DWORD effects= dndActionsToDropEffects( actions); + + sal_Int8 countEffect= 0; + + if( effects & DROPEFFECT_MOVE) + countEffect++; + if( effects & DROPEFFECT_COPY) + countEffect++; + if( effects & DROPEFFECT_LINK) + countEffect++; + + // DROPEFFECT_MOVE is the default effect + DWORD retVal= countEffect > 1 ? DROPEFFECT_MOVE : effects; + return retVal; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/globals.hxx b/dtrans/source/win32/dnd/globals.hxx new file mode 100644 index 000000000..7851c2eec --- /dev/null +++ b/dtrans/source/win32/dnd/globals.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_GLOBALS_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_GLOBALS_HXX + +#include <sal/config.h> + +#include <com/sun/star/uno/Reference.hxx> +#include <osl/mutex.hxx> + +namespace com::sun::star::datatransfer { class XTransferable; } + +#include <wtypes.h> +#include <sal/types.h> + +#define DNDSOURCE_SERVICE_NAME "com.sun.star.datatransfer.dnd.OleDragSource" +#define DNDSOURCE_IMPL_NAME "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1" + +#define DNDTARGET_SERVICE_NAME "com.sun.star.datatransfer.dnd.OleDropTarget" +#define DNDTARGET_IMPL_NAME "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1" + +// This maps key states as occur as parameter, e.g. in IDropTarget::DragEnter, +// IDropSource::QueryContinueDrag, to actions as are declared in +// css::datatransfer::dnd::DNDConstants ( ACTION_MOVE etc). +// If the grfKeyState indicates the ALt or right mousebutton then the returned +// values combines all possible actions. This is because those keys and buttons are +// used when the user expect a menu to appear when he drops. The menu then +// contains entries, such as move, copy, link, cancel. +// An odd fact is that the argument grfKeyState in IDropTarget::Drop does not +// contain mouse buttons (winnt 4 SP6). That indicates that the right mouse button +// is not considered relevant in a drag operation. Contrarily the file explorer +// gives that button a special meaning: the user has to select the effect from +// a context menu on drop. +sal_Int8 dndOleKeysToAction( DWORD grfKeyState, sal_Int8 sourceActions); + +// The function maps a windows DROPEFFECTs to actions +// ( css::datatransfer::dnd::DNDConstants). +// The argument can be a combination of different DROPEFFECTS, +// In that case the return value is also a combination of the +// appropriate actions. +sal_Int8 dndOleDropEffectsToActions( DWORD dwEffect); + +// The function maps actions ( css::datatransfer::dnd::DNDConstants) +// to window DROPEFFECTs. +// The argument can be a combination of different actions +// In that case the return value is also a combination of the +// appropriate DROPEFFECTS. +DWORD dndActionsToDropEffects( sal_Int8 actions); + +// If the argument constitutes only one action then it is mapped to the +// corresponding DROPEFFECT otherwise DROPEFFECT_MOVE is returned. This is +// why move is the default effect (no modifiers pressed, or right mouse button +// or Alt). +DWORD dndActionsToSingleDropEffect( sal_Int8 actions); + +struct MutexDummy +{ + osl::Mutex m_mutex; +}; + +extern css::uno::Reference<css::datatransfer::XTransferable> g_XTransferable; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/idroptarget.cxx b/dtrans/source/win32/dnd/idroptarget.cxx new file mode 100644 index 000000000..8b403eb7a --- /dev/null +++ b/dtrans/source/win32/dnd/idroptarget.cxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "idroptarget.hxx" + +IDropTargetImpl::IDropTargetImpl( DropTarget& pTarget): m_nRefCount( 0), + m_rDropTarget( pTarget) +{ +} + +IDropTargetImpl::~IDropTargetImpl() +{ +} + +//IDropTarget +HRESULT STDMETHODCALLTYPE IDropTargetImpl::QueryInterface( REFIID riid, void **ppvObject) +{ + if( !ppvObject) + return E_POINTER; + *ppvObject= nullptr; + + if( riid == __uuidof( IUnknown)) + *ppvObject= static_cast<IUnknown*>( this); + else if ( riid == __uuidof( IDropTarget)) + *ppvObject= static_cast<IDropTarget*>( this); + + if(*ppvObject) + { + AddRef(); + return S_OK; + } + else + return E_NOINTERFACE; + +} + +ULONG STDMETHODCALLTYPE IDropTargetImpl::AddRef() +{ + return InterlockedIncrement( &m_nRefCount); +} + +ULONG STDMETHODCALLTYPE IDropTargetImpl::Release() +{ + LONG count= InterlockedDecrement( &m_nRefCount); + if( m_nRefCount == 0 ) + delete this; + return count; +} + +STDMETHODIMP IDropTargetImpl::DragEnter( IDataObject __RPC_FAR *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD *pdwEffect) +{ + return m_rDropTarget.DragEnter( pDataObj, grfKeyState, + pt, pdwEffect); +} + +STDMETHODIMP IDropTargetImpl::DragOver( DWORD grfKeyState, + POINTL pt, + DWORD *pdwEffect) +{ + return m_rDropTarget.DragOver( grfKeyState, pt, pdwEffect); +} + +STDMETHODIMP IDropTargetImpl::DragLeave() +{ + return m_rDropTarget.DragLeave(); +} + +STDMETHODIMP IDropTargetImpl::Drop( IDataObject *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + return m_rDropTarget.Drop( pDataObj, grfKeyState, + pt, pdwEffect); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/idroptarget.hxx b/dtrans/source/win32/dnd/idroptarget.hxx new file mode 100644 index 000000000..a86739f87 --- /dev/null +++ b/dtrans/source/win32/dnd/idroptarget.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_IDROPTARGET_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_IDROPTARGET_HXX + +#include "target.hxx" + +class IDropTargetImpl: public IDropTarget +{ + LONG m_nRefCount; + // Calls to IDropTarget functions are delegated to a DropTarget. + DropTarget& m_rDropTarget; + + virtual ~IDropTargetImpl(); // delete is only called by IUnknown::Release + IDropTargetImpl( const IDropTargetImpl& ); + IDropTargetImpl& operator=( const IDropTargetImpl& ); +public: + explicit IDropTargetImpl(DropTarget& rTarget); + + // IDropTarget + virtual HRESULT STDMETHODCALLTYPE QueryInterface( + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) override; + + virtual ULONG STDMETHODCALLTYPE AddRef( ) override; + + virtual ULONG STDMETHODCALLTYPE Release( ) override; + + virtual HRESULT STDMETHODCALLTYPE DragEnter( + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) override; + + virtual HRESULT STDMETHODCALLTYPE DragOver( + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) override; + + virtual HRESULT STDMETHODCALLTYPE DragLeave( ) override; + + virtual HRESULT STDMETHODCALLTYPE Drop( + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) override; + +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/source.cxx b/dtrans/source/win32/dnd/source.cxx new file mode 100644 index 000000000..c797684d2 --- /dev/null +++ b/dtrans/source/win32/dnd/source.cxx @@ -0,0 +1,365 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/awt/MouseEvent.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/any.hxx> + +#include <process.h> +#include <memory> + +#include "source.hxx" +#include "globals.hxx" +#include "sourcecontext.hxx" +#include "../../inc/DtObjFactory.hxx" +#include <rtl/ustring.h> +#include <osl/thread.h> +#include <winuser.h> +#include <stdio.h> + +using namespace cppu; +using namespace osl; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt::MouseButton; +using namespace com::sun::star::awt; +using namespace com::sun::star::lang; + +static unsigned __stdcall DndOleSTAFunc(LPVOID pParams); + +DragSource::DragSource( const Reference<XComponentContext>& rxContext): + WeakComponentImplHelper< XDragSource, XInitialization, XServiceInfo >(m_mutex), + m_xContext( rxContext ), +// m_pcurrentContext_impl(0), + m_hAppWindow(nullptr), + m_MouseButton(0), + m_RunningDndOperationCount(0) +{ +} + +DragSource::~DragSource() +{ +} + +/** First start a new drag and drop thread if + the last one has finished + + ???? + Do we really need a separate thread for + every Dnd operation or only if the source + thread is an MTA thread + ???? +*/ +void DragSource::StartDragImpl( + const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 /*cursor*/, + sal_Int32 /*image*/, + const Reference<XTransferable >& trans, + const Reference<XDragSourceListener >& listener ) +{ + // The actions supported by the drag source + m_sourceActions= sourceActions; + // We need to know which mouse button triggered the operation. + // If it was the left one, then the drop occurs when that button + // has been released and if it was the right one then the drop + // occurs when the right button has been released. If the event is not + // set then we assume that the left button is pressed. + MouseEvent evtMouse; + trigger.Event >>= evtMouse; + m_MouseButton= evtMouse.Buttons; + + // The SourceContext class administers the XDragSourceListener s and + // fires events to them. An instance only exists in the scope of this + // function. However, the drag and drop operation causes callbacks + // to the IDropSource interface implemented in this class (but only + // while this function executes). The source context is also used + // in DragSource::QueryContinueDrag. + m_currentContext = new SourceContext(this, listener); + + // Convert the XTransferable data object into an IDataObject object; + + //--> TRA + g_XTransferable = trans; + //<-- TRA + + m_spDataObject= CDTransObjFactory::createDataObjFromTransferable( + m_xContext, trans); + + // Obtain the id of the thread that created the window + DWORD processId; + m_threadIdWindow= GetWindowThreadProcessId( m_hAppWindow, &processId); + + // hold the instance for the DnD thread, it's too late + // to acquire at the start of the thread procedure + // the thread procedure is responsible for the release + acquire(); + + // The thread accesses members of this instance but does not call acquire. + // Hopefully this instance is not destroyed before the thread has terminated. + unsigned threadId; + HANDLE hThread= reinterpret_cast<HANDLE>(_beginthreadex( + nullptr, 0, DndOleSTAFunc, this, 0, &threadId)); + + // detach from thread + CloseHandle(hThread); +} + +// XInitialization +/** aArguments contains a machine id */ +void SAL_CALL DragSource::initialize( const Sequence< Any >& aArguments ) +{ + if( aArguments.getLength() >=2) + m_hAppWindow= reinterpret_cast<HWND>(static_cast<sal_uIntPtr>(*o3tl::doAccess<sal_uInt64>(aArguments[1]))); + OSL_ASSERT( IsWindow( m_hAppWindow) ); +} + +/** XDragSource */ +sal_Bool SAL_CALL DragSource::isDragImageSupported( ) +{ + return false; +} + +sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ ) +{ + return 0; +} + +/** Notifies the XDragSourceListener by + calling dragDropEnd */ +void SAL_CALL DragSource::startDrag( + const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const Reference<XTransferable >& trans, + const Reference<XDragSourceListener >& listener ) +{ + // Allow only one running dnd operation at a time, + // see XDragSource documentation + + long cnt = InterlockedIncrement(&m_RunningDndOperationCount); + + if (1 == cnt) + { + StartDragImpl(trigger, sourceActions, cursor, image, trans, listener); + } + else + { + cnt = InterlockedDecrement(&m_RunningDndOperationCount); + + DragSourceDropEvent dsde; + + dsde.DropAction = ACTION_NONE; + dsde.DropSuccess = false; + + try + { + listener->dragDropEnd(dsde); + } + catch(RuntimeException&) + { + OSL_FAIL("Runtime exception during event dispatching"); + } + } +} + +/** IDropTarget */ +HRESULT STDMETHODCALLTYPE DragSource::QueryInterface( REFIID riid, void **ppvObject) +{ + if( !ppvObject) + return E_POINTER; + *ppvObject= nullptr; + + if( riid == __uuidof( IUnknown) ) + *ppvObject= static_cast<IUnknown*>( this); + else if ( riid == __uuidof( IDropSource) ) + *ppvObject= static_cast<IDropSource*>( this); + + if(*ppvObject) + { + AddRef(); + return S_OK; + } + else + return E_NOINTERFACE; + +} + +ULONG STDMETHODCALLTYPE DragSource::AddRef() +{ + acquire(); + return static_cast<ULONG>(m_refCount); +} + +ULONG STDMETHODCALLTYPE DragSource::Release() +{ + ULONG ref= m_refCount; + release(); + return --ref; +} + +/** IDropSource */ +HRESULT STDMETHODCALLTYPE DragSource::QueryContinueDrag( +/* [in] */ BOOL fEscapePressed, +/* [in] */ DWORD grfKeyState) +{ +#if defined DBG_CONSOLE_OUT + printf("\nDragSource::QueryContinueDrag"); +#endif + + HRESULT retVal= S_OK; // default continue DnD + + if (fEscapePressed) + { + retVal= DRAGDROP_S_CANCEL; + } + else + { + if( ( m_MouseButton == MouseButton::RIGHT && !(grfKeyState & MK_RBUTTON) ) || + ( m_MouseButton == MouseButton::MIDDLE && !(grfKeyState & MK_MBUTTON) ) || + ( m_MouseButton == MouseButton::LEFT && !(grfKeyState & MK_LBUTTON) ) || + ( m_MouseButton == 0 && !(grfKeyState & MK_LBUTTON) ) ) + { + retVal= DRAGDROP_S_DROP; + } + } + + // fire dropActionChanged event. + // this is actually done by the context, which also detects whether the action + // changed at all + sal_Int8 dropAction= fEscapePressed ? ACTION_NONE : + dndOleKeysToAction( grfKeyState, m_sourceActions); + + sal_Int8 userAction= fEscapePressed ? ACTION_NONE : + dndOleKeysToAction( grfKeyState, -1 ); + + static_cast<SourceContext*>(m_currentContext.get())->fire_dropActionChanged( + dropAction, userAction); + + return retVal; +} + +HRESULT STDMETHODCALLTYPE DragSource::GiveFeedback( +/* [in] */ DWORD +#if defined DBG_CONSOLE_OUT +dwEffect +#endif +) +{ +#if defined DBG_CONSOLE_OUT + printf("\nDragSource::GiveFeedback %d", dwEffect); +#endif + + return DRAGDROP_S_USEDEFAULTCURSORS; +} + +// XServiceInfo +OUString SAL_CALL DragSource::getImplementationName( ) +{ + return DNDSOURCE_IMPL_NAME; +} +// XServiceInfo +sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames( ) +{ + return { DNDSOURCE_SERVICE_NAME }; +} + +/** This function is called as extra thread from + DragSource::executeDrag. The function + carries out a drag and drop operation by calling + DoDragDrop. The thread also notifies all + XSourceListener. */ +unsigned __stdcall DndOleSTAFunc(LPVOID pParams) +{ + osl_setThreadName("DragSource DndOleSTAFunc"); + + // The structure contains all arguments for DoDragDrop and other + DragSource *pSource= static_cast<DragSource*>(pParams); + + // Drag and drop only works in a thread in which OleInitialize is called. + HRESULT hr= OleInitialize( nullptr); + + if(SUCCEEDED(hr)) + { + // We force the creation of a thread message queue. This is necessary + // for a later call to AttachThreadInput + MSG msgtemp; + PeekMessageW( &msgtemp, nullptr, WM_USER, WM_USER, PM_NOREMOVE); + + DWORD threadId= GetCurrentThreadId(); + + // This thread is attached to the thread that created the window. Hence + // this thread also receives all mouse and keyboard messages which are + // needed by DoDragDrop + AttachThreadInput( threadId , pSource->m_threadIdWindow, TRUE ); + + DWORD dwEffect= 0; + hr= DoDragDrop( + pSource->m_spDataObject.get(), + static_cast<IDropSource*>(pSource), + dndActionsToDropEffects( pSource->m_sourceActions), + &dwEffect); + + // #105428 detach my message queue from the other threads + // message queue before calling fire_dragDropEnd else + // the office may appear to hang sometimes + AttachThreadInput( threadId, pSource->m_threadIdWindow, FALSE); + + //--> TRA + // clear the global transferable again + g_XTransferable.clear(); + //<-- TRA + + OSL_ENSURE( hr != E_INVALIDARG, "IDataObject impl does not contain valid data"); + + //Fire event + sal_Int8 action= hr == DRAGDROP_S_DROP ? dndOleDropEffectsToActions( dwEffect) : ACTION_NONE; + + static_cast<SourceContext*>(pSource->m_currentContext.get())->fire_dragDropEnd( + hr == DRAGDROP_S_DROP, action); + + // Destroy SourceContextslkfgj + pSource->m_currentContext= nullptr; + // Destroy the XTransferable wrapper + pSource->m_spDataObject=nullptr; + + OleUninitialize(); + } + + InterlockedDecrement(&pSource->m_RunningDndOperationCount); + + // the DragSource was manually acquired by + // thread starting method DelayedStartDrag + pSource->release(); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/source.hxx b/dtrans/source/win32/dnd/source.hxx new file mode 100644 index 000000000..8ec0162c3 --- /dev/null +++ b/dtrans/source/win32/dnd/source.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCE_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCE_HXX + +#include <com/sun/star/datatransfer/dnd/XDragSource.hpp> +#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <osl/mutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include "globals.hxx" +#include <oleidl.h> + +#include <systools/win32/comtools.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace cppu; +using namespace osl; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; + +class SourceContext; +// RIGHT MOUSE BUTTON drag and drop not supported currently. +// ALT modifier is considered to effect a user selection of effects +class DragSource: + public MutexDummy, + public WeakComponentImplHelper<XDragSource, XInitialization, XServiceInfo>, + public IDropSource + +{ + Reference<XComponentContext> m_xContext; + HWND m_hAppWindow; + + // The mouse button that set off the drag and drop operation + short m_MouseButton; + + // First starting a new drag and drop thread if + // the last one has finished + void StartDragImpl( + const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const Reference<XTransferable >& trans, + const Reference<XDragSourceListener >& listener); + +public: + long m_RunningDndOperationCount; + +public: + // only valid for one dnd operation + // the thread ID of the thread which created the window + DWORD m_threadIdWindow; + // The context notifies the XDragSourceListener s + Reference<XDragSourceContext> m_currentContext; + + // the wrapper for the Transferable ( startDrag) + IDataObjectPtr m_spDataObject; + + sal_Int8 m_sourceActions; + +public: + explicit DragSource(const Reference<XComponentContext>& rxContext); + virtual ~DragSource() override; + DragSource(const DragSource&) = delete; + DragSource &operator= ( const DragSource&) = delete; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported( ) override; + virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) override; + virtual void SAL_CALL startDrag( const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const Reference<XTransferable >& trans, + const Reference<XDragSourceListener >& listener ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + virtual HRESULT STDMETHODCALLTYPE QueryInterface( + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) override; + + virtual ULONG STDMETHODCALLTYPE AddRef( ) override; + + virtual ULONG STDMETHODCALLTYPE Release( ) override; + + // IDropSource + virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag( + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState) override; + + virtual HRESULT STDMETHODCALLTYPE GiveFeedback( + /* [in] */ DWORD dwEffect) override; + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/sourcecontext.cxx b/dtrans/source/win32/dnd/sourcecontext.cxx new file mode 100644 index 000000000..8531fd8a1 --- /dev/null +++ b/dtrans/source/win32/dnd/sourcecontext.cxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include "sourcecontext.hxx" + +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; + +SourceContext::SourceContext( DragSource* pSource, + const Reference<XDragSourceListener>& listener): + WeakComponentImplHelper<XDragSourceContext>(m_mutex), + m_pDragSource( pSource), + m_dragSource( static_cast<XDragSource*>( m_pDragSource) ) +{ +#if OSL_DEBUG_LEVEL > 1 + if( listener.is()) +#endif + rBHelper.addListener( cppu::UnoType<decltype(listener)>::get(), listener ); +} + +SourceContext::~SourceContext() +{ +} + +void SourceContext::addDragSourceListener( + const Reference<XDragSourceListener >& ) +{ +} + +void SourceContext::removeDragSourceListener( + const Reference<XDragSourceListener >& ) +{ +} + +sal_Int32 SAL_CALL SourceContext::getCurrentCursor( ) +{ + return 0; +} + +void SAL_CALL SourceContext::setCursor( sal_Int32 /*cursorId*/ ) +{ +} + +void SAL_CALL SourceContext::setImage( sal_Int32 /*imageId*/ ) +{ +} + +void SAL_CALL SourceContext::transferablesFlavorsChanged( ) +{ +} + +// non -interface functions +// Fires XDragSourceListener::dragDropEnd events. +void SourceContext::fire_dragDropEnd( bool success, sal_Int8 effect) +{ + + DragSourceDropEvent e; + + if( success ) + { + e.DropAction= effect; + e.DropSuccess= true; + } + else + { + e.DropAction= ACTION_NONE; + e.DropSuccess= false; + } + e.DragSource= m_dragSource; + e.DragSourceContext= static_cast<XDragSourceContext*>( this); + e.Source.set( static_cast<XDragSourceContext*>( this), UNO_QUERY); + + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( + cppu::UnoType<XDragSourceListener>::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDragSourceListener> listener( + static_cast<XDragSourceListener*>( iter.next())); + listener->dragDropEnd( e); + } + } +} + +void SourceContext::fire_dropActionChanged( sal_Int8 dropAction, sal_Int8 userAction) +{ + if( m_currentAction != dropAction) + { + m_currentAction= dropAction; + DragSourceDragEvent e; + e.DropAction= dropAction; + e.UserAction= userAction; + e.DragSource= m_dragSource; + e.DragSourceContext= static_cast<XDragSourceContext*>( this); + e.Source.set( static_cast<XDragSourceContext*>( this), UNO_QUERY); + + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( + cppu::UnoType<XDragSourceListener>::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDragSourceListener> listener( + static_cast<XDragSourceListener*>( iter.next())); + listener->dropActionChanged( e); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/sourcecontext.hxx b/dtrans/source/win32/dnd/sourcecontext.hxx new file mode 100644 index 000000000..81b1682eb --- /dev/null +++ b/dtrans/source/win32/dnd/sourcecontext.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCECONTEXT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCECONTEXT_HXX + +#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp> +#include <cppuhelper/compbase.hxx> + +#include "source.hxx" + +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// This class fires events to XDragSourceListener implementations. +// Of that interface only dragDropEnd and dropActionChanged are called. +// The functions dragEnter, dragExit and dragOver are not supported +// currently. +// An instance of SourceContext only lives as long as the drag and drop +// operation lasts. +class SourceContext: public MutexDummy, + public WeakComponentImplHelper<XDragSourceContext> +{ + DragSource* m_pDragSource; + Reference<XDragSource> m_dragSource; + // the action ( copy, move etc) + sal_Int8 m_currentAction; + +public: + SourceContext( DragSource* pSource, const Reference<XDragSourceListener>& listener); + ~SourceContext() override; + SourceContext(const SourceContext&) = delete; + SourceContext &operator= (const SourceContext&) = delete; + + /// @throws RuntimeException + virtual void addDragSourceListener( const Reference<XDragSourceListener >& dsl ); + /// @throws RuntimeException + virtual void removeDragSourceListener( const Reference<XDragSourceListener >& dsl ); + virtual sal_Int32 SAL_CALL getCurrentCursor( ) override; + virtual void SAL_CALL setCursor( sal_Int32 cursorId ) override; + virtual void SAL_CALL setImage( sal_Int32 imageId ) override; + virtual void SAL_CALL transferablesFlavorsChanged( ) override; + + // non - interface functions + void fire_dragDropEnd( bool success, sal_Int8 byte); + void fire_dropActionChanged( sal_Int8 dropAction, sal_Int8 userAction); + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/target.cxx b/dtrans/source/win32/dnd/target.cxx new file mode 100644 index 000000000..7592eb390 --- /dev/null +++ b/dtrans/source/win32/dnd/target.cxx @@ -0,0 +1,628 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/any.hxx> + +#include <stdio.h> +#include "target.hxx" +#include "idroptarget.hxx" +#include "globals.hxx" +#include "targetdropcontext.hxx" +#include "targetdragcontext.hxx" +#include <rtl/ustring.h> +#include <osl/thread.h> + +#include "../dtobj/DOTransferable.hxx" + +using namespace cppu; +using namespace osl; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; + +#define WM_REGISTERDRAGDROP WM_USER + 1 +#define WM_REVOKEDRAGDROP WM_USER + 2 + +DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams); + +DropTarget::DropTarget( const Reference<XComponentContext>& rxContext): + WeakComponentImplHelper<XInitialization,XDropTarget, XServiceInfo>(m_mutex), + m_hWnd( nullptr), + m_threadIdWindow(0), + m_threadIdTarget(0), + m_hOleThread(nullptr), + m_oleThreadId( 0), + m_pDropTarget( nullptr), + m_xContext( rxContext ), + m_bActive(true), + m_nDefaultActions(ACTION_COPY|ACTION_MOVE|ACTION_LINK|ACTION_DEFAULT), + m_nCurrentDropAction( ACTION_NONE), + m_nLastDropAction(0), + m_bDropComplete(false) +{ +} + +DropTarget::~DropTarget() +{ +} +// called from WeakComponentImplHelperX::dispose +// WeakComponentImplHelper calls disposing before it destroys +// itself. +// NOTE: RevokeDragDrop decrements the ref count on the IDropTarget +// interface. (m_pDropTarget) +// If the HWND is invalid then it doesn't decrement and +// the IDropTarget object will live on. MEMORY LEAK +void SAL_CALL DropTarget::disposing() +{ + if( m_threadIdTarget) + { + // Call RevokeDragDrop and wait for the OLE thread to die; + PostThreadMessageW( m_threadIdTarget, WM_REVOKEDRAGDROP, reinterpret_cast<WPARAM>(this), 0); + WaitForSingleObject( m_hOleThread, INFINITE); + CloseHandle( m_hOleThread); + //OSL_ENSURE( SUCCEEDED( hr), "HWND not valid!" ); + } + else + { + RevokeDragDrop( m_hWnd); + m_hWnd= nullptr; + } + if( m_pDropTarget) + { + CoLockObjectExternal( m_pDropTarget, FALSE, TRUE); + m_pDropTarget->Release(); + m_pDropTarget = nullptr; + } + + if( m_oleThreadId) + { + if( m_oleThreadId == CoGetCurrentProcess() ) + OleUninitialize(); + } + +} + +void SAL_CALL DropTarget::initialize( const Sequence< Any >& aArguments ) +{ + // The window must be registered for Dnd by RegisterDragDrop. We must ensure + // that RegisterDragDrop is called from an STA ( OleInitialize) thread. + // As long as the window is registered we need to receive OLE messages in + // an OLE thread. That is to say, if DropTarget::initialize was called from an + // MTA thread then we create an OLE thread in which the window is registered. + // The thread will stay alive until aver RevokeDragDrop has been called. + + // Additionally even if RegisterDragDrop is called from an STA thread we have + // to ensure that it is called from the same thread that created the Window + // otherwise messages sent during DND won't reach the windows message queue. + // Calling AttachThreadInput first would resolve this problem but would block + // the message queue of the calling thread. So if the current thread + // (even if it's an STA thread) and the thread that created the window are not + // identical we need to create a new thread as we do when the calling thread is + // an MTA thread. + + if( aArguments.getLength() > 0) + { + // Get the window handle from aArgument. It is needed for RegisterDragDrop. + m_hWnd= reinterpret_cast<HWND>(static_cast<sal_uIntPtr>(*o3tl::doAccess<sal_uInt64>(aArguments[0]))); + OSL_ASSERT( IsWindow( m_hWnd) ); + + // Obtain the id of the thread that created the window + m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, nullptr); + + HRESULT hr= OleInitialize( nullptr); + + // Current thread is MTA or Current thread and Window thread are not identical + if( hr == RPC_E_CHANGED_MODE || GetCurrentThreadId() != m_threadIdWindow ) + { + OSL_ENSURE( ! m_threadIdTarget,"initialize was called twice"); + // create the IDropTargetImplementation + m_pDropTarget= new IDropTargetImpl( *this ); + m_pDropTarget->AddRef(); + + // Obtain the id of the thread that created the window + m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, nullptr); + // The event is set by the thread that we will create momentarily. + // It indicates that the thread is ready to receive messages. + HANDLE m_evtThreadReady= CreateEventW( nullptr, FALSE, FALSE, nullptr); + + m_hOleThread= CreateThread( nullptr, 0, DndTargetOleSTAFunc, + &m_evtThreadReady, 0, &m_threadIdTarget); + WaitForSingleObject( m_evtThreadReady, INFINITE); + CloseHandle( m_evtThreadReady); + PostThreadMessageW( m_threadIdTarget, WM_REGISTERDRAGDROP, reinterpret_cast<WPARAM>(this), 0); + } + else if( hr == S_OK || hr == S_FALSE) + { + // current thread is STA + // If OleInitialize has been called by the caller then we must not call + // OleUninitialize + if( hr == S_OK) + { + // caller did not call OleInitialize, so we call OleUninitialize + // remember the thread that will call OleUninitialize + m_oleThreadId= CoGetCurrentProcess(); // get a unique thread id + } + + // Get the window handle from aArgument. It is needed for RegisterDragDrop. + // create the IDropTargetImplementation + m_pDropTarget= new IDropTargetImpl( *this ); + m_pDropTarget->AddRef(); + // CoLockObjectExternal is prescribed by the protocol. It bumps up the ref count + if( SUCCEEDED( CoLockObjectExternal( m_pDropTarget, TRUE, FALSE))) + { + if( FAILED( RegisterDragDrop( m_hWnd, m_pDropTarget) ) ) + { + // do clean up if drag and drop is not possible + CoLockObjectExternal( m_pDropTarget, FALSE, FALSE); + m_pDropTarget->Release(); + m_pDropTarget = nullptr; + m_hWnd= nullptr; + } + } + } + else + throw Exception("OleInitialize failed with " + OUString::number(hr), nullptr); + + } +} + +// This function is called as extra thread from DragSource::startDrag. +// The function carries out a drag and drop operation by calling +// DoDragDrop. The thread also notifies all XSourceListener. +DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams) +{ + osl_setThreadName("DropTarget DndTargetOleSTAFunc"); + + HRESULT hr= OleInitialize( nullptr); + if( SUCCEEDED( hr) ) + { + MSG msg; + // force the creation of a message queue + PeekMessageW( &msg, nullptr, 0, 0, PM_NOREMOVE); + // Signal the creator ( DropTarget::initialize) that the thread is + // ready to receive messages. + SetEvent( *static_cast<HANDLE*>(pParams)); + // Thread id is needed for attaching this message queue to the one of the + // thread where the window was created. + DWORD threadId= GetCurrentThreadId(); + // We force the creation of a thread message queue. This is necessary + // for a later call to AttachThreadInput + while( GetMessageW(&msg, nullptr, 0, 0) ) + { + if( msg.message == WM_REGISTERDRAGDROP) + { + DropTarget *pTarget= reinterpret_cast<DropTarget*>(msg.wParam); + // This thread is attached to the thread that created the window. Hence + // this thread also receives all mouse and keyboard messages which are + // needed + AttachThreadInput( threadId , pTarget->m_threadIdWindow, TRUE ); + + if( SUCCEEDED( CoLockObjectExternal(pTarget-> m_pDropTarget, TRUE, FALSE))) + { + if( FAILED( RegisterDragDrop( pTarget-> m_hWnd, pTarget-> m_pDropTarget) ) ) + { + // do clean up if drag and drop is not possible + CoLockObjectExternal( pTarget->m_pDropTarget, FALSE, FALSE); + pTarget->m_pDropTarget->Release(); + pTarget->m_pDropTarget = nullptr; + pTarget->m_hWnd= nullptr; + } + } + } + else if( msg.message == WM_REVOKEDRAGDROP) + { + DropTarget *pTarget= reinterpret_cast<DropTarget*>(msg.wParam); + RevokeDragDrop( pTarget-> m_hWnd); + // Detach this thread from the window thread + AttachThreadInput( threadId, pTarget->m_threadIdWindow, FALSE); + pTarget->m_hWnd= nullptr; + break; + } + TranslateMessage( &msg); + DispatchMessageW( &msg); + } + OleUninitialize(); + } + return 0; +} + +// XServiceInfo +OUString SAL_CALL DropTarget::getImplementationName( ) +{ + return DNDTARGET_IMPL_NAME; +} +// XServiceInfo +sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) +{ + return { DNDTARGET_SERVICE_NAME }; +} + +// XDropTarget +void SAL_CALL DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& dtl ) +{ + rBHelper.addListener( cppu::UnoType<decltype(dtl)>::get(), dtl ); +} + +void SAL_CALL DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& dtl ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(dtl)>::get(), dtl ); +} + +sal_Bool SAL_CALL DropTarget::isActive( ) +{ + return m_bActive; //m_bDropTargetRegistered; +} + +void SAL_CALL DropTarget::setActive( sal_Bool _b ) +{ + MutexGuard g(m_mutex); + m_bActive= _b; +} + +sal_Int8 SAL_CALL DropTarget::getDefaultActions( ) +{ + return m_nDefaultActions; +} + +void SAL_CALL DropTarget::setDefaultActions( sal_Int8 actions ) +{ + OSL_ENSURE( actions < 8, "No valid default actions"); + m_nDefaultActions= actions; +} + +HRESULT DropTarget::DragEnter( IDataObject *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD *pdwEffect) +{ +#if defined DBG_CONSOLE_OUT + printf("\nDropTarget::DragEnter state: %x effect %d", grfKeyState, *pdwEffect); +#endif + if( m_bActive ) + { + // Intersection of pdwEffect and the allowed actions ( setDefaultActions) + m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect); + // m_nLastDropAction has to be set by a listener. If no listener calls + //XDropTargetDragContext::acceptDrag and specifies an action then pdwEffect + // will be DROPEFFECT_NONE throughout + m_nLastDropAction= ACTION_DEFAULT | ACTION_MOVE; + + m_currentDragContext = new TargetDragContext(this); + + //--> TRA + + // shortcut + if ( g_XTransferable.is( ) ) + m_currentData = g_XTransferable; + else + { + // Convert the IDataObject to a XTransferable + m_currentData= CDOTransferable::create( + m_xContext, IDataObjectPtr(pDataObj)); + } + + //<-- TRA + + if( m_nCurrentDropAction != ACTION_NONE) + { + DropTargetDragEnterEvent e; + e.SupportedDataFlavors= m_currentData->getTransferDataFlavors(); + e.DropAction= m_nCurrentDropAction; + e.Source.set( static_cast<XDropTarget*>(this),UNO_QUERY); + e.Context= m_currentDragContext; + POINT point={ pt.x, pt.y}; + ScreenToClient( m_hWnd, &point); + e.LocationX= point.x; + e.LocationY= point.y; + e.SourceActions= dndOleDropEffectsToActions( *pdwEffect); + + fire_dragEnter( e); + // Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set + // by the listener (m_nCurrentDropAction) is allowed by the source. Only an allowed action is set + // in pdwEffect. The listener notification is asynchron, that is we cannot expect that the listener + // has already reacted to the notification. + // If there is more than one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed + // then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed. + // On drop the target should present the user a dialog from which the user may change the action. + sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect); + *pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions); + } + else + { + *pdwEffect= DROPEFFECT_NONE; + } + } + return S_OK; +} + +HRESULT DropTarget::DragOver( DWORD grfKeyState, + POINTL pt, + DWORD *pdwEffect) +{ + if( m_bActive) + { + m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect); + + if( m_nCurrentDropAction) + { + DropTargetDragEvent e; + e.DropAction= m_nCurrentDropAction; + e.Source.set(static_cast<XDropTarget*>(this),UNO_QUERY); + e.Context= m_currentDragContext; + POINT point={ pt.x, pt.y}; + ScreenToClient( m_hWnd, &point); + e.LocationX= point.x; + e.LocationY= point.y; + e.SourceActions= dndOleDropEffectsToActions( *pdwEffect); + + // if grfKeyState has changed since the last DragOver then fire events. + // A listener might change m_nCurrentDropAction by calling the + // XDropTargetDragContext::acceptDrag function. But this is not important + // because in the afterwards fired dragOver event the action reflects + // grgKeyState again. + if( m_nLastDropAction != m_nCurrentDropAction) + fire_dropActionChanged( e); + + // The Event contains a XDropTargetDragContext implementation. + fire_dragOver( e); + // Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set + // by the listener (m_nCurrentDropAction) is allowed by the source. Only an allowed action is set + // in pdwEffect. The listener notification is asynchron, that is we cannot expect that the listener + // has already reacted to the notification. + // If there is more than one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed + // then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed. + // On drop the target should present the user a dialog from which the user may change the action. + sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect); + // set the last action to the current if listener has not changed the value yet + *pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions); + } + else + { + *pdwEffect= DROPEFFECT_NONE; + } + } +#if defined DBG_CONSOLE_OUT + printf("\nDropTarget::DragOver %d", *pdwEffect ); +#endif + return S_OK; +} + +HRESULT DropTarget::DragLeave() +{ +#if defined DBG_CONSOLE_OUT + printf("\nDropTarget::DragLeave"); +#endif + if( m_bActive) + { + + m_currentData=nullptr; + m_currentDragContext= nullptr; + m_currentDropContext= nullptr; + m_nLastDropAction= 0; + + if( m_nDefaultActions != ACTION_NONE) + { + DropTargetEvent e; + e.Source= static_cast<XDropTarget*>(this); + + fire_dragExit( e); + } + } + return S_OK; +} + +HRESULT DropTarget::Drop( IDataObject * /*pDataObj*/, + DWORD grfKeyState, + POINTL pt, + DWORD *pdwEffect) +{ +#if defined DBG_CONSOLE_OUT + printf("\nDropTarget::Drop"); +#endif + if( m_bActive) + { + + m_bDropComplete= false; + + m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect); + m_currentDropContext = new TargetDropContext(this); + if( m_nCurrentDropAction) + { + DropTargetDropEvent e; + e.DropAction= m_nCurrentDropAction; + e.Source.set( static_cast<XDropTarget*>(this), UNO_QUERY); + e.Context= m_currentDropContext; + POINT point={ pt.x, pt.y}; + ScreenToClient( m_hWnd, &point); + e.LocationX= point.x; + e.LocationY= point.y; + e.SourceActions= dndOleDropEffectsToActions( *pdwEffect); + e.Transferable= m_currentData; + fire_drop( e); + + //if fire_drop returns than a listener might have modified m_nCurrentDropAction + if( m_bDropComplete ) + { + sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect); + *pdwEffect= dndActionsToSingleDropEffect( m_nCurrentDropAction & allowedActions); + } + else + *pdwEffect= DROPEFFECT_NONE; + } + else + *pdwEffect= DROPEFFECT_NONE; + + m_currentData= nullptr; + m_currentDragContext= nullptr; + m_currentDropContext= nullptr; + m_nLastDropAction= 0; + } + return S_OK; +} + +void DropTarget::fire_drop( const DropTargetDropEvent& dte) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + listener->drop( dte); + } + } +} + +void DropTarget::fire_dragEnter( const DropTargetDragEnterEvent& e ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + listener->dragEnter( e); + } + } +} + +void DropTarget::fire_dragExit( const DropTargetEvent& dte ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + listener->dragExit( dte); + } + } +} + +void DropTarget::fire_dragOver( const DropTargetDragEvent& dtde ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer ); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + listener->dragOver( dtde); + } + } +} + +void DropTarget::fire_dropActionChanged( const DropTargetDragEvent& dtde ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + listener->dropActionChanged( dtde); + } + } +} + +// Non - interface functions +// DropTarget fires events to XDropTargetListeners. The event object contains an +// XDropTargetDropContext implementation. When the listener calls on that interface +// then the calls are delegated from DropContext (XDropTargetDropContext) to these +// functions. +// Only one listener which visible area is affected is allowed to call on +// XDropTargetDropContext +// Returning sal_False would cause the XDropTargetDropContext or ..DragContext implementation +// to throw an InvalidDNDOperationException, meaning that a Drag is not currently performed. +// return sal_False results in throwing an InvalidDNDOperationException in the caller. + +void DropTarget::_acceptDrop(sal_Int8 dropOperation, const Reference<XDropTargetDropContext>& context) +{ + if( context == m_currentDropContext) + { + m_nCurrentDropAction= dropOperation; + } +} + +void DropTarget::_rejectDrop( const Reference<XDropTargetDropContext>& context) +{ + if( context == m_currentDropContext) + { + m_nCurrentDropAction= ACTION_NONE; + } +} + +void DropTarget::_dropComplete(bool success, const Reference<XDropTargetDropContext>& context) +{ + if(context == m_currentDropContext) + { + m_bDropComplete= success; + } +} + +// DropTarget fires events to XDropTargetListeners. The event object can contains an +// XDropTargetDragContext implementation. When the listener calls on that interface +// then the calls are delegated from DragContext (XDropTargetDragContext) to these +// functions. +// Only one listener which visible area is affected is allowed to call on +// XDropTargetDragContext +void DropTarget::_acceptDrag( sal_Int8 dragOperation, const Reference<XDropTargetDragContext>& context) +{ + if( context == m_currentDragContext) + { + m_nLastDropAction= dragOperation; + } +} + +void DropTarget::_rejectDrag( const Reference<XDropTargetDragContext>& context) +{ + if(context == m_currentDragContext) + { + m_nLastDropAction= ACTION_NONE; + } +} + +// This function determines the action dependent on the pressed +// key modifiers ( CTRL, SHIFT, ALT, Right Mouse Button). The result +// is then checked against the allowed actions which can be set through +// XDropTarget::setDefaultActions. Only those values which are also +// default actions are returned. If setDefaultActions has not been called +// beforehand the default actions comprise all possible actions. +// params: grfKeyState - the modifier keys and mouse buttons currently pressed +inline sal_Int8 DropTarget::getFilteredActions( DWORD grfKeyState, DWORD dwEffect) +{ + sal_Int8 actions= dndOleKeysToAction( grfKeyState, dndOleDropEffectsToActions( dwEffect)); + return actions & m_nDefaultActions; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/target.hxx b/dtrans/source/win32/dnd/target.hxx new file mode 100644 index 000000000..3f266b240 --- /dev/null +++ b/dtrans/source/win32/dnd/target.hxx @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGET_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGET_HXX + +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> +#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <osl/mutex.hxx> + +#include <oleidl.h> +#include "globals.hxx" + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace cppu; +using namespace osl; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; + +// The client +// has to call XComponent::dispose. The thread that calls initialize +// must also execute the destruction of the instance. This is because +// initialize calls OleInitialize and the destructor calls OleUninitialize. +// If the service calls OleInitialize then it also calls OleUnitialize when +// it is destroyed. Therefore no second instance may exist which was +// created in the same thread and still needs OLE. +class DropTarget: public MutexDummy, + public WeakComponentImplHelper< XInitialization, XDropTarget, XServiceInfo> + +{ +private: + friend DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams); + // The native window which acts as drop target. + // It is set in initialize. In case RegisterDragDrop fails it is set + // to NULL + HWND m_hWnd; // set by initialize + // Holds the thread id of the thread which created the window that is the + // drop target. Only used when DropTarget::initialize is called from an MTA + // thread + DWORD m_threadIdWindow; + // This is the thread id of the OLE thread that is created in DropTarget::initialize + // when the calling thread is an MTA + DWORD m_threadIdTarget; + // The handle of the thread that is created in DropTarget::initialize + // when the calling thread is an MTA + HANDLE m_hOleThread; + // The thread id of the thread which called initialize. When the service dies + // than m_oleThreadId is used to determine if the service successfully called + // OleInitialize. If so then OleUninitialize has to be called. + DWORD m_oleThreadId; + // An Instance of IDropTargetImpl which receives calls from the system's drag + // and drop implementation. It delegate the calls to name alike functions in + // this class. + IDropTarget* m_pDropTarget; + + Reference<XComponentContext> m_xContext; + // If m_bActive == sal_True then events are fired to XDropTargetListener s, + // none otherwise. The default value is sal_True. + bool m_bActive; + sal_Int8 m_nDefaultActions; + + // This value is set when a XDropTargetListener calls accept or reject on + // the XDropTargetDropContext or XDropTargetDragContext. + // The values are from the DNDConstants group. + sal_Int8 m_nCurrentDropAction; + // This value is manipulated by the XDropTargetListener + sal_Int8 m_nLastDropAction; + + Reference<XTransferable> m_currentData; + // The current action is used to determine if the USER + // action has changed (dropActionChanged) +// sal_Int8 m_userAction; + // Set by listeners when they call XDropTargetDropContext::dropComplete + bool m_bDropComplete; + Reference<XDropTargetDragContext> m_currentDragContext; + Reference<XDropTargetDropContext> m_currentDropContext; + +public: + explicit DropTarget(const Reference<XComponentContext>& rxContext); + virtual ~DropTarget() override; + DropTarget(DropTarget const &) = delete; + DropTarget &operator= (DropTarget const &) = delete; + + // Overrides WeakComponentImplHelper::disposing which is called by + // WeakComponentImplHelper::dispose + // Must be called. + virtual void SAL_CALL disposing() override; + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( const Reference< XDropTargetListener >& dtl ) override; + virtual void SAL_CALL removeDropTargetListener( const Reference< XDropTargetListener >& dtl ) override; + // Default is not active + virtual sal_Bool SAL_CALL isActive( ) override; + virtual void SAL_CALL setActive( sal_Bool isActive ) override; + virtual sal_Int8 SAL_CALL getDefaultActions( ) override; + virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // Functions called from the IDropTarget implementation ( m_pDropTarget) + virtual HRESULT DragEnter( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + virtual HRESULT STDMETHODCALLTYPE DragOver( + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + virtual HRESULT STDMETHODCALLTYPE DragLeave( ) ; + + virtual HRESULT STDMETHODCALLTYPE Drop( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + +// Non - interface functions -------------------------------------------------- +// XDropTargetDropContext delegated from DropContext + + void _acceptDrop( sal_Int8 dropOperation, const Reference<XDropTargetDropContext>& context); + void _rejectDrop( const Reference<XDropTargetDropContext>& context); + void _dropComplete( bool success, const Reference<XDropTargetDropContext>& context); + +// XDropTargetDragContext delegated from DragContext + void _acceptDrag( sal_Int8 dragOperation, const Reference<XDropTargetDragContext>& context); + void _rejectDrag( const Reference<XDropTargetDragContext>& context); + +protected: + // Gets the current action dependent on the pressed modifiers, the effects + // supported by the drop source (IDropSource) and the default actions of the + // drop target (XDropTarget, this class)) + inline sal_Int8 getFilteredActions( DWORD grfKeyState, DWORD sourceActions); + // Only filters with the default actions + inline sal_Int8 getFilteredActions( DWORD grfKeyState); + + void fire_drop( const DropTargetDropEvent& dte); + void fire_dragEnter( const DropTargetDragEnterEvent& dtde ); + void fire_dragExit( const DropTargetEvent& dte ); + void fire_dragOver( const DropTargetDragEvent& dtde ); + void fire_dropActionChanged( const DropTargetDragEvent& dtde ); + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdragcontext.cxx b/dtrans/source/win32/dnd/targetdragcontext.cxx new file mode 100644 index 000000000..4ffd16123 --- /dev/null +++ b/dtrans/source/win32/dnd/targetdragcontext.cxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "targetdragcontext.hxx" + +TargetDragContext::TargetDragContext( DropTarget* p) +{ + m_pDropTarget= p; + p->acquire(); +} + +TargetDragContext::~TargetDragContext() +{ + m_pDropTarget->release(); +} + +void SAL_CALL TargetDragContext::acceptDrag( sal_Int8 dragOperation ) +{ + m_pDropTarget->_acceptDrag( dragOperation, static_cast<XDropTargetDragContext*>( this) ); + +} +void SAL_CALL TargetDragContext::rejectDrag( ) +{ + m_pDropTarget->_rejectDrag( static_cast<XDropTargetDragContext*>( this) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdragcontext.hxx b/dtrans/source/win32/dnd/targetdragcontext.hxx new file mode 100644 index 000000000..a8f48cad1 --- /dev/null +++ b/dtrans/source/win32/dnd/targetdragcontext.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDRAGCONTEXT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDRAGCONTEXT_HXX + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp> +#include <com/sun/star/datatransfer/DataFlavor.hpp> + +#include "target.hxx" +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +class TargetDragContext: public WeakImplHelper<XDropTargetDragContext> +{ + // some calls to the functions of XDropTargetDragContext are delegated + // to non-interface functions of m_pDropTarget + DropTarget* m_pDropTarget; + +public: + explicit TargetDragContext(DropTarget* pTarget); + ~TargetDragContext() override; + TargetDragContext( const TargetDragContext&) = delete; + TargetDragContext &operator= ( const TargetDragContext&) = delete; + + virtual void SAL_CALL acceptDrag( sal_Int8 dragOperation ) override; + virtual void SAL_CALL rejectDrag( ) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdropcontext.cxx b/dtrans/source/win32/dnd/targetdropcontext.cxx new file mode 100644 index 000000000..9719664a9 --- /dev/null +++ b/dtrans/source/win32/dnd/targetdropcontext.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "targetdropcontext.hxx" + +using namespace ::com::sun::star::datatransfer::dnd; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +TargetDropContext::TargetDropContext( DropTarget* p) +{ + m_pDropTarget= p; + p->acquire(); +} + +TargetDropContext::~TargetDropContext() +{ + m_pDropTarget->release(); +} + +void SAL_CALL TargetDropContext::acceptDrop( sal_Int8 dropOperation ) +{ + m_pDropTarget->_acceptDrop( dropOperation, static_cast<XDropTargetDropContext*>( this) ); +} + +void SAL_CALL TargetDropContext::rejectDrop( ) +{ + m_pDropTarget->_rejectDrop( static_cast<XDropTargetDropContext*>( this) ); +} + +void SAL_CALL TargetDropContext::dropComplete( sal_Bool success ) +{ + m_pDropTarget->_dropComplete( success, static_cast<XDropTargetDropContext*>( this) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdropcontext.hxx b/dtrans/source/win32/dnd/targetdropcontext.hxx new file mode 100644 index 000000000..b7db849fe --- /dev/null +++ b/dtrans/source/win32/dnd/targetdropcontext.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDROPCONTEXT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDROPCONTEXT_HXX + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp> + +#include "target.hxx" + +using namespace ::com::sun::star::datatransfer::dnd; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +class TargetDropContext: public WeakImplHelper<XDropTargetDropContext> +{ + // calls to the functions of XDropTargetDropContext are delegated + // to non-interface functions of m_pDropTarget + DropTarget* m_pDropTarget; + +public: + explicit TargetDropContext(DropTarget* pTarget); + ~TargetDropContext() override; + TargetDropContext( const TargetDropContext&) = delete; + TargetDropContext &operator= ( const TargetDropContext&) = delete; + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrop( sal_Int8 dropOperation ) override; + virtual void SAL_CALL rejectDrop( ) override; + + // XDropTargetDropContext (inherits XDropTargetDragContext) + virtual void SAL_CALL dropComplete( sal_Bool success ) override; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |