diff --git a/reactos/dll/win32/uxtheme/nonclient.c b/reactos/dll/win32/uxtheme/nonclient.c index ad9365f9e6d..99fd38d338f 100644 --- a/reactos/dll/win32/uxtheme/nonclient.c +++ b/reactos/dll/win32/uxtheme/nonclient.c @@ -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(); diff --git a/reactos/dll/win32/uxtheme/system.c b/reactos/dll/win32/uxtheme/system.c index 2f2799fc6e2..a1c6d368219 100644 --- a/reactos/dll/win32/uxtheme/system.c +++ b/reactos/dll/win32/uxtheme/system.c @@ -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) diff --git a/reactos/dll/win32/uxtheme/themehooks.c b/reactos/dll/win32/uxtheme/themehooks.c index 85081dc300b..8ce2c2416bc 100644 --- a/reactos/dll/win32/uxtheme/themehooks.c +++ b/reactos/dll/win32/uxtheme/themehooks.c @@ -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,24 +91,10 @@ 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) @@ -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: { diff --git a/reactos/dll/win32/uxtheme/uxthemep.h b/reactos/dll/win32/uxtheme/uxthemep.h index c54e19378c3..15b3608a627 100644 --- a/reactos/dll/win32/uxtheme/uxthemep.h +++ b/reactos/dll/win32/uxtheme/uxthemep.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -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);