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.
1751 lines
52 KiB
1751 lines
52 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: dtbitmap.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Desktop Wallpaper Routines.
|
|
*
|
|
* History:
|
|
* 29-Jul-1991 MikeKe From win31
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* Local Constants.
|
|
*/
|
|
#define MAXPAL 256
|
|
#define MAXSTATIC 20
|
|
#define TILE_XMINSIZE 2
|
|
#define TILE_YMINSIZE 4
|
|
|
|
/*
|
|
* The version strings are stored in a contiguous-buffer. Each string
|
|
* is of size MAXVERSIONSTRING.
|
|
*/
|
|
|
|
// Size of each string buffer.
|
|
#define MAXVERSIONSTRING 128
|
|
|
|
// Offset into verbuffer of build-string.
|
|
#define OFFSET_BLDSTRING 0
|
|
|
|
// Offset into verbuffer of CSD string.
|
|
#define OFFSET_CSDSTRING OFFSET_BLDSTRING + MAXVERSIONSTRING
|
|
|
|
// Max size of buffer (contains all 3 strings).
|
|
#define MAXVERSIONBUFFER OFFSET_CSDSTRING + MAXVERSIONSTRING
|
|
|
|
WCHAR wszSafeMode[MAX_PATH + 3 * MAXVERSIONSTRING];
|
|
WCHAR SafeModeStr[64];
|
|
int SafeModeStrLen;
|
|
WCHAR wszProductName[MAXVERSIONSTRING];
|
|
WCHAR wszProductBuild[2 * MAXVERSIONSTRING];
|
|
|
|
|
|
__inline PWND _GetShellWindow(
|
|
PDESKTOP pdesk)
|
|
{
|
|
if (pdesk == NULL) {
|
|
return NULL;
|
|
} else {
|
|
return pdesk->pDeskInfo->spwndShell;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetVersionInfo
|
|
*
|
|
* Outputs a string on the desktop indicating debug-version.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
VOID
|
|
GetVersionInfo(
|
|
BOOL Verbose)
|
|
{
|
|
WCHAR NameBuffer[MAXVERSIONBUFFER];
|
|
WCHAR Title1[MAXVERSIONSTRING];
|
|
WCHAR Title2[MAXVERSIONSTRING];
|
|
WCHAR wszPID[MAXVERSIONSTRING];
|
|
WCHAR wszProduct[MAXVERSIONSTRING];
|
|
WCHAR wszPBuild[MAXVERSIONSTRING];
|
|
WCHAR wszEvaluation[MAXVERSIONSTRING];
|
|
UNICODE_STRING UserBuildString;
|
|
UNICODE_STRING UserCSDString;
|
|
NTSTATUS Status;
|
|
UINT uProductStrId;
|
|
|
|
/*
|
|
* Temporary code name handling. Used internally and turned off by ""
|
|
* for release. The matching string in strid.mc doesn't have a space
|
|
* separator between code name and the rest of the title, so this
|
|
* space must be included at end of this code name string.
|
|
*/
|
|
WCHAR wszCodeName[] = L"";
|
|
|
|
RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[] = {
|
|
|
|
{NULL,
|
|
RTL_QUERY_REGISTRY_DIRECT,
|
|
#ifdef PRERELEASE
|
|
L"BuildLab",
|
|
#else
|
|
L"CurrentBuildNumber",
|
|
#endif // PRERELEASE
|
|
&UserBuildString,
|
|
REG_NONE,
|
|
NULL,
|
|
0},
|
|
|
|
{NULL,
|
|
RTL_QUERY_REGISTRY_DIRECT,
|
|
L"CSDVersion",
|
|
&UserCSDString,
|
|
REG_NONE,
|
|
NULL,
|
|
0},
|
|
|
|
{NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
REG_NONE,
|
|
NULL,
|
|
0}
|
|
};
|
|
|
|
UserBuildString.Buffer = &NameBuffer[OFFSET_BLDSTRING];
|
|
UserBuildString.Length = 0;
|
|
UserBuildString.MaximumLength = MAXVERSIONSTRING * sizeof(WCHAR);
|
|
|
|
UserCSDString.Buffer = &NameBuffer[OFFSET_CSDSTRING];
|
|
UserCSDString.Length = 0;
|
|
UserCSDString.MaximumLength = MAXVERSIONSTRING * sizeof(WCHAR);
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
|
|
L"",
|
|
BaseServerRegistryConfigurationTable,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "GetVersionInfo failed with status %x", Status);
|
|
return;
|
|
}
|
|
|
|
ServerLoadString(hModuleWin, STR_DTBS_PRODUCTID, wszPID, ARRAY_SIZE(wszPID));
|
|
ServerLoadString(hModuleWin, STR_DTBS_PRODUCTBUILD, wszPBuild, ARRAY_SIZE(wszPBuild));
|
|
|
|
/*
|
|
* Write out Debugging Version message.
|
|
*/
|
|
|
|
/*
|
|
* Bug 280256 - joejo
|
|
* Create new desktop build information strings
|
|
*/
|
|
if (USER_SHARED_DATA->SuiteMask & (1 << EmbeddedNT)) {
|
|
uProductStrId = STR_DTBS_PRODUCTEMB;
|
|
} else if (USER_SHARED_DATA->NtProductType == NtProductWinNt) {
|
|
#ifdef _WIN64
|
|
uProductStrId = STR_DTBS_PRODUCTWKS64;
|
|
#else
|
|
if (USER_SHARED_DATA->SuiteMask & (1 << Personal)) {
|
|
uProductStrId = STR_DTBS_PRODUCTPER;
|
|
} else {
|
|
uProductStrId = STR_DTBS_PRODUCTPRO;
|
|
}
|
|
#endif
|
|
} else {
|
|
#ifdef _WIN64
|
|
if (USER_SHARED_DATA->SuiteMask & (1 << DataCenter)) {
|
|
uProductStrId = STR_DTBS_PRODUCTDTC64;
|
|
} else if (USER_SHARED_DATA->SuiteMask & (1 << Enterprise)) {
|
|
uProductStrId = STR_DTBS_PRODUCTADV64;
|
|
} else {
|
|
uProductStrId = STR_DTBS_PRODUCTSRV64;
|
|
}
|
|
#else
|
|
if (USER_SHARED_DATA->SuiteMask & (1 << DataCenter)) {
|
|
uProductStrId = STR_DTBS_PRODUCTDTC;
|
|
} else if (USER_SHARED_DATA->SuiteMask & (1 << Enterprise)) {
|
|
uProductStrId = STR_DTBS_PRODUCTADV;
|
|
} else if (USER_SHARED_DATA->SuiteMask & (1 << Blade)) {
|
|
uProductStrId = STR_DTBS_PRODUCTBLA;
|
|
} else if(USER_SHARED_DATA->SuiteMask & (1 << SmallBusinessRestricted)) {
|
|
uProductStrId = STR_DTBS_PRODUCTSBS;
|
|
} else {
|
|
uProductStrId = STR_DTBS_PRODUCTSRV;
|
|
}
|
|
#endif /* _WIN64 */
|
|
}
|
|
|
|
ServerLoadString(hModuleWin, uProductStrId, wszProduct, ARRAY_SIZE(wszProduct));
|
|
|
|
swprintf(
|
|
wszProductName,
|
|
wszPID,
|
|
wszCodeName,
|
|
wszProduct);
|
|
|
|
if (gfUnsignedDrivers) {
|
|
/* This takes precedence */
|
|
ServerLoadString(hModuleWin, STR_TESTINGONLY, wszEvaluation, ARRAY_SIZE(wszEvaluation));
|
|
} else if (USER_SHARED_DATA->SystemExpirationDate.QuadPart) {
|
|
ServerLoadString(hModuleWin, STR_DTBS_EVALUATION, wszEvaluation, ARRAY_SIZE(wszEvaluation));
|
|
} else {
|
|
wszEvaluation[0] = '\0';
|
|
}
|
|
|
|
swprintf(
|
|
wszProductBuild,
|
|
wszPBuild,
|
|
wszEvaluation,
|
|
UserBuildString.Buffer
|
|
);
|
|
|
|
if (Verbose) {
|
|
ServerLoadString(hModuleWin, STR_SAFEMODE_TITLE1, Title1, ARRAY_SIZE(Title1));
|
|
ServerLoadString(hModuleWin, STR_SAFEMODE_TITLE2, Title2, ARRAY_SIZE(Title2));
|
|
|
|
swprintf(
|
|
wszSafeMode,
|
|
UserCSDString.Length == 0 ? Title1 : Title2,
|
|
wszCodeName,
|
|
UserBuildString.Buffer,
|
|
UserCSDString.Buffer,
|
|
USER_SHARED_DATA->NtSystemRoot
|
|
);
|
|
} else {
|
|
ServerLoadString(hModuleWin, STR_SAFEMODE_TITLE3, Title1, ARRAY_SIZE(Title1));
|
|
ServerLoadString(hModuleWin, STR_SAFEMODE_TITLE4, Title2, ARRAY_SIZE(Title2));
|
|
|
|
swprintf(
|
|
wszSafeMode,
|
|
UserCSDString.Length == 0 ? Title1 : Title2,
|
|
wszCodeName,
|
|
UserBuildString.Buffer,
|
|
UserCSDString.Buffer);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetDefaultWallpaperName
|
|
*
|
|
* Get initial bitmap name
|
|
*
|
|
* History:
|
|
* 21-Feb-1995 JimA Created.
|
|
* 06-Mar-1996 ChrisWil Moved to kernel to facilite ChangeDisplaySettings.
|
|
\***************************************************************************/
|
|
VOID
|
|
GetDefaultWallpaperName(
|
|
LPWSTR lpszWallpaper)
|
|
{
|
|
/*
|
|
* Set the initial global wallpaper bitmap name for (Default)
|
|
* The global name is an at most 8 character name with no
|
|
* extension. It is "winnt" for workstation or "lanmannt"
|
|
* for server or server upgrade. It is followed by 256 it
|
|
* is for 256 color devices.
|
|
*/
|
|
if (USER_SHARED_DATA->NtProductType == NtProductWinNt) {
|
|
wcsncpycch(lpszWallpaper, L"winnt", 8);
|
|
} else {
|
|
wcsncpycch(lpszWallpaper, L"lanmannt", 8);
|
|
}
|
|
|
|
lpszWallpaper[8] = (WCHAR)0;
|
|
|
|
if (gpsi->BitsPixel * gpsi->Planes > 4) {
|
|
int iStart = wcslen(lpszWallpaper);
|
|
iStart = min(iStart, 5);
|
|
|
|
lpszWallpaper[iStart] = (WCHAR)0;
|
|
wcscat(lpszWallpaper, L"256");
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetDeskWallpaperName
|
|
*
|
|
* History:
|
|
* 19-Dec-1994 JimA Created.
|
|
* 29-Sep-1995 ChrisWil ReWrote to return filename.
|
|
\***************************************************************************/
|
|
#define GDWPN_KEYSIZE 40
|
|
#define GDWPN_BITSIZE 256
|
|
|
|
LPWSTR GetDeskWallpaperName(PUNICODE_STRING pProfileUserName,
|
|
LPWSTR lpszFile
|
|
)
|
|
{
|
|
WCHAR wszKey[GDWPN_KEYSIZE];
|
|
WCHAR wszNone[GDWPN_KEYSIZE];
|
|
LPWSTR lpszBitmap = NULL;
|
|
|
|
/*
|
|
* Load the none-string. This will be used for comparisons later.
|
|
*/
|
|
ServerLoadString(hModuleWin, STR_NONE, wszNone, ARRAY_SIZE(wszNone));
|
|
|
|
if ((lpszFile == NULL) ||
|
|
(lpszFile == SETWALLPAPER_DEFAULT) ||
|
|
(lpszFile == SETWALLPAPER_METRICS)) {
|
|
|
|
/*
|
|
* Allocate a buffer for the wallpaper. We will assume
|
|
* a default-size in this case.
|
|
*/
|
|
lpszBitmap = UserAllocPool(GDWPN_BITSIZE * sizeof(WCHAR), TAG_SYSTEM);
|
|
if (lpszBitmap == NULL)
|
|
return NULL;
|
|
|
|
/*
|
|
* Get the "Wallpaper" string from WIN.INI's [Desktop] section. The
|
|
* section name is not localized, so hard code it. If the string
|
|
* returned is Empty, then set it up for a none-wallpaper.
|
|
*
|
|
* Unlike the rest of per user settings that got updated in
|
|
* xxxUpdatePerUserSystemParameters, wallpaper is being updated via a
|
|
* direct call to SystemParametersInfo from UpdatePerUserSystemParameters.
|
|
* Force remote settings check in this case.
|
|
*/
|
|
if (!FastGetProfileStringFromIDW(pProfileUserName,
|
|
PMAP_DESKTOP,
|
|
STR_DTBITMAP,
|
|
wszNone,
|
|
lpszBitmap,
|
|
GDWPN_BITSIZE,
|
|
POLICY_REMOTE
|
|
)) {
|
|
wcscpy(lpszBitmap, wszNone);
|
|
}
|
|
|
|
} else {
|
|
|
|
UINT uLen;
|
|
|
|
uLen = wcslen(lpszFile) + 1;
|
|
uLen = max(uLen, GDWPN_BITSIZE);
|
|
|
|
/*
|
|
* Allocate enough space to store the name passed in. Returning
|
|
* NULL will allow the wallpaper to redraw. As well, if we're
|
|
* out of memory, then no need to load a wallpaper anyway.
|
|
*/
|
|
lpszBitmap = UserAllocPool(uLen * sizeof(WCHAR), TAG_SYSTEM);
|
|
if (lpszBitmap == NULL)
|
|
return NULL;
|
|
|
|
wcscpy(lpszBitmap, lpszFile);
|
|
}
|
|
|
|
/*
|
|
* No bitmap if NULL passed in or if (NONE) in win.ini entry. We
|
|
* return NULL to force the redraw of the wallpaper in the kernel.
|
|
*/
|
|
if ((*lpszBitmap == (WCHAR)0) || (_wcsicmp(lpszBitmap, wszNone) == 0)) {
|
|
UserFreePool(lpszBitmap);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* If bitmap name set to (DEFAULT) then set it to the system bitmap.
|
|
*/
|
|
ServerLoadString(hModuleWin, STR_DEFAULT, wszKey, ARRAY_SIZE(wszKey));
|
|
|
|
if (_wcsicmp(lpszBitmap, wszKey) == 0) {
|
|
GetDefaultWallpaperName(lpszBitmap);
|
|
}
|
|
|
|
|
|
return lpszBitmap;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* TestVGAColors
|
|
*
|
|
* Tests whether the log-palette is just a standard 20 palette.
|
|
*
|
|
* History:
|
|
* 29-Sep-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL TestVGAColors(
|
|
LPLOGPALETTE ppal)
|
|
{
|
|
int i;
|
|
int n;
|
|
int size;
|
|
COLORREF clr;
|
|
|
|
static CONST DWORD StupidColors[] = {
|
|
0x00000000, // 0 Sys Black
|
|
0x00000080, // 1 Sys Dk Red
|
|
0x00008000, // 2 Sys Dk Green
|
|
0x00008080, // 3 Sys Dk Yellow
|
|
0x00800000, // 4 Sys Dk Blue
|
|
0x00800080, // 5 Sys Dk Violet
|
|
0x00808000, // 6 Sys Dk Cyan
|
|
0x00c0c0c0, // 7 Sys Lt Grey
|
|
0x00808080, // 248 Sys Lt Gray
|
|
0x000000ff, // 249 Sys Red
|
|
0x0000ff00, // 250 Sys Green
|
|
0x0000ffff, // 251 Sys Yellow
|
|
0x00ff0000, // 252 Sys Blue
|
|
0x00ff00ff, // 253 Sys Violet
|
|
0x00ffff00, // 254 Sys Cyan
|
|
0x00ffffff, // 255 Sys White
|
|
|
|
0x000000BF, // 1 Sys Dk Red again
|
|
0x0000BF00, // 2 Sys Dk Green again
|
|
0x0000BFBF, // 3 Sys Dk Yellow again
|
|
0x00BF0000, // 4 Sys Dk Blue again
|
|
0x00BF00BF, // 5 Sys Dk Violet again
|
|
0x00BFBF00, // 6 Sys Dk Cyan again
|
|
|
|
0x000000C0, // 1 Sys Dk Red again
|
|
0x0000C000, // 2 Sys Dk Green again
|
|
0x0000C0C0, // 3 Sys Dk Yellow again
|
|
0x00C00000, // 4 Sys Dk Blue again
|
|
0x00C000C0, // 5 Sys Dk Violet again
|
|
0x00C0C000, // 6 Sys Dk Cyan again
|
|
};
|
|
|
|
size = (sizeof(StupidColors) / sizeof(StupidColors[0]));
|
|
|
|
for (i = 0; i < (int)ppal->palNumEntries; i++) {
|
|
|
|
clr = ((LPDWORD)ppal->palPalEntry)[i];
|
|
|
|
for (n = 0; n < size; n++) {
|
|
|
|
if (StupidColors[n] == clr)
|
|
break;
|
|
}
|
|
|
|
if (n == size)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DoHTColorAdjustment
|
|
*
|
|
* The default HT-Gamma adjustment was 2.0 on 3.5 (internal to gdi). For
|
|
* 3.51 this value was decreased to 1.0 to accomdate printing. For our
|
|
* desktop-wallpaper we are going to darken it slightly to that the image
|
|
* doesn't appear to light. For the Shell-Release we will provid a UI to
|
|
* allow users to change this for themselves.
|
|
*
|
|
*
|
|
* History:
|
|
* 11-May-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
|
|
#define FIXED_GAMMA (WORD)13000
|
|
|
|
VOID DoHTColorAdjust(
|
|
HDC hdc)
|
|
{
|
|
COLORADJUSTMENT ca;
|
|
|
|
if (GreGetColorAdjustment(hdc, &ca)) {
|
|
|
|
ca.caRedGamma =
|
|
ca.caGreenGamma =
|
|
ca.caBlueGamma = FIXED_GAMMA;
|
|
|
|
GreSetColorAdjustment(hdc, &ca);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ConvertToDDB
|
|
*
|
|
* Converts a DIBSection to a DDB. We do this to speed up drawings so that
|
|
* bitmap-colors don't have to go through a palette-translation match. This
|
|
* will also stretch/expand the image if the syle is set.
|
|
*
|
|
* If the new image requires a halftone-palette, the we will create one and
|
|
* set it as the new wallpaper-palette.
|
|
*
|
|
* History:
|
|
* 26-Oct-1995 ChrisWil Ported.
|
|
* 30-Oct-1995 ChrisWil Added halftoning. Rewote the stretch/expand stuff.
|
|
\***************************************************************************/
|
|
|
|
HBITMAP ConvertToDDB(
|
|
HDC hdc,
|
|
HBITMAP hbmOld,
|
|
HPALETTE hpal)
|
|
{
|
|
BITMAP bm;
|
|
HBITMAP hbmNew;
|
|
|
|
/*
|
|
* This object must be a REALDIB type bitmap.
|
|
*/
|
|
GreExtGetObjectW(hbmOld, sizeof(bm), &bm);
|
|
|
|
/*
|
|
* Create the new wallpaper-surface.
|
|
*/
|
|
if (hbmNew = GreCreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight)) {
|
|
|
|
HPALETTE hpalDst;
|
|
HPALETTE hpalSrc;
|
|
HBITMAP hbmDst;
|
|
HBITMAP hbmSrc;
|
|
UINT bpp;
|
|
BOOL fHalftone = FALSE;
|
|
|
|
/*
|
|
* Select in the surfaces.
|
|
*/
|
|
hbmDst = GreSelectBitmap(ghdcMem2, hbmNew);
|
|
hbmSrc = GreSelectBitmap(ghdcMem, hbmOld);
|
|
|
|
/*
|
|
* Determine image bits/pixel.
|
|
*/
|
|
bpp = (bm.bmPlanes * bm.bmBitsPixel);
|
|
|
|
/*
|
|
* Use the palette if given. If the image is of a greater
|
|
* resolution than the device, then we're going to go through
|
|
* a halftone-palette to get better colors.
|
|
*/
|
|
if (hpal) {
|
|
|
|
hpalDst = _SelectPalette(ghdcMem2, hpal, FALSE);
|
|
hpalSrc = _SelectPalette(ghdcMem, hpal, FALSE);
|
|
|
|
xxxRealizePalette(ghdcMem2);
|
|
|
|
/*
|
|
* Set the halftoning for the destination. This is done
|
|
* for images of greater resolution than the device.
|
|
*/
|
|
if (bpp > gpsi->BitCount) {
|
|
fHalftone = TRUE;
|
|
DoHTColorAdjust(ghdcMem2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the stretchbltmode. This is more necessary when doing
|
|
* halftoning. Since otherwise, the colors won't translate
|
|
* correctly.
|
|
*/
|
|
SetBestStretchMode(ghdcMem2, bpp, fHalftone);
|
|
|
|
/*
|
|
* Set the new surface bits. Use StretchBlt() so the SBMode
|
|
* will be used in color-translation.
|
|
*/
|
|
GreStretchBlt(ghdcMem2,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
ghdcMem,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
SRCCOPY,
|
|
0);
|
|
|
|
/*
|
|
* Restore palettes.
|
|
*/
|
|
if (hpal) {
|
|
_SelectPalette(ghdcMem2, hpalDst, FALSE);
|
|
_SelectPalette(ghdcMem, hpalSrc, FALSE);
|
|
}
|
|
|
|
/*
|
|
* Restore the surfaces.
|
|
*/
|
|
GreSelectBitmap(ghdcMem2, hbmDst);
|
|
GreSelectBitmap(ghdcMem, hbmSrc);
|
|
GreDeleteObject(hbmOld);
|
|
|
|
GreSetBitmapOwner(hbmNew, OBJECT_OWNER_PUBLIC);
|
|
|
|
} else {
|
|
hbmNew = hbmOld;
|
|
}
|
|
|
|
return hbmNew;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreatePaletteFromBitmap
|
|
*
|
|
* Take in a REAL dib handle and create a palette from it. This will not
|
|
* work for bitmaps created by any other means than CreateDIBSection or
|
|
* CreateDIBitmap(CBM_CREATEDIB). This is due to the fact that these are
|
|
* the only two formats who have palettes stored with their object.
|
|
*
|
|
* History:
|
|
* 29-Sep-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
|
|
HPALETTE CreatePaletteFromBitmap(
|
|
HBITMAP hbm)
|
|
{
|
|
HPALETTE hpal;
|
|
LPLOGPALETTE ppal;
|
|
HBITMAP hbmT;
|
|
DWORD size;
|
|
int i;
|
|
|
|
/*
|
|
* Make room for temp logical palette of max size.
|
|
*/
|
|
size = sizeof(LOGPALETTE) + (MAXPAL * sizeof(PALETTEENTRY));
|
|
|
|
ppal = (LPLOGPALETTE)UserAllocPool(size, TAG_SYSTEM);
|
|
if (!ppal)
|
|
return NULL;
|
|
|
|
/*
|
|
* Retrieve the palette from the DIB(Section). The method of calling
|
|
* GreGetDIBColorTable() can only be done on sections or REAL-Dibs.
|
|
*/
|
|
hbmT = GreSelectBitmap(ghdcMem, hbm);
|
|
ppal->palVersion = 0x300;
|
|
ppal->palNumEntries = (WORD)GreGetDIBColorTable(ghdcMem,
|
|
0,
|
|
MAXPAL,
|
|
(LPRGBQUAD)ppal->palPalEntry);
|
|
GreSelectBitmap(ghdcMem, hbmT);
|
|
|
|
/*
|
|
* Create a halftone-palette if their are no entries. Otherwise,
|
|
* swap the RGB values to be palentry-compatible and create us a
|
|
* palette.
|
|
*/
|
|
if (ppal->palNumEntries == 0) {
|
|
hpal = GreCreateHalftonePalette(gpDispInfo->hdcScreen);
|
|
} else {
|
|
|
|
BYTE tmpR;
|
|
|
|
/*
|
|
* Swap red/blue because a RGBQUAD and PALETTEENTRY dont get along.
|
|
*/
|
|
for (i=0; i < (int)ppal->palNumEntries; i++) {
|
|
tmpR = ppal->palPalEntry[i].peRed;
|
|
ppal->palPalEntry[i].peRed = ppal->palPalEntry[i].peBlue;
|
|
ppal->palPalEntry[i].peBlue = tmpR;
|
|
ppal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
|
|
/*
|
|
* If the Bitmap only has VGA colors in it we dont want to
|
|
* use a palette. It just causes unessesary palette flashes.
|
|
*/
|
|
hpal = TestVGAColors(ppal) ? NULL : GreCreatePalette(ppal);
|
|
}
|
|
|
|
UserFreePool(ppal);
|
|
|
|
/*
|
|
* Make this palette public.
|
|
*/
|
|
if (hpal)
|
|
GreSetPaletteOwner(hpal, OBJECT_OWNER_PUBLIC);
|
|
|
|
return hpal;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* TileWallpaper
|
|
*
|
|
* History:
|
|
* 29-Jul-1991 MikeKe From win31
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
TileWallpaper(HDC hdc, LPCRECT lprc, BOOL fOffset)
|
|
{
|
|
int xO;
|
|
int yO;
|
|
int x;
|
|
int y;
|
|
BITMAP bm;
|
|
HBITMAP hbmT = NULL;
|
|
POINT ptOffset;
|
|
|
|
if (fOffset) {
|
|
ptOffset.x = gsrcWallpaper.x;
|
|
ptOffset.y = gsrcWallpaper.y;
|
|
} else {
|
|
ptOffset.x = 0;
|
|
ptOffset.y = 0;
|
|
}
|
|
|
|
/*
|
|
* We need to get the dimensions of the bitmap here rather than rely on
|
|
* the dimensions in srcWallpaper because this function may
|
|
* be called as part of ExpandBitmap, before srcWallpaper is
|
|
* set.
|
|
*/
|
|
if (GreExtGetObjectW(ghbmWallpaper, sizeof(BITMAP), (PBITMAP)&bm)) {
|
|
xO = lprc->left - (lprc->left % bm.bmWidth) + (ptOffset.x % bm.bmWidth);
|
|
if (xO > lprc->left) {
|
|
xO -= bm.bmWidth;
|
|
}
|
|
|
|
yO = lprc->top - (lprc->top % bm.bmHeight) + (ptOffset.y % bm.bmHeight);
|
|
if (yO > lprc->top) {
|
|
yO -= bm.bmHeight;
|
|
}
|
|
|
|
/*
|
|
* Tile the bitmap to the surface.
|
|
*/
|
|
if (hbmT = GreSelectBitmap(ghdcMem, ghbmWallpaper)) {
|
|
for (y = yO; y < lprc->bottom; y += bm.bmHeight) {
|
|
for (x = xO; x < lprc->right; x += bm.bmWidth) {
|
|
GreBitBlt(hdc,
|
|
x,
|
|
y,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
ghdcMem,
|
|
0,
|
|
0,
|
|
SRCCOPY,
|
|
0);
|
|
}
|
|
}
|
|
|
|
GreSelectBitmap(ghdcMem, hbmT);
|
|
}
|
|
}
|
|
|
|
return (hbmT != NULL);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetWallpaperCenterRect
|
|
*
|
|
* Returns the rect of centered wallpaper on a particular monitor.
|
|
*
|
|
* History:
|
|
* 26-Sep-1996 adams Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
GetWallpaperCenterRect(LPRECT lprc, LPPOINT lppt, LPCRECT lprcMonitor)
|
|
{
|
|
RECT rc;
|
|
|
|
|
|
if (gsrcWallpaper.x != 0 || gsrcWallpaper.y != 0) {
|
|
rc.left = lprcMonitor->left + gsrcWallpaper.x;
|
|
rc.top = lprcMonitor->top + gsrcWallpaper.y;
|
|
} else {
|
|
rc.left = (lprcMonitor->left + lprcMonitor->right - gsrcWallpaper.cx) / 2;
|
|
rc.top = (lprcMonitor->top + lprcMonitor->bottom - gsrcWallpaper.cy) / 2;
|
|
}
|
|
|
|
rc.right = rc.left + gsrcWallpaper.cx;
|
|
rc.bottom = rc.top + gsrcWallpaper.cy;
|
|
|
|
lppt->x = max(0, lprcMonitor->left - rc.left);
|
|
lppt->y = max(0, lprcMonitor->top - rc.top);
|
|
|
|
return IntersectRect(lprc, &rc, lprcMonitor);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* CenterOrStretchWallpaper
|
|
*
|
|
*
|
|
* History:
|
|
* 29-Jul-1991 MikeKe From win31
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
CenterOrStretchWallpaper(HDC hdc, LPCRECT lprcMonitor)
|
|
{
|
|
BOOL fStretchToEachMonitor = FALSE;
|
|
RECT rc;
|
|
HBITMAP hbmT;
|
|
BOOL f = FALSE;
|
|
HRGN hrgn;
|
|
POINT pt;
|
|
BITMAP bm;
|
|
int oldStretchMode;
|
|
|
|
/*
|
|
* This used to call TileWallpaper, but this really slowed up the system
|
|
* for small dimension bitmaps. We really only need to blt it once for
|
|
* centered bitmaps.
|
|
*/
|
|
if (hbmT = GreSelectBitmap(ghdcMem, ghbmWallpaper)) {
|
|
if (fStretchToEachMonitor && (gwWPStyle & DTF_STRETCH)) {
|
|
if (GreExtGetObjectW(ghbmWallpaper, sizeof(BITMAP), (PBITMAP)&bm)) {
|
|
oldStretchMode = GreSetStretchBltMode(hdc, COLORONCOLOR);
|
|
f = GreStretchBlt(hdc,
|
|
lprcMonitor->left,
|
|
lprcMonitor->top,
|
|
lprcMonitor->right - lprcMonitor->left,
|
|
lprcMonitor->bottom - lprcMonitor->top,
|
|
ghdcMem,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
SRCCOPY,
|
|
0);
|
|
GreSetStretchBltMode(hdc, oldStretchMode);
|
|
}
|
|
} else {
|
|
if (GetWallpaperCenterRect(&rc, &pt, lprcMonitor)) {
|
|
f = GreBitBlt(hdc,
|
|
rc.left,
|
|
rc.top,
|
|
rc.right - rc.left,
|
|
rc.bottom - rc.top,
|
|
ghdcMem,
|
|
pt.x,
|
|
pt.y,
|
|
SRCCOPY,
|
|
0);
|
|
|
|
/*
|
|
* Fill the bacground (excluding the bitmap) with the desktop
|
|
* brush. Save the DC with the cliprect.
|
|
*/
|
|
if (f && NULL != (hrgn = CreateEmptyRgn())) {
|
|
if (GreGetRandomRgn(hdc, hrgn, 1) != -1) {
|
|
GreExcludeClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
|
|
FillRect(hdc, lprcMonitor, SYSHBR(DESKTOP));
|
|
GreExtSelectClipRgn(hdc, hrgn, RGN_COPY);
|
|
}
|
|
|
|
GreDeleteObject(hrgn);
|
|
}
|
|
}
|
|
}
|
|
|
|
GreSelectBitmap(ghdcMem, hbmT);
|
|
}
|
|
|
|
/*
|
|
* As a last-ditch effort, if something failed, just clear the desktop.
|
|
*/
|
|
if (!f) {
|
|
FillRect(hdc, lprcMonitor, SYSHBR(DESKTOP));
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxDrawWallpaper
|
|
*
|
|
* Performs the drawing of the wallpaper. This can be either tiled or
|
|
* centered. This routine provides the common things like palette-handling.
|
|
* If the (fPaint) is false, then we only to palette realization and no
|
|
* drawing.
|
|
*
|
|
* History:
|
|
* 01-Oct-1995 ChrisWil Ported.
|
|
\***************************************************************************/
|
|
|
|
BOOL xxxDrawWallpaper(
|
|
PWND pwnd,
|
|
HDC hdc,
|
|
PMONITOR pMonitorPaint,
|
|
LPCRECT lprc)
|
|
{
|
|
BOOL f;
|
|
HPALETTE hpalT;
|
|
int i;
|
|
|
|
CheckLock(pwnd);
|
|
CheckLock(pMonitorPaint);
|
|
UserAssert(ghbmWallpaper != NULL);
|
|
UserAssert(lprc);
|
|
|
|
/*
|
|
* Select in the palette if one exists. As a wallpaper, we should only
|
|
* be able to do background-realizations.
|
|
*/
|
|
if (ghpalWallpaper && pMonitorPaint->dwMONFlags & MONF_PALETTEDISPLAY) {
|
|
hpalT = _SelectPalette(hdc, ghpalWallpaper, FALSE);
|
|
i = xxxRealizePalette(hdc);
|
|
} else {
|
|
hpalT = NULL;
|
|
}
|
|
|
|
if (gwWPStyle & DTF_TILE) {
|
|
f = TileWallpaper(hdc, lprc, pwnd != NULL);
|
|
} else {
|
|
f = CenterOrStretchWallpaper(hdc, &pMonitorPaint->rcMonitor);
|
|
}
|
|
|
|
if (hpalT) {
|
|
_SelectPalette(hdc, hpalT, FALSE);
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxExpandBitmap
|
|
*
|
|
* Expand this bitmap to fit the screen. This is used for tiled images
|
|
* only.
|
|
*
|
|
* History:
|
|
* 29-Sep-1995 ChrisWil Ported from Chicago.
|
|
\***************************************************************************/
|
|
|
|
HBITMAP xxxExpandBitmap(
|
|
HBITMAP hbm)
|
|
{
|
|
int nx;
|
|
int ny;
|
|
BITMAP bm;
|
|
HBITMAP hbmNew;
|
|
HBITMAP hbmD;
|
|
LPRECT lprc;
|
|
RECT rc;
|
|
PMONITOR pMonitor;
|
|
TL tlpMonitor;
|
|
|
|
|
|
/*
|
|
* Get the dimensions of the screen and bitmap we'll be dealing with.
|
|
* We'll adjust the xScreen/yScreen to reflect the new surface size.
|
|
* The default adjustment is to stretch the image to fit the screen.
|
|
*/
|
|
GreExtGetObjectW(hbm, sizeof(bm), (PBITMAP)&bm);
|
|
|
|
pMonitor = GetPrimaryMonitor();
|
|
lprc = &pMonitor->rcMonitor;
|
|
nx = (lprc->right / TILE_XMINSIZE) / bm.bmWidth;
|
|
ny = (lprc->bottom / TILE_YMINSIZE) / bm.bmHeight;
|
|
|
|
if (nx == 0)
|
|
nx++;
|
|
|
|
if (ny == 0)
|
|
ny++;
|
|
|
|
if ((nx + ny) <= 2)
|
|
return hbm;
|
|
|
|
|
|
/*
|
|
* Create the surface for the new-bitmap.
|
|
*/
|
|
rc.left = rc.top = 0;
|
|
rc.right = nx * bm.bmWidth;
|
|
rc.bottom = ny * bm.bmHeight;
|
|
hbmD = GreSelectBitmap(ghdcMem, hbm);
|
|
hbmNew = GreCreateCompatibleBitmap(ghdcMem, rc.right, rc.bottom);
|
|
GreSelectBitmap(ghdcMem, hbmD);
|
|
|
|
if (hbmNew == NULL)
|
|
return hbm;
|
|
|
|
if (hbmD = GreSelectBitmap(ghdcMem2, hbmNew)) {
|
|
/*
|
|
* Expand the bitmap to the new surface.
|
|
*/
|
|
ThreadLockAlways(pMonitor, &tlpMonitor);
|
|
xxxDrawWallpaper(NULL, ghdcMem2, pMonitor, &rc);
|
|
ThreadUnlock(&tlpMonitor);
|
|
GreSelectBitmap(ghdcMem2, hbmD);
|
|
}
|
|
|
|
GreDeleteObject(hbm);
|
|
|
|
GreSetBitmapOwner(hbmNew, OBJECT_OWNER_PUBLIC);
|
|
|
|
return hbmNew;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxLoadDesktopWallpaper
|
|
*
|
|
* Load the dib (section) from the client-side. We make this callback to
|
|
* utilize code in USER32 for loading/creating a dib or section. Since,
|
|
* the wallpaper-code can be called from any-process, we can't use DIBSECTIONS
|
|
* for a wallpaper. Luckily we can use Real-DIBs for this. That way we
|
|
* can extract out a palette from the bitmap. We couldn't do this if the
|
|
* bitmap was created "compatible".
|
|
*
|
|
* History:
|
|
* 29-Sep-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL xxxLoadDesktopWallpaper(
|
|
LPWSTR lpszFile)
|
|
{
|
|
UINT LR_flags;
|
|
int dxDesired;
|
|
int dyDesired;
|
|
UNICODE_STRING strName;
|
|
|
|
|
|
/*
|
|
* If the bitmap is somewhat large (big bpp), then we'll deal
|
|
* with it as a real-dib. We'll also do this for 8bpp since it
|
|
* can utilize a palette. Chicago uses DIBSECTIONS since it can
|
|
* count on the one-process handling the drawing. Since, NT can
|
|
* have different processes doing the drawing, we can't use sections.
|
|
*/
|
|
LR_flags = LR_LOADFROMFILE;
|
|
|
|
if (gpDispInfo->fAnyPalette || gpsi->BitCount >= 8) {
|
|
LR_flags |= LR_CREATEREALDIB;
|
|
}
|
|
|
|
/*
|
|
* If we are going to be stretching the bitmap, go ahead and pre-stretch
|
|
* the bitmap to the size of the primary monitor. This makes blitting
|
|
* to the primary monitor quicker (because it doesn't have to stretch),
|
|
* while other monitors will be a little slower.
|
|
*/
|
|
if (gwWPStyle & DTF_STRETCH) {
|
|
PMONITOR pMonitor = GetPrimaryMonitor();
|
|
dxDesired = pMonitor->rcMonitor.right - pMonitor->rcMonitor.left;
|
|
dyDesired = pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top;
|
|
} else {
|
|
dxDesired = dyDesired = 0;
|
|
}
|
|
|
|
/*
|
|
* Make a callback to the client to perform the loading.
|
|
* Saves us some code.
|
|
*/
|
|
RtlInitUnicodeString(&strName, lpszFile);
|
|
|
|
ghbmWallpaper = xxxClientLoadImage(
|
|
&strName,
|
|
0,
|
|
IMAGE_BITMAP,
|
|
dxDesired,
|
|
dyDesired,
|
|
LR_flags,
|
|
TRUE);
|
|
|
|
if (ghbmWallpaper == NULL)
|
|
return FALSE;
|
|
|
|
/*
|
|
* If it's a palette-display, then we will derive the global
|
|
* wallpaper palette from the bitmap.
|
|
*/
|
|
if (gpDispInfo->fAnyPalette) {
|
|
ghpalWallpaper = CreatePaletteFromBitmap(ghbmWallpaper);
|
|
}
|
|
|
|
/*
|
|
* Always try to convert the bitmap to a DDB. On single monitor
|
|
* systems this will improve performance. On multiple-monitor
|
|
* systems, GDI will refuse to create the DDB and just leave it
|
|
* as a DIB at the color format of the primary monitor.
|
|
*/
|
|
ghbmWallpaper = ConvertToDDB(gpDispInfo->hdcScreen, ghbmWallpaper, ghpalWallpaper);
|
|
|
|
/*
|
|
* Mark the bitmap as public, so any process can party with it.
|
|
*/
|
|
GreSetBitmapOwner(ghbmWallpaper, OBJECT_OWNER_PUBLIC);
|
|
|
|
/*
|
|
* Expand bitmap if we are going to tile it. This creates a larger
|
|
* bitmap that contains an even multiple of the source bitmap. This
|
|
* larger bitmap can then be tiled more quickly than the smaller bitmap.
|
|
*/
|
|
if (gwWPStyle & DTF_TILE) {
|
|
ghbmWallpaper = xxxExpandBitmap(ghbmWallpaper);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSetDeskWallpaper
|
|
*
|
|
* Sets the desktop-wallpaper. This deletes the old handles in the process.
|
|
*
|
|
* History:
|
|
* 29-Jul-1991 MikeKe From win31.
|
|
* 01-Oct-1995 ChrisWil Rewrote for LoadImage().
|
|
\***************************************************************************/
|
|
|
|
BOOL xxxSetDeskWallpaper(PUNICODE_STRING pProfileUserName,
|
|
LPWSTR lpszFile)
|
|
{
|
|
BITMAP bm;
|
|
UINT WallpaperStyle2;
|
|
PWND pwndShell;
|
|
TL tl;
|
|
PTHREADINFO ptiCurrent = PtiCurrent();
|
|
PDESKTOP pdesk;
|
|
BOOL fRet = FALSE;
|
|
HBITMAP hbmOld;
|
|
|
|
PROFINTINFO apsi[] = {
|
|
{PMAP_DESKTOP, (LPWSTR)STR_TILEWALL , 0, &gwWPStyle },
|
|
{PMAP_DESKTOP, (LPWSTR)STR_DTSTYLE , 0, &WallpaperStyle2 },
|
|
{PMAP_DESKTOP, (LPWSTR)STR_DTORIGINX, 0, &gsrcWallpaper.x },
|
|
{PMAP_DESKTOP, (LPWSTR)STR_DTORIGINY, 0, &gsrcWallpaper.y },
|
|
{0, NULL, 0, NULL }
|
|
};
|
|
|
|
pdesk = ptiCurrent->rpdesk;
|
|
hbmOld = ghbmWallpaper;
|
|
|
|
if ((lpszFile == SETWALLPAPER_METRICS) && !(gwWPStyle & DTF_STRETCH)) {
|
|
|
|
gsrcWallpaper.x = 0;
|
|
gsrcWallpaper.y = 0;
|
|
|
|
if (ghbmWallpaper)
|
|
goto CreateNewWallpaper;
|
|
|
|
goto Metric_Change;
|
|
}
|
|
|
|
CreateNewWallpaper:
|
|
|
|
/*
|
|
* Delete the old wallpaper and palette if the exist.
|
|
*/
|
|
if (ghpalWallpaper) {
|
|
GreDeleteObject(ghpalWallpaper);
|
|
ghpalWallpaper = NULL;
|
|
}
|
|
|
|
if (ghbmWallpaper) {
|
|
GreDeleteObject(ghbmWallpaper);
|
|
ghbmWallpaper = NULL;
|
|
}
|
|
|
|
/*
|
|
* Kill any SPBs no matter what. This works if we're switching from/to
|
|
* palettized wallpaper. Fixes a lot of problems because palette doesn't
|
|
* change, shell paints funny on desktop, etc.
|
|
*/
|
|
BEGINATOMICCHECK();
|
|
FreeAllSpbs();
|
|
ENDATOMICCHECK();
|
|
|
|
/*
|
|
* If this is a metric-change (and stretched), then we need to
|
|
* reload it. However, since we are called from the winlogon process
|
|
* during a desktop-switch, we would be mapped to the wrong Luid
|
|
* when we attempt to grab the name from GetDeskWallpaperName. This
|
|
* would use the Luid from the DEFAULT user rather than the current
|
|
* logged on user. In order to avoid this, we cache the wallpaer
|
|
* name so that on METRIC-CHANGES we use the current-user's wallpaper.
|
|
*
|
|
* NOTE: we assume that prior to any METRIC change, we have already
|
|
* setup the ghbmWallpaper and lpszCached. This is usually done
|
|
* either on logon or during user desktop-changes through conrol-Panel.
|
|
*/
|
|
if (lpszFile == SETWALLPAPER_METRICS) {
|
|
|
|
UserAssert(gpszWall != NULL);
|
|
|
|
goto LoadWallpaper;
|
|
}
|
|
|
|
/*
|
|
* Free the cached handle.
|
|
*/
|
|
if (gpszWall) {
|
|
UserFreePool(gpszWall);
|
|
gpszWall = NULL;
|
|
}
|
|
|
|
/*
|
|
* Load the wallpaper-name. If this returns FALSE, then
|
|
* the user specified (None). We will return true to force
|
|
* the repainting of the desktop.
|
|
*/
|
|
gpszWall = GetDeskWallpaperName(pProfileUserName,lpszFile);
|
|
if (!gpszWall) {
|
|
fRet = TRUE;
|
|
goto SDW_Exit;
|
|
}
|
|
|
|
/*
|
|
* Retrieve the default settings from the registry.
|
|
*
|
|
* If tile is indicated, then normalize style to not include
|
|
* FIT/STRETCH which are center-only styles. Likewise, if
|
|
* we are centered, then normalize out the TILE bit.
|
|
*/
|
|
FastGetProfileIntsW(pProfileUserName, apsi, 0);
|
|
|
|
gwWPStyle &= DTF_TILE;
|
|
if (!(gwWPStyle & DTF_TILE)) {
|
|
gwWPStyle = WallpaperStyle2 & DTF_STRETCH;
|
|
}
|
|
|
|
/*
|
|
* Load the wallpaper. This makes a callback to the client to
|
|
* perform the bitmap-creation.
|
|
*/
|
|
|
|
LoadWallpaper:
|
|
|
|
if (xxxLoadDesktopWallpaper(gpszWall) == FALSE) {
|
|
gwWPStyle = 0;
|
|
goto SDW_Exit;
|
|
}
|
|
|
|
/*
|
|
* If we have a palette, then we need to do the correct realization and
|
|
* notification.
|
|
*/
|
|
if (ghpalWallpaper != NULL) {
|
|
PWND pwndSend;
|
|
|
|
/*
|
|
* Get the shell window. This could be NULL on system
|
|
* initialization. We will use this to do palette realization.
|
|
*/
|
|
pwndShell = _GetShellWindow(pdesk);
|
|
if (pwndShell) {
|
|
pwndSend = pwndShell;
|
|
} else {
|
|
pwndSend = (pdesk ? pdesk->pDeskInfo->spwnd : NULL);
|
|
}
|
|
|
|
/*
|
|
* Update the desktop with the new bitmap. This cleans
|
|
* out the system-palette so colors can be realized.
|
|
*/
|
|
GreRealizeDefaultPalette(gpDispInfo->hdcScreen, TRUE);
|
|
|
|
/*
|
|
* Don't broadcast if system initialization is occuring. Otherwise
|
|
* this gives the shell first crack at realizing its colors
|
|
* correctly.
|
|
*/
|
|
if (pwndSend) {
|
|
HWND hwnd = HW(pwndSend);
|
|
|
|
ThreadLockAlways(pwndSend, &tl);
|
|
xxxSendNotifyMessage(pwndSend, WM_PALETTECHANGED, (WPARAM)hwnd, 0);
|
|
ThreadUnlock(&tl);
|
|
}
|
|
}
|
|
|
|
Metric_Change:
|
|
if (fRet = GreExtGetObjectW(ghbmWallpaper, sizeof(bm), (PBITMAP)&bm)) {
|
|
gsrcWallpaper.cx = bm.bmWidth;
|
|
gsrcWallpaper.cy = bm.bmHeight;
|
|
}
|
|
|
|
SDW_Exit:
|
|
|
|
/*
|
|
* Notify the shell-window that the wallpaper changed. We need to refresh
|
|
* our local pwndShell here because we might have called-back above.
|
|
*/
|
|
pwndShell = _GetShellWindow(pdesk);
|
|
if ((pwndShell != NULL) &&
|
|
((hbmOld && !ghbmWallpaper) || (!hbmOld && ghbmWallpaper))) {
|
|
|
|
ThreadLockAlways(pwndShell, &tl);
|
|
xxxSendNotifyMessage(pwndShell,
|
|
WM_SHELLNOTIFY,
|
|
SHELLNOTIFY_WALLPAPERCHANGED,
|
|
(LPARAM)ghbmWallpaper);
|
|
ThreadUnlock(&tl);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* DesktopBuildPaint
|
|
*
|
|
* Draw the build information onto the desktop
|
|
*
|
|
* History:
|
|
* 2/4/99 joejo - Bug 280256
|
|
\***************************************************************************/
|
|
void DesktopBuildPaint(
|
|
HDC hdc,
|
|
PMONITOR pMonitor)
|
|
{
|
|
int imode;
|
|
COLORREF oldColor;
|
|
RECT rcText = {0,0,0,0};
|
|
RECT rcBuildInfo = {0,0,0,0};
|
|
HFONT oldFont = GreGetHFONT(hdc);
|
|
SIZE sizeText;
|
|
SIZE sizeProductName;
|
|
SIZE sizeProductBuild;
|
|
SIZE sizeSystemRoot;
|
|
BOOL fDrawSolidBackground = FALSE;
|
|
int cBorder = 5;
|
|
int cMargin = fDrawSolidBackground ? 5 : 0;
|
|
|
|
/*
|
|
* Set up DC
|
|
*/
|
|
imode = GreSetBkMode(hdc, TRANSPARENT);
|
|
|
|
if (fDrawSolidBackground) {
|
|
/*
|
|
* Since we are going to draw our own background, we can always set
|
|
* the pen color to black.
|
|
*/
|
|
oldColor = GreSetTextColor( hdc, RGB(0,0,0) );
|
|
} else {
|
|
/*
|
|
* Since we are not going to draw our own background, we have to work
|
|
* with whatever is already there. This is an ugly hack to try and
|
|
* cover the case where our white text won't show up on a white
|
|
* background. Of course, this doesn't catch the bitmap case. Or
|
|
* the almost white case.
|
|
*/
|
|
if (GreGetBrushColor(SYSHBR(BACKGROUND)) != 0x00ffffff) {
|
|
oldColor = GreSetTextColor( hdc, RGB(255,255,255) );
|
|
} else {
|
|
oldColor = GreSetTextColor( hdc, RGB(0,0,0) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the width in pixels of the longest string we are going to print out.
|
|
*/
|
|
if (gpsi && gpsi->hCaptionFont) {
|
|
GreSelectFont(hdc, gpsi->hCaptionFont);
|
|
}
|
|
|
|
GreGetTextExtentW(
|
|
hdc,
|
|
wszProductName,
|
|
wcslen(wszProductName),
|
|
&sizeProductName,
|
|
GGTE_WIN3_EXTENT);
|
|
|
|
if (ghMenuFont != NULL ) {
|
|
GreSelectFont(hdc, ghMenuFont);
|
|
}
|
|
|
|
GreGetTextExtentW(
|
|
hdc,
|
|
wszProductBuild,
|
|
wcslen(wszProductBuild),
|
|
&sizeProductBuild,
|
|
GGTE_WIN3_EXTENT);
|
|
|
|
if (gDrawVersionAlways) {
|
|
GreGetTextExtentW(
|
|
hdc,
|
|
USER_SHARED_DATA->NtSystemRoot,
|
|
wcslen(USER_SHARED_DATA->NtSystemRoot),
|
|
&sizeSystemRoot,
|
|
GGTE_WIN3_EXTENT);
|
|
} else {
|
|
sizeSystemRoot.cx = 0;
|
|
sizeSystemRoot.cy = 0;
|
|
}
|
|
|
|
sizeText.cx = sizeProductName.cx >= sizeProductBuild.cx ? sizeProductName.cx : sizeProductBuild.cx;
|
|
sizeText.cy = sizeProductName.cy + sizeProductBuild.cy;
|
|
if (gDrawVersionAlways) {
|
|
sizeText.cx = (sizeText.cx >= sizeSystemRoot.cx) ? sizeText.cx : sizeSystemRoot.cx;
|
|
sizeText.cy += sizeSystemRoot.cy;
|
|
}
|
|
|
|
/*
|
|
* Calculate the position for all of the build info on the desktop.
|
|
* We will draw either 2 or 3 lines of text.
|
|
*/
|
|
rcBuildInfo.left = pMonitor->rcWork.right - cBorder - cMargin - sizeText.cx - cMargin;
|
|
rcBuildInfo.top = pMonitor->rcWork.bottom - cBorder - cMargin - sizeText.cy - cMargin;
|
|
rcBuildInfo.right = pMonitor->rcWork.right - cBorder;
|
|
rcBuildInfo.bottom = pMonitor->rcWork.bottom - cBorder;
|
|
|
|
/*
|
|
* Draw the background if we want it.
|
|
*
|
|
*/
|
|
if (fDrawSolidBackground) {
|
|
NtGdiRoundRect(hdc, rcBuildInfo.left, rcBuildInfo.top, rcBuildInfo.right, rcBuildInfo.bottom, 10, 10);
|
|
}
|
|
|
|
/*
|
|
* Print Windows 2000 name
|
|
*/
|
|
if (gpsi && gpsi->hCaptionFont) {
|
|
GreSelectFont(hdc, gpsi->hCaptionFont);
|
|
}
|
|
|
|
rcText.left = rcBuildInfo.left + cMargin;
|
|
rcText.top = rcBuildInfo.top + cMargin;
|
|
rcText.right = rcText.left + sizeText.cx;
|
|
rcText.bottom = rcText.top + sizeProductName.cy;
|
|
|
|
GreSetTextAlign(hdc, TA_RIGHT | TA_BOTTOM);
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
rcText.right,
|
|
rcText.bottom,
|
|
0,
|
|
&rcText,
|
|
wszProductName,
|
|
wcslen(wszProductName),
|
|
(LPINT)NULL
|
|
);
|
|
|
|
/*
|
|
* Print Build Number
|
|
*/
|
|
if (ghMenuFont != NULL ) {
|
|
GreSelectFont(hdc, ghMenuFont);
|
|
}
|
|
|
|
rcText.top = rcText.bottom + 1;
|
|
rcText.bottom = rcText.top + sizeProductBuild.cy;
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
rcText.right,
|
|
rcText.bottom,
|
|
0,
|
|
&rcText,
|
|
wszProductBuild,
|
|
wcslen(wszProductBuild),
|
|
(LPINT)NULL
|
|
);
|
|
|
|
/*
|
|
* If we are in CHK mode, draw the System Dir Path
|
|
*/
|
|
if (gDrawVersionAlways) {
|
|
rcText.top = rcText.bottom + 1;
|
|
rcText.bottom = rcText.top + sizeSystemRoot.cy;
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
rcText.right,
|
|
rcText.bottom,
|
|
0,
|
|
&rcText,
|
|
USER_SHARED_DATA->NtSystemRoot,
|
|
wcslen(USER_SHARED_DATA->NtSystemRoot),
|
|
(LPINT)NULL
|
|
);
|
|
}
|
|
|
|
if (oldFont) {
|
|
GreSelectFont(hdc, oldFont);
|
|
}
|
|
|
|
GreSetBkMode(hdc, imode);
|
|
GreSetTextColor(hdc, oldColor);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxDesktopPaintCallback
|
|
*
|
|
* Draw the wallpaper or fill with the background brush. In debug,
|
|
* also draw the build number on the top of each monitor.
|
|
*
|
|
* History:
|
|
* 20-Sep-1996 adams Created.
|
|
\***************************************************************************/
|
|
BOOL
|
|
xxxDesktopPaintCallback(
|
|
PMONITOR pMonitor,
|
|
HDC hdc,
|
|
LPRECT lprcMonitorClip,
|
|
LPARAM dwData)
|
|
{
|
|
BOOL f;
|
|
PWND pwnd;
|
|
|
|
CheckLock(pMonitor);
|
|
|
|
pwnd = (PWND)dwData;
|
|
|
|
|
|
if (SYSMET(CLEANBOOT)) {
|
|
FillRect(hdc, lprcMonitorClip, ghbrBlack );
|
|
f = TRUE;
|
|
} else {
|
|
/*
|
|
* if this is the disconnected desktop, skip the bitmap paint
|
|
*/
|
|
if (gbDesktopLocked) {
|
|
f = FALSE;
|
|
} else {
|
|
|
|
/*
|
|
* Paint the desktop with a color or the wallpaper.
|
|
*/
|
|
if (ghbmWallpaper) {
|
|
f = xxxDrawWallpaper(
|
|
pwnd,
|
|
hdc,
|
|
pMonitor,
|
|
lprcMonitorClip);
|
|
} else {
|
|
FillRect(hdc, lprcMonitorClip, SYSHBR(DESKTOP));
|
|
f = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SYSMET(CLEANBOOT)
|
|
|| gDrawVersionAlways
|
|
|| gdwCanPaintDesktop) {
|
|
static BOOL fInit = TRUE;
|
|
SIZE size;
|
|
int imode;
|
|
COLORREF oldColor;
|
|
HFONT oldFont = NULL;
|
|
|
|
|
|
/*
|
|
* Grab the stuff from the registry
|
|
*/
|
|
if (fInit) {
|
|
if (SYSMET(CLEANBOOT)) {
|
|
ServerLoadString( hModuleWin, STR_SAFEMODE, SafeModeStr, ARRAY_SIZE(SafeModeStr) );
|
|
SafeModeStrLen = wcslen(SafeModeStr);
|
|
}
|
|
GetVersionInfo(SYSMET(CLEANBOOT) == 0);
|
|
fInit = FALSE;
|
|
}
|
|
|
|
if (SYSMET(CLEANBOOT)) {
|
|
if (gpsi != NULL && gpsi->hCaptionFont != NULL) {
|
|
oldFont = GreSelectFont(hdc, gpsi->hCaptionFont);
|
|
}
|
|
|
|
GreGetTextExtentW(hdc, wszSafeMode, wcslen(wszSafeMode), &size, GGTE_WIN3_EXTENT);
|
|
imode = GreSetBkMode(hdc, TRANSPARENT);
|
|
|
|
oldColor = GreSetTextColor( hdc, RGB(255,255,255) );
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
(pMonitor->rcWork.left + pMonitor->rcWork.right - size.cx) / 2,
|
|
pMonitor->rcWork.top,
|
|
0,
|
|
(LPRECT)NULL,
|
|
wszSafeMode,
|
|
wcslen(wszSafeMode),
|
|
(LPINT)NULL
|
|
);
|
|
|
|
GreGetTextExtentW(hdc, SafeModeStr, SafeModeStrLen, &size, GGTE_WIN3_EXTENT);
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
pMonitor->rcWork.left,
|
|
pMonitor->rcWork.top,
|
|
0,
|
|
(LPRECT)NULL,
|
|
SafeModeStr,
|
|
SafeModeStrLen,
|
|
(LPINT)NULL
|
|
);
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
pMonitor->rcWork.right - size.cx,
|
|
pMonitor->rcWork.top,
|
|
0,
|
|
(LPRECT)NULL,
|
|
SafeModeStr,
|
|
SafeModeStrLen,
|
|
(LPINT)NULL
|
|
);
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
pMonitor->rcWork.right - size.cx,
|
|
pMonitor->rcWork.bottom - gpsi->tmSysFont.tmHeight,
|
|
0,
|
|
(LPRECT)NULL,
|
|
SafeModeStr,
|
|
SafeModeStrLen,
|
|
(LPINT)NULL
|
|
);
|
|
|
|
GreExtTextOutW(
|
|
hdc,
|
|
pMonitor->rcWork.left,
|
|
pMonitor->rcWork.bottom - gpsi->tmSysFont.tmHeight,
|
|
0,
|
|
(LPRECT)NULL,
|
|
SafeModeStr,
|
|
SafeModeStrLen,
|
|
(LPINT)NULL
|
|
);
|
|
|
|
GreSetBkMode(hdc, imode);
|
|
GreSetTextColor(hdc, oldColor);
|
|
|
|
if (oldFont) {
|
|
GreSelectFont(hdc, oldFont);
|
|
}
|
|
} else {
|
|
if (!gbRemoteSession || !gdwTSExcludeDesktopVersion) {
|
|
DesktopBuildPaint(hdc, pMonitor);
|
|
}
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxInvalidateDesktopOnPaletteChange
|
|
*
|
|
* Invalidates the shell window and uncovered areas of the desktop
|
|
* when the palette changes.
|
|
*
|
|
* History:
|
|
* 28-Apr-1997 adams Created.
|
|
\***************************************************************************/
|
|
VOID
|
|
xxxInvalidateDesktopOnPaletteChange(
|
|
PWND pwnd)
|
|
{
|
|
PDESKTOP pdesk;
|
|
PWND pwndShell;
|
|
TL tlpwndShell;
|
|
RECT rc;
|
|
BOOL fRedrawDesktop;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
/*
|
|
* Invalidate the shell window.
|
|
*/
|
|
pdesk = PtiCurrent()->rpdesk;
|
|
pwndShell = _GetShellWindow(pdesk);
|
|
if (!pwndShell) {
|
|
fRedrawDesktop = TRUE;
|
|
rc = gpsi->rcScreen;
|
|
} else {
|
|
ThreadLockAlways(pwndShell, &tlpwndShell);
|
|
xxxRedrawWindow(
|
|
pwndShell,
|
|
NULL,
|
|
NULL,
|
|
RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
|
|
|
/*
|
|
* The shell window may not cover all of the desktop.
|
|
* Invalidate the part of the desktop wallpaper it
|
|
* doesn't sit over.
|
|
*/
|
|
fRedrawDesktop = SubtractRect(&rc, &pwnd->rcWindow, &pwndShell->rcWindow);
|
|
ThreadUnlock(&tlpwndShell);
|
|
}
|
|
|
|
/*
|
|
* Invalidate the desktop window.
|
|
*/
|
|
if (fRedrawDesktop) {
|
|
xxxRedrawWindow(
|
|
pwnd,
|
|
&rc,
|
|
NULL,
|
|
RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxInternalPaintDesktop
|
|
*
|
|
* If fPaint is TRUE, enumerate the monitors to paint the desktop.
|
|
* Otherwise, it selects the bitmap palette into the DC to select
|
|
* its colors into the hardware palette.
|
|
*
|
|
* History:
|
|
* 29-Jul-1991 MikeKe From win31
|
|
\***************************************************************************/
|
|
BOOL xxxInternalPaintDesktop(
|
|
PWND pwnd,
|
|
HDC hdc,
|
|
BOOL fPaint)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
if (fPaint) {
|
|
RECT rcOrg, rcT;
|
|
POINT pt;
|
|
|
|
/*
|
|
* For compatiblity purposes the DC origin of desktop windows
|
|
* is set to the primary monitor, i.e. (0,0). Since we may get
|
|
* either desktop or non-desktop DCs here, temporarily reset
|
|
* the hdc origin to (0,0).
|
|
*/
|
|
GreGetDCOrgEx(hdc, &pt, &rcOrg);
|
|
CopyRect(&rcT, &rcOrg);
|
|
OffsetRect(&rcT, -rcT.left, -rcT.top);
|
|
GreSetDCOrg(hdc, rcT.left, rcT.top, (PRECTL)&rcT);
|
|
|
|
fRet = xxxEnumDisplayMonitors(
|
|
hdc,
|
|
NULL,
|
|
(MONITORENUMPROC) xxxDesktopPaintCallback,
|
|
(LPARAM)pwnd,
|
|
TRUE);
|
|
|
|
/*
|
|
* Reset the DC origin back.
|
|
*/
|
|
GreSetDCOrg(hdc, rcOrg.left, rcOrg.top, (PRECTL)&rcOrg);
|
|
|
|
} else if (ghpalWallpaper &&
|
|
GetPrimaryMonitor()->dwMONFlags & MONF_PALETTEDISPLAY) {
|
|
/*
|
|
* Select in the palette if one exists.
|
|
*/
|
|
HPALETTE hpalT;
|
|
int i;
|
|
|
|
hpalT = _SelectPalette(hdc, ghpalWallpaper, FALSE);
|
|
i = xxxRealizePalette(hdc);
|
|
_SelectPalette(hdc, hpalT, FALSE);
|
|
|
|
if (i > 0) {
|
|
xxxInvalidateDesktopOnPaletteChange(pwnd);
|
|
}
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|