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

movesize.c

Go to the documentation of this file.
00001 /****************************************************************************\ 00002 * Module Name: movesize.c (formerly wmmove.c) 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains Window Moving and Sizing Routines 00007 * 00008 * History: 00009 * 12-Nov-1990 MikeHar Ported from win3 00010 * 13-Feb-1991 IanJa HWND revalidation added 00011 \****************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 00017 #define DRAG_START 0 00018 #define DRAG_MOVE 1 00019 #define DRAG_END 2 00020 00021 /****************************************************************************\ 00022 * These values are indexes that represent rect sides. These indexes are 00023 * used as indexes into rgimpiwx and rgimpiwy (which are indexes into the 00024 * the rect structure) which tell the move code where to store the new x & y 00025 * coordinates. Notice that when two of these values that represent sides 00026 * are added together, we get a unique list of contiguous values starting at 00027 * 1 that represent all the ways we can size a rect. That also leaves 0 free 00028 * a initialization value. 00029 * 00030 * The reason we need rgimpimpiw is for the keyboard interface - we 00031 * incrementally decide what our 'move command' is. With the mouse interface 00032 * we know immediately because we registered a mouse hit on the segment(s) 00033 * we're moving. 00034 * 00035 * 4 5 00036 * \ ___3___ / 00037 * | | 00038 * 1 2 00039 * |_______| 00040 * / 6 \ 00041 * 7 8 00042 * 00043 \****************************************************************************/ 00044 00045 static const int rgimpimpiw[] = {1, 3, 2, 6}; 00046 static const int rgimpiwx[] = {0, 0, 2, -1, 0, 2, -1, 0, 2, 0}; 00047 static const int rgimpiwy[] = {0, -1, -1, 1, 1, 1, 3, 3, 3, 1}; 00048 static const int rgcmdmpix[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 1}; 00049 static const int rgcmdmpiy[] = {0, 0, 0, 3, 3, 3, 6, 6, 6, 3}; 00050 00051 /***************************************************************************\ 00052 * GetMonitorMaxArea 00053 * 00054 * Return the rectangle on a monitor which should be used to 00055 * maximize to, the work rect or the monitor rect. 00056 * 00057 * History: 00058 * 24-Sep-1996 adams Created. 00059 \***************************************************************************/ 00060 00061 void 00062 GetMonitorMaxArea(PWND pwnd, PMONITOR pMonitor, LPRECT * pprc) 00063 { 00064 if ( !TestWF(pwnd, WFMAXBOX) || 00065 !TestWF(pwnd, WFCPRESENT) || 00066 pMonitor->cFullScreen) { 00067 00068 *pprc = &pMonitor->rcMonitor; 00069 } else { 00070 *pprc = &pMonitor->rcWork; 00071 } 00072 } 00073 00074 00075 /***************************************************************************\ 00076 * SizeRect 00077 * 00078 * Match corner or side (defined by cmd) to pt. 00079 * 00080 * History: 00081 * 12-Nov-1990 MikeHar Ported from win3 asm code 00082 \***************************************************************************/ 00083 00084 BOOL SizeRect( 00085 PMOVESIZEDATA pmsd, 00086 DWORD pt) 00087 { 00088 int ax; 00089 int dx; 00090 int index; 00091 int indexOpp; 00092 PINT psideDragCursor = ((PINT)(&pmsd->rcDragCursor)); 00093 PINT psideParent = ((PINT)(&pmsd->rcParent)); 00094 00095 00096 /* 00097 * DO HORIZONTAL 00098 */ 00099 00100 /* 00101 * We know what part of the rect we're moving based on 00102 * what's in cmd. We use cmd as an index into rgimpiw? which 00103 * tells us what part of the rect we're dragging. 00104 */ 00105 00106 /* 00107 * Get the approriate array entry. 00108 */ 00109 index = (int)rgimpiwx[pmsd->cmd]; // AX 00110 00111 /* 00112 * Is it one of the entries we don't map (i.e. -1)? 00113 */ 00114 if (index < 0) 00115 goto mrLoopBottom; 00116 00117 psideDragCursor[index] = LOSHORT(pt); 00118 00119 indexOpp = index ^ 0x2; 00120 00121 /* 00122 * Now check to see if we're below the min or above the max. Get the width 00123 * of the rect in this direction (either x or y) and see if it's bad. If 00124 * so, map the side we're moving to the min or max. 00125 */ 00126 ax = psideDragCursor[index] - psideDragCursor[indexOpp]; 00127 00128 if (indexOpp & 0x2) 00129 ax = -ax; 00130 00131 if ((ax >= (dx = pmsd->ptMinTrack.x)) && 00132 (ax <= (dx = pmsd->ptMaxTrack.x))) { 00133 00134 /* 00135 * Only test for the parent's client boundary if we are a child 00136 * window...Otherwise we are bound to the client of the desktop 00137 * which causes strange drag problems. 00138 */ 00139 if (!TestWF(pmsd->spwnd,WFCHILD)) 00140 goto mrLoopBottom; 00141 00142 /* 00143 * Now see if we're extending beyond our parent's client rect. 00144 * Compute the size the rect can be expanded to in this direction. 00145 */ 00146 dx = abs(psideParent[index] - psideDragCursor[indexOpp]); 00147 00148 if (ax <= dx) 00149 goto mrLoopBottom; 00150 00151 /* 00152 * The width is invalid - map the side we're moving to the other 00153 * side +/- the width. 00154 */ 00155 } 00156 00157 if (indexOpp & 0x2) 00158 dx = -dx; 00159 00160 psideDragCursor[index] = dx + psideDragCursor[indexOpp]; 00161 00162 mrLoopBottom: 00163 00164 /* 00165 * DO VERTICAL 00166 */ 00167 00168 /* 00169 * We know what part of the rect we're moving based on 00170 * what's in cmd. We use cmd as an index into rgimpiw? which 00171 * tells us what part of the rect we're dragging. 00172 */ 00173 00174 /* 00175 * Get the approriate array entry. 00176 */ 00177 index = (int)rgimpiwy[pmsd->cmd]; // AX 00178 00179 /* 00180 * Is it one of the entries we don't map (i.e. -1)? 00181 */ 00182 if (index < 0) 00183 return TRUE; 00184 00185 psideDragCursor[index] = HISHORT(pt); 00186 00187 indexOpp = index ^ 0x2; 00188 00189 /* 00190 * Now check to see if we're below the min or above the max. Get the width 00191 * of the rect in this direction (either x or y) and see if it's bad. If 00192 * so, map the side we're moving to the min or max. 00193 */ 00194 ax = psideDragCursor[index] - psideDragCursor[indexOpp]; 00195 00196 if (indexOpp & 0x2) 00197 ax = -ax; 00198 00199 if ((ax >= (dx = pmsd->ptMinTrack.y)) && 00200 (ax <= (dx = pmsd->ptMaxTrack.y))) { 00201 00202 /* 00203 * Only test for the parent's client boundary if we are a child 00204 * window...Otherwise we are bound to the client of the desktop 00205 * which causes strange drag problems. 00206 */ 00207 if (!TestWF(pmsd->spwnd,WFCHILD)) 00208 return TRUE; 00209 00210 /* 00211 * Now see if we're extending beyond our parent's client rect. 00212 * Compute the size the rect can be expanded to in this direction. 00213 */ 00214 dx = abs(psideParent[index] - psideDragCursor[indexOpp]); 00215 00216 if (ax <= dx) 00217 return TRUE; 00218 00219 /* 00220 * The width is invalid - map the side we're moving to the other 00221 * side +/- the width. 00222 */ 00223 } 00224 00225 if (indexOpp & 0x2) 00226 dx = -dx; 00227 00228 psideDragCursor[index] = dx + psideDragCursor[indexOpp]; 00229 00230 return TRUE; 00231 } 00232 00233 /***************************************************************************\ 00234 * MoveRect 00235 * 00236 * Move the rect to pt, make sure we're not going out of the parent rect. 00237 * 00238 * History: 00239 * 12-Nov-1990 MikeHar Ported from win3 asm code 00240 \***************************************************************************/ 00241 00242 BOOL MoveRect( 00243 PMOVESIZEDATA pmsd, 00244 DWORD pt) 00245 { 00246 RECT rcAnd; 00247 00248 OffsetRect(&pmsd->rcDragCursor, 00249 LOSHORT(pt) - pmsd->rcDragCursor.left, 00250 HISHORT(pt) - pmsd->rcDragCursor.top); 00251 00252 /* 00253 * Don't move the entire rectangle off the screen. 00254 * However, if the window started offscreen completely, let it move. 00255 */ 00256 if (pmsd->fOffScreen) 00257 return TRUE; 00258 00259 if (pmsd->spwnd->spwndParent->hrgnClip) { 00260 return GreRectInRegion( 00261 pmsd->spwnd->spwndParent->hrgnClip, &pmsd->rcDragCursor); 00262 } 00263 00264 return IntersectRect(&rcAnd, &pmsd->rcDragCursor, &pmsd->rcParent); 00265 } 00266 00267 /***************************************************************************\ 00268 * xxxTM_MoveDragRect 00269 * 00270 * History: 00271 * 12-Nov-1990 MikeHar Ported from win3 00272 \***************************************************************************/ 00273 00274 VOID xxxTM_MoveDragRect( 00275 PMOVESIZEDATA pmsd, 00276 LPARAM lParam) 00277 { 00278 UINT msg; 00279 RECT rc; 00280 00281 UserAssert(pmsd == PtiCurrent()->pmsd); 00282 UserAssert(pmsd->cmd != WMSZ_KEYSIZE); 00283 00284 CopyRect(&pmsd->rcDragCursor, &pmsd->rcDrag); 00285 00286 if (pmsd->cmd == WMSZ_MOVE) { 00287 00288 if (!MoveRect(pmsd, (DWORD)lParam)) 00289 return; 00290 00291 msg = WM_MOVING; 00292 00293 } else { 00294 00295 if (!SizeRect(pmsd, (DWORD)lParam)) 00296 return; 00297 00298 msg = WM_SIZING; 00299 } 00300 00301 CopyRect(&rc, &pmsd->rcDragCursor); 00302 xxxSendMessage(pmsd->spwnd, msg, pmsd->cmd, (LPARAM)(LPRECT)&rc); 00303 xxxDrawDragRect(pmsd, &rc, DRAG_MOVE); 00304 00305 if (pmsd->cmd == WMSZ_MOVE) { 00306 00307 /* 00308 * Keep dxMouse & dxMouse relative to the offset from the top left 00309 * corner, the rectangle could've changed on WM_MOVING 00310 */ 00311 pmsd->dxMouse += (rc.left - LOSHORT(lParam)); 00312 pmsd->dyMouse += (rc.top - HISHORT(lParam)); 00313 } 00314 } 00315 00316 /***************************************************************************\ 00317 * CkptRestore 00318 * 00319 * Positions are always relative to the origin of the monitor's working 00320 * area that the window is on, except for rcNormal. That way, windows will 00321 * maximize to the working area of the monitor they find themselves on, and 00322 * not to a random place. 00323 * 00324 * This allows us to keep information in a reasonably independent fashion, 00325 * information that doesn't go out of date when a window moves or the 00326 * monitors are configured differently. 00327 * 00328 * rcNormal is different because that does need to be absolute. It's where 00329 * the window should come up the first time in a normal state. 00330 * 00331 * History: 00332 * 14-Nov-1990 DarrinM Ported from Win 3.0 sources. 00333 \***************************************************************************/ 00334 00335 PCHECKPOINT CkptRestore( 00336 PWND pwnd, 00337 LPCRECT lprcWindow) 00338 { 00339 PCHECKPOINT pcp; 00340 00341 /* 00342 * Don't return or create a checkpoint if the window is dying. 00343 */ 00344 if (HMIsMarkDestroy(pwnd)) 00345 return NULL; 00346 00347 /* 00348 * If it doesn't exist, create it. 00349 */ 00350 if ((pcp = (PCHECKPOINT)_GetProp(pwnd, 00351 PROP_CHECKPOINT, 00352 PROPF_INTERNAL)) == NULL) { 00353 00354 if ((pcp = (PCHECKPOINT)UserAllocPoolWithQuota(sizeof(CHECKPOINT), 00355 TAG_CHECKPT)) == NULL) { 00356 return NULL; 00357 } 00358 00359 if (!InternalSetProp(pwnd, 00360 PROP_CHECKPOINT, 00361 (HANDLE)pcp, 00362 PROPF_INTERNAL)) { 00363 00364 UserFreePool(pcp); 00365 return NULL; 00366 } 00367 00368 /* 00369 * Initialize it to -1 so first minimize will park the icon. 00370 */ 00371 pcp->ptMin.x = -1; 00372 pcp->ptMin.y = -1; 00373 pcp->ptMax.x = -1; 00374 pcp->ptMax.y = -1; 00375 00376 /* 00377 * Initialize pwndTitle to NULL so we create a title window on the 00378 * first minimize of the window 00379 */ 00380 pcp->fDragged = FALSE; 00381 pcp->fWasMaximizedBeforeMinimized = FALSE; 00382 pcp->fWasMinimizedBeforeMaximized = FALSE; 00383 pcp->fMinInitialized = FALSE; 00384 pcp->fMaxInitialized = FALSE; 00385 00386 /* 00387 * BOGUS! We're going to copy this twice if the window isn't 00388 * minimized or maximized. But if it isn't, we're going to get 00389 * a weird size in rcNormal... 00390 */ 00391 CopyRect(&pcp->rcNormal, lprcWindow); 00392 } 00393 00394 /* 00395 * If the window is minimized/maximized, then set the min/max 00396 * point. Otherwise use checkpoint the window-size. 00397 */ 00398 if (TestWF(pwnd, WFMINIMIZED)) { 00399 pcp->fMinInitialized = TRUE; 00400 pcp->ptMin.x = lprcWindow->left; 00401 pcp->ptMin.y = lprcWindow->top; 00402 } else if (TestWF(pwnd, WFMAXIMIZED)) { 00403 pcp->fMaxInitialized = TRUE; 00404 00405 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00406 if (TestWF(pwnd, WFREALLYMAXIMIZABLE)) { 00407 pcp->fMaxInitialized = FALSE; 00408 pcp->ptMax.x = -1; 00409 pcp->ptMax.y = -1; 00410 } else { 00411 PMONITOR pMonitor; 00412 LPRECT lprc; 00413 00414 pMonitor = _MonitorFromRect(lprcWindow, MONITOR_DEFAULTTOPRIMARY); 00415 GetMonitorMaxArea(pwnd, pMonitor, &lprc); 00416 pcp->ptMax.x = lprcWindow->left - lprc->left; 00417 pcp->ptMax.y = lprcWindow->top - lprc->top; 00418 } 00419 } else { 00420 pcp->ptMax.x = lprcWindow->left; 00421 pcp->ptMax.y = lprcWindow->top; 00422 } 00423 } else { 00424 CopyRect(&pcp->rcNormal, lprcWindow); 00425 } 00426 00427 return pcp; 00428 } 00429 00430 /***************************************************************************\ 00431 * xxxMS_TrackMove 00432 * 00433 * History: 00434 * 12-Nov-1990 MikeHar Ported from win3 00435 \***************************************************************************/ 00436 00437 void xxxMS_TrackMove( 00438 PWND pwnd, 00439 UINT message, 00440 WPARAM wParam, 00441 LPARAM lParam, 00442 PMOVESIZEDATA pmsd) 00443 { 00444 int dxMove; 00445 int dyMove; 00446 POINT pt; 00447 BOOL fSlower; 00448 RECT rc; 00449 PCHECKPOINT pcp; 00450 LPWORD ps; 00451 PTHREADINFO ptiCurrent = PtiCurrent(); 00452 00453 CheckLock(pwnd); 00454 UserAssert(IsWinEventNotifyDeferredOK()); 00455 UserAssert(pmsd == ptiCurrent->pmsd); 00456 00457 pt.x = LOSHORT(lParam); 00458 pt.y = HISHORT(lParam); 00459 00460 switch (message) { 00461 case WM_LBUTTONUP: 00462 00463 /* 00464 * Do final move! 00465 */ 00466 xxxTM_MoveDragRect(pmsd, lParam); 00467 00468 00469 /* 00470 * Don't reset the mouse position when done. 00471 */ 00472 pmsd->fmsKbd = FALSE; 00473 00474 Accept: 00475 00476 /* 00477 * Turn off rect, unlock screen, release capture, and stop tracking. 00478 * 1 specifies end and accept drag. 00479 */ 00480 bSetDevDragRect(gpDispInfo->hDev, NULL, NULL); 00481 if (ptiCurrent->TIF_flags & TIF_TRACKRECTVISIBLE) { 00482 xxxDrawDragRect(pmsd, NULL, DDR_ENDACCEPT); 00483 ptiCurrent->TIF_flags &= ~TIF_TRACKRECTVISIBLE; 00484 } 00485 00486 TrackMoveCancel: 00487 00488 /* 00489 * Revalidation: if pwnd is unexpectedly deleted, jump here to cleanup. 00490 * If pwnd is/becomes invalid between here and return, continue with 00491 * cleanup as best as possible. 00492 */ 00493 zzzClipCursor((LPRECT)NULL); 00494 LockWindowUpdate2(NULL, TRUE); 00495 xxxReleaseCapture(); 00496 00497 /* 00498 * First unlock task and reset cursor. 00499 */ 00500 pmsd->fTrackCancelled = TRUE; 00501 00502 /* 00503 * If using the keyboard, restore the initial mouse position. 00504 */ 00505 if (pmsd->fmsKbd) { 00506 /* 00507 * No DeferWinEventNotify required - xxx calls above & below 00508 */ 00509 zzzInternalSetCursorPos(pmsd->ptRestore.x, 00510 pmsd->ptRestore.y 00511 ); 00512 } 00513 00514 /* 00515 * Move to new location relative to parent. 00516 */ 00517 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00518 rc.left = rc.top = 0; 00519 } else { 00520 rc.left = pwnd->spwndParent->rcClient.left; 00521 rc.top = pwnd->spwndParent->rcClient.top; 00522 } 00523 00524 if (!EqualRect(&pmsd->rcDrag, &pmsd->rcWindow)) { 00525 00526 if (!xxxCallHook(HCBT_MOVESIZE, 00527 (WPARAM)HWq(pwnd), 00528 (LPARAM)&pmsd->rcDrag, 00529 WH_CBT)) { 00530 00531 RECT rcT; 00532 00533 if (pmsd->cmd != WMSZ_MOVE) { 00534 00535 if (TestWF(pwnd, WFMINIMIZED)) { 00536 00537 CopyOffsetRect(&rcT, 00538 &pmsd->rcWindow, 00539 -rc.left, 00540 -rc.top); 00541 00542 /* 00543 * Save the minimized position. 00544 */ 00545 CkptRestore(pwnd, &rcT); 00546 SetMinimize(pwnd, SMIN_CLEAR); 00547 00548 } else if (TestWF(pwnd, WFMAXIMIZED)) { 00549 ClrWF(pwnd, WFMAXIMIZED); 00550 } 00551 00552 } else if (TestWF(pwnd, WFMINIMIZED)) { 00553 00554 CopyOffsetRect(&rcT, 00555 &pmsd->rcWindow, 00556 -rc.left, 00557 -rc.top); 00558 00559 00560 if (pcp = CkptRestore(pwnd, &rcT)) 00561 pcp->fDragged = TRUE; 00562 } 00563 00564 } else { 00565 CopyRect(&pmsd->rcDrag, &pmsd->rcWindow); 00566 } 00567 } 00568 00569 /* 00570 * Move to new location relative to parent. 00571 */ 00572 #if defined(USE_MIRRORING) 00573 if (TestWF(pwnd->spwndParent,WEFLAYOUTRTL)) { 00574 /* 00575 * If this is a mirrored window, then measure the client 00576 * coordinates from the parent's right edge, not the left one. 00577 */ 00578 int iLeft; 00579 00580 OffsetRect(&pmsd->rcDrag, -pwnd->spwndParent->rcClient.right, -rc.top); 00581 iLeft = pmsd->rcDrag.left; 00582 pmsd->rcDrag.left = (pmsd->rcDrag.right * -1); 00583 pmsd->rcDrag.right = (iLeft * -1); 00584 } 00585 else 00586 #endif 00587 OffsetRect(&pmsd->rcDrag, -rc.left, -rc.top); 00588 00589 /* 00590 * For top level windows, make sure at least part of the caption 00591 * caption is always visible in the desktop area. This will 00592 * ensure that once moved, the window can be moved back. 00593 */ 00594 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00595 00596 int dy; 00597 BOOL fMonitor; 00598 PMONITOR pMonitor; 00599 00600 UserAssert(HIBYTE(WEFTOPMOST) == HIBYTE(WEFTOOLWINDOW)); 00601 fMonitor = TestWF(pwnd, WEFTOPMOST | WEFTOOLWINDOW); 00602 dy = (TestWF(pwnd, WEFTOOLWINDOW) ? 00603 SYSMET(CYSMCAPTION) : SYSMET(CYCAPTION)) - SYSMET(CYBORDER); 00604 00605 if (gpDispInfo->cMonitors == 1) { 00606 pMonitor = GetPrimaryMonitor(); 00607 } else { 00608 int y; 00609 LPRECT lprc; 00610 00611 y = pmsd->rcDrag.top + dy; 00612 00613 /* 00614 * Make sure that some part of the caption is showing on some 00615 * monitor... 00616 */ 00617 for ( pMonitor = gpDispInfo->pMonitorFirst; 00618 pMonitor; 00619 pMonitor = pMonitor->pMonitorNext) { 00620 00621 if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) 00622 continue; 00623 00624 if (fMonitor) { 00625 lprc = &pMonitor->rcMonitor; 00626 } else { 00627 lprc = &pMonitor->rcWork; 00628 } 00629 00630 /* 00631 * Is the Y coordinate visible on screen somewhere? 00632 */ 00633 if (y >= lprc->top && y < lprc->bottom) 00634 goto AllSet; 00635 } 00636 00637 /* 00638 * Oops, have to move the window so that some part of 00639 * the caption is visible on screen. 00640 */ 00641 pMonitor = _MonitorFromRect(&pmsd->rcDrag, MONITOR_DEFAULTTONEAREST); 00642 } 00643 00644 if (fMonitor) { 00645 pmsd->rcDrag.top = max(pmsd->rcDrag.top, pMonitor->rcMonitor.top - dy); 00646 } else { 00647 pmsd->rcDrag.top = max(pmsd->rcDrag.top, pMonitor->rcWork.top - dy); 00648 } 00649 00650 AllSet: 00651 ; 00652 } 00653 00654 /* 00655 * OR in SWP_NOSIZE so it doesn't redraw if we're just moving. 00656 */ 00657 xxxSetWindowPos( 00658 pwnd, 00659 NULL, 00660 pmsd->rcDrag.left, 00661 pmsd->rcDrag.top, 00662 pmsd->rcDrag.right - pmsd->rcDrag.left, 00663 pmsd->rcDrag.bottom - pmsd->rcDrag.top, 00664 (DWORD)((pmsd->cmd == (int)WMSZ_MOVE) ? SWP_NOSIZE : 0)); 00665 00666 if (TestWF(pwnd, WFMINIMIZED)) { 00667 CkptRestore(pwnd, &pmsd->rcDrag); 00668 } 00669 00670 if (FWINABLE()) { 00671 xxxWindowEvent(EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0); 00672 } 00673 00674 /* 00675 * Send this message for winoldapp support 00676 */ 00677 xxxSendMessage(pwnd, WM_EXITSIZEMOVE, 0L, 0L); 00678 break; 00679 00680 case WM_KEYDOWN: 00681 case WM_SYSKEYDOWN: 00682 00683 /* 00684 * Assume we're not moving the drag rectangle. 00685 */ 00686 dxMove = 00687 dyMove = 0; 00688 00689 /* 00690 * We move or size slower if the control key is down. 00691 */ 00692 fSlower = (_GetKeyState(VK_CONTROL) < 0); 00693 00694 switch (wParam) { 00695 case VK_RETURN: 00696 lParam = _GetMessagePos(); 00697 goto Accept; 00698 00699 case VK_ESCAPE: 00700 00701 /* 00702 * 2 specifies end and cancel drag. 00703 */ 00704 bSetDevDragRect(gpDispInfo->hDev, NULL, NULL); 00705 if (ptiCurrent->TIF_flags & TIF_TRACKRECTVISIBLE) { 00706 xxxDrawDragRect(pmsd, NULL, DDR_ENDCANCEL); 00707 ptiCurrent->TIF_flags &= ~TIF_TRACKRECTVISIBLE; 00708 } 00709 00710 CopyRect(&pmsd->rcDrag, &pmsd->rcWindow); 00711 00712 goto TrackMoveCancel; 00713 00714 case VK_LEFT: 00715 case VK_RIGHT: 00716 00717 if (pmsd->impx == 0) { 00718 00719 pmsd->impx = rgimpimpiw[wParam - VK_LEFT]; 00720 goto NoOffset; 00721 00722 } else { 00723 00724 dxMove = (fSlower ? 1 : max(SYSMET(CXSIZE) / 2, 1)); 00725 00726 if (wParam == VK_LEFT) 00727 dxMove = -dxMove; 00728 00729 goto KeyMove; 00730 } 00731 00732 case VK_UP: 00733 case VK_DOWN: 00734 00735 if (pmsd->impy == 0) { 00736 00737 pmsd->impy = rgimpimpiw[wParam - VK_LEFT]; 00738 NoOffset: 00739 pmsd->dxMouse = pmsd->dyMouse = 0; 00740 00741 } else { 00742 00743 dyMove = (fSlower ? 1 : max(SYSMET(CYSIZE) / 2, 1)); 00744 00745 if (wParam == VK_UP) { 00746 dyMove = -dyMove; 00747 } 00748 } 00749 00750 KeyMove: 00751 if (pmsd->cmd == WMSZ_MOVE) { 00752 00753 /* 00754 * Use the current rect position as the current mouse 00755 * position 00756 */ 00757 lParam = (DWORD)(POINTTOPOINTS(*((POINT *)&pmsd->rcDrag))); 00758 00759 } else { 00760 00761 /* 00762 * Get the current mouse position 00763 */ 00764 lParam = _GetMessagePos(); 00765 } 00766 00767 /* 00768 * Calc the new 'mouse' pos 00769 */ 00770 if (pmsd->impx != 0) { 00771 ps = ((WORD *)(&lParam)) + 0; 00772 *ps = (WORD)(*((int *)&pmsd->rcDragCursor + 00773 rgimpiwx[pmsd->impx]) + 00774 dxMove); 00775 } 00776 00777 if (pmsd->impy != 0) { 00778 ps = ((WORD *)(&lParam)) + 1; 00779 *ps = (WORD)(*((int *)&pmsd->rcDragCursor + 00780 rgimpiwy[pmsd->impy]) + 00781 dyMove); 00782 } 00783 00784 if (pmsd->cmd != WMSZ_MOVE) { 00785 00786 /* 00787 * Calculate the new move command. 00788 */ 00789 pmsd->cmd = pmsd->impx + pmsd->impy; 00790 00791 /* 00792 * Change the mouse cursor for this condition. 00793 */ 00794 xxxSendMessage( 00795 pwnd, 00796 WM_SETCURSOR, 00797 (WPARAM)HW(pwnd), 00798 MAKELONG((SHORT)(pmsd->cmd + HTSIZEFIRST - WMSZ_SIZEFIRST), WM_MOUSEMOVE)); 00799 } 00800 00801 /* 00802 * We don't want to call zzzInternalSetCursorPos() if the 00803 * rect position is outside of rcParent because that'll 00804 * generate a mouse move which will jerk the rect back 00805 * again. This is here so we can move rects partially off 00806 * screen without regard to the mouse position. 00807 */ 00808 pt.x = LOSHORT(lParam) - pmsd->dxMouse; 00809 pt.y = HISHORT(lParam) - pmsd->dyMouse; 00810 00811 if (pwnd->spwndParent->hrgnClip) { 00812 if (GrePtInRegion(pwnd->spwndParent->hrgnClip, pt.x, pt.y)) { 00813 zzzInternalSetCursorPos(pt.x, pt.y); 00814 } 00815 } else { 00816 if (PtInRect(&pmsd->rcParent, pt)) { 00817 zzzInternalSetCursorPos(pt.x, pt.y); 00818 } 00819 } 00820 00821 /* 00822 * Move or size the rect using lParam as our mouse 00823 * coordinates 00824 */ 00825 xxxTM_MoveDragRect(pmsd, lParam); 00826 break; 00827 00828 } // of inner switch 00829 break; 00830 00831 case WM_MOUSEMOVE: 00832 xxxTM_MoveDragRect(pmsd, lParam); 00833 break; 00834 } 00835 } 00836 00837 /***************************************************************************\ 00838 * xxxMS_FlushWigglies 00839 * 00840 * History: 00841 * 12-Nov-1990 MikeHar Ported from win3 00842 \***************************************************************************/ 00843 00844 VOID xxxMS_FlushWigglies(VOID) 00845 { 00846 MSG msg; 00847 00848 /* 00849 * HACK! 00850 * 00851 * Calling zzzInternalSetCursorPos() while initializing the cursor 00852 * position appears to be posting a bogus MouseMove 00853 * message... don't really have the time 00854 * now to figure out why... so spit out all the mouse move messages 00855 * before entering the main move/size loop. CraigC. 00856 */ 00857 while (xxxPeekMessage(&msg, 00858 NULL, 00859 WM_MOUSEMOVE, 00860 WM_MOUSEMOVE, 00861 PM_REMOVE | PM_NOYIELD)); 00862 } 00863 00864 /***************************************************************************\ 00865 * xxxTrackInitSize 00866 * 00867 * NOTE: to recover from hwnd invalidation, just return and let ? 00868 * 00869 * History: 00870 * 12-Nov-1990 MikeHar Ported from win3 00871 \***************************************************************************/ 00872 00873 BOOL xxxTrackInitSize( 00874 PWND pwnd, 00875 UINT message, 00876 WPARAM wParam, 00877 LPARAM lParam, 00878 PMOVESIZEDATA pmsd) 00879 { 00880 int ht; 00881 POINT pt; 00882 RECT rc; 00883 PTHREADINFO ptiCurrent = PtiCurrent(); 00884 00885 CheckLock(pwnd); 00886 UserAssert(pmsd == ptiCurrent->pmsd); 00887 UserAssert(IsWinEventNotifyDeferredOK()); 00888 00889 POINTSTOPOINT(pt, lParam); 00890 00891 _ClientToScreen(pwnd, (LPPOINT)&pt); 00892 ht = FindNCHit(pwnd, POINTTOPOINTS(pt)); 00893 00894 switch (message) { 00895 00896 case WM_KEYDOWN: 00897 if (pmsd->cmd == WMSZ_MOVE) { 00898 xxxSendMessage(pwnd, 00899 WM_SETCURSOR, 00900 (WPARAM)HW(pwnd), 00901 MAKELONG(WMSZ_KEYSIZE, WM_MOUSEMOVE)); 00902 } 00903 /* keys below are only allowed */ 00904 switch (wParam) { 00905 case VK_RETURN: 00906 case VK_ESCAPE: 00907 case VK_LEFT: 00908 case VK_RIGHT: 00909 case VK_UP: 00910 case VK_DOWN: 00911 pmsd->fInitSize = FALSE; 00912 break; 00913 } 00914 return TRUE; 00915 00916 case WM_LBUTTONDOWN: 00917 if (!PtInRect(&pmsd->rcDrag, pt)) { 00918 00919 /* 00920 *** FALL THRU *** 00921 */ 00922 00923 case WM_LBUTTONUP: 00924 00925 /* 00926 * Cancel everything. 00927 */ 00928 { 00929 PTHREADINFO ptiCurrent = PtiCurrent(); 00930 00931 bSetDevDragRect(gpDispInfo->hDev, NULL, NULL); 00932 if (ptiCurrent->TIF_flags & TIF_TRACKRECTVISIBLE) { 00933 xxxDrawDragRect(pmsd, NULL, DDR_ENDCANCEL); 00934 ptiCurrent->TIF_flags &= ~TIF_TRACKRECTVISIBLE; 00935 } 00936 00937 pmsd->fInitSize = FALSE; 00938 zzzClipCursor(NULL); 00939 } 00940 00941 xxxReleaseCapture(); 00942 pmsd->fTrackCancelled = TRUE; 00943 return FALSE; 00944 00945 } else { 00946 00947 /* 00948 * Now start hit testing for a border. 00949 */ 00950 goto CheckFrame; 00951 } 00952 00953 case WM_MOUSEMOVE: 00954 00955 /* 00956 * The mouse is down, hit test for a border on mouse moves. 00957 */ 00958 if (wParam == MK_LBUTTON) { 00959 00960 CheckFrame: 00961 00962 switch (pmsd->cmd) { 00963 case WMSZ_MOVE: 00964 00965 /* 00966 * If we are on the caption bar, exit. 00967 */ 00968 if (ht == HTCAPTION) { 00969 00970 /* 00971 * Change the mouse cursor. 00972 */ 00973 xxxSendMessage(pwnd, 00974 WM_SETCURSOR, 00975 (WPARAM)HW(pwnd), 00976 MAKELONG(WMSZ_KEYSIZE, WM_MOUSEMOVE)); 00977 00978 pmsd->dxMouse = pmsd->rcWindow.left - pt.x; 00979 pmsd->dyMouse = pmsd->rcWindow.top - pt.y; 00980 pmsd->fInitSize = FALSE; 00981 return TRUE; 00982 } 00983 break; 00984 00985 case WMSZ_KEYSIZE: 00986 00987 /* 00988 * If we are on a frame control, change the cursor and exit. 00989 */ 00990 if (ht >= HTSIZEFIRST && ht <= HTSIZELAST) { 00991 00992 /* 00993 * Change the mouse cursor 00994 */ 00995 xxxSendMessage(pwnd, 00996 WM_SETCURSOR, 00997 (WPARAM)HW(pwnd), 00998 MAKELONG(ht, WM_MOUSEMOVE)); 00999 01000 pmsd->fInitSize = FALSE; 01001 01002 /* 01003 * Set the proper cmd for SizeRect(). 01004 * 01005 * HACK! Depends on order of HTSIZE* defines! 01006 */ 01007 pmsd->impx = rgcmdmpix[ht - HTSIZEFIRST + 1]; 01008 pmsd->impy = rgcmdmpiy[ht - HTSIZEFIRST + 1]; 01009 pmsd->cmd = pmsd->impx + pmsd->impy; 01010 01011 pmsd->dxMouse = *((UINT FAR *)&pmsd->rcWindow + rgimpiwx[pmsd->cmd]) - pt.x; 01012 pmsd->dyMouse = *((UINT FAR *)&pmsd->rcWindow + rgimpiwy[pmsd->cmd]) - pt.y; 01013 01014 return TRUE; 01015 } 01016 } 01017 01018 } else { 01019 01020 /* 01021 * If button not down, and we are moving the window, change the 01022 * cursor shape depending upon where the mouse is pointing. This 01023 * allows the cursor to change to the arrows when over the window 01024 * frame. 01025 */ 01026 CopyRect(&rc, &pwnd->rcWindow); 01027 if (PtInRect(&rc, pt)) { 01028 if ((ht >= HTSIZEFIRST) && (ht <= HTSIZELAST)) { 01029 xxxSendMessage(pwnd, 01030 WM_SETCURSOR, 01031 (WPARAM)HW(pwnd), 01032 MAKELONG(ht, WM_MOUSEMOVE)); 01033 01034 break; 01035 } 01036 } 01037 01038 zzzSetCursor(SYSCUR(SIZEALL)); 01039 } 01040 break; 01041 } 01042 01043 return TRUE; 01044 } 01045 01046 /***************************************************************************\ 01047 * xxxMoveSize 01048 * 01049 * History: 01050 * 12-Nov-1990 MikeHar Ported from win3 01051 \***************************************************************************/ 01052 01053 VOID xxxMoveSize( 01054 PWND pwnd, 01055 UINT cmdMove, 01056 DWORD wptStart) 01057 { 01058 MSG msg; 01059 int x; 01060 int y; 01061 int i; 01062 RECT rcSys; 01063 PTHREADINFO ptiCurrent = PtiCurrent(); 01064 PMOVESIZEDATA pmsd; 01065 TL tlpwndT; 01066 PWND pwndT; 01067 POINT ptStart; 01068 MINMAXINFO mmi; 01069 01070 CheckLock(pwnd); 01071 UserAssert(IsWinEventNotifyDeferredOK()); 01072 01073 /* 01074 * Don't allow the app to track a window 01075 * from another queue. 01076 */ 01077 if (GETPTI(pwnd)->pq != ptiCurrent->pq) 01078 return; 01079 01080 if (ptiCurrent->pmsd != NULL) 01081 return; 01082 01083 /* 01084 * If the window with the focus is a combobox, hide the dropdown 01085 * listbox before tracking starts. The dropdown listbox is not a 01086 * child of the window being moved, therefore it won't be moved along 01087 * with the window. 01088 * 01089 * NOTE: Win 3.1 doesn't perform this check. 01090 */ 01091 if ((pwndT = ptiCurrent->pq->spwndFocus) != NULL) { 01092 01093 if (GETFNID(pwndT) == FNID_COMBOBOX) { 01094 ; 01095 } else if ((pwndT->spwndParent != NULL) && 01096 (GETFNID(pwndT->spwndParent) == FNID_COMBOBOX)) { 01097 01098 pwndT = pwndT->spwndParent; 01099 } else { 01100 pwndT = NULL; 01101 } 01102 01103 if (pwndT != NULL) { 01104 ThreadLockAlwaysWithPti(ptiCurrent, pwndT, &tlpwndT); 01105 xxxSendMessage(pwndT, CB_SHOWDROPDOWN, FALSE, 0); 01106 ThreadUnlock(&tlpwndT); 01107 } 01108 } 01109 01110 /* 01111 * Allocate and zero the movesize data structure 01112 */ 01113 pmsd = (PMOVESIZEDATA)UserAllocPoolWithQuotaZInit( 01114 sizeof(MOVESIZEDATA), TAG_MOVESIZE); 01115 01116 if (pmsd == NULL) 01117 return; 01118 01119 /* 01120 * Assign the move data into the pti. If the thread is destroyed before 01121 * we free the data the DestroyThreadInfo() routine will free the move data 01122 */ 01123 ptiCurrent->pmsd = pmsd; 01124 01125 Lock(&(pmsd->spwnd), pwnd); 01126 01127 /* 01128 * Set fForeground so we know whether to draw or not. 01129 */ 01130 pmsd->fForeground = (ptiCurrent->pq == gpqForeground) ? TRUE : FALSE; 01131 01132 /* 01133 * Lower the priority of the thread doing the dragging to make sure 01134 * that we don't starve other threads and they get to repaint more often. 01135 */ 01136 if (ptiCurrent == gptiForeground) { 01137 SetForegroundPriority(ptiCurrent, FALSE); 01138 } 01139 01140 /* 01141 * Get the client and window rects. 01142 */ 01143 CopyRect(&pmsd->rcWindow, &pwnd->rcWindow); 01144 01145 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 01146 if ( TestWF(pwnd, WEFTOPMOST) || 01147 TestWF(pwnd, WEFTOOLWINDOW) || 01148 gpDispInfo->cMonitors > 1) { 01149 01150 pmsd->rcParent = gpDispInfo->rcScreen; 01151 } else { 01152 pmsd->rcParent = GetPrimaryMonitor()->rcWork; 01153 } 01154 } else { 01155 CopyRect(&pmsd->rcParent, &pwnd->spwndParent->rcClient); 01156 01157 /* 01158 * If the parent does have a region, intersect with its bounding rect. 01159 */ 01160 if (pwnd->spwndParent->hrgnClip != NULL) { 01161 01162 RECT rcT; 01163 01164 GreGetRgnBox(pwnd->spwndParent->hrgnClip, &rcT); 01165 IntersectRect(&pmsd->rcParent, &pmsd->rcParent, &rcT); 01166 } 01167 } 01168 01169 /* 01170 * This works for multiple monitors _and_ regional windows 01171 */ 01172 if (pwnd->spwndParent->hrgnClip) { 01173 pmsd->fOffScreen = !GreRectInRegion(pwnd->spwndParent->hrgnClip, &pmsd->rcWindow); 01174 } else { 01175 pmsd->fOffScreen = !IntersectRect(&rcSys, &pmsd->rcWindow, &pmsd->rcParent); 01176 } 01177 01178 /* 01179 * No need to DeferWinEventNotify(), judging by xxxInitSendValidateMinMaxInfo below 01180 */ 01181 zzzClipCursor(&pmsd->rcParent); 01182 CopyRect(&rcSys, &pmsd->rcWindow); 01183 01184 if (TestWF(pwnd, WFMINIMIZED)) { 01185 01186 /* 01187 * No need to send WM_GETMINMAXINFO since we know the minimized size. 01188 */ 01189 pmsd->ptMinTrack.x = pmsd->ptMaxTrack.x = SYSMET(CXMINIMIZED); 01190 pmsd->ptMinTrack.y = pmsd->ptMaxTrack.y = SYSMET(CYMINIMIZED); 01191 01192 } else { 01193 xxxInitSendValidateMinMaxInfo(pwnd, &mmi); 01194 pmsd->ptMinTrack = mmi.ptMinTrackSize; 01195 pmsd->ptMaxTrack = mmi.ptMaxTrackSize; 01196 } 01197 01198 /* 01199 * Set up the drag rectangle. 01200 */ 01201 CopyRect(&pmsd->rcDrag, &pmsd->rcWindow); 01202 CopyRect(&pmsd->rcDragCursor, &pmsd->rcDrag); 01203 01204 ptStart.x = LOSHORT(wptStart); 01205 ptStart.y = HISHORT(wptStart); 01206 01207 /* 01208 * Assume Move/Size from mouse. 01209 */ 01210 pmsd->fInitSize = FALSE; 01211 pmsd->fmsKbd = FALSE; 01212 01213 /* 01214 * Get the mouse position for this move/size command. 01215 */ 01216 switch (pmsd->cmd = cmdMove) { 01217 case WMSZ_KEYMOVE: 01218 pmsd->cmd = cmdMove = WMSZ_MOVE; 01219 01220 /* 01221 ** FALL THRU ** 01222 */ 01223 01224 case WMSZ_KEYSIZE: 01225 /* 01226 * No need to DeferWinEventNotify() - pmsd won't go away, and pwnd is locked 01227 */ 01228 zzzSetCursor(SYSCUR(SIZEALL)); 01229 01230 if (!TestWF(pwnd, WFMINIMIZED)) 01231 pmsd->fInitSize = TRUE; 01232 01233 /* 01234 * Workaround: always behave as if the command is 01235 * issued using keyboard. 01236 * if it's found as the wrong way, the behavior is defined as: 01237 * if (mnFocus == KEYBDHOLD) || 01238 * ((mnFocus == MOUSEHOLD) && TestWF(pwnd, WFMINIMIZED))) { 01239 * In order to do this, mnFocus should be saved somewhere. 01240 * originally, mnFocus was saved in MenuState. 01241 */ 01242 pmsd->fmsKbd = TRUE; 01243 pmsd->ptRestore.x = LOSHORT(wptStart); 01244 pmsd->ptRestore.y = HISHORT(wptStart); 01245 01246 /* 01247 * Center cursor in caption area of window 01248 */ 01249 01250 /* 01251 * Horizontally 01252 */ 01253 ptStart.x = (pmsd->rcDrag.left + pmsd->rcDrag.right) / 2; 01254 01255 /* 01256 * Vertically 01257 */ 01258 if (TestWF(pwnd,WFMINIMIZED) || (pmsd->cmd != WMSZ_MOVE)) { 01259 ptStart.y = (pmsd->rcDrag.top + pmsd->rcDrag.bottom) / 2; 01260 } else { 01261 int dy; 01262 01263 dy = GetCaptionHeight(pwnd); 01264 ptStart.y = pmsd->rcDrag.top + SYSMET(CYFIXEDFRAME) + dy / 2; 01265 } 01266 01267 zzzInternalSetCursorPos(ptStart.x, ptStart.y); 01268 xxxMS_FlushWigglies(); 01269 break; 01270 01271 default: 01272 break; 01273 } 01274 01275 pmsd->fDragFullWindows = TEST_BOOL_PUDF(PUDF_DRAGFULLWINDOWS); 01276 SET_OR_CLEAR_PUDF(PUDF_DRAGGINGFULLWINDOW, pmsd->fDragFullWindows); 01277 01278 /* 01279 * If we hit with the mouse, set up impx and impy so that we 01280 * can use the keyboard too. 01281 */ 01282 pmsd->impx = rgcmdmpix[cmdMove]; 01283 pmsd->impy = rgcmdmpiy[cmdMove]; 01284 01285 /* 01286 * Setup dxMouse and dyMouse - If we're sizing with the keyboard these 01287 * guys are set to zero down in the keyboard code. 01288 */ 01289 if ((i = rgimpiwx[cmdMove]) != (-1)) 01290 pmsd->dxMouse = *((int *)&pmsd->rcWindow + (short)i) - ptStart.x; 01291 01292 if ((i = rgimpiwy[cmdMove]) != (-1)) 01293 pmsd->dyMouse = *((int *)&pmsd->rcWindow + (short)i) - ptStart.y; 01294 01295 /* 01296 * Tell Gdi the width of the drag rect (if its a special size) 01297 * Turn the drag rect on. 0 specifies start drag. 01298 */ 01299 if (!TestWF(pwnd, WFSIZEBOX)) 01300 bSetDevDragWidth(gpDispInfo->hDev, 1); 01301 01302 if (FWINABLE()) { 01303 xxxWindowEvent(EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0); 01304 } 01305 01306 xxxDrawDragRect(pmsd, NULL, DDR_START); 01307 ptiCurrent->TIF_flags |= TIF_TRACKRECTVISIBLE; 01308 01309 msg.lParam = MAKELONG(ptStart.x, ptStart.y); 01310 01311 /* 01312 * Right here win3.1 calls LockWindowUpdate(). This calls zzzSetFMouseMoved() 01313 * which ensures that the next message in the queue is a mouse message. 01314 * We need that mouse message as the first message because the first 01315 * call to TrackInitSize() assumes that lParam is an x, y from a mouse 01316 * message - scottlu. 01317 */ 01318 zzzSetFMouseMoved(); 01319 01320 /* 01321 * Send this message for winoldapp support 01322 */ 01323 xxxSendMessage(pwnd, WM_ENTERSIZEMOVE, 0L, 0L); 01324 xxxCapture(ptiCurrent, pwnd, CLIENT_CAPTURE_INTERNAL); 01325 01326 /* 01327 * Show the move cursor for non-mouse systems. 01328 */ 01329 zzzShowCursor(TRUE); 01330 01331 while (!(pmsd->fTrackCancelled)) { 01332 01333 /* 01334 * Let other messages not related to dragging be dispatched 01335 * to the application window. 01336 * In the case of clock, clock will now receive messages to 01337 * update the time displayed instead of having the time display 01338 * freeze while we are dragging. 01339 */ 01340 while (ptiCurrent->pq->spwndCapture == pwnd) { 01341 01342 if (xxxPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 01343 01344 if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) 01345 || (msg.message == WM_QUEUESYNC) 01346 || (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)) { 01347 01348 break; 01349 } 01350 01351 if (_CallMsgFilter(&msg, cmdMove == WMSZ_MOVE ? MSGF_MOVE : MSGF_SIZE)) { 01352 continue; 01353 } 01354 01355 xxxTranslateMessage(&msg, 0); 01356 /* 01357 * To prevent applications from doing 01358 * a PeekMessage loop and getting the mouse move messages that 01359 * are destined for the xxxMoveSize PeekMessage loop, we OR in 01360 * this flag. See comments in input.c for xxxInternalGetMessage. 01361 */ 01362 ptiCurrent->TIF_flags |= TIF_MOVESIZETRACKING; 01363 xxxDispatchMessage(&msg); 01364 ptiCurrent->TIF_flags &= ~TIF_MOVESIZETRACKING; 01365 01366 } else { 01367 /* 01368 * If we've been cancelled by someone else, or our pwnd 01369 * has been destroyed, blow out of here. 01370 */ 01371 if (pmsd->fTrackCancelled) 01372 break; 01373 01374 if (!xxxWaitMessage()) 01375 break; 01376 } 01377 } 01378 01379 /* 01380 * If we've lost capture while tracking, 01381 * cancel the move/size operation. 01382 */ 01383 if (ptiCurrent->pq->spwndCapture != pwnd) { 01384 01385 /* 01386 * Fake a key-down of the escape key to cancel. 01387 */ 01388 xxxMS_TrackMove(pwnd, WM_KEYDOWN, (DWORD)VK_ESCAPE, 1, pmsd); 01389 goto MoveSizeCleanup; 01390 } 01391 01392 /* 01393 * If we've been cancelled by someone else, or our pwnd 01394 * has been destroyed, blow out of here. 01395 */ 01396 if (pmsd->fTrackCancelled) { 01397 pmsd->fTrackCancelled = FALSE; 01398 goto MoveSizeCleanup; 01399 } 01400 01401 /* 01402 * If we get a WM_QUEUESYNC, let the CBT hook know. 01403 */ 01404 if (msg.message == WM_QUEUESYNC) { 01405 xxxCallHook(HCBT_QS, 0, 0, WH_CBT); 01406 } 01407 01408 if (pmsd->fInitSize) { 01409 if (!xxxTrackInitSize(pwnd, msg.message, msg.wParam, msg.lParam, 01410 pmsd)) { 01411 break; 01412 } 01413 } 01414 01415 /* 01416 * Convert captured mouse into screen coordinates. 01417 */ 01418 x = msg.pt.x + pmsd->dxMouse; 01419 y = msg.pt.y + pmsd->dyMouse; 01420 01421 /* 01422 * This is checked twice so the same message is not processed both 01423 * places. 01424 */ 01425 if (!pmsd->fInitSize) { 01426 xxxMS_TrackMove(pwnd, msg.message, msg.wParam, MAKELONG(x, y), 01427 pmsd); 01428 } 01429 } 01430 01431 MoveSizeCleanup: 01432 01433 /* 01434 * Reset priority if still in the foreground thread. 01435 */ 01436 01437 if (ptiCurrent == gptiForeground) { 01438 SetForegroundPriority(ptiCurrent, TRUE); 01439 } 01440 01441 /* 01442 * Reset the border size if it was abnormal 01443 */ 01444 01445 if (!TestWF(pwnd, WFSIZEBOX)) 01446 bSetDevDragWidth(gpDispInfo->hDev, gpsi->gclBorder + BORDER_EXTRA); 01447 01448 /* 01449 * Revalidation: If pwnd is deleted unexpectedly, jump here to cleanup. 01450 */ 01451 01452 bSetDevDragRect(gpDispInfo->hDev, NULL, NULL); 01453 ptiCurrent->TIF_flags &= ~(TIF_TRACKRECTVISIBLE); 01454 01455 if (pmsd->fDragFullWindows) { 01456 if (ghrgnUpdateSave != NULL) { 01457 GreDeleteObject(ghrgnUpdateSave); 01458 ghrgnUpdateSave = NULL; 01459 gnUpdateSave = 0; 01460 } 01461 } 01462 01463 CLEAR_PUDF(PUDF_DRAGGINGFULLWINDOW); 01464 01465 ptiCurrent->pmsd = NULL; 01466 01467 Unlock(&pmsd->spwnd); 01468 01469 01470 zzzShowCursor(FALSE); 01471 01472 /* 01473 * Free the move/size data structure 01474 */ 01475 UserFreePool(pmsd); 01476 } 01477 01478 /***************************************************************************\ 01479 * This calls xxxRedrawHungWindow() on windows that do not belong to this thread. 01480 * 01481 * History: 01482 * 27-May-1994 johannec 01483 \***************************************************************************/ 01484 01485 VOID xxxUpdateOtherThreadsWindows( 01486 PWND pwnd, 01487 HRGN hrgnFullDrag) 01488 { 01489 PWND pwndChild; 01490 TL tlpwndChild; 01491 PTHREADINFO ptiCurrent = PtiCurrent(); 01492 01493 CheckLock(pwnd); 01494 01495 xxxRedrawHungWindow(pwnd, hrgnFullDrag); 01496 01497 /* 01498 * If the parent window does not have the flag WFCLIPCHILDREN set, 01499 * there is no need to redraw its children. 01500 */ 01501 if (!TestWF(pwnd, WFCLIPCHILDREN)) 01502 return; 01503 01504 pwndChild = pwnd->spwndChild; 01505 ThreadLockNever(&tlpwndChild); 01506 while (pwndChild != NULL) { 01507 ThreadLockExchangeAlways(pwndChild, &tlpwndChild); 01508 xxxUpdateOtherThreadsWindows(pwndChild, hrgnFullDrag); 01509 pwndChild = pwndChild->spwndNext; 01510 } 01511 01512 ThreadUnlock(&tlpwndChild); 01513 } 01514 01515 /***************************************************************************\ 01516 * This calls UpdateWindow() on every window that is owned by this thread 01517 * and calls xxxRedrawHungWindow() for windows owned by other threads. 01518 * 01519 * History: 01520 * 28-Sep-1993 mikeke Created 01521 \***************************************************************************/ 01522 01523 VOID xxxUpdateThreadsWindows( 01524 PTHREADINFO pti, 01525 PWND pwnd, 01526 HRGN hrgnFullDrag) 01527 { 01528 TL tlpwnd; 01529 01530 CheckLock(pwnd); 01531 01532 ThreadLockNever(&tlpwnd); 01533 while (pwnd != NULL) { 01534 ThreadLockExchangeAlways(pwnd, &tlpwnd); 01535 if (GETPTI(pwnd) == pti) { 01536 xxxUpdateWindow(pwnd); 01537 } else { 01538 xxxUpdateOtherThreadsWindows(pwnd, hrgnFullDrag); 01539 } 01540 01541 pwnd = pwnd->spwndNext; 01542 } 01543 01544 ThreadUnlock(&tlpwnd); 01545 } 01546 01547 /***************************************************************************\ 01548 * xxxDrawDragRect 01549 * 01550 * Draws the drag rect for sizing and moving windows. When moving windows, 01551 * can move full windows including client area. lprc new rect to move to. 01552 * if lprc is null, flags specify why. 01553 * 01554 * flags: DDR_START 0 - start drag. 01555 * DDR_ENDACCEPT 1 - end and accept 01556 * DDR_ENDCANCEL 2 - end and cancel. 01557 * 01558 * History: 01559 * 07-29-91 darrinm Ported from Win 3.1 sources. 01560 \***************************************************************************/ 01561 01562 VOID xxxDrawDragRect( 01563 PMOVESIZEDATA pmsd, 01564 LPRECT lprc, 01565 UINT type) 01566 { 01567 HDC hdc; 01568 int lvBorder; 01569 HRGN hrgnClip; 01570 01571 /* 01572 * If we're dragging an icon, or we're not foreground, don't draw 01573 * the dragging rect. 01574 */ 01575 if (!pmsd->fForeground) { 01576 01577 if (lprc != NULL) 01578 CopyRect(&pmsd->rcDrag, lprc); 01579 01580 return; 01581 } 01582 01583 /* 01584 * If it already equals, just return. 01585 */ 01586 if ((lprc != NULL) && EqualRect(&pmsd->rcDrag, lprc)) 01587 return; 01588 01589 if (!(pmsd->fDragFullWindows)) { 01590 01591 /* 01592 * If we were not able to lock the screen (because some other process 01593 * or thread had the screen locked), then get a dc but make sure 01594 * it is totally clipped to nothing. 01595 * NO longer a posibility 01596 */ 01597 01598 /* 01599 * Clip to client rect of parent. (Client given in screen coords.) 01600 */ 01601 hrgnClip = GreCreateRectRgnIndirect(&pmsd->rcParent); 01602 01603 /* 01604 * Clip to the parent's window clipping rgn if it has one. 01605 */ 01606 if (hrgnClip != NULL && pmsd->spwnd->spwndParent->hrgnClip != NULL) 01607 IntersectRgn(hrgnClip, 01608 hrgnClip, 01609 pmsd->spwnd->spwndParent->hrgnClip); 01610 01611 if (hrgnClip == NULL) 01612 hrgnClip = HRGN_FULL; 01613 01614 /* 01615 * If lprc == NULL, just draw rcDrag once. If lprc != NULL, 01616 * undraw *lprc, draw rcDrag, copy in *lprc. 01617 */ 01618 01619 /* 01620 * Use size 1 for minimized or non-sizeable windows. Otherwise 01621 * use the # of borders (2 for outer edge, 1 for border, clBorder for 01622 * size border. 01623 */ 01624 if (TestWF(pmsd->spwnd, WFMINIMIZED) || !TestWF(pmsd->spwnd, WFSIZEBOX)) 01625 lvBorder = 1; 01626 else 01627 lvBorder = 3 + gpsi->gclBorder; 01628 01629 /* 01630 * Get a screen DC clipped to the parent, select in a gray brush. 01631 */ 01632 hdc = _GetDCEx( 01633 PWNDDESKTOP(pmsd->spwnd), 01634 hrgnClip, 01635 DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE); 01636 01637 if (lprc != NULL) { 01638 01639 /* 01640 * Move the frame to a new location by delta drawing 01641 */ 01642 GreLockDisplay(gpDispInfo->hDev); 01643 bMoveDevDragRect(gpDispInfo->hDev, (PRECTL) lprc); 01644 CopyRect(&pmsd->rcDrag, lprc); 01645 GreUnlockDisplay(gpDispInfo->hDev); 01646 01647 } else { 01648 01649 if (type == DDR_START) { 01650 bSetDevDragRect(gpDispInfo->hDev, 01651 (PRECTL)&pmsd->rcDrag, 01652 (PRECTL)&pmsd->rcParent); 01653 } 01654 } 01655 01656 /* 01657 * Release the DC & delete hrgnClip 01658 */ 01659 _ReleaseDC(hdc); 01660 01661 } else { 01662 01663 RECT rcSWP; 01664 HRGN hrgnFullDragNew; 01665 HRGN hrgnFullDragOld; 01666 PTHREADINFO ptiCancel = GETPTI(pmsd->spwnd); 01667 PTHREADINFO ptiCurrent = PtiCurrent(); 01668 PWND pwnd; 01669 TL tlpwnd; 01670 01671 #if DBG 01672 /* 01673 * If ptiCancel != ptiCurrent, we must have come from xxxCancelTracking, 01674 * which has already locked ptiCancel. 01675 */ 01676 if (ptiCancel != ptiCurrent) { 01677 CheckLock(ptiCancel); 01678 } 01679 #endif 01680 01681 /* 01682 * To prevent applications (like Micrografx Draw) from doing 01683 * a PeekMessage loop and getting the mouse move messages that 01684 * are destined for the xxxMoveSize PeekMessage loop, we OR in 01685 * this flag. See comments in input.c for xxxInternalGetMessage. 01686 */ 01687 ptiCancel->TIF_flags |= TIF_MOVESIZETRACKING; 01688 01689 if (lprc != NULL) 01690 CopyRect(&(pmsd->rcDrag), lprc); 01691 01692 CopyRect(&rcSWP, &(pmsd->rcDrag)); 01693 01694 /* 01695 * Convert coordinates to client if the window is a child window or 01696 * if it's a popup-with parent. The test for the popup is necessary 01697 * to solve a problem where a popup was assigned a parent of a MDI- 01698 * CLIENT window. 01699 */ 01700 if (pmsd->spwnd->spwndParent != NULL && !FTopLevel(pmsd->spwnd)) { 01701 _ScreenToClient(pmsd->spwnd->spwndParent, (LPPOINT)&rcSWP); 01702 _ScreenToClient(pmsd->spwnd->spwndParent, ((LPPOINT)&rcSWP)+1); 01703 01704 #if defined(USE_MIRRORING) 01705 // 01706 // If the parent of this window is mirrored, then mirror the 01707 // rectangle coordinates so that child MDI windows work 01708 // properly 01709 // 01710 if( TestWF(pmsd->spwnd->spwndParent,WEFLAYOUTRTL) ) 01711 { 01712 int iLeft = rcSWP.left; 01713 rcSWP.left = rcSWP.right; 01714 rcSWP.right = iLeft; 01715 } 01716 #endif 01717 } 01718 01719 /* 01720 * Don't bother being optimal here. There's one case where we 01721 * really shouldn't blow away the SPB--the window is being sized 01722 * bigger. We do want to do this when moving or sizing the window 01723 * smaller. Why bother detecting the first case? 01724 */ 01725 if (TestWF(pmsd->spwnd, WFHASSPB)){ 01726 01727 PSPB pspb; 01728 RECT rc; 01729 01730 /* 01731 * If we're intersecting the original window rect and the window 01732 * has an SPB saved onboard, then just free it. Otherwise the 01733 * window will move, the entire SPB will blt over it, we'll 01734 * invalidate the intersection, and the window will repaint, 01735 * causing mad flicker. 01736 */ 01737 pspb = FindSpb(pmsd->spwnd); 01738 01739 CopyRect(&rc, &pmsd->spwnd->rcWindow); 01740 if (lprc && IntersectRect(&rc, &rc, lprc)){ 01741 FreeSpb(pspb); 01742 } 01743 } 01744 01745 hrgnFullDragOld = GreCreateRectRgnIndirect(&pmsd->spwnd->rcWindow); 01746 01747 if (pmsd->spwnd->hrgnClip != NULL) 01748 IntersectRgn(hrgnFullDragOld, 01749 hrgnFullDragOld, 01750 pmsd->spwnd->hrgnClip); 01751 01752 xxxSetWindowPos(pmsd->spwnd, 01753 NULL, 01754 rcSWP.left, rcSWP.top, 01755 rcSWP.right-rcSWP.left, rcSWP.bottom-rcSWP.top, 01756 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); 01757 01758 /* 01759 * We locked ptiCancel, so ptiCancel->pmsd has not been unexpectedly 01760 * freed in DeleteThreadInfo(), but xxxMoveSize() may have terminated 01761 * during our callback to xxxSetWindowPos and freed the pmsd there. 01762 */ 01763 if (ptiCancel->pmsd != pmsd) { 01764 RIPMSG3(RIP_ERROR, 01765 "xxxDrawDragRect: ptiCancel(%#p)->pmsd(%#p) != pmsd(%#p)\n", 01766 ptiCancel, ptiCancel->pmsd, pmsd); 01767 goto CleanupAfterPmsdDisappearance; 01768 } 01769 hrgnFullDragNew = GreCreateRectRgnIndirect(&pmsd->spwnd->rcWindow); 01770 01771 if (pmsd->spwnd->hrgnClip != NULL) { 01772 IntersectRgn(hrgnFullDragNew, 01773 hrgnFullDragNew, 01774 pmsd->spwnd->hrgnClip); 01775 } 01776 01777 /* 01778 * Set the full drag update region that is used in xxxRedrawHungWindow. 01779 */ 01780 if (hrgnFullDragNew == NULL) { 01781 01782 /* 01783 * We couldn't create the new full drag region so don't 01784 * use the full drag region to xxxRedrawHungWindow. Using 01785 * NULL with force a redraw of the entire window's hrgnUpdate. 01786 * (which is what we used to do, overdrawing but at least 01787 * covering the invalidated areas). 01788 */ 01789 if (hrgnFullDragOld != NULL) { 01790 GreDeleteObject(hrgnFullDragOld); 01791 hrgnFullDragOld = NULL; 01792 } 01793 01794 } else { 01795 01796 if (hrgnFullDragOld != NULL) { 01797 01798 /* 01799 * Subtract the new window rect from the old window rect 01800 * to create the update region caused by the drag. 01801 */ 01802 SubtractRgn(hrgnFullDragOld, hrgnFullDragOld, hrgnFullDragNew); 01803 } 01804 } 01805 01806 pwnd = PWNDDESKTOP(pmsd->spwnd)->spwndChild; 01807 ThreadLock(pwnd, &tlpwnd); 01808 xxxUpdateThreadsWindows(ptiCurrent, pwnd, hrgnFullDragOld); 01809 ThreadUnlock(&tlpwnd); 01810 01811 GreDeleteObject(hrgnFullDragNew); 01812 01813 CleanupAfterPmsdDisappearance: 01814 GreDeleteObject(hrgnFullDragOld); 01815 01816 ptiCancel->TIF_flags &= ~TIF_MOVESIZETRACKING; 01817 } 01818 } 01819 01820 /***************************************************************************\ 01821 * xxxCancelTrackingForThread 01822 * 01823 * 01824 \***************************************************************************/ 01825 01826 VOID xxxCancelTrackingForThread( 01827 PTHREADINFO ptiCancel) 01828 { 01829 PMOVESIZEDATA pmsdCancel; 01830 01831 UserAssert(ptiCancel); 01832 01833 /* 01834 * If this thread isn't around any more, skip it. 01835 */ 01836 if (ptiCancel == NULL) 01837 return; 01838 01839 if ((pmsdCancel = ptiCancel->pmsd) != NULL) { 01840 01841 /* 01842 * Found one, now stop tracking. 01843 */ 01844 pmsdCancel->fTrackCancelled = TRUE; 01845 01846 /* 01847 * Only remove the tracking rectangle if it's 01848 * been made visible. 01849 */ 01850 if (ptiCancel->TIF_flags & TIF_TRACKRECTVISIBLE) { 01851 bSetDevDragRect(gpDispInfo->hDev, NULL, NULL); 01852 if (!(pmsdCancel->fDragFullWindows)) { 01853 xxxDrawDragRect(pmsdCancel, NULL, DDR_ENDCANCEL); 01854 } 01855 } 01856 01857 /* 01858 * Leave TIF_TRACKING set to prevent xxxMoveSize() 01859 * recursion. 01860 */ 01861 ptiCancel->TIF_flags &= ~TIF_TRACKRECTVISIBLE; 01862 if (ptiCancel->pq) { 01863 SetWakeBit(ptiCancel, QS_MOUSEMOVE); 01864 } 01865 01866 /* 01867 * If the tracking window is still in menuloop, send the 01868 * WM_CANCELMODE message so that it can exit the menu. 01869 * This fixes the bug where we have 2 icons with their 01870 * system menu up. 01871 * 8/5/94 johannec 01872 */ 01873 if (IsInsideMenuLoop(ptiCancel) && ptiCancel->pmsd) 01874 _PostMessage(ptiCancel->pmsd->spwnd, WM_CANCELMODE, 0, 0); 01875 01876 /* 01877 * Turn off capture 01878 */ 01879 xxxCapture(ptiCancel, NULL, NO_CAP_CLIENT); 01880 } 01881 } 01882 01883 /***************************************************************************\ 01884 * xxxCancelTracking 01885 * 01886 * 01887 \***************************************************************************/ 01888 01889 #define MAX_THREADS 12 01890 01891 VOID xxxCancelTracking(VOID) 01892 { 01893 PTHREADINFO pti; 01894 PTHREADINFO ptiList[MAX_THREADS]; 01895 TL tlptiList[MAX_THREADS]; 01896 TL tlspwndList[MAX_THREADS]; 01897 UINT cThreads = 0; 01898 INT i; 01899 PLIST_ENTRY pHead; 01900 PLIST_ENTRY pEntry; 01901 PTHREADINFO ptiCurrent = PtiCurrent(); 01902 01903 /* 01904 * Build a list of threads that we need to look at. We can't just 01905 * walk the pointer list while we're doing the work, because we 01906 * might leave the critical section and the pointer could get 01907 * deleted out from under us. 01908 */ 01909 pHead = &grpdeskRitInput->PtiList; 01910 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 01911 01912 pti = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 01913 01914 if (pti->pmsd != NULL) { 01915 01916 UserAssert(cThreads < MAX_THREADS); 01917 01918 if (cThreads < MAX_THREADS) { 01919 ThreadLockPti(ptiCurrent, pti, &tlptiList[cThreads]); 01920 ThreadLockAlwaysWithPti(ptiCurrent, pti->pmsd->spwnd, &tlspwndList[cThreads]); 01921 ptiList[cThreads++] = pti; 01922 } 01923 } 01924 } 01925 01926 /* 01927 * Walk the list backwards so the unlocks will be done in the right order. 01928 */ 01929 for (i = cThreads - 1; i >= 0; i--) { 01930 if (!(ptiList[i]->TIF_flags & TIF_INCLEANUP)) { 01931 xxxCancelTrackingForThread(ptiList[i]); 01932 } 01933 01934 ThreadUnlock(&tlspwndList[i]); 01935 ThreadUnlockPti(ptiCurrent, &tlptiList[i]); 01936 } 01937 }

Generated on Sat May 15 19:40:52 2004 for test by doxygen 1.3.7