HRESULT WinCE_DoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect) { MSG msg; POINT dest = {0,0}; POINT lastDraw = {-1,-1}; DWORD effect = DROPEFFECT_NONE; DWORD lastEffect = -1; IDropTarget * currentTarget = NULL; IWebViewPrivate * webView = NULL; IDataObject * dataObject = pDataObj; IDropSource * dropSource = pDropSource; HRESULT feedbackHR = DRAGDROP_S_USEDEFAULTCURSORS; HCURSOR startCursor = ::GetCursor(); HCURSOR noCursor = LoadCursor(NULL, IDC_NO); // If there is a change in the keyboard or mouse button state, DoDragDrop calls // IDropSource::QueryContinueDrag and determines whether to continue the drag, to // drop the data, or to cancel the operation based on the return value. BOOL escapePressed = FALSE; DWORD keyState = MK_LBUTTON; if (GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT) keyState |= MK_CONTROL; if (GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT) keyState |= MK_SHIFT; HRESULT result = dropSource->QueryContinueDrag(escapePressed, keyState); bool dragActive = (result == S_OK); POINTL screenPoint; while (dragActive && GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); // Filter all mouse and key events during the drag and drop: if (msg.message == WM_LBUTTONUP || msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONUP || msg.message == WM_RBUTTONDOWN || msg.message == WM_MOUSEMOVE || msg.message == WM_KEYDOWN || msg.message == WM_KEYUP || msg.message == WM_CHAR || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP || msg.message == WM_SYSCHAR) { if (msg.message == WM_MOUSEMOVE) { PERFORMANCE_START(WTF::PerformanceTrace::InputEvent,"DragDropManager: Mouse Move"); } else if (msg.message == WM_LBUTTONUP) { PERFORMANCE_START(WTF::PerformanceTrace::InputEvent,"DragDropManager: Mouse Up"); } else { PERFORMANCE_START(WTF::PerformanceTrace::InputEvent,"DragDropManager: Other Input"); } bool stateChanged = false; if (msg.message == WM_MOUSEMOVE || msg.message == WM_LBUTTONUP) { POINT pt = {GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)}; ::ClientToScreen(msg.hwnd, &pt); screenPoint.x = pt.x; screenPoint.y = pt.y; dest.x = pt.x - currentDragImage.ptOffset.x; dest.y = pt.y - currentDragImage.ptOffset.y; if (msg.message == WM_MOUSEMOVE) { // Which window is my mouse over? HWND mouseWnd = WindowFromPoint(dest); IDropTarget * newTarget = NULL; if (mouseWnd != NULL && dragMap) { DragWindowMap::iterator it = dragMap->find(mouseWnd); if (it != dragMap->end()) newTarget = it->second; } if (currentTarget && currentTarget != newTarget) { currentTarget->DragLeave(); feedbackHR = dropSource->GiveFeedback(DROPEFFECT_NONE); } if (newTarget) { effect = DROPEFFECT_NONE; //is this the correct way to set effect? if (pdwEffect) effect = *pdwEffect; if (currentTarget != newTarget) { newTarget->DragEnter(dataObject, keyState, screenPoint, &effect); feedbackHR = dropSource->GiveFeedback(effect); // Find out if the target is a webview now. if (webView) webView->Release(); newTarget->QueryInterface(IID_IWebViewPrivate, (void**) &webView); } else if (currentTarget) { currentTarget->DragOver(keyState, screenPoint, &effect); feedbackHR = dropSource->GiveFeedback(effect); } } if (webView) { dragImageVisible = true; dragAreaInvalid = true; } if (feedbackHR == DRAGDROP_S_USEDEFAULTCURSORS && effect != lastEffect) { switch (effect) { case DROPEFFECT_NONE: ::SetCursor(noCursor); break; /* MS doesn't give us these cursors!!! case DROPEFFECT_COPY: break; case DROPEFFECT_MOVE: break; case DROPEFFECT_LINK: break; */ default: ::SetCursor(startCursor); break; } lastEffect = effect; } currentTarget = newTarget; } else if (msg.message == WM_LBUTTONUP) { keyState = 0; stateChanged = true; } } else if (msg.message == WM_KEYDOWN) { if (msg.wParam == VK_ESCAPE) { escapePressed = TRUE; stateChanged = true; } } else if (msg.message == WM_KEYUP) { if (msg.wParam == VK_ESCAPE) { escapePressed = FALSE; stateChanged = true; } } if (stateChanged) { result = dropSource->QueryContinueDrag(escapePressed, keyState); if (result != S_OK) { dragImageVisible = false; dragAreaInvalid = true; if (currentTarget && effect && result == DRAGDROP_S_DROP) { effect = DROPEFFECT_NONE; //FIXME: should we reset effect or not? result = currentTarget->Drop(dataObject, keyState, screenPoint, &effect); if (SUCCEEDED(result)) { result = DRAGDROP_S_DROP; if (pdwEffect) *pdwEffect = effect; } } else { result = DRAGDROP_S_CANCEL; } dragActive = false; } } PERFORMANCE_END(WTF::PerformanceTrace::InputEvent); } else { DispatchMessage(&msg); } if (dragAreaInvalid && webView && dragImageCairo) { PERFORMANCE_START(WTF::PerformanceTrace::Paint, "DragDropManager::Paint"); HDC screenDC = ::GetDC(NULL); cairo_surface_t * screenSurface = cairo_win32_surface_create(screenDC); cairo_t *crScreen = cairo_create(screenSurface); HWND wnd; webView->viewWindow((OLE_HANDLE*) &wnd); RECT dirty; if (invalidDragRect.left != -1) { dirty = invalidDragRect; } else { POINT p = {0, 0}; ::ClientToScreen(wnd, &p); ::GetClientRect(wnd, &dirty); dirty.left += p.x; dirty.top += p.y; dirty.right += p.x; dirty.bottom += p.y; } if (dragImageVisible) { POINT * prevDraw = NULL; if (lastDraw.x != -1 && (lastDraw.x != dest.x || lastDraw.y != dest.y)) prevDraw = &lastDraw; drawDragImage(crScreen, dest, prevDraw, webView, wnd, true, &dirty); lastDraw = dest; invalidDragRect.left = -1; } else { // erase the drag image wherever we last put it: drawDragImage(crScreen, lastDraw, NULL, webView, wnd, false, &dirty); } cairo_destroy(crScreen); cairo_surface_destroy(screenSurface); ::ReleaseDC(NULL, screenDC); dragAreaInvalid = false; PERFORMANCE_END(WTF::PerformanceTrace::Paint); } } if (currentTarget && result != DRAGDROP_S_DROP) { currentTarget->DragLeave(); } ::SetCursor(startCursor); if (webView) webView->Release(); if (dragImageCairo) { cairo_surface_destroy(dragImageCairo); dragImageCairo = NULL; } return result; }
// @pymethod int|PyIDropTarget|DragOver|Called as the dragged object moves over the window // @rdesc Your implementation of this function should return a shellcon.DROPEFFECT_* value indicating if the // object can be accepted at the current position PyObject *PyIDropTarget::DragOver(PyObject *self, PyObject *args) { IDropTarget *pIDT = GetI(self); if ( pIDT == NULL ) return NULL; // @pyparm int|grfKeyState||Combination of win32con.MK_* flags containing keyboard modifier state POINTL pt; PyObject *obpt; // @pyparm (int, int)|pt||(x,y) Screen coordinates of cursor DWORD dwEffect; // @pyparm int|pdwEffect||shellcon.DROPEFFECT_* value DWORD grfKeyState; if ( !PyArg_ParseTuple(args, "lOl:DragOver", &grfKeyState, &obpt, &dwEffect) ) return NULL; BOOL bPythonIsHappy = TRUE; if (bPythonIsHappy && !PyObject_AsPOINTL( obpt, &pt )) bPythonIsHappy = FALSE; if (!bPythonIsHappy) return NULL; HRESULT hr; PY_INTERFACE_PRECALL; hr = pIDT->DragOver( grfKeyState, pt, &dwEffect ); PY_INTERFACE_POSTCALL; if ( FAILED(hr) ) return PyCom_BuildPyException(hr, pIDT, IID_IDropTarget ); return PyInt_FromLong(dwEffect); }