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

cursor.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: cursor.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains code for dealing with cursors. 00007 * 00008 * History: 00009 * 03-Dec-1990 DavidPe Created. 00010 * 01-Feb-1991 MikeKe Added Revalidation code (None) 00011 * 12-Feb-1991 JimA Added access checks 00012 * 21-Jan-1992 IanJa ANSI/Unicode neutralized (null op) 00013 * 02-Aug-1992 DarrinM Added animated cursor code 00014 \***************************************************************************/ 00015 00016 #include "precomp.h" 00017 #pragma hdrstop 00018 00019 /***************************************************************************\ 00020 * zzzSetCursor (API) 00021 * 00022 * This API sets the cursor image for the current thread. 00023 * 00024 * History: 00025 * 12-03-90 DavidPe Created. 00026 \***************************************************************************/ 00027 00028 PCURSOR zzzSetCursor( 00029 PCURSOR pcur) 00030 { 00031 PQ pq; 00032 PCURSOR pcurPrev; 00033 PTHREADINFO ptiCurrent = PtiCurrent(); 00034 00035 pq = ptiCurrent->pq; 00036 00037 pcurPrev = pq->spcurCurrent; 00038 00039 if (pq->spcurCurrent != pcur) { 00040 00041 /* 00042 * Lock() returns pobjOld - if it is still valid. Don't want to 00043 * return a pcurPrev that is an invalid pointer. 00044 */ 00045 pcurPrev = LockQCursor(pq, pcur); 00046 00047 /* 00048 * If no thread 'owns' the cursor, we must be in initialization 00049 * so go ahead and assign it to ourself. 00050 */ 00051 if (gpqCursor == NULL) 00052 gpqCursor = pq; 00053 00054 /* 00055 * If we're changing the local-cursor for the thread currently 00056 * representing the global-cursor, update the cursor image now. 00057 */ 00058 if (pq == gpqCursor) { 00059 TL tlpcur; 00060 ThreadLockWithPti(ptiCurrent, pcurPrev, &tlpcur); 00061 zzzUpdateCursorImage(); 00062 pcurPrev = ThreadUnlock(&tlpcur); 00063 } 00064 } 00065 00066 return pcurPrev; 00067 } 00068 00069 /***************************************************************************\ 00070 * zzzSetCursorPos (API) 00071 * 00072 * This API sets the cursor position. 00073 * 00074 * History: 00075 * 03-Dec-1990 DavidPe Created. 00076 * 12-Feb-1991 JimA Added access check 00077 * 16-May-1991 mikeke Changed to return BOOL 00078 \***************************************************************************/ 00079 00080 BOOL zzzSetCursorPos( 00081 int x, 00082 int y) 00083 { 00084 /* 00085 * Blow it off if the caller doesn't have the proper access rights 00086 */ 00087 if (!CheckWinstaWriteAttributesAccess()) { 00088 return FALSE; 00089 } 00090 00091 zzzInternalSetCursorPos(x, y); 00092 00093 /* 00094 * Save the absolute coordinates in the global array 00095 * for GetMouseMovePointsEx. 00096 */ 00097 SAVEPOINT(x, y, 00098 SYSMET(CXVIRTUALSCREEN) - 1, 00099 SYSMET(CYVIRTUALSCREEN) - 1, 00100 NtGetTickCount(), 0); 00101 00102 return TRUE; 00103 } 00104 00105 /***************************************************************************\ 00106 * zzzInternalSetCursorPos 00107 * 00108 * This function is used whenever the server needs to set the cursor 00109 * position, regardless of the caller's access rights. 00110 * 00111 * History: 00112 * 12-Feb-1991 JimA Created. 00113 \***************************************************************************/ 00114 VOID zzzInternalSetCursorPos( 00115 int x, 00116 int y 00117 ) 00118 { 00119 00120 gptCursorAsync.x = x; 00121 gptCursorAsync.y = y; 00122 00123 BoundCursor(&gptCursorAsync); 00124 gpsi->ptCursor = gptCursorAsync; 00125 GreMovePointer(gpDispInfo->hDev, gpsi->ptCursor.x, gpsi->ptCursor.y); 00126 00127 /* 00128 * Cursor has changed position, so generate a mouse event so the 00129 * window underneath the new location knows it's there and sets the 00130 * shape accordingly. 00131 */ 00132 zzzSetFMouseMoved(); 00133 } 00134 00135 /***************************************************************************\ 00136 * IncCursorLevel 00137 * DecCursorLevel 00138 * 00139 * Keeps track of this thread show/hide cursor level as well as the queue 00140 * it is associated with. Thread levels are done so that when 00141 * AttachThreadInput() is called we can do exact level calculations in the 00142 * new queue. 00143 * 00144 * 15-Jan-1993 ScottLu Created. 00145 \***************************************************************************/ 00146 00147 VOID IncCursorLevel( 00148 PTHREADINFO pti) 00149 { 00150 pti->iCursorLevel++; 00151 pti->pq->iCursorLevel++; 00152 } 00153 00154 VOID DecCursorLevel( 00155 PTHREADINFO pti) 00156 { 00157 pti->iCursorLevel--; 00158 pti->pq->iCursorLevel--; 00159 } 00160 00161 /***************************************************************************\ 00162 * zzzShowCursor (API) 00163 * 00164 * This API allows the application to hide or show the cursor image. 00165 * 00166 * History: 00167 * 03-Dec-1990 JimA Implemented for fake cursor stuff 00168 \***************************************************************************/ 00169 00170 int zzzShowCursor( 00171 BOOL fShow) 00172 { 00173 PTHREADINFO pti = PtiCurrent(); 00174 PQ pq; 00175 int iCursorLevel; 00176 00177 pq = pti->pq; 00178 /* 00179 * To preserve pq 00180 */ 00181 DeferWinEventNotify(); 00182 00183 if (fShow) { 00184 00185 IncCursorLevel(pti); 00186 00187 if ((pq == gpqCursor) && (pq->iCursorLevel == 0)) 00188 zzzUpdateCursorImage(); 00189 00190 } else { 00191 00192 DecCursorLevel(pti); 00193 00194 if ((pq == gpqCursor) && (pq->iCursorLevel == -1)) 00195 zzzUpdateCursorImage(); 00196 } 00197 00198 iCursorLevel = pq->iCursorLevel; 00199 zzzEndDeferWinEventNotify(); 00200 00201 return iCursorLevel; 00202 } 00203 00204 /***************************************************************************\ 00205 * zzzClipCursor (API) 00206 * 00207 * This API sets the cursor clipping rectangle which restricts where the 00208 * cursor can go. If prcClip is NULL, the clipping rectangle will be the 00209 * screen. 00210 * 00211 * History: 00212 * 03-Dec-1990 DavidPe Created. 00213 * 16-May-1991 MikeKe Changed to return BOOL 00214 \***************************************************************************/ 00215 00216 BOOL zzzClipCursor( 00217 LPCRECT prcClip) 00218 { 00219 PEPROCESS Process = PsGetCurrentProcess(); 00220 00221 /* 00222 * Don't let this happen if it doesn't have access. 00223 */ 00224 if (Process != gpepCSRSS && !CheckWinstaWriteAttributesAccess()) { 00225 return FALSE; 00226 } 00227 00228 /* 00229 * The comment from NT 3.51: 00230 * Non-foreground threads can only set the clipping rectangle 00231 * if it was empty, or if they are restoring it to the whole screen. 00232 * 00233 * But the code from NT 3.51 says "IsRectEmpty" instead of 00234 * "!IsRectEmpty", as would follow from the comment. We leave 00235 * the code as it was, as following the comment appears to 00236 * break apps. 00237 * 00238 * CONSIDER: Removing this test altogether after NT4.0 ships. 00239 */ 00240 if ( PtiCurrent()->pq != gpqForeground && 00241 prcClip != NULL && 00242 IsRectEmpty(&grcCursorClip)) { 00243 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in _ClipCursor"); 00244 return FALSE; 00245 } 00246 00247 if (prcClip == NULL) { 00248 00249 grcCursorClip = gpDispInfo->rcScreen; 00250 00251 } else { 00252 00253 /* 00254 * Never let our cursor leave the screen. Can't use IntersectRect() 00255 * because it doesn't allow rects with 0 width or height. 00256 */ 00257 grcCursorClip.left = max(gpDispInfo->rcScreen.left , prcClip->left); 00258 grcCursorClip.right = min(gpDispInfo->rcScreen.right , prcClip->right); 00259 grcCursorClip.top = max(gpDispInfo->rcScreen.top , prcClip->top); 00260 grcCursorClip.bottom = min(gpDispInfo->rcScreen.bottom, prcClip->bottom); 00261 00262 /* 00263 * Check for invalid clip rect. 00264 */ 00265 if (grcCursorClip.left > grcCursorClip.right || 00266 grcCursorClip.top > grcCursorClip.bottom) { 00267 00268 grcCursorClip = gpDispInfo->rcScreen; 00269 } 00270 } 00271 00272 /* 00273 * Update the cursor position if it's currently outside the 00274 * cursor clip-rect. 00275 */ 00276 if (!PtInRect(&grcCursorClip, gpsi->ptCursor)) { 00277 zzzInternalSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y); 00278 } 00279 00280 return TRUE; 00281 } 00282 00283 /***************************************************************************\ 00284 * BoundCursor 00285 * 00286 * This rountine 'clips' gptCursorAsync to be within rcCursorClip. This 00287 * routine treats rcCursorClip as non-inclusive so the bottom and right sides 00288 * get bound to rcCursorClip.bottom/right - 1. 00289 * 00290 * Is called in OR out of the USER critical section!! IANJA 00291 * 00292 * History: 00293 * 03-Dec-1990 DavidPe Created. 00294 \***************************************************************************/ 00295 #ifdef LOCK_MOUSE_CODE 00296 #pragma alloc_text(MOUSE, BoundCursor) 00297 #endif 00298 00299 VOID BoundCursor( 00300 LPPOINT lppt) 00301 { 00302 if (TEST_PUDF(PUDF_VDMBOUNDSACTIVE) && gspwndFullScreen != NULL) { 00303 00304 if (lppt->x < grcVDMCursorBounds.left) { 00305 lppt->x = grcVDMCursorBounds.left; 00306 } else if (lppt->x >= grcVDMCursorBounds.right) { 00307 lppt->x = grcVDMCursorBounds.right - 1; 00308 } 00309 00310 if (lppt->y < grcVDMCursorBounds.top) { 00311 lppt->y = grcVDMCursorBounds.top; 00312 } else if (lppt->y >= grcVDMCursorBounds.bottom) { 00313 lppt->y = grcVDMCursorBounds.bottom - 1; 00314 } 00315 00316 } else { 00317 00318 if (lppt->x < grcCursorClip.left) { 00319 lppt->x = grcCursorClip.left; 00320 } else if (lppt->x >= grcCursorClip.right) { 00321 lppt->x = grcCursorClip.right - 1; 00322 } 00323 00324 if (lppt->y < grcCursorClip.top) { 00325 lppt->y = grcCursorClip.top; 00326 } else if (lppt->y >= grcCursorClip.bottom) { 00327 lppt->y = grcCursorClip.bottom - 1; 00328 } 00329 } 00330 00331 /* 00332 * If we have more than one monitor, then we need to clip the 00333 * cursor to a point on the desktop. 00334 */ 00335 if (!gpDispInfo->fDesktopIsRect) { 00336 ClipPointToDesktop(lppt); 00337 } 00338 } 00339 00340 /***************************************************************************\ 00341 * SetVDMCursorBounds 00342 * 00343 * This routine is needed so when a vdm is running, the mouse is not bounded 00344 * by the screen. This is so the vdm can correctly virtualize the DOS mouse 00345 * device driver. It can't deal with user always bounding to the screen, 00346 * so it sets wide open bounds. 00347 * 00348 * 20-May-1993 ScottLu Created. 00349 \***************************************************************************/ 00350 00351 VOID SetVDMCursorBounds( 00352 LPRECT lprc) 00353 { 00354 if (lprc != NULL) { 00355 00356 /* 00357 * Set grcVDMCursorBounds before TEST_PUDF(PUDF_VDMBOUNDSACTIVE), because 00358 * MoveEvent() calls BoundCursor() from outside the USER CritSect! 00359 */ 00360 grcVDMCursorBounds = *lprc; 00361 SET_PUDF(PUDF_VDMBOUNDSACTIVE); 00362 00363 } else { 00364 00365 /* 00366 * Turn vdm bounds off. 00367 */ 00368 CLEAR_PUDF(PUDF_VDMBOUNDSACTIVE); 00369 } 00370 } 00371 00372 /***************************************************************************\ 00373 * zzzAnimateCursor 00374 * 00375 * When an animated cursor is loaded and the wait cursor is up this routine 00376 * gets called to maintain the cursor animation. 00377 * 00378 * Should only be called by the cursor animation timer. 00379 * 00380 * History: 00381 * 02-Oct-1991 DarrinM Created. 00382 * 03-Aug-1994 SanfordS Calibrated. 00383 \***************************************************************************/ 00384 00385 #if defined (_M_IX86) && (_MSC_VER <= 1100) 00386 #pragma optimize("s", off) 00387 #endif 00388 00389 VOID zzzAnimateCursor( 00390 PWND pwndDummy, 00391 UINT message, 00392 UINT_PTR nID, 00393 LPARAM lParam) 00394 { 00395 int iicur; 00396 PACON pacon; 00397 TL tlpacon; 00398 int LostTime; 00399 int tTime; 00400 00401 pacon = (PACON)gpcurLogCurrent; 00402 00403 if (pacon == NULL || !(pacon->CURSORF_flags & CURSORF_ACON)) { 00404 gdwLastAniTick = 0; 00405 return; 00406 } 00407 00408 /* 00409 * Find out actual time loss since last update. 00410 */ 00411 if (gdwLastAniTick) { 00412 00413 LostTime = NtGetTickCount() - gdwLastAniTick - 00414 (pacon->ajifRate[pacon->iicur] * 100 / 6); 00415 00416 if (LostTime < 0) 00417 LostTime = 0; 00418 00419 } else { 00420 00421 LostTime = 0; 00422 } 00423 00424 /* 00425 * Increment the animation index. 00426 */ 00427 iicur = pacon->iicur + 1; 00428 if (iicur >= pacon->cicur) 00429 iicur = 0; 00430 00431 pacon->iicur = iicur; 00432 00433 /* 00434 * This forces the new cursor to be drawn. 00435 */ 00436 ThreadLockAlways(pacon, &tlpacon); 00437 zzzUpdateCursorImage(); 00438 00439 tTime = pacon->ajifRate[iicur] * 100 / 6; 00440 00441 while (tTime < LostTime) { 00442 00443 /* 00444 * Animation is outrunning our ability to render it - skip frames 00445 * to catch up. 00446 */ 00447 LostTime -= tTime; 00448 00449 /* 00450 * Increment the animation index. 00451 */ 00452 iicur = pacon->iicur + 1; 00453 if (iicur >= pacon->cicur) 00454 iicur = 0; 00455 00456 pacon->iicur = iicur; 00457 00458 tTime = pacon->ajifRate[iicur] * 100 / 6; 00459 } 00460 ThreadUnlock(&tlpacon); 00461 00462 gdwLastAniTick = NtGetTickCount() - LostTime; 00463 gidCursorTimer = InternalSetTimer(NULL, gidCursorTimer, tTime - LostTime, zzzAnimateCursor, TMRF_RIT | TMRF_ONESHOT); 00464 00465 return; 00466 00467 00468 DBG_UNREFERENCED_PARAMETER(pwndDummy); 00469 DBG_UNREFERENCED_PARAMETER(message); 00470 DBG_UNREFERENCED_PARAMETER(nID); 00471 DBG_UNREFERENCED_PARAMETER(lParam); 00472 } 00473 00474 /**************************************************************************\ 00475 * FCursorShadowed 00476 * 00477 \**************************************************************************/ 00478 00479 __inline FCursorShadowed(PCURSINFO pci) 00480 { 00481 return (TestALPHA(CURSORSHADOW) && (pci->CURSORF_flags & CURSORF_SYSTEM)); 00482 } 00483 00484 #if defined (_M_IX86) && (_MSC_VER <= 1100) 00485 #pragma optimize("", on) 00486 #endif 00487 00488 /**************************************************************************\ 00489 * zzzUpdateCursorImage 00490 * 00491 * History: 00492 * 14-Jan-1992 DavidPe Created. 00493 * 09-Aug-1992 DarrinM Added animated cursor code. 00494 \**************************************************************************/ 00495 00496 VOID zzzUpdateCursorImage() 00497 { 00498 PCURSOR pcurLogNew; 00499 PCURSOR pcurPhysNew; 00500 PACON pacon; 00501 PCURSOR pcurPhysOld; 00502 00503 if (gpqCursor == NULL) 00504 return; 00505 00506 if ((gpqCursor->iCursorLevel < 0) || (gpqCursor->spcurCurrent == NULL)) { 00507 00508 pcurLogNew = NULL; 00509 00510 } else { 00511 00512 /* 00513 * Assume we're using the current cursor. 00514 */ 00515 pcurLogNew = gpqCursor->spcurCurrent; 00516 00517 /* 00518 * Check to see if we should use the "app starting" cursor. 00519 */ 00520 if (gtimeStartCursorHide != 0) { 00521 00522 if (gpqCursor->spcurCurrent == SYSCUR(ARROW) || 00523 gpqCursor->spcurCurrent == SYSCUR(APPSTARTING)) { 00524 00525 pcurLogNew = SYSCUR(APPSTARTING); 00526 } 00527 } 00528 } 00529 00530 /* 00531 * If the logical cursor is changing then start/stop the cursor 00532 * animation timer as appropriate. 00533 */ 00534 if (pcurLogNew != gpcurLogCurrent) { 00535 00536 /* 00537 * If the old cursor was animating, shut off the animation timer. 00538 */ 00539 if (gtmridAniCursor != 0) { 00540 /* 00541 * Disable animation. 00542 */ 00543 KILLRITTIMER(NULL, gtmridAniCursor); 00544 gtmridAniCursor = 0; 00545 } 00546 00547 /* 00548 * If the new cursor is animated, start the animation timer. 00549 */ 00550 if ((pcurLogNew != NULL) && (pcurLogNew->CURSORF_flags & CURSORF_ACON)) { 00551 00552 /* 00553 * Start the animation over from the beginning. 00554 */ 00555 pacon = (PACON)pcurLogNew; 00556 pacon->iicur = 0; 00557 00558 gdwLastAniTick = NtGetTickCount(); 00559 00560 /* 00561 * Use the rate table to keep the timer on track. 00562 * 1 Jiffy = 1/60 sec = 100/6 ms 00563 */ 00564 gtmridAniCursor = InternalSetTimer(NULL, gtmridAniCursor, 00565 pacon->ajifRate[0] * 100 / 6, zzzAnimateCursor, TMRF_RIT | TMRF_ONESHOT); 00566 } 00567 } 00568 00569 /* 00570 * If this is an animated cursor, find and use the current frame 00571 * of the animation. NOTE: this is done AFTER the AppStarting 00572 * business so the AppStarting cursor itself can be animated. 00573 */ 00574 if (pcurLogNew != NULL && pcurLogNew->CURSORF_flags & CURSORF_ACON) { 00575 00576 pcurPhysNew = ((PACON)pcurLogNew)->aspcur[((PACON)pcurLogNew)-> 00577 aicur[((PACON)pcurLogNew)->iicur]]; 00578 } else { 00579 00580 pcurPhysNew = pcurLogNew; 00581 } 00582 00583 /* 00584 * Remember the new logical cursor. 00585 */ 00586 gpcurLogCurrent = pcurLogNew; 00587 00588 /* 00589 * If the physical cursor is changing then update screen. 00590 */ 00591 if (pcurPhysNew != gpcurPhysCurrent) { 00592 00593 pcurPhysOld = gpcurPhysCurrent; 00594 00595 gpcurPhysCurrent = pcurPhysNew; 00596 00597 if (pcurPhysNew == NULL) { 00598 00599 SetPointer(FALSE); 00600 00601 } else { 00602 ULONG fl = 0; 00603 00604 if (pcurLogNew->CURSORF_flags & CURSORF_ACON) { 00605 fl |= SPS_ANIMATEUPDATE; 00606 } 00607 if (FCursorShadowed(GETPCI(pcurLogNew))) { 00608 fl |= SPS_ALPHA; 00609 } 00610 GreSetPointer(gpDispInfo->hDev, GETPCI(pcurPhysNew), fl); 00611 } 00612 00613 /* 00614 * Notify anyone who cares about the change 00615 * This can happen on the RIT, so we need to pass on the real 00616 * thread/process ID. Hence we use hwndCursor. 00617 * This comment is from WIn'95 so it may not be true - IanJa. 00618 */ 00619 if (FWINABLE()) { 00620 DWORD event; 00621 /* 00622 * These are the events we send: 00623 * hcurPhys now NULL -> EVENT_OBJECT_HIDE 00624 * hcurPhys was NULL -> EVENT_OBJECT_SHOW 00625 * hcurPhys changing -> EVENT_OBJECT_NAMECHANGE 00626 * Since we only go through this code if hcurPhys is actually 00627 * changing, these checks are simple. 00628 */ 00629 if (!pcurPhysNew) { 00630 event = EVENT_OBJECT_HIDE; 00631 } else if (!pcurPhysOld) { 00632 event = EVENT_OBJECT_SHOW; 00633 } else { 00634 event = EVENT_OBJECT_NAMECHANGE; 00635 } 00636 zzzWindowEvent(event, NULL, OBJID_CURSOR, INDEXID_CONTAINER, WEF_USEPWNDTHREAD); 00637 } 00638 } 00639 } 00640 00641 #if DBG 00642 00643 /***************************************************************************\ 00644 * DbgLockQCursor 00645 * 00646 * Special routine to lock cursors into a queue. Besides a pointer 00647 * to the cursor, the handle is also saved. 00648 * Returns the pointer to the previous current cursor for that queue. 00649 * 00650 * History: 00651 * 26-Jan-1993 JimA Created. 00652 \***************************************************************************/ 00653 00654 PCURSOR DbgLockQCursor( 00655 PQ pq, 00656 PCURSOR pcur) 00657 { 00658 /* 00659 * See if the queue is marked for destuction. If so, we should not 00660 * be trying to lock a cursor. 00661 */ 00662 UserAssertMsg0(!(pq->QF_flags & QF_INDESTROY), 00663 "LockQCursor: Attempting to lock cursor to freed queue"); 00664 00665 return Lock(&pq->spcurCurrent, pcur); 00666 } 00667 00668 #endif // DBG 00669 00670 /***************************************************************************\ 00671 * SetPointer 00672 * 00673 * 29-Mar-1998 vadimg created 00674 \***************************************************************************/ 00675 00676 void SetPointer(BOOL fSet) 00677 { 00678 if (fSet) { 00679 if (gpqCursor != NULL && gpqCursor->iCursorLevel >= 0 && 00680 gpqCursor->spcurCurrent != NULL && 00681 SYSMET(MOUSEPRESENT)) { 00682 00683 PCURSINFO pci = GETPCI(gpqCursor->spcurCurrent); 00684 ULONG fl = FCursorShadowed(pci) ? SPS_ALPHA : 0; 00685 00686 GreSetPointer(gpDispInfo->hDev, pci, fl); 00687 } 00688 } else { 00689 GreSetPointer(gpDispInfo->hDev, NULL, 0); 00690 } 00691 } 00692 00693 /***************************************************************************\ 00694 * HideCursorNoCapture 00695 * 00696 * Set the cursor to NULL if the mouse is not captured 00697 * 00698 * 20-May-1998 MCostea created 00699 \***************************************************************************/ 00700 00701 void zzzHideCursorNoCapture() 00702 { 00703 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00704 00705 if (!ptiCurrent->pq->spwndCapture && (GetAppCompatFlags2(VER40) & GACF2_EDITNOMOUSEHIDE) == 0) { 00706 zzzSetCursor(NULL); 00707 } 00708 }

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