Author: gadamopoulos Date: Fri Jan 17 17:52:58 2014 New Revision: 61654
URL: http://svn.reactos.org/svn/reactos?rev=61654&view=rev Log: [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
Modified: trunk/reactos/dll/win32/uxtheme/nonclient.c trunk/reactos/dll/win32/uxtheme/system.c trunk/reactos/dll/win32/uxtheme/themehooks.c trunk/reactos/dll/win32/uxtheme/uxthemep.h
Modified: trunk/reactos/dll/win32/uxtheme/nonclient.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/uxtheme/nonclient... ============================================================================== --- trunk/reactos/dll/win32/uxtheme/nonclient.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/uxtheme/nonclient.c [iso-8859-1] Fri Jan 17 17:52:58 2014 @@ -155,9 +155,8 @@ 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 ); @@ -178,8 +177,6 @@
CloseThemeData (pcontext->theme); CloseThemeData (pcontext->scrolltheme); - - SetPropW(pcontext->hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme), pcontext->hPrevTheme);
if(pcontext->hRgn != NULL) { @@ -289,10 +286,7 @@ { 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 @@
/* 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 @@
/* 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,28 +678,56 @@ { 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_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_SYSMENU) + { + if (HT_ISBUTTON(ht) || HT_ISBUTTON(pcontext->lastHitTest)) + ThemeDrawCaptionButtons(&context, ht, 0); + } + + 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,17 +736,32 @@ 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_HSCROLL) - ThemeDrawScrollBar(&context, SB_HORZ, NULL); - - if(context.wi.dwStyle & WS_VSCROLL) + if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pWndContext->lastHitTest)) + ThemeDrawCaptionButtons(&context, 0, 0); + + if (context.wi.dwStyle & WS_HSCROLL && pWndContext->lastHitTest == HTHSCROLL) + ThemeDrawScrollBar(&context, SB_HORZ, NULL); + + 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 @@ 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 @@ 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 @@ 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); - } - - ThemeDrawCaptionButtons(&context, 0, 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, ht, 0); ThemeCleanupDrawContext(&context);
ReleaseCapture();
Modified: trunk/reactos/dll/win32/uxtheme/system.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/uxtheme/system.c?... ============================================================================== --- trunk/reactos/dll/win32/uxtheme/system.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/uxtheme/system.c [iso-8859-1] Fri Jan 17 17:52:58 2014 @@ -50,7 +50,7 @@ static ATOM atSubIdList; ATOM atWndContrext;
-static PTHEME_FILE ActiveThemeFile; +PTHEME_FILE ActiveThemeFile;
/***********************************************************************/
@@ -136,6 +136,39 @@ MSSTYLES_ParseThemeIni(ActiveThemeFile); } 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; }
/*********************************************************************** @@ -186,7 +219,14 @@ 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 @@ WCHAR tmp[2]; HRESULT hr;
+ TRACE("UXTHEME_ApplyTheme\n"); + if (tf && !ActiveThemeFile) { UXTHEME_BackupSystemMetrics(); @@ -562,7 +604,7 @@ WCHAR tmp[10]; DWORD buffsize;
- TRACE("\n"); + TRACE("IsThemeActive\n"); SetLastError(ERROR_SUCCESS);
if (ActiveThemeFile)
Modified: trunk/reactos/dll/win32/uxtheme/themehooks.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/uxtheme/themehook... ============================================================================== --- trunk/reactos/dll/win32/uxtheme/themehooks.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/uxtheme/themehooks.c [iso-8859-1] Fri Jan 17 17:52:58 2014 @@ -83,7 +83,7 @@ return TRUE; }
-void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext) +void SetThemeRegion(HWND hWnd) { HTHEME hTheme; RECT rcWindow; @@ -91,24 +91,10 @@ 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) @@ -118,8 +104,6 @@ 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 @@ 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 @@ 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; -} +int OnPostWinPosChanged(HWND hWnd, WINDOWPOS* pWinPos) +{ + PWND_CONTEXT pcontext; + DWORD style; + + /* 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()) + { + if(pcontext->HasThemeRgn) + { + pcontext->HasThemeRgn = FALSE; + user32ApiHook.SetWindowRgn(hWnd, 0, TRUE); + } + return 0; + } + + pcontext->DirtyThemeRegion = FALSE; + pcontext->HasThemeRgn = TRUE; + pcontext->UpdatingRgn = TRUE; + SetThemeRegion(hWnd); + pcontext->UpdatingRgn = FALSE; + + return 0; + }
/********************************************************************** * Hook Functions @@ -172,7 +184,7 @@ 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 @@ 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 @@ 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 @@ { case WM_WINDOWPOSCHANGED: { - return OnPostWinPosChanged(hWnd); + return OnPostWinPosChanged(hWnd, (WINDOWPOS*)lParam); } case WM_DESTROY: {
Modified: trunk/reactos/dll/win32/uxtheme/uxthemep.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/uxtheme/uxthemep.... ============================================================================== --- trunk/reactos/dll/win32/uxtheme/uxthemep.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/uxtheme/uxthemep.h [iso-8859-1] Fri Jan 17 17:52:58 2014 @@ -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 @@ 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 @@ 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 ATOM atWindowTheme; extern ATOM atWndContrext; extern BOOL gbThemeHooksActive; +extern PTHEME_FILE ActiveThemeFile;
void UXTHEME_InitSystem(HINSTANCE hInst); void UXTHEME_LoadTheme(BOOL bLoad);