Sync to Wine-20050725:

Thomas Weidenmueller <wine-patches@reactsoft.com>
- IsThemeDialogTextureEnabled should have one parameter to match the
  prototype in the official headers.
Mike McCormack <mike@codeweavers.com>
- gcc 4.0 -Wpointer-sign fixes (Reg* functions).
Stefan Huehner <stefan@huehner.org>
- Make some function static.
- Fix -Wmissing-declarations warnings.
Frank Richter <frank.richter@gmail.com>
- Enable/disable "flat menus" based on the setting from the active
  theme.
- Have the theme INI file parsed upon theme activation and not just when
  the first theme data is requested; that way, the themed system colors
  are set correctly from the start, and not just after some theme data
  was requested.
- GetThemeBackgroundContentRect() does not use the content margins
  alone, it also falls back to the border size or sizing margins, and if
  it can't find any possible margins at all, it returns the original
  rectangle.
- Make dialog theme texture setting non-global (ie a per-window
  setting).
- Better viewport origin in DrawThemeParentBackground().
- OpenThemeData() now always sets the window theme to the handle
  returned (even if that is NULL) - previously, it could happen that
  when no theme was active or the theme data could not be opened that
  the window theme remained became then-dangling (and hence subsequent
  calls to GetWindowTheme() would return that bogus theme).
- Correct border rectangle drawing.
- Don't crash if NULL is passed as the class list to OpenThemeData().
- UXTHEME_LoadImage(): Set default image count to 1 to avoid division by
  zero in case image count property is not given. Properly support 0
  state IDs.
- Every window needs to receive WM_THEMECHANGED (esp. controls), so also
  send it to child windows.
- Changed the default transparent color in case none was explicitly
  specified from the upper left pixel color to magenta. Empirically
  gives better results.
- Write WCHAR strings to registry with correct size.
- Opening some theme class data now also increases the reference count
  of the theme file, so as long as theme class data is still opened
  somewhere, the theme file won't get freed. Otherwise, it could happen
  that invalid class data was used, which could lead to problems.

svn path=/trunk/; revision=17342
This commit is contained in:
Gé van Geldorp 2005-08-12 18:22:47 +00:00
parent dbd7ad25e3
commit 013ea78e1d
4 changed files with 132 additions and 50 deletions

View file

