[uxtheme]
authorGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 15 Aug 2011 10:22:23 +0000 (10:22 +0000)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 15 Aug 2011 10:22:23 +0000 (10:22 +0000)
- 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

dll/win32/uxtheme/ncthm.h
dll/win32/uxtheme/system.c
dll/win32/uxtheme/themehooks.c
dll/win32/uxtheme/uxthemedll.h

index 0707e9f..4b9e76b 100644 (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;
+
index deb84ce..1c3ea2a 100644 (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');
-        }
-        else {
-            bThemeActive = FALSE;
-            TRACE("Failed to get ThemeActive: %d\n", GetLastError());
+    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);
         }
-        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");
 }
 
 /***********************************************************************
index b83c20d..1b8f9b7 100644 (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;
 }
\ No newline at end of file
index a118609..5f3cd00 100644 (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 */