📄 system.c
字号:
/*
* Win32 5.1 Theme system
*
* Copyright (C) 2003 Kevin Koltzau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "vfwmsgs.h"
#include "uxtheme.h"
#include "tmschema.h"
#include "uxthemedll.h"
#include "msstyles.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
/***********************************************************************
* Defines and global variables
*/
static const WCHAR szThemeManager[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','\\',
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
'T','h','e','m','e','M','a','n','a','g','e','r','\0'
};
static const WCHAR szThemeActive[] = {'T','h','e','m','e','A','c','t','i','v','e','\0'};
static const WCHAR szSizeName[] = {'S','i','z','e','N','a','m','e','\0'};
static const WCHAR szColorName[] = {'C','o','l','o','r','N','a','m','e','\0'};
static const WCHAR szDllName[] = {'D','l','l','N','a','m','e','\0'};
static const WCHAR szIniDocumentation[] = {'d','o','c','u','m','e','n','t','a','t','i','o','n','\0'};
HINSTANCE hDllInst;
ATOM atDialogThemeEnabled;
static DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS;
static ATOM atWindowTheme;
static ATOM atSubAppName;
static ATOM atSubIdList;
static BOOL bThemeActive = FALSE;
static WCHAR szCurrentTheme[MAX_PATH];
static WCHAR szCurrentColor[64];
static WCHAR szCurrentSize[64];
/***********************************************************************/
static BOOL CALLBACK UXTHEME_broadcast_msg_enumchild (HWND hWnd, LPARAM msg)
{
PostMessageW(hWnd, msg, 0, 0);
return TRUE;
}
/* Broadcast a message to *all* windows, including children */
static BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg)
{
if (hWnd == NULL)
{
EnumWindows (UXTHEME_broadcast_msg, msg);
}
else
{
PostMessageW(hWnd, msg, 0, 0);
EnumChildWindows (hWnd, UXTHEME_broadcast_msg_enumchild, msg);
}
return TRUE;
}
/* At the end of the day this is a subset of what SHRegGetPath() does - copied
* here to avoid linking against shlwapi. */
static DWORD query_reg_path (HKEY hKey, LPCWSTR lpszValue,
LPVOID pvData)
{
DWORD dwRet, dwType, dwUnExpDataLen = MAX_PATH, dwExpDataLen;
TRACE("(hkey=%p,%s,%p)\n", hKey, debugstr_w(lpszValue),
pvData);
dwRet = RegQueryValueExW(hKey, lpszValue, 0, &dwType, pvData, &dwUnExpDataLen);
if (dwRet!=ERROR_SUCCESS && dwRet!=ERROR_MORE_DATA)
return dwRet;
if (dwType == REG_EXPAND_SZ)
{
DWORD nBytesToAlloc;
/* Expand type REG_EXPAND_SZ into REG_SZ */
LPWSTR szData;
/* If the caller didn't supply a buffer or the buffer is too small we have
* to allocate our own
*/
if (dwRet == ERROR_MORE_DATA)
{
WCHAR cNull = '\0';
nBytesToAlloc = dwUnExpDataLen;
szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
RegQueryValueExW (hKey, lpszValue, 0, NULL, (LPBYTE)szData, &nBytesToAlloc);
dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
LocalFree((HLOCAL) szData);
}
else
{
nBytesToAlloc = (lstrlenW(pvData) + 1) * sizeof(WCHAR);
szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc );
lstrcpyW(szData, pvData);
dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, MAX_PATH );
if (dwExpDataLen > MAX_PATH) dwRet = ERROR_MORE_DATA;
dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
LocalFree((HLOCAL) szData);
}
}
RegCloseKey(hKey);
return dwRet;
}
/***********************************************************************
* UXTHEME_LoadTheme
*
* Set the current active theme from the registry
*/
static void UXTHEME_LoadTheme(void)
{
HKEY hKey;
DWORD buffsize;
HRESULT hr;
WCHAR tmp[10];
PTHEME_FILE pt;
/* Get current theme configuration */
if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
TRACE("Loading theme config\n");
buffsize = sizeof(tmp)/sizeof(tmp[0]);
if(!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize)) {
bThemeActive = (tmp[0] != '0');
}
else {
bThemeActive = FALSE;
TRACE("Failed to get ThemeActive: %d\n", GetLastError());
}
buffsize = sizeof(szCurrentColor)/sizeof(szCurrentColor[0]);
if(RegQueryValueExW(hKey, szColorName, NULL, NULL, (LPBYTE)szCurrentColor, &buffsize))
szCurrentColor[0] = '\0';
buffsize = sizeof(szCurrentSize)/sizeof(szCurrentSize[0]);
if(RegQueryValueExW(hKey, szSizeName, NULL, NULL, (LPBYTE)szCurrentSize, &buffsize))
szCurrentSize[0] = '\0';
if (query_reg_path (hKey, szDllName, szCurrentTheme))
szCurrentTheme[0] = '\0';
RegCloseKey(hKey);
}
else
TRACE("Failed to open theme registry key\n");
if(bThemeActive) {
/* Make sure the theme requested is actually valid */
hr = MSSTYLES_OpenThemeFile(szCurrentTheme,
szCurrentColor[0]?szCurrentColor:NULL,
szCurrentSize[0]?szCurrentSize:NULL,
&pt);
if(FAILED(hr)) {
bThemeActive = FALSE;
szCurrentTheme[0] = '\0';
szCurrentColor[0] = '\0';
szCurrentSize[0] = '\0';
}
else {
/* Make sure the global color & size match the theme */
lstrcpynW(szCurrentColor, pt->pszSelectedColor, sizeof(szCurrentColor)/sizeof(szCurrentColor[0]));
lstrcpynW(szCurrentSize, pt->pszSelectedSize, sizeof(szCurrentSize)/sizeof(szCurrentSize[0]));
MSSTYLES_SetActiveTheme(pt, FALSE);
TRACE("Theme active: %s %s %s\n", debugstr_w(szCurrentTheme),
debugstr_w(szCurrentColor), debugstr_w(szCurrentSize));
MSSTYLES_CloseThemeFile(pt);
}
}
if(!bThemeActive) {
MSSTYLES_SetActiveTheme(NULL, FALSE);
TRACE("Theming not active\n");
}
}
/***********************************************************************/
static const char * const SysColorsNames[] =
{
"Scrollbar", /* COLOR_SCROLLBAR */
"Background", /* COLOR_BACKGROUND */
"ActiveTitle", /* COLOR_ACTIVECAPTION */
"InactiveTitle", /* COLOR_INACTIVECAPTION */
"Menu", /* COLOR_MENU */
"Window", /* COLOR_WINDOW */
"WindowFrame", /* COLOR_WINDOWFRAME */
"MenuText", /* COLOR_MENUTEXT */
"WindowText", /* COLOR_WINDOWTEXT */
"TitleText", /* COLOR_CAPTIONTEXT */
"ActiveBorder", /* COLOR_ACTIVEBORDER */
"InactiveBorder", /* COLOR_INACTIVEBORDER */
"AppWorkSpace", /* COLOR_APPWORKSPACE */
"Hilight", /* COLOR_HIGHLIGHT */
"HilightText", /* COLOR_HIGHLIGHTTEXT */
"ButtonFace", /* COLOR_BTNFACE */
"ButtonShadow", /* COLOR_BTNSHADOW */
"GrayText", /* COLOR_GRAYTEXT */
"ButtonText", /* COLOR_BTNTEXT */
"InactiveTitleText", /* COLOR_INACTIVECAPTIONTEXT */
"ButtonHilight", /* COLOR_BTNHIGHLIGHT */
"ButtonDkShadow", /* COLOR_3DDKSHADOW */
"ButtonLight", /* COLOR_3DLIGHT */
"InfoText", /* COLOR_INFOTEXT */
"InfoWindow", /* COLOR_INFOBK */
"ButtonAlternateFace", /* COLOR_ALTERNATEBTNFACE */
"HotTrackingColor", /* COLOR_HOTLIGHT */
"GradientActiveTitle", /* COLOR_GRADIENTACTIVECAPTION */
"GradientInactiveTitle", /* COLOR_GRADIENTINACTIVECAPTION */
"MenuHilight", /* COLOR_MENUHILIGHT */
"MenuBar", /* COLOR_MENUBAR */
};
static const WCHAR strColorKey[] =
{ 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
'C','o','l','o','r','s',0 };
static const WCHAR keyFlatMenus[] = { 'F','l','a','t','M','e','n','u', 0};
static const WCHAR keyGradientCaption[] = { 'G','r','a','d','i','e','n','t',
'C','a','p','t','i','o','n', 0 };
static const WCHAR keyNonClientMetrics[] = { 'N','o','n','C','l','i','e','n','t',
'M','e','t','r','i','c','s',0 };
static const WCHAR keyIconTitleFont[] = { 'I','c','o','n','T','i','t','l','e',
'F','o','n','t',0 };
static const struct BackupSysParam
{
int spiGet, spiSet;
const WCHAR* keyName;
} backupSysParams[] =
{
{SPI_GETFLATMENU, SPI_SETFLATMENU, keyFlatMenus},
{SPI_GETGRADIENTCAPTIONS, SPI_SETGRADIENTCAPTIONS, keyGradientCaption},
{-1, -1, 0}
};
#define NUM_SYS_COLORS (COLOR_MENUBAR+1)
static void save_sys_colors (HKEY baseKey)
{
char colorStr[13];
HKEY hKey;
int i;
if (RegCreateKeyExW( baseKey, strColorKey,
0, 0, 0, KEY_ALL_ACCESS,
0, &hKey, 0 ) == ERROR_SUCCESS)
{
for (i = 0; i < NUM_SYS_COLORS; i++)
{
COLORREF col = GetSysColor (i);
sprintf (colorStr, "%d %d %d",
GetRValue (col), GetGValue (col), GetBValue (col));
RegSetValueExA (hKey, SysColorsNames[i], 0, REG_SZ,
(BYTE*)colorStr, strlen (colorStr)+1);
}
RegCloseKey (hKey);
}
}
/* Before activating a theme, query current system colors, certain settings
* and backup them in the registry, so they can be restored when the theme
* is deactivated */
static void UXTHEME_BackupSystemMetrics(void)
{
HKEY hKey;
const struct BackupSysParam* bsp = backupSysParams;
if (RegCreateKeyExW( HKEY_CURRENT_USER, szThemeManager,
0, 0, 0, KEY_ALL_ACCESS,
0, &hKey, 0) == ERROR_SUCCESS)
{
NONCLIENTMETRICSW ncm;
LOGFONTW iconTitleFont;
/* back up colors */
save_sys_colors (hKey);
/* back up "other" settings */
while (bsp->spiGet >= 0)
{
DWORD value;
SystemParametersInfoW (bsp->spiGet, 0, &value, 0);
RegSetValueExW (hKey, bsp->keyName, 0, REG_DWORD,
(LPBYTE)&value, sizeof (value));
bsp++;
}
/* back up non-client metrics */
memset (&ncm, 0, sizeof (ncm));
ncm.cbSize = sizeof (ncm);
SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof (ncm), &ncm, 0);
RegSetValueExW (hKey, keyNonClientMetrics, 0, REG_BINARY, (LPBYTE)&ncm,
sizeof (ncm));
memset (&iconTitleFont, 0, sizeof (iconTitleFont));
SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof (iconTitleFont),
&iconTitleFont, 0);
RegSetValueExW (hKey, keyIconTitleFont, 0, REG_BINARY,
(LPBYTE)&iconTitleFont, sizeof (iconTitleFont));
RegCloseKey (hKey);
}
}
/* Read back old settings after a theme was deactivated */
static void UXTHEME_RestoreSystemMetrics(void)
{
HKEY hKey;
const struct BackupSysParam* bsp = backupSysParams;
if (RegOpenKeyExW (HKEY_CURRENT_USER, szThemeManager,
0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
HKEY colorKey;
/* read backed-up colors */
if (RegOpenKeyExW (hKey, strColorKey,
0, KEY_QUERY_VALUE, &colorKey) == ERROR_SUCCESS)
{
int i;
COLORREF sysCols[NUM_SYS_COLORS];
int sysColsIndices[NUM_SYS_COLORS];
int sysColCount = 0;
for (i = 0; i < NUM_SYS_COLORS; i++)
{
DWORD type;
char colorStr[13];
DWORD count = sizeof(colorStr);
if (RegQueryValueExA (colorKey, SysColorsNames[i], 0,
&type, (LPBYTE) colorStr, &count) == ERROR_SUCCESS)
{
int r, g, b;
if (sscanf (colorStr, "%d %d %d", &r, &g, &b) == 3)
{
sysColsIndices[sysColCount] = i;
sysCols[sysColCount] = RGB(r, g, b);
sysColCount++;
}
}
}
RegCloseKey (colorKey);
SetSysColors (sysColCount, sysColsIndices, sysCols);
}
/* read backed-up other settings */
while (bsp->spiGet >= 0)
{
DWORD value;
DWORD count = sizeof(value);
DWORD type;
if (RegQueryValueExW (hKey, bsp->keyName, 0,
&type, (LPBYTE)&value, &count) == ERROR_SUCCESS)
{
SystemParametersInfoW (bsp->spiSet, 0, (LPVOID)value,
SPIF_UPDATEINIFILE);
}
bsp++;
}
/* read backed-up non-client metrics */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -