/** * @file lldragdrop32.cpp * @brief Handler for Windows specific drag and drop (OS to client) code * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #if LL_WINDOWS #if LL_OS_DRAGDROP_ENABLED #include "linden_common.h" #include "llwindowwin32.h" #include "llkeyboardwin32.h" #include "llwindowcallbacks.h" #include "lldragdropwin32.h" class LLDragDropWin32Target: public IDropTarget { public: //////////////////////////////////////////////////////////////////////////////// // LLDragDropWin32Target( HWND hWnd ) : mRefCount( 1 ), mAppWindowHandle( hWnd ), mAllowDrop( false) { }; virtual ~LLDragDropWin32Target() { }; //////////////////////////////////////////////////////////////////////////////// // ULONG __stdcall AddRef( void ) { return InterlockedIncrement( &mRefCount ); }; //////////////////////////////////////////////////////////////////////////////// // ULONG __stdcall Release( void ) { LONG count = InterlockedDecrement( &mRefCount ); if ( count == 0 ) { delete this; return 0; } else { return count; }; }; //////////////////////////////////////////////////////////////////////////////// // HRESULT __stdcall QueryInterface( REFIID iid, void** ppvObject ) { if ( iid == IID_IUnknown || iid == IID_IDropTarget ) { AddRef(); *ppvObject = this; return S_OK; } else { *ppvObject = 0; return E_NOINTERFACE; }; }; //////////////////////////////////////////////////////////////////////////////// // HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // support CF_TEXT using a HGLOBAL? if ( S_OK == pDataObject->QueryGetData( &fmtetc ) ) { mAllowDrop = true; mDropUrl = std::string(); mIsSlurl = false; STGMEDIUM stgmed; if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) ) { PVOID data = GlobalLock( stgmed.hGlobal ); mDropUrl = std::string( (char*)data ); // XXX MAJOR MAJOR HACK! LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); if (NULL != window_imp) { LLCoordGL gl_coord( 0, 0 ); POINT pt2; pt2.x = pt.x; pt2.y = pt.y; ScreenToClient( mAppWindowHandle, &pt2 ); LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); window_imp->convertCoords(cursor_coord_window, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl ); switch (result) { case LLWindowCallbacks::DND_COPY: *pdwEffect = DROPEFFECT_COPY; break; case LLWindowCallbacks::DND_LINK: *pdwEffect = DROPEFFECT_LINK; break; case LLWindowCallbacks::DND_MOVE: *pdwEffect = DROPEFFECT_MOVE; break; case LLWindowCallbacks::DND_NONE: default: *pdwEffect = DROPEFFECT_NONE; break; } }; GlobalUnlock( stgmed.hGlobal ); ReleaseStgMedium( &stgmed ); }; SetFocus( mAppWindowHandle ); } else { mAllowDrop = false; *pdwEffect = DROPEFFECT_NONE; }; return S_OK; }; //////////////////////////////////////////////////////////////////////////////// // HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { if ( mAllowDrop ) { // XXX MAJOR MAJOR HACK! LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); if (NULL != window_imp) { LLCoordGL gl_coord( 0, 0 ); POINT pt2; pt2.x = pt.x; pt2.y = pt.y; ScreenToClient( mAppWindowHandle, &pt2 ); LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); window_imp->convertCoords(cursor_coord_window, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_TRACK, mDropUrl ); switch (result) { case LLWindowCallbacks::DND_COPY: *pdwEffect = DROPEFFECT_COPY; break; case LLWindowCallbacks::DND_LINK: *pdwEffect = DROPEFFECT_LINK; break; case LLWindowCallbacks::DND_MOVE: *pdwEffect = DROPEFFECT_MOVE; break; case LLWindowCallbacks::DND_NONE: default: *pdwEffect = DROPEFFECT_NONE; break; } }; } else { *pdwEffect = DROPEFFECT_NONE; }; return S_OK; }; //////////////////////////////////////////////////////////////////////////////// // HRESULT __stdcall DragLeave( void ) { // XXX MAJOR MAJOR HACK! LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); if (NULL != window_imp) { LLCoordGL gl_coord( 0, 0 ); MASK mask = gKeyboard->currentMask(TRUE); window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_STOP_TRACKING, mDropUrl ); }; return S_OK; }; //////////////////////////////////////////////////////////////////////////////// // HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { if ( mAllowDrop ) { // window impl stored in Window data (neat!) LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA ); if ( NULL != window_imp ) { LLCoordGL gl_coord( 0, 0 ); POINT pt_client; pt_client.x = pt.x; pt_client.y = pt.y; ScreenToClient( mAppWindowHandle, &pt_client ); LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); window_imp->convertCoords(cursor_coord_window, &gl_coord); llinfos << "### (Drop) URL is: " << mDropUrl << llendl; llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl; llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; llinfos << llendl; // no keyboard modifier option yet but we could one day MASK mask = gKeyboard->currentMask( TRUE ); // actually do the drop LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_DROPPED, mDropUrl ); switch (result) { case LLWindowCallbacks::DND_COPY: *pdwEffect = DROPEFFECT_COPY; break; case LLWindowCallbacks::DND_LINK: *pdwEffect = DROPEFFECT_LINK; break; case LLWindowCallbacks::DND_MOVE: *pdwEffect = DROPEFFECT_MOVE; break; case LLWindowCallbacks::DND_NONE: default: *pdwEffect = DROPEFFECT_NONE; break; } }; } else { *pdwEffect = DROPEFFECT_NONE; }; return S_OK; }; //////////////////////////////////////////////////////////////////////////////// // private: LONG mRefCount; HWND mAppWindowHandle; bool mAllowDrop; std::string mDropUrl; bool mIsSlurl; friend class LLWindowWin32; }; //////////////////////////////////////////////////////////////////////////////// // LLDragDropWin32::LLDragDropWin32() : mDropTarget( NULL ), mDropWindowHandle( NULL ) { } //////////////////////////////////////////////////////////////////////////////// // LLDragDropWin32::~LLDragDropWin32() { } //////////////////////////////////////////////////////////////////////////////// // bool LLDragDropWin32::init( HWND hWnd ) { if ( NOERROR != OleInitialize( NULL ) ) return FALSE; mDropTarget = new LLDragDropWin32Target( hWnd ); if ( mDropTarget ) { HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE ); if ( S_OK == result ) { result = RegisterDragDrop( hWnd, mDropTarget ); if ( S_OK != result ) { // RegisterDragDrop failed return false; }; // all ok mDropWindowHandle = hWnd; } else { // Unable to lock OLE object return false; }; }; // success return true; } //////////////////////////////////////////////////////////////////////////////// // void LLDragDropWin32::reset() { if ( mDropTarget ) { RevokeDragDrop( mDropWindowHandle ); CoLockObjectExternal( mDropTarget, FALSE, TRUE ); mDropTarget->Release(); }; OleUninitialize(); } #endif // LL_OS_DRAGDROP_ENABLED #endif // LL_WINDOWS