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.
 
 
 
 
 
 

479 lines
15 KiB

/****************************** Module Header ******************************\
* Module Name: class.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains RegisterClass and the related window class management
* functions.
*
* History:
* 12-20-94 FritzS
*
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
BOOL VisWindow(PWND,DWORD);
/***************************************************************************\
* xxxSetClassIconEnum
\***************************************************************************/
BOOL xxxSetClassIconEnum(
PWND pwnd,
LPARAM lParam)
{
CheckLock(pwnd);
if (pwnd->pcls == (PCLS)lParam) {
/*
* If the window doesn't have a small icon or it comes from
* WM_QUERYDRAGICON, redraw the title. In the WM_QUERYDRAGICON
* case, get rid of the small icon so redrawing the title will
* create it if necessary.
*/
if (TestWF(pwnd, WFSMQUERYDRAGICON)) {
DestroyWindowSmIcon(pwnd);
}
if (!_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp),PROPF_INTERNAL)) {
xxxRedrawTitle(pwnd, DC_ICON);
}
}
return TRUE;
}
/***************************************************************************\
* SetClassIcon
*
* Changes the big/small icon of a class. Called from SetClassWord().
\***************************************************************************/
PCURSOR xxxSetClassIcon(
PWND pwnd,
PCLS pcls,
PCURSOR pCursor,
int gcw)
{
PTHREADINFO pti = PtiCurrent();
PCURSOR pCursorOld;
HCURSOR hCursorOld;
TL tlpwndChild;
BOOL fRedraw;
CheckLock(pwnd);
/*
* Save old icon.
*/
pCursorOld = ((gcw == GCLP_HICON) ? pcls->spicn : pcls->spicnSm);
if (pCursorOld != pCursor) {
fRedraw = TRUE;
hCursorOld = PtoH(pCursorOld);
/*
* Set new icon.
*/
if (gcw == GCLP_HICON) {
/*
* Destroy private cached small icon first.
*/
if (pcls->spicnSm && !DestroyClassSmIcon(pcls)) {
fRedraw = FALSE;
}
Lock(&(pcls->spicn), pCursor);
} else {
/*
* We don't allow apps to see the small icons we create from
* their big icons. They can see their own. Saves memory
* leak problems and is easier.
*/
if (pcls->CSF_flags & CSF_CACHEDSMICON) {
DestroyClassSmIcon(pcls);
hCursorOld = NULL;
}
Lock(&(pcls->spicnSm), pCursor);
}
if (pcls->spicn && !pcls->spicnSm) {
xxxCreateClassSmIcon(pcls);
}
if (fRedraw) {
if (pcls->cWndReferenceCount > 1) {
ThreadLock(pti->rpdesk->pDeskInfo->spwnd->spwndChild, &tlpwndChild);
xxxInternalEnumWindow(pti->rpdesk->pDeskInfo->spwnd->spwndChild,
xxxSetClassIconEnum,
(LPARAM)pcls,
BWL_ENUMLIST);
ThreadUnlock(&tlpwndChild);
} else {
xxxSetClassIconEnum(pwnd, (LPARAM)pcls);
}
}
/*
* Revalidate the old cursor
*/
if (hCursorOld != NULL) {
pCursorOld = HMRevalidateHandleNoRip(hCursorOld);
} else {
pCursorOld = NULL;
}
}
return pCursorOld;
}
/***************************************************************************\
* DestroyClassSmIcon
*
* Destroys the small icon of a class if we've created a cached one.
\***************************************************************************/
BOOL DestroyClassSmIcon(
PCLS pcls)
{
/*
* If we don't have a cached icon, then no work.
*/
if (pcls->CSF_flags & CSF_CACHEDSMICON) {
if (pcls->spicnSm) {
_DestroyCursor(pcls->spicnSm, CURSOR_ALWAYSDESTROY);
Unlock(&pcls->spicnSm);
}
pcls->CSF_flags &= ~CSF_CACHEDSMICON;
return TRUE;
}
return FALSE;
}
/***************************************************************************\
* xxxCreateClassSmIcon
*
* Creates a cached class small icon from a class big icon.
\***************************************************************************/
VOID xxxCreateClassSmIcon(
PCLS pcls)
{
PCURSOR pcur;
UserAssert(pcls->cWndReferenceCount > 0);
UserAssert(pcls->spicn);
UserAssert(!pcls->spicnSm);
pcur = xxxClientCopyImage(PtoH(pcls->spicn),
pcls->spicn->rt == PTR_TO_ID(RT_ICON) ? IMAGE_ICON : IMAGE_CURSOR,
SYSMET(CXSMICON),
SYSMET(CYSMICON),
LR_DEFAULTCOLOR | LR_COPYFROMRESOURCE);
Lock(&pcls->spicnSm, pcur);
if (pcls->spicnSm) {
pcls->CSF_flags |= CSF_CACHEDSMICON;
}
}
/***************************************************************************\
* xxxSetWindowStyle
*
* Changes the style bits of a window. Called from SetWindowLong(). This
* sends two messages, a changing and a changed. Upon receipt of a
* WM_STYLECHANGING message, a window can muck with the style bits for
* validation purposes. The WM_STYLECHANGED message is simply after the
* fact.
\***************************************************************************/
LONG xxxSetWindowStyle(
PWND pwnd,
int gwl,
DWORD styleNew)
{
STYLESTRUCT sty;
BOOL fWasChild, fIsChild, fBefore, fAfter;
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
sty.styleOld = ((gwl == GWL_STYLE) ? pwnd->style : pwnd->ExStyle);
sty.styleNew = styleNew;
/*
* Note that we don't do validation before _and_ after. It is sufficient
* to do our stuff at the end.
*/
/*
* We break Quicken 2.0 if we send the messages. That's why we version
* switch them.
*
* Send a WM_STYLECHANGING message to the window, so it can muck with
* the style bits. Like validate some stuff.
*/
if (TestWF(pwnd, WFWIN40COMPAT)) {
xxxSendMessage(pwnd, WM_STYLECHANGING, gwl, (LPARAM)(LPSTYLESTRUCT)&sty);
}
/*
* Now do our own validation.
*/
if (gwl == GWL_STYLE) {
BOOL fWasVisWindow;
/*
* If this is an edit control that has ES_PASSWORD set and
* the caller does not own it and is trying to reset it,
* fail the call.
*/
if (PpiCurrent() != GETPTI(pwnd)->ppi && IS_EDIT(pwnd) &&
(sty.styleOld & ES_PASSWORD) && !(sty.styleNew & ES_PASSWORD)) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in xxxSetWindowStyle");
return 0;
}
/* Listbox ownerdraw style check was moved to the client side (client\ntstubs.c) */
/*
* Do proper validation on style bits.
*/
if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) {
sty.styleNew |= WS_CLIPSIBLINGS;
}
/*
* If the clipping-ness is changing, invalidate the dc cache.
*/
if ((sty.styleNew & (WS_CLIPCHILDREN | WS_CLIPSIBLINGS)) !=
(sty.styleOld & (WS_CLIPCHILDREN | WS_CLIPSIBLINGS))) {
/*
* No need to DeferWinEventNotify() - pwnd is locked
*/
zzzInvalidateDCCache(pwnd, IDC_DEFAULT);
}
/*
* This breaks all Paradox dialogs 1.0-5.0 that have combos. They
* enumerate all child windows, add on minimized, then sit in a peek
* loop. After that they enumerate all child windows and remove
* WS_MINIMIZE--except the code below won't let them.
*
* Result is weird painting and an inability to use the dialog any
* more short of dismissing it
*
* Temp fix: Check for child window first.
*/
/*
* if this window is REALLY minimized (minimized bit is set and caption
* present bit is removed), then don't allow app to remove the minimize
* bit -- this fixes FoxBlow's attempt at being the OS -- jeffbog
*/
if (!TestWF(pwnd, WFCHILD) &&
TestWF(pwnd, WFMINIMIZED) &&
!TestWF(pwnd, WFCPRESENT) &&
!(sty.styleNew & WS_MINIMIZE)) {
sty.styleNew |= WS_MINIMIZE;
}
/*
* If we're changing the child bit, deal with spmenu appropriately.
* If we're turning into a child, change spmenu to an id. If we're
* turning into a top level window, turn spmenu into a menu.
*/
fWasChild = TestwndChild(pwnd);
pwnd->style = sty.styleNew;
fIsChild = TestwndChild(pwnd);
/*
* If we turned into a top level window, change spmenu to NULL.
* If we turned into a child from a top level window, unlock spmenu.
*/
if (fWasChild && !fIsChild) {
pwnd->spmenu = NULL;
}
if (!fWasChild && fIsChild) {
ClrWF(pwnd, WFMPRESENT);
UnlockWndMenu(pwnd, &pwnd->spmenu);
}
/*
* If the visible, child, or minimized style is changing,
* then update the cVisWindows count
*/
fWasVisWindow = VisWindow(pwnd, sty.styleOld);
if (fWasVisWindow != VisWindow(pwnd, sty.styleNew)) {
if (fWasVisWindow) {
DecVisWindows(pwnd);
} else {
IncVisWindows(pwnd);
}
}
} else {
/*
* First, see if the app might be setting bits that it really
* doesn't know about. If so, replace those bits with the
* current values.
*/
if (GetAppCompatFlags2(VER40) & GACF2_NO50EXSTYLEBITS) {
sty.styleNew &= WS_EX_VALID40;
} else {
/*
* Don't let aplications set unused extended bits.
*/
if (sty.styleNew & ~WS_EX_ALLVALID) {
RIPMSGF1(RIP_WARNING,
"Trying to set reserved exStyle bits 0x%x",
sty.styleNew);
}
sty.styleNew &= WS_EX_ALLVALID;
}
/*
* Is someone trying to toggle the WS_EX_TOPMOST style bit?
*/
if ((sty.styleOld & WS_EX_TOPMOST) != (sty.styleNew & WS_EX_TOPMOST)) {
RIPMSG0(RIP_WARNING, "Can't change WS_EX_TOPMOST with SetWindowLong");
/*
* BACKWARDS COMPATIBILITY HACK
* If stuff is getting stored in the high word, then it must be
* Lotus 123-W sticking a FAR pointer in this field. So don't
* modify it.
*/
if (TestWF(pwnd, WFWIN40COMPAT) || !HIWORD(sty.styleNew)) {
/*
* Don't let the bit be flipped.
*/
sty.styleNew &= ~WS_EX_TOPMOST;
sty.styleNew |= (sty.styleOld & WS_EX_TOPMOST);
}
}
/*
* Check pwnd->ExStyle directly since sty.styleOld can now be
* different from the real state of the window, because of the
* callbacks in this function from the time sty.styleOld was
* remembered and up to now. We must call the layering functions
* based on the real state of the layering bit.
*/
fBefore = (pwnd->ExStyle & WS_EX_LAYERED);
fAfter = (sty.styleNew & WS_EX_LAYERED);
if (fBefore && !fAfter) {
UnsetLayeredWindow(pwnd);
} else if (!fBefore && fAfter) {
if (!xxxSetLayeredWindow(pwnd, TRUE)) {
return 0;
}
}
fBefore = (pwnd->ExStyle & WS_EX_COMPOSITED);
fAfter = (sty.styleNew & WS_EX_COMPOSITED);
if (!fBefore && fAfter) {
/*
* If we are turning WS_EX_COMPOSITED on, none of our parents
* should already have WS_EX_COMPOSITED turned on. If any do,
* since we were explicitely trying to turn this style on, fail
* the call.
*/
if (GetStyleWindow(pwnd->spwndParent, WEFCOMPOSITED) != NULL) {
return 0;
}
}
if (fBefore && !fAfter) {
UnsetRedirectedWindow(pwnd, REDIRECT_COMPOSITED);
} else if (!fBefore && fAfter) {
if (!SetRedirectedWindow(pwnd, REDIRECT_COMPOSITED)) {
return 0;
}
/*
* We have successfully turned WS_EX_COMPOSITED on for ourself, so
* need to ensure that none of our child have WS_EX_COMPOSITED also
* turned on.
*/
xxxTurnOffCompositing(pwnd, TRUE);
}
#ifdef REDIRECTION
{
BOOL fVisrgnChange = FALSE;
fBefore = (pwnd->ExStyle & WS_EX_EXTREDIRECTED);
fAfter = (sty.styleNew & WS_EX_EXTREDIRECTED);
if (fBefore && !fAfter) {
UnsetRedirectedWindow(pwnd, REDIRECT_EXTREDIRECTED);
fVisrgnChange = TRUE;
} else if (!fBefore && fAfter) {
if (!SetRedirectedWindow(pwnd, REDIRECT_EXTREDIRECTED)) {
return 0;
}
fVisrgnChange = TRUE;
}
if (fVisrgnChange) {
BEGINATOMICCHECK();
zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE);
ENDATOMICCHECK();
}
}
#endif
/*
* The bits we use internally should be preserved
*/
pwnd->ExStyle = sty.styleNew | (pwnd->ExStyle & ~WS_EX_ALLVALID);
if ((sty.styleOld ^ sty.styleNew)
& (WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LAYOUTRTL)) {
xxxRedrawFrame(pwnd);
}
}
/*
* See if we still need the 3D edge since the window styles changed.
*/
if (NeedsWindowEdge(pwnd->style, pwnd->ExStyle, TestWF(pwnd, WFWIN40COMPAT))) {
SetWF(pwnd, WEFWINDOWEDGE);
} else {
ClrWF(pwnd, WEFWINDOWEDGE);
}
/*
* Send a WM_STYLECHANGED message.
*/
if (TestWF(pwnd, WFWIN40COMPAT)) {
xxxSendMessage(pwnd, WM_STYLECHANGED, gwl, (LPARAM)(LPSTYLESTRUCT)&sty);
}
return sty.styleOld;
}
/***************************************************************************\
* VisWindow
*
* Based on style, determines if this is considered to be "visible" by
* queue foreground styles.
\***************************************************************************/
BOOL VisWindow(
PWND pwnd,
DWORD style)
{
return (FTopLevel(pwnd) && !(style & WS_MINIMIZE) && (style & WS_VISIBLE));
}