[UXTHEME] -Rename WND_CONTEXT to WND_DATA to avoid confusion with the DRAW_CONTEXT...
[reactos.git] / reactos / dll / win32 / uxtheme / themehooks.c
index f5101e0..6560648 100644 (file)
 USERAPIHOOK user32ApiHook;
 BYTE gabDWPmessages[UAHOWP_MAX_SIZE];
 BYTE gabMSGPmessages[UAHOWP_MAX_SIZE];
+BYTE gabDLGPmessages[UAHOWP_MAX_SIZE];
 BOOL gbThemeHooksActive = FALSE;
 
-PWND_CONTEXT ThemeGetWndContext(HWND hWnd)
+PWND_DATA ThemeGetWndData(HWND hWnd)
 {
-    PWND_CONTEXT pcontext;
+    PWND_DATA pwndData;
 
-    pcontext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContext));
-    if(pcontext == NULL)
+    pwndData = (PWND_DATA)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContext));
+    if(pwndData == NULL)
     {
-        pcontext = HeapAlloc(GetProcessHeap(), 
+        pwndData = HeapAlloc(GetProcessHeap(), 
                             HEAP_ZERO_MEMORY, 
-                            sizeof(WND_CONTEXT));
-        if(pcontext == NULL)
+                            sizeof(WND_DATA));
+        if(pwndData == NULL)
         {
             return NULL;
         }
         
-        SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContext), pcontext);
+        SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContext), pwndData);
     }
 
-    return pcontext;
+    return pwndData;
 }
 
-void ThemeDestroyWndContext(HWND hWnd)
+void ThemeDestroyWndData(HWND hWnd)
 {
-    PWND_CONTEXT pContext;
+    PWND_DATA pwndData;
     DWORD ProcessId;
 
-    /*Do not destroy WND_CONTEXT of a window that belong to another process */
+    /*Do not destroy WND_DATA of a window that belong to another process */
     GetWindowThreadProcessId(hWnd, &ProcessId);
     if(ProcessId != GetCurrentProcessId())
     {
         return;
     }
 
-    pContext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContext));
-    if(pContext == NULL)
+    pwndData = (PWND_DATA)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContext));
+    if(pwndData == NULL)
     {
         return;
     }
 
-    if(pContext->HasThemeRgn)
+    if(pwndData->HasThemeRgn)
     {
         user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
     }
-    
-    HeapFree(GetProcessHeap(), 0, pContext);
+
+    if (pwndData->hTabBackgroundBrush != NULL)
+    {
+        CloseThemeData(GetWindowTheme(hWnd));
+
+        DeleteObject(pwndData->hTabBackgroundBrush);
+        pwndData->hTabBackgroundBrush = NULL;
+    }
+
+    if (pwndData->hTabBackgroundBmp != NULL)
+    {
+        DeleteObject(pwndData->hTabBackgroundBmp);
+        pwndData->hTabBackgroundBmp = NULL;
+    }
+
+    HeapFree(GetProcessHeap(), 0, pwndData);
 
     SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContext), NULL);
 }
 
 static BOOL CALLBACK ThemeCleanupChildWndContext (HWND hWnd, LPARAM msg)
 {
-    ThemeDestroyWndContext(hWnd);
+    ThemeDestroyWndData(hWnd);
     return TRUE;
 }
 
@@ -76,7 +91,7 @@ static BOOL CALLBACK ThemeCleanupWndContext(HWND hWnd, LPARAM msg)
     }
     else
     {
-        ThemeDestroyWndContext(hWnd);
+        ThemeDestroyWndData(hWnd);
         EnumChildWindows (hWnd, ThemeCleanupChildWndContext, 0);
     }
 
@@ -97,7 +112,9 @@ void SetThemeRegion(HWND hWnd)
     GetWindowInfo(hWnd, &wi);
 
     /* Get the caption part id */
-    if (wi.dwExStyle & WS_EX_TOOLWINDOW)
+    if (wi.dwStyle & WS_MINIMIZE)
+        iPart = WP_MINCAPTION;
+    else if (wi.dwExStyle & WS_EX_TOOLWINDOW)
         iPart = WP_SMALLCAPTION;
     else if (wi.dwStyle & WS_MAXIMIZE)
         iPart = WP_MAXCAPTION;
