Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

649 lines
17 KiB

/****************************** 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;
}