[uxtheme]

- Properly disable themes when theme hooks are removed
- Add WND_CONTEXT a per window struct that will hold several theme specific information. For now it contains only theme region related info. It will be stored as a window property
- Implement destroying WND_CONTEXT for every window when theme hooks are removed or when the window is destroyed
- Hook the messages that are sent to dialogs, like they are hooked for normal windows
- Hook SetWindowRgn call from user32. When an application calls it, uxtheme will stop setting window region on its own region
- Implement setting a custom window region for windows after receiving WM_WINDOWPOSCHANGED message using GetThemeBackgroundRegion

svn path=/branches/GSoC_2011/ThemesSupport/; revision=53262
This commit is contained in:
Giannis Adamopoulos 2011-08-15 10:22:23 +00:00
parent 5ceabc031a
commit 10bed5b061
4 changed files with 250 additions and 25 deletions

View file

@ -1,4 +1,11 @@
typedef struct _WND_CONTEXT
{
BOOL HasAppDefinedRgn;
BOOL HasThemeRgn;
BOOL UpdatingRgn;
} WND_CONTEXT, *PWND_CONTEXT;
typedef struct _DRAW_CONTEXT
{
HWND hWnd;
@ -91,5 +98,9 @@ ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
void
ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext);
PWND_CONTEXT
ThemeGetWndContext(HWND hWnd);
extern ATOM atWindowTheme;
extern ATOM atWndContrext;

View file