@@ -133,7 +150,7 @@ void SetThemeRegion(HWND hWnd)
 
 int OnPostWinPosChanged(HWND hWnd, WINDOWPOS* pWinPos)
 {
-    PWND_CONTEXT pcontext;
+    PWND_DATA pwndData;
     DWORD style;
 
     /* We only proceed to change the window shape if it has a caption */
@@ -142,37 +159,37 @@ int OnPostWinPosChanged(HWND hWnd, WINDOWPOS* pWinPos)
         return 0;
 
     /* Get theme data for this window */
-    pcontext = ThemeGetWndContext(hWnd);
-    if (pcontext == NULL)
+    pwndData = ThemeGetWndData(hWnd);
+    if (pwndData == 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)
+    if ((pWinPos->flags & SWP_NOSIZE) != 0 && pwndData->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)
+    if (pwndData->HasAppDefinedRgn == TRUE)
         return 0;
 
     /* Calling SetWindowRgn will call SetWindowPos again so we need to avoid this recursion */
-    if (pcontext->UpdatingRgn == TRUE)
+    if (pwndData->UpdatingRgn == TRUE)
         return 0;
 
     if(!IsAppThemed())
     {
-        if(pcontext->HasThemeRgn)
+        if(pwndData->HasThemeRgn)
         {
-            pcontext->HasThemeRgn = FALSE;
+            pwndData->HasThemeRgn = FALSE;
             user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
         }
         return 0;
     }
 
-    pcontext->DirtyThemeRegion = FALSE;
-    pcontext->HasThemeRgn = TRUE;
-    pcontext->UpdatingRgn = TRUE;
+    pwndData->DirtyThemeRegion = FALSE;
+    pwndData->HasThemeRgn = TRUE;
+    pwndData->UpdatingRgn = TRUE;
     SetThemeRegion(hWnd);
-    pcontext->UpdatingRgn = FALSE;
+    pwndData->UpdatingRgn = FALSE;
 
      return 0;
  }
