|
|
/***************************************************************************\
* * File: DragDrop.cpp * * Description: * DragDrop.cpp implements drag and drop operations * * * History: * 7/31/2000: JStall: Created * * Copyright (C) 2000 by Microsoft Corporation. All rights reserved. * \***************************************************************************/
#include "stdafx.h"
#include "Ctrl.h"
#include "OldDragDrop.h"
#include <SmObject.h>
static const GUID guidDropTarget = { 0x6a8bb3c8, 0xcbfc, 0x40d1, { 0x98, 0x1e, 0x3f, 0x8a, 0xaf, 0x99, 0x13, 0x7b } }; // {6A8BB3C8-CBFC-40d1-981E-3F8AAF99137B}
/***************************************************************************\
***************************************************************************** * * class OldTargetLock * ***************************************************************************** \***************************************************************************/
/***************************************************************************\
* * OldTargetLock::Lock * * Lock() prepares for executing inside the Context when being called back * from OLE's IDropTarget that was registered. * \***************************************************************************/
BOOL OldTargetLock::Lock( IN OldDropTarget * p, // OldDropTarget being used
OUT DWORD * pdwEffect, // Resulting DROPEFFECT if failure
IN BOOL fAddRef) // Lock DT during use
{ m_fAddRef = fAddRef; m_punk = static_cast<IUnknown *> (p);
if (m_fAddRef) { m_punk->AddRef(); }
if (p->m_hgadSubject == NULL) { if (pdwEffect != NULL) { *pdwEffect = DROPEFFECT_NONE; } return FALSE; }
return TRUE; }
/***************************************************************************\
***************************************************************************** * * class OldDropTarget * * NOTE: With the current design and implementation, OldDropTarget can not be * "removed" from an object until the object is destroyed. If this needs to * change, we need to revisit this. * ***************************************************************************** \***************************************************************************/
const IID * OldDropTarget::s_rgpIID[] = { &__uuidof(IUnknown), &__uuidof(IDropTarget), NULL };
PRID OldDropTarget::s_pridListen = 0;
//
// NOTE: We are calling back directly on the IDropTarget's, so we need to grab
// a read-only lock so that the tree doesn't get smashed.
//
/***************************************************************************\
* * OldDropTarget::~OldDropTarget * * ~OldDropTarget() cleans up resources used by the OldDropTarget. * \***************************************************************************/
OldDropTarget::~OldDropTarget() { OldTargetLock lt; lt.Lock(this, NULL, FALSE); xwDragLeave(); SafeRelease(m_pdoSrc);
OldExtension::Destroy(); }
/***************************************************************************\
* * OldDropTarget::Build * * Build() builds a new OldDropTarget instance. This should only be called for * a RootGadget that doesn't already have a DT. * \***************************************************************************/
HRESULT OldDropTarget::Build( IN HGADGET hgadRoot, // RootGadget
IN HWND hwnd, // Containing HWND
OUT OldDropTarget ** ppdt) // Newly created DT
{ AssertMsg(hgadRoot != NULL, "Must have a valid root");
//
// Setup a new OldDropTarget on this Gadget / HWND.
//
if (!GetComManager()->Init(ComManager::sOLE)) { return E_OUTOFMEMORY; }
SmObjectT<OldDropTarget, IDropTarget> * pdt = new SmObjectT<OldDropTarget, IDropTarget>; if (pdt == NULL) { return E_OUTOFMEMORY; } pdt->AddRef();
HRESULT hr = GetComManager()->RegisterDragDrop(hwnd, static_cast<IDropTarget *> (pdt)); if (FAILED(hr)) { pdt->Release(); return E_OUTOFMEMORY; } //CoLockObjectExternal(pdt, TRUE, FALSE);
hr = pdt->Create(hgadRoot, &guidDropTarget, &s_pridListen, OldExtension::oUseExisting); if ((hr == DU_S_ALREADYEXISTS) || FAILED(hr)) { GetComManager()->RevokeDragDrop(hwnd); pdt->Release(); return hr; }
pdt->m_hwnd = hwnd;
*ppdt = pdt; return S_OK; }
/***************************************************************************\
* * OldDropTarget::DragEnter * * DragEnter() is called by OLE when entering the DT. * \***************************************************************************/
STDMETHODIMP OldDropTarget::DragEnter( IN IDataObject * pdoSrc, // Source data
IN DWORD grfKeyState, // Keyboard modifiers
IN POINTL ptDesktopPxl, // Cursor location on desktop
OUT DWORD * pdwEffect) // Resulting DROPEFFECT
{ if (pdoSrc == NULL) { return E_INVALIDARG; }
OldTargetLock tl; if (!tl.Lock(this, pdwEffect)) { return S_OK; }
//
// Cache the DataObject.
//
SafeRelease(m_pdoSrc); if (pdoSrc != NULL) { pdoSrc->AddRef(); m_pdoSrc = pdoSrc; }
m_grfLastKeyState = grfKeyState;
POINT ptClientPxl; return xwDragScan(ptDesktopPxl, pdwEffect, &ptClientPxl); }
/***************************************************************************\
* * OldDropTarget::DragOver * * DragOver() is called by OLE during the drag operation to give feedback * while inside the DT. * \***************************************************************************/
STDMETHODIMP OldDropTarget::DragOver( IN DWORD grfKeyState, // Keyboard modifiers
IN POINTL ptDesktopPxl, // Cursor location on desktop
OUT DWORD * pdwEffect) // Resulting DROPEFFECT
{ OldTargetLock tl; if (!tl.Lock(this, pdwEffect)) { return S_OK; }
m_grfLastKeyState = grfKeyState;
POINT ptClientPxl; return xwDragScan(ptDesktopPxl, pdwEffect, &ptClientPxl); }
/***************************************************************************\
* * OldDropTarget::DragLeave * * DragLeave() is called by OLE when leaving the DT. * \***************************************************************************/
STDMETHODIMP OldDropTarget::DragLeave() { OldTargetLock tl; if (!tl.Lock(this, NULL)) { return S_OK; }
xwDragLeave(); SafeRelease(m_pdoSrc);
return S_OK; }
/***************************************************************************\
* * OldDropTarget::Drop * * Drop() is called by OLE when the user has dropped while inside DT. * \***************************************************************************/
STDMETHODIMP OldDropTarget::Drop( IN IDataObject * pdoSrc, // Source data
IN DWORD grfKeyState, // Keyboard modifiers
IN POINTL ptDesktopPxl, // Cursor location on desktop
OUT DWORD * pdwEffect) // Resulting DROPEFFECT
{ OldTargetLock tl; if (!tl.Lock(this, pdwEffect)) { return S_OK; }
if (!HasTarget()) { *pdwEffect = DROPEFFECT_NONE; return S_OK; }
m_grfLastKeyState = grfKeyState;
//
// Update to get the latest Gadget information.
//
POINT ptClientPxl; HRESULT hr = xwDragScan(ptDesktopPxl, pdwEffect, &ptClientPxl); if (FAILED(hr) || (*pdwEffect == DROPEFFECT_NONE)) { return hr; }
AssertMsg(HasTarget(), "Must have a target if UpdateTarget() succeeds");
//
// Now that the state has been updated, execute the actual drop.
//
POINTL ptDrop = { ptClientPxl.x, ptClientPxl.y }; m_pdtCur->Drop(pdoSrc, m_grfLastKeyState, ptDrop, pdwEffect);
xwDragLeave(); SafeRelease(m_pdoSrc);
return S_OK; }
/***************************************************************************\
* * OldDropTarget::xwDragScan * * xwDragScan() is called from the various IDropTarget methods to process * a request coming from outside. * \***************************************************************************/
HRESULT OldDropTarget::xwDragScan( IN POINTL ptDesktopPxl, // Cursor location on desktop
OUT DWORD * pdwEffect, // Resulting DROPEFFECT
OUT POINT * pptClientPxl) // Cursor location in client
{ POINT ptContainerPxl; RECT rcDesktopPxl;
GetClientRect(m_hwnd, &rcDesktopPxl); ClientToScreen(m_hwnd, (LPPOINT) &(rcDesktopPxl.left));
ptContainerPxl.x = ptDesktopPxl.x - rcDesktopPxl.left; ptContainerPxl.y = ptDesktopPxl.y - rcDesktopPxl.top;;
return xwUpdateTarget(ptContainerPxl, pdwEffect, pptClientPxl); }
/***************************************************************************\
* * OldDropTarget::xwUpdateTarget * * xwUpdateTarget() provides the "worker" of DropTarget, updating * Enter, Leave, and Over information for the Gadgets in the tree. * \***************************************************************************/
HRESULT OldDropTarget::xwUpdateTarget( IN POINT ptContainerPxl, // Cursor location in container
OUT DWORD * pdwEffect, // Resulting DROPEFFECT
OUT POINT * pptClientPxl) // Cursor location in client
{ AssertMsg(HasSource(), "Only call when have valid data source"); AssertWritePtr(pdwEffect); AssertWritePtr(pptClientPxl);
m_ptLastContainerPxl = ptContainerPxl;
//
// Determine the Gadget that is currently at the drop location. We use this
// as a starting point.
//
HGADGET hgadFound = FindGadgetFromPoint(m_hgadSubject, ptContainerPxl, GS_VISIBLE | GS_ENABLED, pptClientPxl); if (hgadFound == NULL) { *pdwEffect = DROPEFFECT_NONE; return S_OK; }
return xwUpdateTarget(hgadFound, pdwEffect, pptClientPxl); }
/***************************************************************************\
* * OldDropTarget::xwUpdateTarget * * xwUpdateTarget() provides the "worker" of DropTarget, updating * Enter, Leave, and Over information for the Gadgets in the tree. * \***************************************************************************/
HRESULT OldDropTarget::xwUpdateTarget( IN HGADGET hgadFound, // Gadget getting Drop
OUT DWORD * pdwEffect, // Resulting DROPEFFECT
IN POINT * pptClientPxl) // Cursor location in client
{ HRESULT hr = S_OK;
//
// Check if the drop Gadget has changed.
//
if ((hgadFound != NULL) && (hgadFound != m_hgadDrop)) { //
// Ask the new Gadget if he wants to participate in Drag & Drop.
//
GMSG_QUERYDROPTARGET msg; ZeroMemory(&msg, sizeof(msg)); msg.cbSize = sizeof(msg); msg.nMsg = GM_QUERY; msg.nCode = GQUERY_DROPTARGET; msg.hgadMsg = hgadFound;
static int s_cSend = 0; Trace("Send Query: %d to 0x%p\n", s_cSend++, hgadFound);
HRESULT hr = DUserSendEvent(&msg, SGM_FULL); if (IsHandled(hr)) { if ((msg.hgadDrop != NULL) && (msg.pdt != NULL)) { if (msg.hgadDrop != hgadFound) { //
// The message returned a different to handle the DnD request,
// so we need to re-adjust. We know that this Gadget is enabled
// and visible since it is in our parent chain and we are already
// enabled and visible.
//
#if DBG
BOOL fChain = FALSE; IsGadgetParentChainStyle(msg.hgadDrop, GS_VISIBLE | GS_ENABLED, &fChain, 0); if (!fChain) { Trace("WARNING: DUser: DropTarget: Parent chain for 0x%p is not fully visible and enabled.\n", msg.hgadDrop); } #endif
MapGadgetPoints(hgadFound, msg.hgadDrop, pptClientPxl, 1); } } } else { msg.hgadDrop = NULL; msg.pdt = NULL; }
//
// Notify the old Gadget that the Drag operation has left him.
// Update to new state
// Notify the new Gadget that the Drag operation has entered him.
//
if (m_hgadDrop != msg.hgadDrop) { xwDragLeave();
m_hgadDrop = msg.hgadDrop; m_pdtCur = msg.pdt;
hr = xwDragEnter(pptClientPxl, pdwEffect); if (FAILED(hr) || (*pdwEffect == DROPEFFECT_NONE)) { goto Exit; } } else { SafeRelease(msg.pdt); *pdwEffect = DROPEFFECT_NONE; } }
//
// Update the DropTarget
//
if (HasTarget()) { POINTL ptDrop = { pptClientPxl->x, pptClientPxl->y }; hr = m_pdtCur->DragOver(m_grfLastKeyState, ptDrop, pdwEffect); }
Exit: AssertMsg(FAILED(hr) || ((*pdwEffect == DROPEFFECT_NONE) && !HasTarget()) || HasTarget(), "Check valid return state");
return hr; }
/***************************************************************************\
* * OldDropTarget::xwDragEnter * * xwDragEnter() is called when entering a new Gadget during a DnD operation. * \***************************************************************************/
HRESULT OldDropTarget::xwDragEnter( IN OUT POINT * pptClientPxl, // Client location (updated)
OUT DWORD * pdwEffect) // Resulting DROPEFFECT
{ AssertMsg(HasSource(), "Only call when have valid data source");
//
// Notify the new Gadget that the drop has entered him.
//
if (HasTarget()) { POINTL ptDrop = { pptClientPxl->x, pptClientPxl->y }; HRESULT hr = m_pdtCur->DragEnter(m_pdoSrc, m_grfLastKeyState, ptDrop, pdwEffect); if (FAILED(hr)) { return hr; } } else { *pdwEffect = DROPEFFECT_NONE; }
return S_OK; }
/***************************************************************************\
* * OldDropTarget::xwDragLeave * * xwDragLeave() is called when leaving a Gadget during a DnD operation. * \***************************************************************************/
void OldDropTarget::xwDragLeave() { if (HasTarget()) { m_pdtCur->DragLeave(); m_pdtCur->Release(); m_pdtCur = NULL;
m_hgadDrop = NULL; } }
//------------------------------------------------------------------------------
void OldDropTarget::OnDestroyListener() { Release(); }
//------------------------------------------------------------------------------
void OldDropTarget::OnDestroySubject() { if (IsWindow(m_hwnd)) { GetComManager()->RevokeDragDrop(m_hwnd); }
//CoLockObjectExternal(pdt, FALSE, TRUE);
OldExtension::DeleteHandle(); }
|