/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS uxtheme.dll * FILE: dll/win32/uxtheme/themehooks.c * PURPOSE: uxtheme user api hook functions * PROGRAMMER: Giannis Adamopoulos */ #include "uxthemep.h" USERAPIHOOK user32ApiHook; BYTE gabDWPmessages[UAHOWP_MAX_SIZE]; BYTE gabMSGPmessages[UAHOWP_MAX_SIZE]; BOOL gbThemeHooksActive = FALSE; 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) { HTHEME hTheme; RECT rcWindow; HRGN hrgn, hrgn1; int CaptionHeight, iPart; WINDOWINFO wi; TRACE("SetThemeRegion %d\n", hWnd); wi.cbSize = sizeof(wi); GetWindowInfo(hWnd, &wi); /* 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; 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 = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, 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, 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 */ static LRESULT CALLBACK ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if(!IsAppThemed()) { return user32ApiHook.DefWindowProcW(hWnd, Msg, wParam, lParam); } return ThemeWndProc(hWnd, Msg, wParam, lParam, user32ApiHook.DefWindowProcW); } static LRESULT CALLBACK ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if(!IsAppThemed()) { return user32ApiHook.DefWindowProcA(hWnd, Msg, wParam, lParam); } return ThemeWndProc(hWnd, Msg, wParam, lParam, user32ApiHook.DefWindowProcA); } static LRESULT CALLBACK ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown) { switch(Msg) { case WM_THEMECHANGED: 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; } 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, (WINDOWPOS*)lParam); } 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) { if (!puah || State != uahLoadInit) { UXTHEME_LoadTheme(FALSE); ThemeCleanupWndContext(NULL, 0); gbThemeHooksActive = FALSE; return TRUE; } gbThemeHooksActive = TRUE; /* Store the original functions from user32 */ user32ApiHook = *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); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSEMOVE); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSELEAVE); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCHITTEST); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCLBUTTONDOWN); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWCAPTION); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWFRAME); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETTEXT); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_WINDOWPOSCHANGED); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CONTEXTMENU); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_STYLECHANGED); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETICON); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCDESTROY); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SYSCOMMAND); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORMSGBOX); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORBTN); UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORSTATIC); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_CREATE); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_SETTINGCHANGE); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_DRAWITEM); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MEASUREITEM); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGING); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGED); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGING); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGED); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCCREATE); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCDESTROY); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCPAINT); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MENUCHAR); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MDISETMENU); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED); UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT); UXTHEME_LoadTheme(TRUE); return TRUE; } typedef BOOL (WINAPI * PREGISTER_UAH_WINXP)(HINSTANCE hInstance, USERAPIHOOKPROC CallbackFunc); typedef BOOL (WINAPI * PREGISTER_UUAH_WIN2003)(PUSERAPIHOOKINFO puah); BOOL WINAPI ThemeHooksInstall() { PVOID lpFunc; OSVERSIONINFO osvi; BOOL ret; lpFunc = GetProcAddress(GetModuleHandle("user32.dll"), "RegisterUserApiHook"); ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { PREGISTER_UAH_WINXP lpfuncxp = (PREGISTER_UAH_WINXP)lpFunc; ret = lpfuncxp(hDllInst, ThemeInitApiHook); } else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { PREGISTER_UUAH_WIN2003 lpfunc2003 = (PREGISTER_UUAH_WIN2003)lpFunc; USERAPIHOOKINFO uah; uah.m_size = sizeof(uah); uah.m_dllname1 = L"uxtheme.dll"; uah.m_funname1 = L"ThemeInitApiHook"; uah.m_dllname2 = NULL; uah.m_funname2 = NULL; ret = lpfunc2003(&uah); } else { UNIMPLEMENTED; ret = FALSE; } UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED); return ret; } BOOL WINAPI ThemeHooksRemove() { BOOL ret; ret = UnregisterUserApiHook(); UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED); return ret; }