@ -41,7 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
* Defines and global variables
*/
DWORD dwDialogTextureFlags;
extern ATOM atDialogThemeEnabled;
/***********************************************************************/
@ -50,8 +50,19 @@ DWORD dwDialogTextureFlags;
*/
HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
{
static const WCHAR szTab[] = { 'T','a','b',0 };
HRESULT hr;
TRACE("(%p,0x%08lx\n", hwnd, dwFlags);
dwDialogTextureFlags = dwFlags;
hr = SetPropW (hwnd, MAKEINTATOMW (atDialogThemeEnabled),
(HANDLE)(dwFlags|0x80000000));
/* 0x80000000 serves as a "flags set" flag */
if (FAILED(hr))
return hr;
if (dwFlags & ETDT_USETABTEXTURE)
return SetWindowTheme (hwnd, NULL, szTab);
else
return SetWindowTheme (hwnd, NULL, NULL);
return S_OK;
}
@ -60,7 +71,15 @@ HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
*/
BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
{
DWORD dwDialogTextureFlags;
TRACE("(%p)\n", hwnd);
dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
MAKEINTATOMW (atDialogThemeEnabled));
if (dwDialogTextureFlags == 0)
/* Means EnableThemeDialogTexture wasn't called for this dialog */
return TRUE;
return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
}
@ -95,7 +114,7 @@ HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
}
SetViewportOrgEx(hdc, rt.left, rt.top, &org);
OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
@ -190,7 +209,7 @@ static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iState
HBITMAP *hBmp, RECT *bmpRect)
{
int imagelayout = IL_VERTICAL;
int imagecount = 0;
int imagecount = 1;
BITMAP bmp;
WCHAR szPath[MAX_PATH];
PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
@ -213,12 +232,12 @@ static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iState
int height = bmp.bmHeight/imagecount;
bmpRect->left = 0;
bmpRect->right = bmp.bmWidth;
bmpRect->top = (min(imagecount, iStateId)-1) * height;
bmpRect->top = (max(min(imagecount, iStateId), 1)-1) * height;
bmpRect->bottom = bmpRect->top + height;
}
else {
int width = bmp.bmWidth/imagecount;
bmpRect->left = (min(imagecount, iStateId)-1) * width;
bmpRect->left = (max(min(imagecount, iStateId), 1)-1) * width;
bmpRect->right = bmpRect->left + width;
bmpRect->top = 0;
bmpRect->bottom = bmp.bmHeight;
@ -302,8 +321,8 @@ static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
GetThemeBool(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENT, &transparent);
if(transparent) {
if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_GLYPHTRANSPARENTCOLOR, &transparentcolor))) {
/* If image is transparent, but no color was specified, get the color of the upper left corner */
transparentcolor = GetPixel(hdcSrc, 0, 0);
/* If image is transparent, but no color was specified, use magenta */
transparentcolor = RGB(255, 0, 255);
}
}
GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
@ -588,15 +607,17 @@ static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
if(bordersize > 0) {
POINT ptCorners[4];
POINT ptCorners[5];
ptCorners[0].x = pRect->left;
ptCorners[0].y = pRect->top;
ptCorners[1].x = pRect->right;
ptCorners[1].x = pRect->right-1;
ptCorners[1].y = pRect->top;
ptCorners[2].x = pRect->right;
ptCorners[2].y = pRect->bottom;
ptCorners[2].x = pRect->right-1;
ptCorners[2].y = pRect->bottom-1;
ptCorners[3].x = pRect->left;
ptCorners[3].y = pRect->bottom;
ptCorners[3].y = pRect->bottom-1;
ptCorners[4].x = pRect->left;
ptCorners[4].y = pRect->top;
InflateRect(pRect, -bordersize, -bordersize);
if(pOptions->dwFlags & DTBG_OMITBORDER)
@ -607,7 +628,7 @@ static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
return HRESULT_FROM_WIN32(GetLastError());
oldPen = SelectObject(hdc, hPen);
if(!Polyline(hdc, ptCorners, 4))
if(!Polyline(hdc, ptCorners, 5))
hr = HRESULT_FROM_WIN32(GetLastError());
SelectObject(hdc, oldPen);
@ -855,15 +876,34 @@ HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId
if(!hTheme)
return E_HANDLE;
/* try content margins property... */
hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
if(FAILED(hr)) {
TRACE("Margins not found\n");
return hr;
if(SUCCEEDED(hr)) {
pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
} else {
/* otherwise, try to determine content rect from the background type and props */
int bgtype = BT_BORDERFILL;
memcpy(pContentRect, pBoundingRect, sizeof(RECT));
GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
if(bgtype == BT_BORDERFILL) {
int bordersize = 1;
GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
InflateRect(pContentRect, -bordersize, -bordersize);
} else if ((bgtype == BT_IMAGEFILE)
&& (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
TMT_SIZINGMARGINS, NULL, &margin)))) {
pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
}
/* If nothing was found, leave unchanged */
}
pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);

View file

