From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/clist/clcfiledrop.cpp | 278 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/modules/clist/clcfiledrop.cpp (limited to 'src/modules/clist/clcfiledrop.cpp') diff --git a/src/modules/clist/clcfiledrop.cpp b/src/modules/clist/clcfiledrop.cpp new file mode 100644 index 0000000000..aae299d7b8 --- /dev/null +++ b/src/modules/clist/clcfiledrop.cpp @@ -0,0 +1,278 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "commonheaders.h" +#include "clc.h" +#include + +struct CDropTarget : IDropTarget +{ + LONG refCount; + IDropTargetHelper *pDropTargetHelper; + + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject); + + HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT STDMETHODCALLTYPE DragLeave(void); + HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); +} +static dropTarget; + +static HWND hwndCurrentDrag = NULL; +static int originalSelection; + +HRESULT CDropTarget::QueryInterface(REFIID riid, LPVOID * ppvObj) +{ + if (riid == IID_IDropTarget) { + *ppvObj = this; + AddRef(); + return S_OK; + } + *ppvObj = NULL; + return E_NOINTERFACE; +} + +ULONG CDropTarget::AddRef(void) +{ + return InterlockedIncrement(&refCount); +} + +ULONG CDropTarget::Release(void) +{ + if (refCount == 1) { + if (pDropTargetHelper) + pDropTargetHelper->Release(); + } + return InterlockedDecrement(&refCount); +} + +static HANDLE HContactFromPoint(HWND hwnd, struct ClcData *dat, int x, int y, int *hitLine) +{ + int hit; + struct ClcContact *contact; + DWORD hitFlags; + char *szProto; + DWORD protoCaps; + + hit = cli.pfnHitTest(hwnd, dat, x, y, &contact, NULL, &hitFlags); + if (hit == -1 || !(hitFlags & (CLCHT_ONITEMLABEL | CLCHT_ONITEMICON)) || contact->type != CLCIT_CONTACT) + return NULL; + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) contact->hContact, 0); + if (szProto == NULL) + return NULL; + protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); + if (!(protoCaps & PF1_FILESEND)) + return NULL; + if (ID_STATUS_OFFLINE == DBGetContactSettingWord(contact->hContact, szProto, "Status", ID_STATUS_OFFLINE)) + return NULL; + if (hitLine) + *hitLine = hit; + return contact->hContact; +} + +HRESULT CDropTarget::DragOver(DWORD /*grfKeyState*/, POINTL pt, DWORD * pdwEffect) +{ + POINT shortPt; + struct ClcData *dat; + RECT clRect; + int hit; + HANDLE hContact; + + if (pDropTargetHelper && hwndCurrentDrag) + pDropTargetHelper->DragOver((POINT*)&pt, *pdwEffect); + + *pdwEffect = 0; + if (hwndCurrentDrag == NULL) { + *pdwEffect = DROPEFFECT_NONE; + return S_OK; + } + CallService(MS_CLIST_PAUSEAUTOHIDE, 0, 0); + dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0); + shortPt.x = pt.x; + shortPt.y = pt.y; + ScreenToClient(hwndCurrentDrag, &shortPt); + GetClientRect(hwndCurrentDrag, &clRect); + + if (shortPt.y < dat->dragAutoScrollHeight || shortPt.y >= clRect.bottom - dat->dragAutoScrollHeight) { + *pdwEffect |= DROPEFFECT_SCROLL; + cli.pfnScrollTo(hwndCurrentDrag, dat, dat->yScroll + (shortPt.y < dat->dragAutoScrollHeight ? -1 : 1) * dat->rowHeight * 2, 0); + } + hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, &hit); + if (hContact == NULL) { + hit = -1; + *pdwEffect |= DROPEFFECT_NONE; + } + else + *pdwEffect |= DROPEFFECT_COPY; + + if (dat->selection != hit) { + dat->selection = hit; + cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE); + if (pDropTargetHelper) pDropTargetHelper->Show(FALSE); + UpdateWindow(hwndCurrentDrag); + if (pDropTargetHelper) pDropTargetHelper->Show(TRUE); + } + + return S_OK; +} + +HRESULT CDropTarget::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +{ + HWND hwnd; + TCHAR szWindowClass[64]; + POINT shortPt; + + shortPt.x = pt.x; + shortPt.y = pt.y; + hwnd = WindowFromPoint(shortPt); + GetClassName(hwnd, szWindowClass, SIZEOF(szWindowClass)); + if (!lstrcmp(szWindowClass, CLISTCONTROL_CLASS)) { + struct ClcData *dat; + hwndCurrentDrag = hwnd; + dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0); + originalSelection = dat->selection; + dat->showSelAlways = 1; + } + if (pDropTargetHelper && hwndCurrentDrag) + pDropTargetHelper->DragEnter(hwndCurrentDrag, pDataObj, (POINT*)&pt, *pdwEffect); + return DragOver(grfKeyState, pt, pdwEffect); +} + +HRESULT CDropTarget::DragLeave(void) +{ + if (hwndCurrentDrag) { + struct ClcData *dat; + if (pDropTargetHelper) + pDropTargetHelper->DragLeave(); + dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0); + dat->showSelAlways = 0; + dat->selection = originalSelection; + cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE); + } + hwndCurrentDrag = NULL; + return S_OK; +} + +static void AddToFileList(TCHAR ***pppFiles, int *totalCount, const TCHAR *szFilename) +{ + *pppFiles = (TCHAR **) mir_realloc(*pppFiles, (++*totalCount + 1) * sizeof(TCHAR *)); + (*pppFiles)[*totalCount] = NULL; + (*pppFiles)[*totalCount - 1] = mir_tstrdup(szFilename); + if (GetFileAttributes(szFilename) & FILE_ATTRIBUTE_DIRECTORY) { + WIN32_FIND_DATA fd; + HANDLE hFind; + TCHAR szPath[MAX_PATH]; + lstrcpy(szPath, szFilename); + lstrcat(szPath, _T("\\*")); + if (hFind = FindFirstFile(szPath, &fd)) { + do { + if (!lstrcmp(fd.cFileName, _T(".")) || !lstrcmp(fd.cFileName, _T(".."))) + continue; + lstrcpy(szPath, szFilename); + lstrcat(szPath, _T("\\")); + lstrcat(szPath, fd.cFileName); + AddToFileList(pppFiles, totalCount, szPath); + } while (FindNextFile(hFind, &fd)); + FindClose(hFind); + } + } +} + +HRESULT CDropTarget::Drop(IDataObject * pDataObj, DWORD /*fKeyState*/, POINTL pt, DWORD * pdwEffect) +{ + FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg; + HDROP hDrop; + POINT shortPt; + struct ClcData *dat; + HANDLE hContact; + + if (pDropTargetHelper && hwndCurrentDrag) + pDropTargetHelper->Drop(pDataObj, (POINT*)&pt, *pdwEffect); + + *pdwEffect = DROPEFFECT_NONE; + if (hwndCurrentDrag == NULL || S_OK != pDataObj->GetData(&fe, &stg)) + return S_OK; + hDrop = (HDROP) stg.hGlobal; + dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0); + + shortPt.x = pt.x; + shortPt.y = pt.y; + ScreenToClient(hwndCurrentDrag, &shortPt); + hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, NULL); + if (hContact != NULL) { + TCHAR **ppFiles = NULL; + TCHAR szFilename[MAX_PATH]; + int fileCount, totalCount = 0, i; + + fileCount = DragQueryFile(hDrop, -1, NULL, 0); + ppFiles = NULL; + for (i = 0; i < fileCount; i++) { + DragQueryFile(hDrop, i, szFilename, SIZEOF(szFilename)); + AddToFileList(&ppFiles, &totalCount, szFilename); + } + + if (!CallService(MS_FILE_SENDSPECIFICFILEST, (WPARAM) hContact, (LPARAM) ppFiles)) + *pdwEffect = DROPEFFECT_COPY; + + for (i = 0; ppFiles[i]; i++) + mir_free(ppFiles[i]); + mir_free(ppFiles); + } + + if (stg.pUnkForRelease) + stg.pUnkForRelease->Release(); + else + GlobalFree(stg.hGlobal); + + DragLeave(); + return S_OK; +} + +static VOID CALLBACK CreateDropTargetHelperTimerProc(HWND hwnd, UINT, UINT_PTR idEvent, DWORD) +{ + KillTimer(hwnd, idEvent); + //This is a ludicrously slow function (~200ms) so we delay load it a bit. + if (S_OK != CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, + IID_IDropTargetHelper, (LPVOID*)&dropTarget.pDropTargetHelper)) + dropTarget.pDropTargetHelper = NULL; +} + +void InitFileDropping(void) +{ + // Disabled as this function loads tons of dlls for no apparenet reason + // we will se what the reaction will be +// SetTimer(NULL, 1, 1000, CreateDropTargetHelperTimerProc); +} + +void fnRegisterFileDropping(HWND hwnd) +{ + RegisterDragDrop(hwnd, (IDropTarget *) & dropTarget); +} + +void fnUnregisterFileDropping(HWND hwnd) +{ + RevokeDragDrop(hwnd); +} -- cgit v1.2.3