[uxtheme]

- Greatly reduce needless repaints in the non client area but remembering the last hittest of the mouse events to redraw it only when it is needed
- Do not reset the theme region every time we move a window, also make sure we try to set a theme region only when it is needed
- Do not use OpenThemeData but use MSSTYLES_OpenThemeClass directly
- Do not reload the active theme every time we get a WM_THEMECHANGED message, make sure to see if the active theme was already loaded before trying to load it again
- See CORE-7775

svn path=/trunk/; revision=61654
This commit is contained in:
Giannis Adamopoulos 2014-01-17 17:52:58 +00:00
parent f895117bca
commit e5825e6426
4 changed files with 187 additions and 69 deletions

View file

@ -155,9 +155,8 @@ ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
GetWindowInfo(hWnd, &pcontext->wi);
pcontext->hWnd = hWnd;
pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle);
pcontext->hPrevTheme = GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme));
pcontext->theme = OpenThemeData(pcontext->hWnd, L"WINDOW");
pcontext->scrolltheme = OpenThemeData(pcontext->hWnd, L"SCROLLBAR");
pcontext->theme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"WINDOW");
pcontext->scrolltheme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"SCROLLBAR");
pcontext->CaptionHeight = pcontext->wi.cyWindowBorders;
pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
@ -179,8 +178,6 @@ ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext)
CloseThemeData (pcontext->theme);
CloseThemeData (pcontext->scrolltheme);
SetPropW(pcontext->hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme), pcontext->hPrevTheme);
if(pcontext->hRgn != NULL)
{
DeleteObject(pcontext->hRgn);
@ -289,10 +286,7 @@ ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext, DWORD htHot, DWORD htDown)
{
RECT rcCurrent;
/* Check if the window has caption buttons */
if (!((pcontext->wi.dwStyle & WS_CAPTION) && (pcontext->wi.dwStyle & WS_SYSMENU)))
return ;
/* Calculate the area of the caption */
rcCurrent.top = rcCurrent.left = 0;
rcCurrent.right = pcontext->wi.rcWindow.right - pcontext->wi.rcWindow.left;
rcCurrent.bottom = pcontext->CaptionHeight;
@ -336,7 +330,7 @@ ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
/* Draw the caption background*/
rcPart = *prcCurrent;
rcPart.bottom = pcontext->CaptionHeight;
rcPart.bottom = rcPart.top + pcontext->CaptionHeight;
prcCurrent->top = rcPart.bottom;
DrawThemeBackground(pcontext->theme, pcontext->hDC,iPart,iState,&rcPart,NULL);
@ -400,7 +394,7 @@ ThemeDrawBorders(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
/* Draw the left border */
rcPart = *prcCurrent;
rcPart.right = pcontext->wi.cxWindowBorders ;
rcPart.right = rcPart.left + pcontext->wi.cxWindowBorders ;
prcCurrent->left = rcPart.right;
DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMELEFT, iState, &rcPart, NULL);
@ -684,29 +678,57 @@ ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
{
DRAW_CONTEXT context;
TRACKMOUSEEVENT tme;
DWORD style;
PWND_CONTEXT pcontext;
/* First of all check if we have something to do here */
style = GetWindowLongW(hWnd, GWL_STYLE);
if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
return 0;
/* Get theme data for this window */
pcontext = ThemeGetWndContext(hWnd);
if (pcontext == NULL)
return 0;
/* Begin tracking in the non client area if we are not tracking yet */
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_QUERY;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
if (tme.dwFlags != (TME_LEAVE | TME_NONCLIENT))
if (tme.dwFlags != (TME_LEAVE | TME_NONCLIENT))
{
tme.hwndTrack = hWnd;
tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
TrackMouseEvent(&tme);
}
/* Dont do any drawing if the hit test wasn't changed */
if (ht == pcontext->lastHitTest)
return 0;
ThemeInitDrawContext(&context, hWnd, 0);
ThemeDrawCaptionButtons(&context, ht, 0);
if (context.wi.dwStyle & WS_SYSMENU)
{
if (HT_ISBUTTON(ht) || HT_ISBUTTON(pcontext->lastHitTest))
ThemeDrawCaptionButtons(&context, ht, 0);
}
if(context.wi.dwStyle & WS_HSCROLL)
ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
if(context.wi.dwStyle & WS_VSCROLL)
ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
if (context.wi.dwStyle & WS_HSCROLL)
{
if (ht == HTHSCROLL || pcontext->lastHitTest == HTHSCROLL)
ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
}
if (context.wi.dwStyle & WS_VSCROLL)
{
if (ht == HTVSCROLL || pcontext->lastHitTest == HTVSCROLL)
ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
}
ThemeCleanupDrawContext(&context);
pcontext->lastHitTest = ht;
return 0;
}
@ -714,18 +736,33 @@ static LRESULT
ThemeHandleNcMouseLeave(HWND hWnd)
{
DRAW_CONTEXT context;
DWORD style;
PWND_CONTEXT pWndContext;
/* First of all check if we have something to do here */
style = GetWindowLongW(hWnd, GWL_STYLE);
if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
return 0;
/* Get theme data for this window */
pWndContext = ThemeGetWndContext(hWnd);
if (pWndContext == NULL)
return 0;
ThemeInitDrawContext(&context, hWnd, 0);
ThemeDrawCaptionButtons(&context, 0, 0);
if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pWndContext->lastHitTest))
ThemeDrawCaptionButtons(&context, 0, 0);
if(context.wi.dwStyle & WS_HSCROLL)
ThemeDrawScrollBar(&context, SB_HORZ, NULL);
if (context.wi.dwStyle & WS_HSCROLL && pWndContext->lastHitTest == HTHSCROLL)
ThemeDrawScrollBar(&context, SB_HORZ, NULL);
if(context.wi.dwStyle & WS_VSCROLL)
if (context.wi.dwStyle & WS_VSCROLL && pWndContext->lastHitTest == HTVSCROLL)
ThemeDrawScrollBar(&context, SB_VERT, NULL);
ThemeCleanupDrawContext(&context);
pWndContext->lastHitTest = HTNOWHERE;
return 0;
}
@ -733,17 +770,19 @@ static VOID
ThemeHandleButton(HWND hWnd, WPARAM wParam)
{
MSG Msg;
BOOL Pressed = TRUE; // , OldState;
BOOL Pressed = TRUE;
WPARAM SCMsg, ht;
ULONG Style;
DRAW_CONTEXT context;
PWND_CONTEXT pWndContext;
Style = GetWindowLongW(hWnd, GWL_STYLE);
if (!((Style & WS_CAPTION) && (Style & WS_SYSMENU)))
return ;
switch (wParam)
{
case HTCLOSE:
if (!(Style & WS_SYSMENU))
return;
SCMsg = SC_CLOSE;
break;
case HTMINBUTTON:
@ -760,8 +799,14 @@ ThemeHandleButton(HWND hWnd, WPARAM wParam)
return;
}
/* Get theme data for this window */
pWndContext = ThemeGetWndContext(hWnd);
if (pWndContext == NULL)
return;
ThemeInitDrawContext(&context, hWnd, 0);
ThemeDrawCaptionButtons(&context, 0, wParam);
pWndContext->lastHitTest = wParam;
SetCapture(hWnd);
@ -776,14 +821,19 @@ ThemeHandleButton(HWND hWnd, WPARAM wParam)
if (Msg.message != WM_MOUSEMOVE)
continue;
//OldState = Pressed;
ht = SendMessage(hWnd, WM_NCHITTEST, 0, MAKELPARAM(Msg.pt.x, Msg.pt.y));
Pressed = (ht == wParam);
ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
/* Only draw the buttons if the hit test changed */
if (ht != pWndContext->lastHitTest &&
(HT_ISBUTTON(ht) || HT_ISBUTTON(pWndContext->lastHitTest)))
{
ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
pWndContext->lastHitTest = ht;
}
}
ThemeDrawCaptionButtons(&context, 0, 0);
ThemeDrawCaptionButtons(&context, ht, 0);
ThemeCleanupDrawContext(&context);
ReleaseCapture();

