PageRenderTime 31ms CodeModel.GetById 1ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llwindow/lldragdropwin32.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 365 lines | 257 code | 46 blank | 62 comment | 31 complexity | 4c63a23075d78f255d698ca8afb10fb7 MD5 | raw file
  1/**
  2 * @file lldragdrop32.cpp
  3 * @brief Handler for Windows specific drag and drop (OS to client) code
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#if LL_WINDOWS
 28
 29#if LL_OS_DRAGDROP_ENABLED
 30
 31#include "linden_common.h"
 32
 33#include "llwindowwin32.h"
 34#include "llkeyboardwin32.h"
 35#include "llwindowcallbacks.h"
 36#include "lldragdropwin32.h"
 37
 38class LLDragDropWin32Target: 
 39	public IDropTarget
 40{
 41	public:
 42		////////////////////////////////////////////////////////////////////////////////
 43		//
 44		LLDragDropWin32Target( HWND  hWnd ) :
 45			mRefCount( 1 ),
 46			mAppWindowHandle( hWnd ),
 47			mAllowDrop(false),
 48			mIsSlurl(false)
 49		{
 50		};
 51
 52		virtual ~LLDragDropWin32Target()
 53		{
 54		};
 55
 56		////////////////////////////////////////////////////////////////////////////////
 57		//
 58		ULONG __stdcall AddRef( void )
 59		{
 60			return InterlockedIncrement( &mRefCount );
 61		};
 62
 63		////////////////////////////////////////////////////////////////////////////////
 64		//
 65		ULONG __stdcall Release( void )
 66		{
 67			LONG count = InterlockedDecrement( &mRefCount );
 68				
 69			if ( count == 0 )
 70			{
 71				delete this;
 72				return 0;
 73			}
 74			else
 75			{
 76				return count;
 77			};
 78		};
 79
 80		////////////////////////////////////////////////////////////////////////////////
 81		//
 82		HRESULT __stdcall QueryInterface( REFIID iid, void** ppvObject )
 83		{
 84			if ( iid == IID_IUnknown || iid == IID_IDropTarget )
 85			{
 86				AddRef();
 87				*ppvObject = this;
 88				return S_OK;
 89			}
 90			else
 91			{
 92				*ppvObject = 0;
 93				return E_NOINTERFACE;
 94			};
 95		};
 96
 97		////////////////////////////////////////////////////////////////////////////////
 98		//
 99		HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
100		{
101			FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
102
103			// support CF_TEXT using a HGLOBAL?
104			if ( S_OK == pDataObject->QueryGetData( &fmtetc ) )
105			{
106				mAllowDrop = true;
107				mDropUrl = std::string();
108				mIsSlurl = false;
109
110				STGMEDIUM stgmed;
111				if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) )
112				{
113					PVOID data = GlobalLock( stgmed.hGlobal );
114					mDropUrl = std::string( (char*)data );
115					// XXX MAJOR MAJOR HACK!
116					LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA);
117					if (NULL != window_imp)
118					{
119						LLCoordGL gl_coord( 0, 0 );
120
121						POINT pt2;
122						pt2.x = pt.x;
123						pt2.y = pt.y;
124						ScreenToClient( mAppWindowHandle, &pt2 );
125
126						LLCoordWindow cursor_coord_window( pt2.x, pt2.y );
127						window_imp->convertCoords(cursor_coord_window, &gl_coord);
128						MASK mask = gKeyboard->currentMask(TRUE);
129
130						LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, 
131							LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl );
132
133						switch (result)
134						{
135						case LLWindowCallbacks::DND_COPY:
136							*pdwEffect = DROPEFFECT_COPY;
137							break;
138						case LLWindowCallbacks::DND_LINK:
139							*pdwEffect = DROPEFFECT_LINK;
140							break;
141						case LLWindowCallbacks::DND_MOVE:
142							*pdwEffect = DROPEFFECT_MOVE;
143							break;
144						case LLWindowCallbacks::DND_NONE:
145						default:
146							*pdwEffect = DROPEFFECT_NONE;
147							break;
148						}
149					};
150
151					GlobalUnlock( stgmed.hGlobal );
152					ReleaseStgMedium( &stgmed );
153				};
154				SetFocus( mAppWindowHandle );
155			}
156			else
157			{
158				mAllowDrop = false;
159				*pdwEffect = DROPEFFECT_NONE;
160			};
161
162			return S_OK;
163		};
164
165		////////////////////////////////////////////////////////////////////////////////
166		//
167		HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
168		{
169			if ( mAllowDrop )
170			{
171				// XXX MAJOR MAJOR HACK!
172				LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA);
173				if (NULL != window_imp)
174				{
175					LLCoordGL gl_coord( 0, 0 );
176
177					POINT pt2;
178					pt2.x = pt.x;
179					pt2.y = pt.y;
180					ScreenToClient( mAppWindowHandle, &pt2 );
181
182					LLCoordWindow cursor_coord_window( pt2.x, pt2.y );
183					window_imp->convertCoords(cursor_coord_window, &gl_coord);
184					MASK mask = gKeyboard->currentMask(TRUE);
185
186					LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, 
187						LLWindowCallbacks::DNDA_TRACK, mDropUrl );
188					
189					switch (result)
190					{
191					case LLWindowCallbacks::DND_COPY:
192						*pdwEffect = DROPEFFECT_COPY;
193						break;
194					case LLWindowCallbacks::DND_LINK:
195						*pdwEffect = DROPEFFECT_LINK;
196						break;
197					case LLWindowCallbacks::DND_MOVE:
198						*pdwEffect = DROPEFFECT_MOVE;
199						break;
200					case LLWindowCallbacks::DND_NONE:
201					default:
202						*pdwEffect = DROPEFFECT_NONE;
203						break;
204					}
205				};
206			}
207			else
208			{
209				*pdwEffect = DROPEFFECT_NONE;
210			};
211
212			return S_OK;
213		};
214
215		////////////////////////////////////////////////////////////////////////////////
216		//
217		HRESULT __stdcall DragLeave( void )
218		{
219			// XXX MAJOR MAJOR HACK!
220			LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA);
221			if (NULL != window_imp)
222			{
223				LLCoordGL gl_coord( 0, 0 );
224				MASK mask = gKeyboard->currentMask(TRUE);
225				window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_STOP_TRACKING, mDropUrl );
226			};
227			return S_OK;
228		};
229
230		////////////////////////////////////////////////////////////////////////////////
231		//
232		HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
233		{
234			if ( mAllowDrop )
235			{
236				// window impl stored in Window data (neat!)
237				LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA );
238				if ( NULL != window_imp )
239				{
240					LLCoordGL gl_coord( 0, 0 );
241
242					POINT pt_client;
243					pt_client.x = pt.x;
244					pt_client.y = pt.y;
245					ScreenToClient( mAppWindowHandle, &pt_client );
246
247					LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y );
248					window_imp->convertCoords(cursor_coord_window, &gl_coord);
249					llinfos << "### (Drop) URL is: " << mDropUrl << llendl;
250					llinfos << "###        raw coords are: " << pt.x << " x " << pt.y << llendl;
251					llinfos << "###	    client coords are: " << pt_client.x << " x " << pt_client.y << llendl;
252					llinfos << "###         GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl;
253					llinfos << llendl;
254
255					// no keyboard modifier option yet but we could one day
256					MASK mask = gKeyboard->currentMask( TRUE );
257
258					// actually do the drop
259					LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, 
260						LLWindowCallbacks::DNDA_DROPPED, mDropUrl );
261
262					switch (result)
263					{
264					case LLWindowCallbacks::DND_COPY:
265						*pdwEffect = DROPEFFECT_COPY;
266						break;
267					case LLWindowCallbacks::DND_LINK:
268						*pdwEffect = DROPEFFECT_LINK;
269						break;
270					case LLWindowCallbacks::DND_MOVE:
271						*pdwEffect = DROPEFFECT_MOVE;
272						break;
273					case LLWindowCallbacks::DND_NONE:
274					default:
275						*pdwEffect = DROPEFFECT_NONE;
276						break;
277					}
278				};
279			}
280			else
281			{
282				*pdwEffect = DROPEFFECT_NONE;
283			};
284
285			return S_OK;
286		};
287
288	////////////////////////////////////////////////////////////////////////////////
289	//
290	private:
291		LONG mRefCount;
292		HWND mAppWindowHandle;
293		bool mAllowDrop;
294		std::string mDropUrl;
295		bool mIsSlurl;
296		friend class LLWindowWin32;
297};
298
299////////////////////////////////////////////////////////////////////////////////
300//
301LLDragDropWin32::LLDragDropWin32() :
302	mDropTarget( NULL ),
303	mDropWindowHandle( NULL )
304
305{
306}
307
308////////////////////////////////////////////////////////////////////////////////
309//
310LLDragDropWin32::~LLDragDropWin32()
311{
312}
313
314////////////////////////////////////////////////////////////////////////////////
315//
316bool LLDragDropWin32::init( HWND hWnd )
317{
318	if ( NOERROR != OleInitialize( NULL ) )
319		return FALSE; 
320
321	mDropTarget = new LLDragDropWin32Target( hWnd );
322	if ( mDropTarget )
323	{
324		HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE );
325		if ( S_OK == result )
326		{
327			result = RegisterDragDrop( hWnd, mDropTarget );
328			if ( S_OK != result )
329			{
330				// RegisterDragDrop failed
331				return false;
332			};
333
334			// all ok
335			mDropWindowHandle = hWnd;
336		}
337		else
338		{
339			// Unable to lock OLE object
340			return false;
341		};
342	};
343
344	// success
345	return true;
346}
347
348////////////////////////////////////////////////////////////////////////////////
349//
350void LLDragDropWin32::reset()
351{
352	if ( mDropTarget )
353	{
354		RevokeDragDrop( mDropWindowHandle );
355		CoLockObjectExternal( mDropTarget, FALSE, TRUE );
356		mDropTarget->Release();  
357	};
358	
359	OleUninitialize();
360}
361
362#endif // LL_OS_DRAGDROP_ENABLED
363
364#endif // LL_WINDOWS
365