@@ -186,12 +203,6 @@ ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {      
     if(!IsAppThemed())
     {
-        if (Msg == WM_NCUAHDRAWCAPTION)
-        {
-            user32ApiHook.DrawCaption(hWnd, NULL, NULL, 0);
-            return 0;
-        }
-
         return user32ApiHook.DefWindowProcW(hWnd, 
                                             Msg, 
                                             wParam, 
@@ -210,12 +221,6 @@ ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {
     if(!IsAppThemed())
     {
-        if (Msg == WM_NCUAHDRAWCAPTION)
-        {
-            user32ApiHook.DrawCaption(hWnd, NULL, NULL, 0);
-            return 0;
-        }
-
         return user32ApiHook.DefWindowProcA(hWnd, 
                                             Msg, 
                                             wParam, 
@@ -235,14 +240,33 @@ ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR
     switch(Msg)
     {
         case WM_THEMECHANGED:
+        {
+            PWND_DATA pwndData = ThemeGetWndData(hWnd);
+
             if (GetAncestor(hWnd, GA_PARENT) == GetDesktopWindow())
                 UXTHEME_LoadTheme(TRUE);
+
+            if (pwndData == NULL)
+                return 0;
+
+            if (pwndData->hTabBackgroundBrush != NULL)
+            {
+                DeleteObject(pwndData->hTabBackgroundBrush);
+                pwndData->hTabBackgroundBrush = NULL;
+            }
+
+            if (pwndData->hTabBackgroundBmp != NULL)
+            {
+                DeleteObject(pwndData->hTabBackgroundBmp);
+                pwndData->hTabBackgroundBmp = NULL;
+            }
+        }
         case WM_NCCREATE:
         {
-            PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
-            if (pcontext == NULL)
+            PWND_DATA pwndData = ThemeGetWndData(hWnd);
+            if (pwndData == NULL)
                 return 0;
-            pcontext->DirtyThemeRegion = TRUE;
+            pwndData->DirtyThemeRegion = TRUE;
         }
     }
 
@@ -259,9 +283,9 @@ ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR
         {
             return OnPostWinPosChanged(hWnd, (WINDOWPOS*)lParam);
         }
-        case WM_DESTROY:
+        case WM_NCDESTROY:
         {
-            ThemeDestroyWndContext(hWnd);
+            ThemeDestroyWndData(hWnd);
             return 0;
         }
     }
@@ -269,18 +293,178 @@ ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR
     return 0;
 }
 
+HRESULT GetDiaogTextureBrush(HTHEME theme, HWND hwnd, HDC hdc, HBRUSH* result, BOOL changeOrigin)
+{
+    PWND_DATA pwndData;
+
+    pwndData = ThemeGetWndData(hwnd);
+    if (pwndData == NULL)
+        return E_FAIL;
+
+    if (pwndData->hTabBackgroundBrush == NULL)
+    {
+        HBITMAP hbmp;
+        RECT dummy, bmpRect;
+        BOOL hasImageAlpha;
+
+        UXTHEME_LoadImage(theme, 0, TABP_BODY, 0, &dummy, FALSE, &hbmp, &bmpRect, &hasImageAlpha);
+        if (changeOrigin)
+        {
+            /* Unfortunately SetBrushOrgEx doesn't work at all */
+            RECT rcWindow, rcParent;
+            UINT y;
+            HDC hdcPattern, hdcHackPattern;
+            HBITMAP hbmpOld1, hbmpold2, hbmpHack;
+
+            GetWindowRect(hwnd, &rcWindow);
+            GetWindowRect(GetParent(hwnd), &rcParent);
+            y = (rcWindow.top - rcParent.top) % bmpRect.bottom;
+
+            hdcPattern = CreateCompatibleDC(hdc);
+            hbmpOld1 = (HBITMAP)SelectObject(hdcPattern, hbmp);
+
+            hdcHackPattern = CreateCompatibleDC(hdc);
+            hbmpHack = CreateCompatibleBitmap(hdc, bmpRect.right, bmpRect.bottom);
+            hbmpold2 = (HBITMAP)SelectObject(hdcHackPattern, hbmpHack);
+
+            BitBlt(hdcHackPattern, 0, 0, bmpRect.right, bmpRect.bottom - y, hdcPattern, 0, y, SRCCOPY);
+            BitBlt(hdcHackPattern, 0, bmpRect.bottom - y, bmpRect.right, y, hdcPattern, 0, 0, SRCCOPY);
+
+            hbmpold2 = (HBITMAP)SelectObject(hdcHackPattern, hbmpold2);
+            hbmpOld1 = (HBITMAP)SelectObject(hdcPattern, hbmpOld1);
+
+            DeleteDC(hdcPattern);
+            DeleteDC(hdcHackPattern);
+
+            /* Keep the handle of the bitmap we created so that it can be used later */
+            pwndData->hTabBackgroundBmp = hbmpHack;
+            hbmp = hbmpHack;
+        }
+
+        /* hbmp is cached so there is no need to free it */
+        pwndData->hTabBackgroundBrush = CreatePatternBrush(hbmp);
+    }
+
+    if (!pwndData->hTabBackgroundBrush)
+        return E_FAIL;
+
+    *result = pwndData->hTabBackgroundBrush;
+    return S_OK;
+}
+
+void HackFillStaticBg(HWND hwnd, HDC hdc, HBRUSH* result)
+{
+    RECT rcStatic;
+
+    GetClientRect(hwnd, &rcStatic);
+    FillRect(hdc, &rcStatic, *result);
+
+    SetBkMode (hdc, TRANSPARENT);
+    *result = GetStockObject (NULL_BRUSH);
+}
+
+static LRESULT CALLBACK
+ThemeDlgPreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
+{
+    return 0;
+}
+
+static LRESULT CALLBACK
+ThemeDlgPostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
+{
+    switch(Msg)
+    {
+        case WM_CTLCOLORDLG:
+        case WM_CTLCOLORBTN:
+        case WM_CTLCOLORSTATIC:
+        {
+            HWND hwndTarget = (HWND)lParam;
+            HDC hdc = (HDC)wParam;
+            HBRUSH* phbrush = (HBRUSH*)ret;
+            HTHEME hTheme;
+
+            if (!IsAppThemed())
+                break;
+
+            if (!IsThemeDialogTextureEnabled (hWnd))
+                break;
+
+            hTheme = GetWindowTheme(hWnd);
+            if (!hTheme)
+                hTheme = OpenThemeData(hWnd, L"TAB");
+
+            if (!hTheme)
+                break;
+
+            GetDiaogTextureBrush(hTheme, hwndTarget, hdc, phbrush, Msg != WM_CTLCOLORDLG);
+
+#if 1 
+            {
+                WCHAR controlClass[32];
+                GetClassNameW (hwndTarget, controlClass, sizeof(controlClass) / sizeof(controlClass[0]));
+
+                /* This is a hack for the static class. Windows have a v6 static class just for this. */
+                if (lstrcmpiW (controlClass, WC_STATICW) == 0)
+                    HackFillStaticBg(hwndTarget, hdc, phbrush);
+            }
+#endif
+            break;
+        }
+    }
+
+    return 0;
+}
+
 int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
 {
-    PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
-    if(pcontext)
+    PWND_DATA pwndData = ThemeGetWndData(hWnd);
+    if(pwndData)
     {
-        pcontext->HasAppDefinedRgn = TRUE;
-        pcontext->HasThemeRgn = FALSE;
+        pwndData->HasAppDefinedRgn = TRUE;
+        pwndData->HasThemeRgn = FALSE;
     }
 
     return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
 }
 
+BOOL WINAPI ThemeGetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
+{
+    PWND_DATA pwndData;
+    DWORD style;
+    BOOL ret;
+
+    /* Avoid creating a window context if it is not needed */
+    if(!IsAppThemed())
+        goto dodefault;
+
+    style = GetWindowLongW(hwnd, GWL_STYLE);
+    if((style & (WS_HSCROLL|WS_VSCROLL))==0)
+        goto dodefault;
+
+    pwndData = ThemeGetWndData(hwnd);
+    if (pwndData == NULL)
+        goto dodefault;
+
+    /* 
+     * Uxtheme needs to handle the tracking of the scrollbar itself 
+     * This means than if an application needs to get the track position
+     * with GetScrollInfo, it will get wrong data. So uxtheme needs to
+     * hook it and set the correct tracking position itself
+     */
+    ret = user32ApiHook.GetScrollInfo(hwnd, fnBar, lpsi);
+    if ( lpsi && 
+        (lpsi->fMask & SIF_TRACKPOS) &&
+         pwndData->SCROLL_TrackingWin == hwnd && 
+         pwndData->SCROLL_TrackingBar == fnBar)
+    {
+        lpsi->nTrackPos = pwndData->SCROLL_TrackingVal;
+    }
+    return ret;
+
+dodefault:
+    return user32ApiHook.GetScrollInfo(hwnd, fnBar, lpsi);
+}
+
 /**********************************************************************
  *      Exports
  */
@@ -305,16 +489,17 @@ ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
     puah->DefWindowProcW = ThemeDefWindowProcW;
     puah->PreWndProc = ThemePreWindowProc;
     puah->PostWndProc = ThemePostWindowProc;
-    puah->PreDefDlgProc = ThemePreWindowProc;
-    puah->PostDefDlgProc = ThemePostWindowProc;
+    puah->PreDefDlgProc = ThemeDlgPreWindowProc;
+    puah->PostDefDlgProc = ThemeDlgPostWindowProc;
     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.MsgBitArray = gabDLGPmessages;
     puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
 
     puah->SetWindowRgn = ThemeSetWindowRgn;
+    puah->GetScrollInfo = ThemeGetScrollInfo;
 
     UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
     UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
@@ -351,6 +536,16 @@ ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
     UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
     UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
 
+    puah->DlgProcArray.MsgBitArray = gabDLGPmessages;
+    puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
+
+    UAH_HOOK_MESSAGE(puah->DlgProcArray, WM_INITDIALOG);
+    UAH_HOOK_MESSAGE(puah->DlgProcArray, WM_CTLCOLORMSGBOX);
+    UAH_HOOK_MESSAGE(puah->DlgProcArray, WM_CTLCOLORBTN);
+    UAH_HOOK_MESSAGE(puah->DlgProcArray, WM_CTLCOLORDLG);
+    UAH_HOOK_MESSAGE(puah->DlgProcArray, WM_CTLCOLORSTATIC);
+    UAH_HOOK_MESSAGE(puah->DlgProcArray, WM_PRINTCLIENT);
+
     UXTHEME_LoadTheme(TRUE);
 
     return TRUE;