View file

@ -50,7 +50,7 @@ static ATOM atSubAppName;
static ATOM atSubIdList;
ATOM atWndContrext;
static PTHEME_FILE ActiveThemeFile;
PTHEME_FILE ActiveThemeFile;
/***********************************************************************/
@ -138,6 +138,39 @@ static HRESULT UXTHEME_SetActiveTheme(PTHEME_FILE tf)
return S_OK;
}
static BOOL bIsThemeActive(LPCWSTR pszTheme, LPCWSTR pszColor, LPCWSTR pszSize)
{
if (ActiveThemeFile == NULL)
return FALSE;
if (wcscmp(pszTheme, ActiveThemeFile->szThemeFile) != 0)
return FALSE;
if (!pszColor[0])
{
if (ActiveThemeFile->pszAvailColors != ActiveThemeFile->pszSelectedColor)
return FALSE;
}
else
{
if (wcscmp(pszColor, ActiveThemeFile->pszSelectedColor) != 0)
return FALSE;
}
if (!pszSize[0])
{
if (ActiveThemeFile->pszAvailSizes != ActiveThemeFile->pszSelectedSize)
return FALSE;
}
else
{
if (wcscmp(pszSize, ActiveThemeFile->pszSelectedSize) != 0)
return FALSE;
}
return TRUE;
}
/***********************************************************************
* UXTHEME_LoadTheme
*
@ -186,7 +219,14 @@ void UXTHEME_LoadTheme(BOOL bLoad)
bThemeActive = FALSE;
}
if(bThemeActive) {
if(bThemeActive)
{
if( bIsThemeActive(szCurrentTheme, szCurrentColor, szCurrentSize) )
{
TRACE("Tried to load active theme again\n");
return;
}
/* Make sure the theme requested is actually valid */
hr = MSSTYLES_OpenThemeFile(szCurrentTheme,
szCurrentColor[0]?szCurrentColor:NULL,
@ -471,6 +511,8 @@ static HRESULT UXTHEME_ApplyTheme(PTHEME_FILE tf)
WCHAR tmp[2];
HRESULT hr;
TRACE("UXTHEME_ApplyTheme\n");
if (tf && !ActiveThemeFile)
{
UXTHEME_BackupSystemMetrics();
@ -562,7 +604,7 @@ BOOL WINAPI IsThemeActive(void)
WCHAR tmp[10];
DWORD buffsize;
TRACE("\n");
TRACE("IsThemeActive\n");
SetLastError(ERROR_SUCCESS);
if (ActiveThemeFile)

View file

@ -83,7 +83,7 @@ static BOOL CALLBACK ThemeCleanupWndContext(HWND hWnd, LPARAM msg)
return TRUE;
}
void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
void SetThemeRegion(HWND hWnd)
{
HTHEME hTheme;
RECT rcWindow;
@ -91,25 +91,11 @@ void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
int CaptionHeight, iPart;
WINDOWINFO wi;
if(!IsAppThemed())
{
if(pcontext->HasThemeRgn)
{
pcontext->HasThemeRgn = FALSE;
user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
}
return;
}
TRACE("SetThemeRegion %d\n", hWnd);
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;
@ -118,8 +104,6 @@ void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
else
iPart = WP_CAPTION;
pcontext->HasThemeRgn = TRUE;
CaptionHeight = wi.cyWindowBorders;
CaptionHeight += GetSystemMetrics(wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
@ -129,10 +113,8 @@ void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
rcWindow.top = 0;
rcWindow.left = 0;
hTheme = OpenThemeData (hWnd, L"WINDOW");
hTheme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"WINDOW");
GetThemeBackgroundRegion(hTheme, 0, iPart, FS_ACTIVE, &rcWindow, &hrgn);
CloseThemeData(hTheme);
GetWindowRect(hWnd, &rcWindow);
@ -149,21 +131,51 @@ void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
user32ApiHook.SetWindowRgn(hWnd, hrgn, TRUE);
}
int OnPostWinPosChanged(HWND hWnd)
int OnPostWinPosChanged(HWND hWnd, WINDOWPOS* pWinPos)
{
PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
PWND_CONTEXT pcontext;
DWORD style;
if(pcontext &&
pcontext->HasAppDefinedRgn == FALSE &&
pcontext->UpdatingRgn == FALSE)
/* We only proceed to change the window shape if it has a caption */
style = GetWindowLongW(hWnd, GWL_STYLE);
if((style & WS_CAPTION)!=WS_CAPTION)
return 0;
/* Get theme data for this window */
pcontext = ThemeGetWndContext(hWnd);
if (pcontext == NULL)
return 0;
/* Do not change the region of the window if its size wasn't changed */
if ((pWinPos->flags & SWP_NOSIZE) != 0 && pcontext->DirtyThemeRegion == FALSE)
return 0;
/* We don't touch the shape of the window if the application sets it on its own */
if (pcontext->HasAppDefinedRgn == TRUE)
return 0;
/* Calling SetWindowRgn will call SetWindowPos again so we need to avoid this recursion */
if (pcontext->UpdatingRgn == TRUE)
return 0;
if(!IsAppThemed())
{
pcontext->UpdatingRgn = TRUE;
SetThemeRegion(hWnd, pcontext);
pcontext = ThemeGetWndContext(hWnd);
pcontext->UpdatingRgn = FALSE;
if(pcontext->HasThemeRgn)
{
pcontext->HasThemeRgn = FALSE;
user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
}
return 0;
}
return 0;
}
pcontext->DirtyThemeRegion = FALSE;
pcontext->HasThemeRgn = TRUE;
pcontext->UpdatingRgn = TRUE;
SetThemeRegion(hWnd);
pcontext->UpdatingRgn = FALSE;
return 0;
}
/**********************************************************************
* Hook Functions
@ -172,7 +184,7 @@ int OnPostWinPosChanged(HWND hWnd)
static LRESULT CALLBACK
ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if(!IsThemeActive())
if(!IsAppThemed())
{
return user32ApiHook.DefWindowProcW(hWnd,
Msg,
@ -190,7 +202,7 @@ ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
static LRESULT CALLBACK
ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if(!IsThemeActive())
if(!IsAppThemed())
{
return user32ApiHook.DefWindowProcA(hWnd,
Msg,
@ -211,8 +223,15 @@ ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR
switch(Msg)
{
case WM_THEMECHANGED:
UXTHEME_LoadTheme(TRUE);
return 0;
if (GetAncestor(hWnd, GA_PARENT) == GetDesktopWindow())
UXTHEME_LoadTheme(TRUE);
case WM_NCCREATE:
{
PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
if (pcontext == NULL)
return 0;
pcontext->DirtyThemeRegion = TRUE;
}
}
return 0;
@ -226,7 +245,7 @@ ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR
{
case WM_WINDOWPOSCHANGED:
{
return OnPostWinPosChanged(hWnd);
return OnPostWinPosChanged(hWnd, (WINDOWPOS*)lParam);
}
case WM_DESTROY:
{

View file

@ -8,6 +8,7 @@
#include <windowsx.h>
#include <undocuser.h>
#include <uxtheme.h>
#include <uxundoc.h>
#include <vfwmsgs.h>
#include <tmschema.h>
@ -111,14 +112,17 @@ LPCWSTR UXINI_GetNextValue(PUXINI_FILE uf, DWORD *dwNameLen, LPCWSTR *lpValue, D
BOOL UXINI_FindValue(PUXINI_FILE uf, LPCWSTR lpName, LPCWSTR *lpValue, DWORD *dwValueLen);
/* The window context stores data for the window needed through the life of the window */
typedef struct _WND_CONTEXT
{
UINT lastHitTest;
BOOL HasAppDefinedRgn;
BOOL HasThemeRgn;
BOOL UpdatingRgn;
BOOL DirtyThemeRegion;
} WND_CONTEXT, *PWND_CONTEXT;
/* The draw context stores data that are needed by the drawing operations in the non client area of the window */
typedef struct _DRAW_CONTEXT
{
HWND hWnd;
@ -168,6 +172,8 @@ enum SCROLL_HITTEST
SCROLL_BOTTOM_ARROW /* Bottom or right arrow */
};
#define HT_ISBUTTON(ht) ((ht) == HTMINBUTTON || (ht) == HTMAXBUTTON || (ht) == HTCLOSE || (ht) == HTHELP)
#define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \
((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
@ -208,6 +214,7 @@ extern HINSTANCE hDllInst;
extern ATOM atWindowTheme;
extern ATOM atWndContrext;
extern BOOL gbThemeHooksActive;
extern PTHEME_FILE ActiveThemeFile;
void UXTHEME_InitSystem(HINSTANCE hInst);
void UXTHEME_LoadTheme(BOOL bLoad);