@ -34,6 +34,7 @@
#include "uxthemedll.h"
#include "msstyles.h"
#include "ncthm.h"
#include "wine/debug.h"
@ -64,6 +65,7 @@ static DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS;
ATOM atWindowTheme;
static ATOM atSubAppName;
static ATOM atSubIdList;
ATOM atWndContrext;
static BOOL bThemeActive = FALSE;
static WCHAR szCurrentTheme[MAX_PATH];
@ -148,7 +150,7 @@ static DWORD query_reg_path (HKEY hKey, LPCWSTR lpszValue,
*
* Set the current active theme from the registry
*/
void UXTHEME_LoadTheme(void)
void UXTHEME_LoadTheme(BOOL bLoad)
{
HKEY hKey;
DWORD buffsize;
@ -156,29 +158,36 @@ void UXTHEME_LoadTheme(void)
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');
if(bLoad == TRUE)
{
/* 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 {
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");
}
else
TRACE("Failed to open theme registry key\n");
{
bThemeActive = FALSE;
}
if(bThemeActive) {
/* Make sure the theme requested is actually valid */
@ -542,6 +551,7 @@ void UXTHEME_InitSystem(HINSTANCE hInst)
atSubAppName = GlobalAddAtomW(szSubAppName);
atSubIdList = GlobalAddAtomW(szSubIdList);
atDialogThemeEnabled = GlobalAddAtomW(szDialogThemeEnabled);
atWndContrext = GlobalAddAtomW(L"ux_WndContext");
}
/***********************************************************************

View file

@ -12,6 +12,9 @@
#include "vfwmsgs.h"
#include "uxtheme.h"
#include "uxthemedll.h"
#include "ncthm.h"
#include "tmschema.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
@ -26,6 +29,163 @@ USERAPIHOOK user32ApiHook;
BYTE gabDWPmessages[UAHOWP_MAX_SIZE];
BYTE gabMSGPmessages[UAHOWP_MAX_SIZE];
PWND_CONTEXT ThemeGetWndContext(HWND hWnd)
{
PWND_CONTEXT pcontext;
pcontext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext));
if(pcontext == NULL)
{
pcontext = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(WND_CONTEXT));
if(pcontext == NULL)
{
return NULL;
}
SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext), pcontext);
}
return pcontext;
}
void ThemeDetroyWndContext(HWND hWnd)
{
PWND_CONTEXT pContext;
DWORD ProcessId;
/*Do not destroy WND_CONTEXT of a window that belong to another process */
GetWindowThreadProcessId(hWnd, &ProcessId);
if(ProcessId != GetCurrentProcessId())
{
return;
}
pContext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext));
if(pContext == NULL)
{
return;
}
if(pContext->HasThemeRgn)
{
user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
}
HeapFree(GetProcessHeap(), 0, pContext);
SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext), NULL);
}
static BOOL CALLBACK ThemeCleanupChildWndContext (HWND hWnd, LPARAM msg)
{
ThemeDetroyWndContext(hWnd);
return TRUE;
}
static BOOL CALLBACK ThemeCleanupWndContext(HWND hWnd, LPARAM msg)
{
if (hWnd == NULL)
{
EnumWindows (ThemeCleanupWndContext, 0);
}
else
{
ThemeDetroyWndContext(hWnd);
EnumChildWindows (hWnd, ThemeCleanupChildWndContext, 0);
}
return TRUE;
}
void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
{
HTHEME hTheme;
RECT rcWindow;
HRGN hrgn, hrgn1;
int CaptionHeight, iPart;
WINDOWINFO wi;
if(!IsAppThemed())
{
if(pcontext->HasThemeRgn)
{
pcontext->HasThemeRgn = FALSE;
user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
}
return;
}
wi.cbSize = sizeof(wi);
GetWindowInfo(hWnd, &wi);
if((wi.dwStyle & WS_CAPTION)!=WS_CAPTION)
{
return;
}
/* Get the caption part id */
if (wi.dwExStyle & WS_EX_TOOLWINDOW)
iPart = WP_SMALLCAPTION;
else if (wi.dwStyle & WS_MAXIMIZE)
iPart = WP_MAXCAPTION;
else
iPart = WP_CAPTION;
pcontext->HasThemeRgn = TRUE;
CaptionHeight = wi.cyWindowBorders;
CaptionHeight += GetSystemMetrics(wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
GetWindowRect(hWnd, &rcWindow);
rcWindow.right -= rcWindow.left;
rcWindow.bottom = CaptionHeight;
rcWindow.top = 0;
rcWindow.left = 0;
hTheme = OpenThemeData (hWnd, L"WINDOW");
GetThemeBackgroundRegion(hTheme, 0, iPart, FS_ACTIVE, &rcWindow, &hrgn);
CloseThemeData(hTheme);
GetWindowRect(hWnd, &rcWindow);
rcWindow.right -= rcWindow.left;
rcWindow.bottom -= rcWindow.top;
rcWindow.top = CaptionHeight;
rcWindow.left = 0;
hrgn1 = CreateRectRgnIndirect(&rcWindow);
CombineRgn(hrgn, hrgn, hrgn1, RGN_OR );
DeleteObject(hrgn1);
user32ApiHook.SetWindowRgn(hWnd, hrgn, TRUE);
}
int OnPostWinPosChanged(HWND hWnd)
{
PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
if(pcontext &&
pcontext->HasAppDefinedRgn == FALSE &&
pcontext->UpdatingRgn == FALSE)
{
pcontext->UpdatingRgn = TRUE;
SetThemeRegion(hWnd, pcontext);
pcontext = ThemeGetWndContext(hWnd);
pcontext->UpdatingRgn = FALSE;
}
return 0;
}
/**********************************************************************
* Hook Functions
*/
static LRESULT CALLBACK
ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
@ -75,12 +235,50 @@ ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR
return 0;
}
static LRESULT CALLBACK
ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
{
switch(Msg)
{
case WM_WINDOWPOSCHANGED:
{
return OnPostWinPosChanged(hWnd);
}
case WM_DESTROY:
{
ThemeDetroyWndContext(hWnd);
return 0;
}
}
return 0;
}
int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
{
PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
if(pcontext)
{
pcontext->HasAppDefinedRgn = TRUE;
pcontext->HasThemeRgn = FALSE;
}
return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
}
/**********************************************************************
* Exports
*/
BOOL CALLBACK
ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
{
/* Sanity checks for the caller */
if (!puah || State != uahLoadInit)
{
UXTHEME_LoadTheme(FALSE);
ThemeCleanupWndContext(NULL, 0);
return TRUE;
}
@ -90,10 +288,17 @@ ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
puah->DefWindowProcA = ThemeDefWindowProcA;
puah->DefWindowProcW = ThemeDefWindowProcW;
puah->PreWndProc = ThemePreWindowProc;
puah->PostWndProc = ThemePostWindowProc;
puah->PreDefDlgProc = ThemePreWindowProc;
puah->PostDefDlgProc = ThemePostWindowProc;
puah->DefWndProcArray.MsgBitArray = gabDWPmessages;
puah->DefWndProcArray.Size = UAHOWP_MAX_SIZE;
puah->WndProcArray.MsgBitArray = gabMSGPmessages;
puah->WndProcArray.Size = UAHOWP_MAX_SIZE;
puah->DlgProcArray.MsgBitArray = gabMSGPmessages;
puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
puah->SetWindowRgn = ThemeSetWindowRgn;
UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
@ -130,7 +335,7 @@ ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
UXTHEME_LoadTheme();
UXTHEME_LoadTheme(TRUE);
return TRUE;
}
@ -187,8 +392,7 @@ ThemeHooksRemove()
ret = UnregisterUserApiHook();
if(IsThemeActive())
UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
return ret;
}

View file

@ -95,7 +95,7 @@ HRESULT WINAPI ParseThemeIniFile(LPCWSTR pszIniFileName, LPWSTR pszUnknown,
ParseThemeIniFileProc callback, LPVOID lpData);
extern void UXTHEME_InitSystem(HINSTANCE hInst);
extern void UXTHEME_LoadTheme(void);
extern void UXTHEME_LoadTheme(BOOL bLoad);
extern BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg);
/* No alpha blending */