Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

dragdrop.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: dragdrop.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Stuff for object-oriented direct manipulation, designed first for the shell. 00007 * 00008 * History: 00009 * 08-06-91 darrinm Ported from Win 3.1. 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 PCURSOR xxxQueryDropObject(PWND pwnd, LPDROPSTRUCT lpds); 00016 00017 /***************************************************************************\ 00018 * DragObject (API) 00019 * 00020 * Contains the main dragging loop. 00021 * 00022 * History: 00023 * 08-06-91 darrinm Ported from Win 3.1 sources. 00024 \***************************************************************************/ 00025 00026 DWORD xxxDragObject( 00027 PWND pwndParent, 00028 PWND pwndFrom, // NULL is valid 00029 UINT wFmt, 00030 ULONG_PTR dwData, 00031 PCURSOR pcur) 00032 { 00033 MSG msg, msgKey; 00034 DWORD result = 0; 00035 BOOL fDrag = TRUE; 00036 LPDROPSTRUCT lpds; 00037 PWND pwndDragging = NULL; 00038 PWND pwndTop; 00039 PCURSOR pcurOld, pcurT; 00040 PWND pwndT; 00041 TL tlpwndT; 00042 TL tlpwndTop; 00043 TL tlpwndDragging; 00044 TL tlPool; 00045 PTHREADINFO pti = PtiCurrent(); 00046 00047 CheckLock(pwndParent); 00048 CheckLock(pwndFrom); 00049 CheckLock(pcur); 00050 UserAssert(IsWinEventNotifyDeferredOK()); 00051 00052 lpds = (LPDROPSTRUCT)UserAllocPoolWithQuota(2 * sizeof(DROPSTRUCT), TAG_DRAGDROP); 00053 if (lpds == NULL) 00054 return 0; 00055 00056 ThreadLockPool(pti, lpds, &tlPool); 00057 lpds->hwndSource = HW(pwndFrom); 00058 lpds->wFmt = wFmt; 00059 lpds->dwData = dwData; 00060 00061 if (pcur != NULL) { 00062 /* 00063 * No need to DeferWinEventNotify() - pwndFrom is locked 00064 */ 00065 pcurOld = zzzSetCursor(pcur); 00066 } else { 00067 pcurOld = pti->pq->spcurCurrent; 00068 } 00069 00070 if (pwndFrom) { 00071 for (pwndTop = pwndFrom; TestwndChild(pwndTop); 00072 pwndTop = pwndTop->spwndParent) ; 00073 00074 ThreadLockWithPti(pti, pwndTop, &tlpwndTop); 00075 xxxUpdateWindow(pwndTop); 00076 ThreadUnlock(&tlpwndTop); 00077 } 00078 00079 if (FWINABLE()) { 00080 xxxWindowEvent(EVENT_SYSTEM_DRAGDROPSTART, pwndFrom, OBJID_WINDOW, INDEXID_CONTAINER, 0); 00081 } 00082 00083 xxxSetCapture(pwndFrom); 00084 zzzShowCursor(TRUE); 00085 00086 ThreadLockWithPti(pti, pwndDragging, &tlpwndDragging); 00087 00088 while (fDrag && pti->pq->spwndCapture == pwndFrom) { 00089 while (!(xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 00090 xxxPeekMessage(&msg, NULL, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE) || 00091 xxxPeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))) { 00092 if (!xxxSleepThread(QS_MOUSE | QS_KEY, 0, TRUE)) { 00093 ThreadUnlock(&tlpwndDragging); 00094 ThreadUnlockAndFreePool(pti, &tlPool); 00095 return 0; 00096 } 00097 } 00098 00099 /* 00100 * Be sure to eliminate any extra keydown messages that are 00101 * being queued up by MOUSE message processing. 00102 */ 00103 00104 while (xxxPeekMessage(&msgKey, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) 00105 ; 00106 00107 if ( (pti->pq->spwndCapture != pwndFrom) || 00108 (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) ) 00109 { 00110 if (pcurT = SYSCUR(NO)) 00111 zzzSetCursor(pcurT); 00112 break; 00113 } 00114 00115 RtlCopyMemory(lpds + 1, lpds, sizeof(DROPSTRUCT)); 00116 00117 /* 00118 * in screen coordinates 00119 */ 00120 lpds->ptDrop = msg.pt; 00121 00122 pcurT = xxxQueryDropObject(pwndParent, lpds); 00123 00124 /* 00125 * Returning FALSE to a WM_QUERYDROPOBJECT message means drops 00126 * aren't supported and the 'illegal drop target' cursor should be 00127 * displayed. Returning TRUE means the target is valid and the 00128 * regular drag cursor should be displayed. Also, through a bit 00129 * of polymorphic magic one can return a cursor handle to override 00130 * the normal drag cursor. 00131 */ 00132 if (pcurT == (PCURSOR)FALSE) { 00133 pcurT = SYSCUR(NO); 00134 lpds->hwndSink = NULL; 00135 } else if (pcurT == (PCURSOR)TRUE) { 00136 pcurT = pcur; 00137 } 00138 00139 if (pcurT != NULL) 00140 zzzSetCursor(pcurT); 00141 00142 /* 00143 * send the WM_DRAGLOOP after the above zzzSetCursor() to allow the 00144 * receiver to change the cursor at WM_DRAGLOOP time with a zzzSetCursor() 00145 */ 00146 if (pwndFrom) { 00147 xxxSendMessage(pwndFrom, WM_DRAGLOOP, (pcurT != SYSCUR(NO)), 00148 (LPARAM)lpds); 00149 } 00150 00151 /* 00152 * send these messages internally only 00153 */ 00154 if (pwndDragging != RevalidateHwnd(lpds->hwndSink)) { 00155 if (pwndDragging != NULL) { 00156 xxxSendMessage(pwndDragging, WM_DRAGSELECT, FALSE, 00157 (LPARAM)(lpds + 1)); 00158 } 00159 pwndDragging = RevalidateHwnd(lpds->hwndSink); 00160 ThreadUnlock(&tlpwndDragging); 00161 ThreadLockWithPti(pti, pwndDragging, &tlpwndDragging); 00162 00163 if (pwndDragging != NULL) { 00164 xxxSendMessage(pwndDragging, WM_DRAGSELECT, TRUE, (LPARAM)lpds); 00165 } 00166 } else { 00167 if (pwndDragging != NULL) { 00168 xxxSendMessage(pwndDragging, WM_DRAGMOVE, 0, (LPARAM)lpds); 00169 } 00170 } 00171 00172 switch (msg.message) { 00173 case WM_LBUTTONUP: 00174 case WM_NCLBUTTONUP: 00175 fDrag = FALSE; 00176 break; 00177 } 00178 } 00179 00180 ThreadUnlock(&tlpwndDragging); 00181 00182 /* 00183 * If the capture has been lost (i.e. fDrag == TRUE), don't do the drop. 00184 */ 00185 if (fDrag) 00186 pcurT = SYSCUR(NO); 00187 00188 /* 00189 * before the actual drop, clean up the cursor, as the app may do 00190 * stuff here... 00191 */ 00192 xxxReleaseCapture(); 00193 zzzShowCursor(FALSE); 00194 00195 zzzSetCursor(pcurOld); 00196 00197 /* 00198 * we either got lbuttonup or enter 00199 */ 00200 if (pcurT != SYSCUR(NO)) { 00201 00202 /* 00203 * object allows drop... send drop message 00204 */ 00205 pwndT = ValidateHwnd(lpds->hwndSink); 00206 if (pwndT != NULL) { 00207 00208 ThreadLockAlwaysWithPti(pti, pwndT, &tlpwndT); 00209 00210 /* 00211 * Allow this guy to activate. 00212 */ 00213 GETPTI(pwndT)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 00214 TAGMSG1(DBGTAG_FOREGROUND, "xxxDragObject set TIF %#p", GETPTI(pwndT)); 00215 result = (DWORD)xxxSendMessage(pwndT, WM_DROPOBJECT, 00216 (WPARAM)HW(pwndFrom), (LPARAM)lpds); 00217 00218 ThreadUnlock(&tlpwndT); 00219 } 00220 } 00221 00222 if (FWINABLE()) { 00223 xxxWindowEvent(EVENT_SYSTEM_DRAGDROPEND, pwndFrom, OBJID_WINDOW, INDEXID_CONTAINER, 0); 00224 } 00225 00226 ThreadUnlockAndFreePool(pti, &tlPool); 00227 return result; 00228 } 00229 00230 00231 /***************************************************************************\ 00232 * QueryDropObject 00233 * 00234 * Determines where in the window heirarchy the "drop" takes place, and 00235 * sends a message to the deepest child window first. If that window does 00236 * not respond, we go up the heirarchy (recursively, for the moment) until 00237 * we either get a window that does respond or the parent doesn't respond. 00238 * 00239 * History: 00240 * 08-06-91 darrinm Ported from Win 3.1 sources. 00241 \***************************************************************************/ 00242 00243 PCURSOR xxxQueryDropObject( 00244 PWND pwnd, 00245 LPDROPSTRUCT lpds) 00246 { 00247 PWND pwndT; 00248 PCURSOR pcurT = NULL; 00249 POINT pt; 00250 BOOL fNC; 00251 TL tlpwndT; 00252 CheckLock(pwnd); 00253 00254 /* 00255 * pt is in screen coordinates 00256 */ 00257 pt = lpds->ptDrop; 00258 00259 /* 00260 * reject points outside this window or if the window is disabled 00261 */ 00262 if (!PtInRect(&pwnd->rcWindow, pt) || TestWF(pwnd, WFDISABLED)) 00263 return NULL; 00264 00265 /* 00266 * Check to see if in window region (if it has one) 00267 */ 00268 if (pwnd->hrgnClip != NULL) { 00269 if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y)) 00270 return NULL; 00271 } 00272 00273 /* 00274 * are we dropping in the nonclient area of the window or on an iconic 00275 * window? 00276 */ 00277 if (fNC = (TestWF(pwnd, WFMINIMIZED) || !PtInRect(&pwnd->rcClient, pt))) { 00278 goto SendQueryDrop; 00279 } 00280 00281 /* 00282 * dropping in client area 00283 */ 00284 _ScreenToClient(pwnd, &pt); 00285 pwndT = _ChildWindowFromPointEx(pwnd, pt, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE); 00286 _ClientToScreen(pwnd, &pt); 00287 00288 pcurT = NULL; 00289 if (pwndT && pwndT != pwnd) { 00290 ThreadLock(pwndT, &tlpwndT); 00291 pcurT = xxxQueryDropObject(pwndT, lpds); 00292 ThreadUnlock(&tlpwndT); 00293 } 00294 00295 if (pcurT == NULL) { 00296 00297 /* 00298 * there are no children who are in the right place or who want 00299 * drops... convert the point into client coordinates of the 00300 * current window. Because of the recursion, this is already 00301 * done if a child window grabbed the drop. 00302 */ 00303 SendQueryDrop: 00304 _ScreenToClient(pwnd, &lpds->ptDrop); 00305 lpds->hwndSink = HWq(pwnd); 00306 00307 /* 00308 * To avoid hanging dropper (sender) app we do a SendMessageTimeout to 00309 * the droppee (receiver) 00310 */ 00311 if ((PCURSOR)xxxSendMessageTimeout(pwnd, WM_QUERYDROPOBJECT, fNC, 00312 (LPARAM)lpds, SMTO_ABORTIFHUNG, 3*1000, (PLONG_PTR)&pcurT) == FALSE) 00313 pcurT = (PCURSOR)FALSE; 00314 00315 if (pcurT != (PCURSOR)FALSE && pcurT != (PCURSOR)TRUE) 00316 pcurT = HMValidateHandle((HCURSOR)pcurT, TYPE_CURSOR); 00317 00318 /* 00319 * restore drop point to screen coordinates if this window won't 00320 * take drops 00321 */ 00322 if (pcurT == NULL) 00323 lpds->ptDrop = pt; 00324 } 00325 return pcurT; 00326 } 00327 00328 00329 /***************************************************************************\ 00330 * xxxDragDetect (API) 00331 * 00332 * 00333 * 00334 * History: 00335 * 08-06-91 darrinm Ported from Win 3.1 sources. 00336 \***************************************************************************/ 00337 00338 BOOL xxxDragDetect( 00339 PWND pwnd, 00340 POINT pt) 00341 { 00342 return xxxIsDragging(pwnd, pt, WM_LBUTTONUP); 00343 } 00344 00345 /***************************************************************************\ 00346 * xxxIsDragging 00347 * 00348 * 00349 * 00350 * History: 00351 * 05-17-94 johnl Ported from Chicago sources 00352 \***************************************************************************/ 00353 00354 BOOL xxxIsDragging(PWND pwnd, POINT ptScreen, UINT uMsg) 00355 { 00356 RECT rc; 00357 MSG msg; 00358 BOOL fDragging; 00359 BOOL fCheck; 00360 TL tlpwndDragging; 00361 PTHREADINFO pti = PtiCurrent(); 00362 00363 /* 00364 * Check synchronous mouse state, and punt if the mouse isn't down 00365 * according to the queue. 00366 */ 00367 if (!(_GetKeyState((uMsg == WM_LBUTTONUP ? VK_LBUTTON : VK_RBUTTON)) & 0x8000)) 00368 return FALSE; 00369 00370 xxxSetCapture(pwnd); 00371 00372 *(LPPOINT)&rc.left = ptScreen; 00373 *(LPPOINT)&rc.right = ptScreen; 00374 InflateRect(&rc, SYSMET(CXDRAG), SYSMET(CYDRAG)); 00375 00376 fDragging = FALSE; 00377 fCheck = TRUE; 00378 00379 ThreadLockWithPti(pti, pwnd, &tlpwndDragging); 00380 while (fCheck) { 00381 while ( !( 00382 xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,PM_REMOVE) || 00383 xxxPeekMessage(&msg, NULL, WM_QUEUESYNC, WM_QUEUESYNC,PM_REMOVE) || 00384 xxxPeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,PM_REMOVE) 00385 ) 00386 && (pti->pq->spwndCapture == pwnd)) { 00387 /* 00388 * If there is no input for half a second (500ms) consider that 00389 * we are dragging. If we don't specify a timeout value, the 00390 * thread may sleep here forever and wouldn't repaint, etc. 00391 */ 00392 if (!xxxSleepThread(QS_MOUSE | QS_KEY, 500, TRUE)) { 00393 fDragging = TRUE; 00394 goto Cleanup; 00395 } 00396 } 00397 00398 /* 00399 * Cancel if the button was released or we no longer have the capture. 00400 */ 00401 if ( pti->pq->spwndCapture != pwnd || msg.message == uMsg) { 00402 fCheck = FALSE; 00403 } else { 00404 switch (msg.message) { 00405 00406 case WM_MOUSEMOVE: 00407 if (!PtInRect(&rc, msg.pt)) { 00408 fDragging = TRUE; 00409 fCheck = FALSE; 00410 } 00411 break; 00412 00413 case WM_QUEUESYNC: 00414 /* 00415 * CBT Hook needs to know 00416 */ 00417 xxxCallHook(HCBT_QS, 0, 0, WH_CBT); 00418 break; 00419 00420 case WM_KEYDOWN: 00421 /* 00422 * <Esc> cancels drag detection 00423 */ 00424 if (msg.wParam == VK_ESCAPE) 00425 fCheck = FALSE; 00426 break; 00427 00428 } 00429 } 00430 } 00431 00432 Cleanup: 00433 if (pti->pq->spwndCapture == pwnd) 00434 xxxReleaseCapture(); 00435 00436 ThreadUnlock(&tlpwndDragging); 00437 return fDragging ; 00438 }

Generated on Sat May 15 19:39:46 2004 for test by doxygen 1.3.7