|
|
/****************************** Module Header ******************************\
* Module Name: caret.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Caret code. Every thread has a caret in its queue structure. * * History: * 11-17-90 ScottLu Created. * 01-Feb-1991 mikeke Added Revalidation code (None) * 02-12-91 JimA Added access checks \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* UT_CaretSet * * Checks to see if the current queue has a caret. If pwnd != NULL, check * to see if the caret is for pwnd. * * History: * 11-17-90 ScottLu Ported. \***************************************************************************/ BOOL UT_CaretSet( PWND pwnd) { PQ pq; PTHREADINFO ptiCurrent;
/*
* Current queue have a caret? If not, return FALSE. */ ptiCurrent = PtiCurrent(); pq = ptiCurrent->pq;
if (pq->caret.spwnd == NULL) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Access denied in UT_CaretSet to current queue's caret");
return FALSE; }
/*
* If the current task does not own the caret, then return FALSE. We let * 32 bit multithreaded apps set the caret position from a second thread * for compatibility to our NT 3.1 BETAs. */ if (pq->caret.tid != TIDq(ptiCurrent)) { PTHREADINFO ptiCursorOwner = PtiFromThreadId(pq->caret.tid);
if ((ptiCurrent->TIF_flags & TIF_16BIT) || ptiCursorOwner == NULL || ptiCurrent->ppi != ptiCursorOwner->ppi) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Access denied in UT_CaretSet");
return FALSE; } }
/*
* If pwnd == NULL, we're just checking to see if current queue has * caret. It does, so return TRUE. */ if (pwnd == NULL) { return TRUE; }
/*
* pwnd != NULL. Check to see if the caret is for pwnd. If so, return * TRUE. */ if (pwnd == pq->caret.spwnd) { return TRUE; } else { return FALSE; } }
/***************************************************************************\
* UT_InvertCaret * * Invert the caret. * * History: * 11-17-90 ScottLu Ported. \***************************************************************************/ VOID UT_InvertCaret( VOID) { HDC hdc; PWND pwnd; PQ pq; HBITMAP hbmSave; BOOL fRestore;
pq = PtiCurrent()->pq; pwnd = pq->caret.spwnd;
if (pwnd == NULL || !IsVisible(pwnd)) { pq->caret.fVisible = FALSE; return; }
/*
* Get a DC for this window and draw the caret. */ hdc = _GetDC(pwnd); if (fRestore = (pwnd->hrgnUpdate ? TRUE : FALSE)) { GreSaveDC(hdc); if (TestWF(pwnd, WFWIN31COMPAT)) { _ExcludeUpdateRgn(hdc, pwnd); } }
/*
* If the caret bitmap is NULL, the caret is a white pattern invert. * If the caret bitmap is == 1, the caret is a gray pattern. * If the caret bitmap is > 1, the caret is really a bitmap. */ if (pq->caret.hBitmap > (HBITMAP)1) {
/*
* The caret is a bitmap. SRCINVERT it onto the screen. */ hbmSave = GreSelectBitmap(ghdcMem, pq->caret.hBitmap); GreBitBlt(hdc, pq->caret.x, pq->caret.y, pq->caret.cx, pq->caret.cy, ghdcMem, 0, 0, SRCINVERT, 0);
GreSelectBitmap(ghdcMem, hbmSave); } else { POLYPATBLT PolyData;
/*
* The caret is a pattern (gray or white). PATINVERT it onto the * screen. */ PolyData.x = pq->caret.x; PolyData.y = pq->caret.y; PolyData.cx = pq->caret.cx; PolyData.cy = pq->caret.cy;
if (pq->caret.hBitmap == (HBITMAP)1) { PolyData.BrClr.hbr = gpsi->hbrGray; } else { PolyData.BrClr.hbr = ghbrWhite; }
GrePolyPatBlt(hdc, PATINVERT, &PolyData, 1, PPB_BRUSH); }
if (fRestore) { GreRestoreDC(hdc, -1); }
_ReleaseDC(hdc); }
/***************************************************************************\
* zzzInternalDestroyCaret * * Internal routine for killing the caret for this thread. * * History: * 11-17-90 ScottLu Ported \***************************************************************************/ VOID zzzInternalDestroyCaret( VOID) { PQ pq; PTHREADINFO ptiCurrent = PtiCurrent(); PWND pwndCaret; TL tlpwndCaret;
/*
* Hide the caret, kill the timer, and null out the caret structure. */ zzzInternalHideCaret(); pq = ptiCurrent->pq;
if (pq->caret.hTimer != 0) { _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET); pq->caret.hTimer = 0; }
pq->caret.hBitmap = NULL; pq->caret.iHideLevel = 0;
pwndCaret = pq->caret.spwnd; if (pwndCaret != NULL) { ThreadLockWithPti(ptiCurrent, pwndCaret, &tlpwndCaret); Unlock(&pq->caret.spwnd);
zzzWindowEvent(EVENT_OBJECT_DESTROY, pwndCaret, OBJID_CARET, INDEXID_CONTAINER, 0);
ThreadUnlock(&tlpwndCaret); } }
/***************************************************************************\
* zzzDestroyCaret * * External api for destroying the caret of the current thread. * * History: * 11-17-90 ScottLu Ported. * 16-May-1991 mikeke Changed to return BOOL \***************************************************************************/ BOOL zzzDestroyCaret( VOID) { if (UT_CaretSet(NULL)) { zzzInternalDestroyCaret(); return TRUE; } else { return FALSE; } }
/***************************************************************************\
* xxxCreateCaret * * External api for creating the caret. * * History: * 11-17-90 ScottLu Ported. * 16-May-1991 mikeke Changed to return BOOL \***************************************************************************/ BOOL xxxCreateCaret( PWND pwnd, HBITMAP hBitmap, int cx, int cy) { PQ pq; BITMAP bitmap; PTHREADINFO ptiCurrent = PtiCurrent();
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
pq = ptiCurrent->pq;
/*
* Don't allow the app to create a caret in a window * from another queue. */ if (GETPTI(pwnd)->pq != pq) { return FALSE; }
/*
* Defer WinEvent notifications to preserve pq. */ DeferWinEventNotify();
if (pq->caret.spwnd != NULL) { zzzInternalDestroyCaret(); }
Lock(&pq->caret.spwnd, pwnd); pq->caret.iHideLevel = 1; pq->caret.fOn = TRUE; pq->caret.fVisible = FALSE; pq->caret.tid = TIDq(ptiCurrent);
if (cy == 0) { cy = SYSMET(CYBORDER); } if (cx == 0) { cx = SYSMET(CXBORDER); }
if ((pq->caret.hBitmap = hBitmap) > (HBITMAP)1) { GreExtGetObjectW(hBitmap, sizeof(BITMAP), &bitmap); cy = bitmap.bmHeight; cx = bitmap.bmWidth; }
pq->caret.cy = cy; pq->caret.cx = cx; if (gpsi->dtCaretBlink != -1 && !IsRemoteConnection()) { pq->caret.hTimer = _SetSystemTimer(pwnd, IDSYS_CARET, gpsi->dtCaretBlink, CaretBlinkProc); } else { pq->caret.hTimer = 0; }
UserAssert(pwnd == pq->caret.spwnd); zzzEndDeferWinEventNotify();
/*
* It's best to force this routine to be an xxx routine: that way we can * force pwnd to be locked and force notifications from within this * routine and all of the callers are happy with this. */ xxxWindowEvent(EVENT_OBJECT_CREATE, pwnd, OBJID_CARET, INDEXID_CONTAINER, 0);
return TRUE; }
/***************************************************************************\
* zzzInternalShowCaret * * Internal routine for showing the caret for this thread. * * History: * 11-17-90 ScottLu Ported. \***************************************************************************/ VOID zzzInternalShowCaret( VOID) { PQ pq = PtiCurrent()->pq;
/*
* If the caret hide level is aleady 0 (meaning it's ok to show) and the * caret is not physically on, try to invert now if it's turned on. */ if (pq->caret.iHideLevel == 0) { if (!pq->caret.fVisible) { if ((pq->caret.fVisible = pq->caret.fOn) != 0) { UT_InvertCaret(); } }
return; }
/*
* Adjust the hide caret hide count. If we hit 0, we can show the caret. * Try to invert it if it's turned on. */ if (--pq->caret.iHideLevel == 0) { if ((pq->caret.fVisible = pq->caret.fOn) != 0) { UT_InvertCaret(); }
zzzWindowEvent(EVENT_OBJECT_SHOW, pq->caret.spwnd, OBJID_CARET, INDEXID_CONTAINER, 0); } }
/***************************************************************************\
* zzzInternalHideCaret * * Internal routine for hiding the caret. * * History: * 11-17-90 ScottLu Created. \***************************************************************************/ VOID zzzInternalHideCaret( VOID) { PQ pq = PtiCurrent()->pq;
/*
* If the caret is physically visible, invert it to turn off the bits. * Adjust the hide count upwards to remember this hide level. */ if (pq->caret.fVisible) { UT_InvertCaret(); }
pq->caret.fVisible = FALSE; pq->caret.iHideLevel++;
/*
* Is the caret transitioning to being hidden? If so, iHideLevel is * going from 0 to 1. */ if (pq->caret.iHideLevel == 1) { zzzWindowEvent(EVENT_OBJECT_HIDE, pq->caret.spwnd, OBJID_CARET, INDEXID_CONTAINER, 0); } }
/***************************************************************************\
* zzzShowCaret * * External routine for showing the caret. * * History: * 11-17-90 ScottLu Ported. * 16-May-1991 mikeke Changed to return BOOL \***************************************************************************/ BOOL zzzShowCaret( PWND pwnd) { if (UT_CaretSet(pwnd)) { zzzInternalShowCaret(); return TRUE; } else { return FALSE; } }
/***************************************************************************\
* zzzHideCaret * * External api to hide the caret. * * History: * 11-17-90 ScottLu Ported. * 16-May-1991 mikeke Changed to return BOOL \***************************************************************************/ BOOL zzzHideCaret( PWND pwnd) { if (UT_CaretSet(pwnd)) { zzzInternalHideCaret(); return TRUE; } else { return FALSE; } }
/***************************************************************************\
* CaretBlinkProc * * This routine gets called by DispatchMessage when it gets the WM_SYSTIMER * message - it blinks the caret. * * History: * 11-17-90 ScottLu Ported. \***************************************************************************/ VOID CaretBlinkProc( PWND pwnd, UINT message, UINT_PTR id, LPARAM lParam) { PQ pq = PtiCurrent()->pq;
UNREFERENCED_PARAMETER(message); UNREFERENCED_PARAMETER(id); UNREFERENCED_PARAMETER(lParam);
/*
* If this window doesn't even have a timer, just return. TRUE is * returned, which gets returned from DispatchMessage(). Why? Because * it is compatible with Win3. */ if (pwnd != pq->caret.spwnd) { return; }
if (gpsi->dtCaretBlink == -1 && pq->caret.fOn && pq->caret.fVisible) { /*
* Kill the timer for performance. */ _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET); return; }
/*
* Flip the logical cursor state. If the hide level permits it, flip * the physical state and draw the caret. */ pq->caret.fOn ^= 1; if (pq->caret.iHideLevel == 0) { pq->caret.fVisible ^= 1; UT_InvertCaret(); } }
/***************************************************************************\
* _SetCaretBlinkTime * * Sets the system caret blink time. * * History: * 11-17-90 ScottLu Created. * 02-12-91 JimA Added access check * 16-May-1991 mikeke Changed to return BOOL \***************************************************************************/ BOOL _SetCaretBlinkTime( UINT cmsBlink) { PQ pq;
/*
* Blow it off if the caller doesn't have the proper access rights. */ if (!CheckWinstaWriteAttributesAccess()) { return FALSE; }
/*
* Blow it off if this value is under policy control. */ if (CheckDesktopPolicy(NULL, (PCWSTR)STR_BLINK)) { return FALSE; }
gpsi->dtCaretBlink = cmsBlink;
pq = PtiCurrent()->pq; if (pq->caret.hTimer) { _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET); if (gpsi->dtCaretBlink != -1 && !IsRemoteConnection()) { pq->caret.hTimer = _SetSystemTimer(pq->caret.spwnd, IDSYS_CARET, gpsi->dtCaretBlink, CaretBlinkProc); } else { pq->caret.hTimer = 0; } }
return TRUE; }
/***************************************************************************\
* zzzSetCaretPos * * External routine for setting the caret pos. * * History: * 11-17-90 ScottLu Ported. * 02-12-91 JimA Added access check \***************************************************************************/ BOOL zzzSetCaretPos( int x, int y) { PQ pq;
/*
* If this thread does not have the caret set, return FALSE. */ if (!UT_CaretSet(NULL)) { RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in zzzSetCaretPos"); return FALSE; }
/*
* If the caret isn't changing position, do nothing (but return success). */ pq = PtiCurrent()->pq; if (pq->caret.x == x && pq->caret.y == y) { return TRUE; }
/*
* For windows that have private DCs, we have to store the client coordinate * equivelent for the logical coordinate caret positioning. */ if (pq->caret.spwnd != NULL && pq->caret.spwnd->pcls->style & CS_OWNDC) { RECT rcOwnDcCaret; HDC hdc;
rcOwnDcCaret.left = x; rcOwnDcCaret.top = y; rcOwnDcCaret.right = x + pq->caret.cx; rcOwnDcCaret.bottom = y + pq->caret.cy;
hdc = _GetDC(pq->caret.spwnd); GreLPtoDP(hdc, (LPPOINT)(&rcOwnDcCaret), 2); _ReleaseDC(hdc);
pq->caret.xOwnDc = rcOwnDcCaret.left; pq->caret.yOwnDc = rcOwnDcCaret.top; pq->caret.cxOwnDc = rcOwnDcCaret.right - rcOwnDcCaret.left; pq->caret.cyOwnDc = rcOwnDcCaret.bottom - rcOwnDcCaret.top; }
/*
* If the caret is visible, turn it off while we move it. */ if (pq->caret.fVisible) { UT_InvertCaret(); }
/*
* Adjust to the new position. */ pq->caret.x = x; pq->caret.y = y;
/*
* Set a new timer so it'll blink in the new position dtCaretBlink * milliseconds from now. */ if (pq->caret.hTimer != 0) { _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET); }
if (gpsi->dtCaretBlink != -1 && !IsRemoteConnection()) { pq->caret.hTimer = _SetSystemTimer(pq->caret.spwnd, IDSYS_CARET, gpsi->dtCaretBlink, CaretBlinkProc); } else { pq->caret.hTimer = 0; }
pq->caret.fOn = TRUE;
/*
* Draw it immediately now if the hide level permits it. */ pq->caret.fVisible = FALSE; if (pq->caret.iHideLevel == 0) { pq->caret.fVisible = TRUE; UT_InvertCaret(); }
zzzWindowEvent(EVENT_OBJECT_LOCATIONCHANGE, pq->caret.spwnd, OBJID_CARET, INDEXID_CONTAINER, 0);
return TRUE; }
|