@ -253,7 +253,7 @@ PUXINI_FILE MSSTYLES_GetThemeIni(PTHEME_FILE tf)
*
* Retrieve the ini file for the selected color/style
*/
PUXINI_FILE MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf)
static PUXINI_FILE MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf)
{
static const WCHAR szFileResNamesResource[] = {
'F','I','L','E','R','E','S','N','A','M','E','S','\0'
@ -320,7 +320,7 @@ PUXINI_FILE MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf)
* iPartId Location to store part id
* iStateId Location to store state id
*/
BOOL MSSTYLES_ParseIniSectionName(LPCWSTR lpSection, DWORD dwLen, LPWSTR szAppName, LPWSTR szClassName, int *iPartId, int *iStateId)
static BOOL MSSTYLES_ParseIniSectionName(LPCWSTR lpSection, DWORD dwLen, LPWSTR szAppName, LPWSTR szClassName, int *iPartId, int *iStateId)
{
WCHAR sec[255];
WCHAR part[60] = {'\0'};
@ -423,7 +423,7 @@ PTHEME_CLASS MSSTYLES_FindClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszC
* RETURNS
* The class added, or a class previously added with the same name
*/
PTHEME_CLASS MSSTYLES_AddClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassName)
static PTHEME_CLASS MSSTYLES_AddClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassName)
{
PTHEME_CLASS cur = MSSTYLES_FindClass(tf, pszAppName, pszClassName);
if(cur) return cur;
@ -480,7 +480,7 @@ PTHEME_PARTSTATE MSSTYLES_FindPartState(PTHEME_CLASS tc, int iPartId, int iState
* RETURNS
* The part/state added, or a part/state previously added with the same IDs
*/
PTHEME_PARTSTATE MSSTYLES_AddPartState(PTHEME_CLASS tc, int iPartId, int iStateId)
static PTHEME_PARTSTATE MSSTYLES_AddPartState(PTHEME_CLASS tc, int iPartId, int iStateId)
{
PTHEME_PARTSTATE cur = MSSTYLES_FindPartState(tc, iPartId, iStateId, NULL);
if(cur) return cur;
@ -507,7 +507,7 @@ PTHEME_PARTSTATE MSSTYLES_AddPartState(PTHEME_CLASS tc, int iPartId, int iStateI
* RETURNS
* The property found, or NULL
*/
PTHEME_PROPERTY MSSTYLES_LFindProperty(PTHEME_PROPERTY tp, int iPropertyPrimitive, int iPropertyId)
static PTHEME_PROPERTY MSSTYLES_LFindProperty(PTHEME_PROPERTY tp, int iPropertyPrimitive, int iPropertyId)
{
PTHEME_PROPERTY cur = tp;
while(cur) {
@ -596,7 +596,7 @@ PTHEME_PROPERTY MSSTYLES_FindMetric(int iPropertyPrimitive, int iPropertyId)
* RETURNS
* The property added, or a property previously added with the same IDs
*/
PTHEME_PROPERTY MSSTYLES_AddProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen, BOOL isGlobal)
static PTHEME_PROPERTY MSSTYLES_AddProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen, BOOL isGlobal)
{
PTHEME_PROPERTY cur = MSSTYLES_PSFindProperty(ps, iPropertyPrimitive, iPropertyId);
/* Should duplicate properties overwrite the original, or be ignored? */
@ -637,7 +637,7 @@ PTHEME_PROPERTY MSSTYLES_AddProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive
* RETURNS
* The property added, or a property previously added with the same IDs
*/
PTHEME_PROPERTY MSSTYLES_AddMetric(PTHEME_FILE tf, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen)
static PTHEME_PROPERTY MSSTYLES_AddMetric(PTHEME_FILE tf, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen)
{
PTHEME_PROPERTY cur = MSSTYLES_FFindMetric(tf, iPropertyPrimitive, iPropertyId);
/* Should duplicate properties overwrite the original, or be ignored? */
@ -709,6 +709,10 @@ void MSSTYLES_ParseThemeIni(PTHEME_FILE tf)
FIXME("Invalid color value for %s\n", debugstr_w(szPropertyName));
}
}
else if (iPropertyId == TMT_FLATMENUS) {
BOOL flatMenus = (*lpValue == 'T') || (*lpValue == 't');
SystemParametersInfoW (SPI_SETFLATMENU, 0, (PVOID)flatMenus, 0);
}
/* Catch all metrics, including colors */
MSSTYLES_AddMetric(tf, iPropertyPrimitive, iPropertyId, lpValue, dwValueLen);
}
@ -806,6 +810,8 @@ PTHEME_CLASS MSSTYLES_OpenThemeClass(LPCWSTR pszAppName, LPCWSTR pszClassList)
}
if(cls) {
TRACE("Opened app %s, class %s from list %s\n", debugstr_w(cls->szAppName), debugstr_w(cls->szClassName), debugstr_w(pszClassList));
cls->tf = tfActiveTheme;
cls->tf->dwRefCount++;
}
return cls;
}
@ -819,11 +825,12 @@ PTHEME_CLASS MSSTYLES_OpenThemeClass(LPCWSTR pszAppName, LPCWSTR pszClassList)
* tc Theme class to close
*
* NOTES
* There is currently no need clean anything up for theme classes,
* so do nothing for now
* The MSSTYLES_CloseThemeFile decreases the refcount of the owning
* theme file and cleans it up, if needed.
*/
HRESULT MSSTYLES_CloseThemeClass(PTHEME_CLASS tc)
{
MSSTYLES_CloseThemeFile (tc->tf);
return S_OK;
}

View file

@ -46,8 +46,11 @@ typedef struct _THEME_PARTSTATE {
struct _THEME_PARTSTATE *next;
} THEME_PARTSTATE, *PTHEME_PARTSTATE;
struct _THEME_FILE;
typedef struct _THEME_CLASS {
HMODULE hTheme;
struct _THEME_FILE* tf;
WCHAR szAppName[MAX_THEME_APP_NAME];
WCHAR szClassName[MAX_THEME_CLASS_NAME];
PTHEME_PARTSTATE partstate;

View file

@ -62,6 +62,7 @@ DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS;
ATOM atWindowTheme;
ATOM atSubAppName;
ATOM atSubIdList;
ATOM atDialogThemeEnabled;
BOOL bThemeActive = FALSE;
WCHAR szCurrentTheme[MAX_PATH];
@ -70,6 +71,27 @@ 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;
}
/***********************************************************************
* UXTHEME_LoadTheme
*
@ -78,7 +100,7 @@ WCHAR szCurrentSize[64];
static void UXTHEME_LoadTheme(void)
{
HKEY hKey;
LONG buffsize;
DWORD buffsize;
HRESULT hr;
WCHAR tmp[10];
PTHEME_FILE pt;
@ -169,9 +191,12 @@ HRESULT UXTHEME_SetActiveTheme(PTHEME_FILE tf)
tmp[1] = '\0';
RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (const BYTE*)tmp, sizeof(WCHAR)*2);
if(bThemeActive) {
RegSetValueExW(hKey, szColorName, 0, REG_SZ, (const BYTE*)szCurrentColor, lstrlenW(szCurrentColor)+1);
RegSetValueExW(hKey, szSizeName, 0, REG_SZ, (const BYTE*)szCurrentSize, lstrlenW(szCurrentSize)+1);
RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*)szCurrentTheme, lstrlenW(szCurrentTheme)+1);
RegSetValueExW(hKey, szColorName, 0, REG_SZ, (const BYTE*)szCurrentColor,
(lstrlenW(szCurrentColor)+1)*sizeof(WCHAR));
RegSetValueExW(hKey, szSizeName, 0, REG_SZ, (const BYTE*)szCurrentSize,
(lstrlenW(szCurrentSize)+1)*sizeof(WCHAR));
RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*)szCurrentTheme,
(lstrlenW(szCurrentTheme)+1)*sizeof(WCHAR));
}
else {
RegDeleteValueW(hKey, szColorName);
@ -200,12 +225,16 @@ void UXTHEME_InitSystem(HINSTANCE hInst)
static const WCHAR szSubIdList[] = {
'u','x','_','s','u','b','i','d','l','s','t','\0'
};
static const WCHAR szDialogThemeEnabled[] = {
'u','x','_','d','i','a','l','o','g','t','h','e','m','e','\0'
};
hDllInst = hInst;
atWindowTheme = GlobalAddAtomW(szWindowTheme);
atSubAppName = GlobalAddAtomW(szSubAppName);
atSubIdList = GlobalAddAtomW(szSubIdList);
atWindowTheme = GlobalAddAtomW(szWindowTheme);
atSubAppName = GlobalAddAtomW(szSubAppName);
atSubIdList = GlobalAddAtomW(szSubIdList);
atDialogThemeEnabled = GlobalAddAtomW(szDialogThemeEnabled);
UXTHEME_LoadTheme();
}
@ -247,7 +276,7 @@ HRESULT WINAPI EnableTheming(BOOL fEnable)
RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (LPBYTE)szEnabled, sizeof(WCHAR));
RegCloseKey(hKey);
}
PostMessageW(HWND_BROADCAST, WM_THEMECHANGED, 0, 0);
UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
}
return S_OK;
}
@ -295,20 +324,23 @@ HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR pszClassList)
WCHAR szClassBuff[256];
LPCWSTR pszAppName;
LPCWSTR pszUseClassList;
HTHEME hTheme;
TRACE("(%p,%s)\n", hwnd, debugstr_w(pszClassList));
if(!bThemeActive)
return NULL;
HTHEME hTheme = NULL;
TRACE("(%p,%s)", hwnd, debugstr_w(pszClassList));
pszAppName = UXTHEME_GetWindowProperty(hwnd, atSubAppName, szAppBuff, sizeof(szAppBuff)/sizeof(szAppBuff[0]));
/* If SetWindowTheme was used on the window, that overrides the class list passed to this function */
pszUseClassList = UXTHEME_GetWindowProperty(hwnd, atSubIdList, szClassBuff, sizeof(szClassBuff)/sizeof(szClassBuff[0]));
if(!pszUseClassList)
pszUseClassList = pszClassList;
if(bThemeActive)
{
pszAppName = UXTHEME_GetWindowProperty(hwnd, atSubAppName, szAppBuff, sizeof(szAppBuff)/sizeof(szAppBuff[0]));
/* If SetWindowTheme was used on the window, that overrides the class list passed to this function */
pszUseClassList = UXTHEME_GetWindowProperty(hwnd, atSubIdList, szClassBuff, sizeof(szClassBuff)/sizeof(szClassBuff[0]));
if(!pszUseClassList)
pszUseClassList = pszClassList;
hTheme = MSSTYLES_OpenThemeClass(pszAppName, pszUseClassList);
if (pszUseClassList)
hTheme = MSSTYLES_OpenThemeClass(pszAppName, pszUseClassList);
}
if(IsWindow(hwnd))
SetPropW(hwnd, MAKEINTATOMW(atWindowTheme), hTheme);
TRACE(" = %p\n", hTheme);
return hTheme;
}
@ -338,7 +370,7 @@ HRESULT WINAPI SetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName,
if(SUCCEEDED(hr))
hr = UXTHEME_SetWindowProperty(hwnd, atSubIdList, pszSubIdList);
if(SUCCEEDED(hr))
PostMessageW(hwnd, WM_THEMECHANGED, 0, 0);
UXTHEME_broadcast_msg (hwnd, WM_THEMECHANGED);
return hr;
}
@ -554,7 +586,7 @@ HRESULT WINAPI ApplyTheme(HTHEMEFILE hThemeFile, char *unknown, HWND hWnd)
HRESULT hr;
TRACE("(%p,%s,%p)\n", hThemeFile, unknown, hWnd);
hr = UXTHEME_SetActiveTheme(hThemeFile);
PostMessageW(HWND_BROADCAST, WM_THEMECHANGED, 0, 0);
UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
return hr;
}