Commit 6f139def authored by Zhiyi Zhang's avatar Zhiyi Zhang Committed by Alexandre Julliard

uxtheme/tests: Add EnableThemeDialogTexture() tests.

These tests show that DefDlgProcA/W() are hooked to implemented dialog theming, using a pattern brush created from the tab body part. For dialogs that need theming, EnableThemeDialogTexture(ETDT_USETABTEXTURE) or EnableThemeDialogTexture(ETDT_USEAEROWIZARDTABTEXTURE) is called for the dialog. And then static or button controls in comctl32 v6 call EnableThemeDialogTexture(ETDT_ENABLE) to activate it. A WM_ERASEBKGND is also needed to activate dialog theming. test_WM_CTLCOLORSTATIC() in dlls/comctl32/tests/static.c doesn't send this message after EnableThemeDialogTexture() calls, which misdirected me to think that DefDlgProcA/W() are not hooked. Signed-off-by: 's avatarZhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 7b32a327
/* Unit test suite for uxtheme API functions
*
* Copyright 2006 Paul Vriens
* Copyright 2021-2022 Zhiyi Zhang for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -33,6 +34,8 @@
#include "msg.h"
#include "wine/test.h"
#include "v6util.h"
static HTHEME (WINAPI * pOpenThemeDataEx)(HWND, LPCWSTR, DWORD);
static HTHEME (WINAPI *pOpenThemeDataForDpi)(HWND, LPCWSTR, UINT);
static HPAINTBUFFER (WINAPI *pBeginBufferedPaint)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *);
......@@ -1545,8 +1548,656 @@ static void test_DrawThemeParentBackground(void)
UnregisterClassA("TestDrawThemeParentBackgroundClass", GetModuleHandleA(0));
}
struct test_EnableThemeDialogTexture_param
{
const CHAR *class_name;
DWORD style;
};
static const struct message empty_seq[] =
{
{0}
};
static HWND dialog_child;
static DWORD dialog_init_flag;
static BOOL handle_WM_CTLCOLORSTATIC;
static INT_PTR CALLBACK test_EnableThemeDialogTexture_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
struct test_EnableThemeDialogTexture_param *param;
struct message message = {0};
message.message = msg;
message.flags = sent | wparam | lparam;
message.wParam = wp;
message.lParam = lp;
add_message(sequences, PARENT_SEQ_INDEX, &message);
switch (msg)
{
case WM_INITDIALOG:
param = (struct test_EnableThemeDialogTexture_param *)lp;
dialog_child = CreateWindowA(param->class_name, "child",
param->style | WS_CHILD | WS_VISIBLE, 1, 2, 50, 50, hwnd,
(HMENU)100, 0, NULL);
ok(dialog_child != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
if (dialog_init_flag)
EnableThemeDialogTexture(hwnd, dialog_init_flag);
return TRUE;
case WM_CTLCOLORSTATIC:
return (INT_PTR)(handle_WM_CTLCOLORSTATIC ? GetSysColorBrush(COLOR_MENU) : 0);
case WM_CLOSE:
DestroyWindow(dialog_child);
dialog_child = NULL;
return TRUE;
default:
return FALSE;
}
}
static void test_EnableThemeDialogTexture(void)
{
struct test_EnableThemeDialogTexture_param param;
HWND dialog, child, hwnd, hwnd2;
int mode, old_mode, count, i, j;
COLORREF color, old_color;
HBRUSH brush, brush2;
HDC child_hdc, hdc;
LOGBRUSH log_brush;
ULONG_PTR proc;
WNDCLASSA cls;
HTHEME theme;
DWORD error;
BITMAP bmp;
HRESULT hr;
LRESULT lr;
POINT org;
SIZE size;
BOOL ret;
struct
{
DLGTEMPLATE template;
WORD menu;
WORD class;
WORD title;
} temp = {{0}};
static const DWORD flags[] =
{
ETDT_DISABLE,
ETDT_ENABLE,
ETDT_USETABTEXTURE,
ETDT_USEAEROWIZARDTABTEXTURE,
ETDT_ENABLETAB,
ETDT_ENABLEAEROWIZARDTAB,
/* Bad flags */
0,
ETDT_DISABLE | ETDT_ENABLE,
ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB
};
static const struct invalid_flag_test
{
DWORD flag;
BOOL enabled;
BOOL todo;
}
invalid_flag_tests[] =
{
{0, FALSE},
{ETDT_DISABLE | ETDT_ENABLE, FALSE},
{ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB, TRUE},
{ETDT_USETABTEXTURE | ETDT_USEAEROWIZARDTABTEXTURE, TRUE, TRUE},
{ETDT_VALIDBITS, FALSE},
{~ETDT_VALIDBITS, FALSE},
{~ETDT_VALIDBITS | ETDT_DISABLE, FALSE}
};
static const struct class_test
{
struct test_EnableThemeDialogTexture_param param;
BOOL texture_enabled;
}
class_tests[] =
{
{{ANIMATE_CLASSA}},
{{WC_BUTTONA, BS_PUSHBUTTON}, TRUE},
{{WC_BUTTONA, BS_DEFPUSHBUTTON}, TRUE},
{{WC_BUTTONA, BS_CHECKBOX}, TRUE},
{{WC_BUTTONA, BS_AUTOCHECKBOX}, TRUE},
{{WC_BUTTONA, BS_RADIOBUTTON}, TRUE},
{{WC_BUTTONA, BS_3STATE}, TRUE},
{{WC_BUTTONA, BS_AUTO3STATE}, TRUE},
{{WC_BUTTONA, BS_GROUPBOX}, TRUE},
{{WC_BUTTONA, BS_USERBUTTON}, TRUE},
{{WC_BUTTONA, BS_AUTORADIOBUTTON}, TRUE},
{{WC_BUTTONA, BS_PUSHBOX}, TRUE},
{{WC_BUTTONA, BS_OWNERDRAW}, TRUE},
{{WC_BUTTONA, BS_SPLITBUTTON}, TRUE},
{{WC_BUTTONA, BS_DEFSPLITBUTTON}, TRUE},
{{WC_BUTTONA, BS_COMMANDLINK}, TRUE},
{{WC_BUTTONA, BS_DEFCOMMANDLINK}, TRUE},
{{WC_COMBOBOXA}},
{{WC_COMBOBOXEXA}},
{{DATETIMEPICK_CLASSA}},
{{WC_EDITA}},
{{WC_HEADERA}},
{{HOTKEY_CLASSA}},
{{WC_IPADDRESSA}},
{{WC_LISTBOXA}},
{{WC_LISTVIEWA}},
{{MONTHCAL_CLASSA}},
{{WC_NATIVEFONTCTLA}},
{{WC_PAGESCROLLERA}},
{{PROGRESS_CLASSA}},
{{REBARCLASSNAMEA}},
{{WC_STATICA, SS_LEFT}, TRUE},
{{WC_STATICA, SS_ICON}, TRUE},
{{WC_STATICA, SS_BLACKRECT}, TRUE},
{{WC_STATICA, SS_OWNERDRAW}, TRUE},
{{WC_STATICA, SS_BITMAP}, TRUE},
{{WC_STATICA, SS_ENHMETAFILE}, TRUE},
{{WC_STATICA, SS_ETCHEDHORZ}, TRUE},
{{STATUSCLASSNAMEA}},
{{"SysLink"}},
{{WC_TABCONTROLA}},
{{TOOLBARCLASSNAMEA}},
{{TOOLTIPS_CLASSA}},
{{TRACKBAR_CLASSA}},
{{WC_TREEVIEWA}},
{{UPDOWN_CLASSA}},
{{WC_SCROLLBARA}},
};
if (!IsThemeActive())
{
skip("Theming is inactive.\n");
return;
}
memset(&cls, 0, sizeof(cls));
cls.lpfnWndProc = DefWindowProcA;
cls.hInstance = GetModuleHandleA(NULL);
cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
cls.hbrBackground = GetStockObject(GRAY_BRUSH);
cls.lpszClassName = "TestEnableThemeDialogTextureClass";
RegisterClassA(&cls);
temp.template.style = WS_CHILD | WS_VISIBLE;
temp.template.cx = 100;
temp.template.cy = 100;
param.class_name = cls.lpszClassName;
param.style = 0;
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc, (LPARAM)&param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
child = GetDlgItem(dialog, 100);
ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
child_hdc = GetDC(child);
/* Test that dialog procedure is unchanged */
proc = GetWindowLongPtrA(dialog, DWLP_DLGPROC);
ok(proc == (ULONG_PTR)test_EnableThemeDialogTexture_proc, "Unexpected proc %#lx.\n", proc);
/* Test dialog texture is disabled by default. EnableThemeDialogTexture() needs to be called */
ret = IsThemeDialogTextureEnabled(dialog);
todo_wine
ok(!ret, "Expected theme dialog texture disabled.\n");
ok(GetWindowTheme(dialog) == NULL, "Expected NULL theme handle.\n");
/* Test ETDT_ENABLE | ETDT_USETABTEXTURE doesn't take effect immediately */
hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE | ETDT_USETABTEXTURE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
ret = IsThemeDialogTextureEnabled(dialog);
ok(ret, "Expected theme dialog texture enabled.\n");
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
GetSysColorBrush(COLOR_BTNFACE), brush);
ret = GetBrushOrgEx(child_hdc, &org);
ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError());
ok(org.x == 0 && org.y == 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org));
/* Test WM_THEMECHANGED doesn't make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
lr = SendMessageA(dialog, WM_THEMECHANGED, 0, 0);
ok(lr == 0, "WM_THEMECHANGED failed.\n");
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
GetSysColorBrush(COLOR_BTNFACE), brush);
/* Test WM_ERASEBKGND make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0);
ok(lr != 0, "WM_ERASEBKGND failed.\n");
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected brush changed.\n");
/* Test disabling theme dialog texture should change the brush immediately */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
hr = EnableThemeDialogTexture(dialog, ETDT_DISABLE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
todo_wine
ok(brush2 != brush, "Expected a different brush.\n");
ok(brush2 == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
GetSysColorBrush(COLOR_BTNFACE), brush2);
/* Test re-enabling theme dialog texture with ETDT_ENABLE doesn't change the brush */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush2 == brush, "Expected the same brush.\n");
ok(brush2 == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
GetSysColorBrush(COLOR_BTNFACE), brush2);
/* Test adding ETDT_USETABTEXTURE should change the brush immediately */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
hr = EnableThemeDialogTexture(dialog, ETDT_USETABTEXTURE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
todo_wine
ok(brush2 != brush, "Expected a different brush.\n");
/* Test ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE should change the brush immediately */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
/* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
if (LOBYTE(LOWORD(GetVersion())) < 6)
ok(brush2 == brush, "Expected the same brush.\n");
else
todo_wine
ok(brush2 != brush, "Expected a different brush.\n");
hr = EnableThemeDialogTexture(dialog, ETDT_DISABLE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE | ETDT_USETABTEXTURE);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
/* Test that the dialog procedure should take precedence over DefDlgProc() for WM_CTLCOLORSTATIC */
handle_WM_CTLCOLORSTATIC = TRUE;
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush == GetSysColorBrush(COLOR_MENU), "Expected brush %p, got %p.\n",
GetSysColorBrush(COLOR_MENU), brush);
handle_WM_CTLCOLORSTATIC = FALSE;
/* Test that WM_CTLCOLORSTATIC changes brush origin when dialog texture is on */
ret = SetBrushOrgEx(child_hdc, 0, 0, NULL);
ok(ret, "SetBrushOrgEx failed, error %u.\n", GetLastError());
SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ret = GetBrushOrgEx(child_hdc, &org);
ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError());
todo_wine
ok(org.x == -1 && org.y == -2, "Expected (-1,-2), got %s.\n", wine_dbgstr_point(&org));
/* Test that WM_CTLCOLORSTATIC changes background mode when dialog texture is on */
old_mode = SetBkMode(child_hdc, OPAQUE);
ok(old_mode != 0, "SetBkMode failed.\n");
SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
mode = SetBkMode(child_hdc, old_mode);
todo_wine
ok(mode == TRANSPARENT, "Expected mode %#x, got %#x.\n", TRANSPARENT, mode);
/* Test that WM_CTLCOLORSTATIC changes background color when dialog texture is on */
old_color = SetBkColor(child_hdc, 0xaa5511);
ok(old_color != CLR_INVALID, "SetBkColor failed.\n");
SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
color = SetBkColor(child_hdc, old_color);
ok(color == GetSysColor(COLOR_BTNFACE), "Expected background color %#x, got %#x.\n",
GetSysColor(COLOR_BTNFACE), color);
/* Test that dialog doesn't have theme handle opened for itself */
ok(GetWindowTheme(dialog) == NULL, "Expected NULL theme handle.\n");
/* Test that the returned brush is a pattern brush created from the tab body */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
memset(&log_brush, 0, sizeof(log_brush));
count = GetObjectA(brush, sizeof(log_brush), &log_brush);
ok(count == sizeof(log_brush), "GetObjectA failed, error %u.\n", GetLastError());
todo_wine
ok(log_brush.lbColor == 0, "Expected brush color %#x, got %#x.\n", 0, log_brush.lbColor);
todo_wine
ok(log_brush.lbStyle == BS_PATTERN, "Expected brush style %#x, got %#x.\n", BS_PATTERN,
log_brush.lbStyle);
memset(&bmp, 0, sizeof(bmp));
count = GetObjectA((HBITMAP)log_brush.lbHatch, sizeof(bmp), &bmp);
todo_wine
ok(count == sizeof(bmp), "GetObjectA failed, error %u.\n", GetLastError());
theme = OpenThemeData(NULL, L"Tab");
ok(theme != NULL, "OpenThemeData failed.\n");
size.cx = 0;
size.cy = 0;
hr = GetThemePartSize(theme, NULL, TABP_BODY, 0, NULL, TS_TRUE, &size);
ok(hr == S_OK, "GetThemePartSize failed, hr %#x.\n", hr);
todo_wine
ok(bmp.bmWidth == size.cx, "Expected width %d, got %d.\n", size.cx, bmp.bmWidth);
todo_wine
ok(bmp.bmHeight == size.cy, "Expected height %d, got %d.\n", size.cy, bmp.bmHeight);
CloseThemeData(theme);
/* Test that DefDlgProcA/W() are hooked for WM_CTLCOLORSTATIC */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
brush2 = (HBRUSH)DefDlgProcW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush2 == brush, "Expected the same brush.\n");
brush2 = (HBRUSH)DefDlgProcA(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush2 == brush, "Expected the same brush.\n");
/* Test that DefWindowProcA/W() are also hooked for WM_CTLCOLORSTATIC */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
brush2 = (HBRUSH)DefWindowProcW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush2 == brush, "Expected the same brush.\n");
brush2 = (HBRUSH)DefWindowProcA(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush2 == brush, "Expected the same brush.\n");
/* Test that DefWindowProcA/W() are not hooked for WM_ERASEBKGND. So the background is still
* drawn with hbrBackground, which in this case, is GRAY_BRUSH.
*
* This test means it could be that both DefWindowProc() and DefDlgProc() are hooked for
* WM_CTLCOLORSTATIC and only DefDlgProc() is hooked for WM_ERASEBKGND. Or it could mean
* DefWindowProc() is hooked for WM_CTLCOLORSTATIC and DefDlgProc() is hooked for WM_ERASEBKGND.
* Considering the dialog theming needs a WM_ERASEBKGND to activate, it would be weird for let
* only DefWindowProc() to hook WM_CTLCOLORSTATIC. For example, what's the point of hooking
* WM_CTLCOLORSTATIC in DefWindowProc() for a feature that can only be activated in
* DefDlgProc()? So I tend to believe both DefWindowProc() and DefDlgProc() are hooked for
* WM_CTLCOLORSTATIC */
hwnd = CreateWindowA(cls.lpszClassName, "parent", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, 0, 0,
0, NULL);
ok(hwnd != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
hwnd2 = CreateWindowA(WC_STATICA, "child", WS_CHILD | WS_VISIBLE, 10, 10, 20, 20, hwnd, NULL, 0,
NULL);
hr = EnableThemeDialogTexture(hwnd, ETDT_ENABLETAB);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
ret = IsThemeDialogTextureEnabled(hwnd);
ok(ret, "Wrong dialog texture status.\n");
flush_events();
hdc = GetDC(hwnd);
color = GetPixel(hdc, 0, 0);
ok(color == 0x808080 || broken(color == 0xffffffff), /* Win 7 may report 0xffffffff */
"Expected color %#x, got %#x.\n", 0x808080, color);
color = GetPixel(hdc, 50, 50);
ok(color == 0x808080 || broken(color == 0xffffffff), /* Win 7 may report 0xffffffff */
"Expected color %#x, got %#x.\n", 0x808080, color);
color = GetPixel(hdc, 99, 99);
ok(color == 0x808080 || broken(color == 0xffffffff), /* Win 7 may report 0xffffffff */
"Expected color %#x, got %#x.\n", 0x808080, color);
ReleaseDC(hwnd, hdc);
/* Test EnableThemeDialogTexture() doesn't work for non-dialog windows */
hdc = GetDC(hwnd2);
brush = (HBRUSH)SendMessageW(hwnd, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd2);
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
ReleaseDC(hwnd2, hdc);
DestroyWindow(hwnd);
/* Test that the brush is not a system object and has only one reference and shouldn't be freed */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ret = DeleteObject(brush);
ok(ret, "DeleteObject failed, error %u.\n", GetLastError());
SetLastError(0xdeadbeef);
ret = GetObjectA(brush, sizeof(log_brush), &log_brush);
error = GetLastError();
todo_wine
ok(!ret || broken(ret) /* XP */, "GetObjectA succeeded.\n");
todo_wine
ok(error == ERROR_INVALID_PARAMETER || broken(error == 0xdeadbeef) /* XP */,
"Expected error %u, got %u.\n", ERROR_INVALID_PARAMETER, error);
ret = DeleteObject(brush);
todo_wine
ok(!ret || broken(ret) /* XP */, "DeleteObject succeeded.\n");
/* Should still report the same brush handle after the brush handle was freed */
brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush2 == brush, "Expected the same brush.\n");
/* Test WM_THEMECHANGED can update the brush now that ETDT_ENABLE | ETDT_USETABTEXTURE is in
* effect. This test needs to be ran last as it affect other tests for the same dialog for
* unknown reason, causing the brush not to update */
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
lr = SendMessageA(dialog, WM_THEMECHANGED, 0, 0);
ok(lr == 0, "WM_THEMECHANGED failed.\n");
brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
todo_wine
ok(brush2 != brush, "Expected a different brush.\n");
ReleaseDC(child, child_hdc);
EndDialog(dialog, 0);
/* Test invalid flags */
for (i = 0; i < ARRAY_SIZE(invalid_flag_tests); ++i)
{
winetest_push_context("%d flag %#x", i, invalid_flag_tests[i].flag);
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc, (LPARAM)&param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
hr = EnableThemeDialogTexture(dialog, invalid_flag_tests[i].flag);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
ret = IsThemeDialogTextureEnabled(dialog);
todo_wine_if(invalid_flag_tests[i].todo)
ok(ret == invalid_flag_tests[i].enabled, "Wrong dialog texture status.\n");
EndDialog(dialog, 0);
winetest_pop_context();
}
/* Test different flag combinations */
for (i = 0; i < ARRAY_SIZE(flags); ++i)
{
for (j = 0; j < ARRAY_SIZE(flags); ++j)
{
/* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
if (LOBYTE(LOWORD(GetVersion())) < 6
&& ((flags[i] | flags[j]) & ETDT_USEAEROWIZARDTABTEXTURE))
continue;
winetest_push_context("%#x to %#x", flags[i], flags[j]);
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc, (LPARAM)&param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
flush_events();
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = EnableThemeDialogTexture(dialog, flags[i]);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
"EnableThemeDialogTexture first flag", TRUE);
ret = IsThemeDialogTextureEnabled(dialog);
/* Non-zero flags without ETDT_DISABLE enables dialog texture */
todo_wine_if(flags[i] == ETDT_USETABTEXTURE || flags[i] == ETDT_USEAEROWIZARDTABTEXTURE)
ok(ret == (!(flags[i] & ETDT_DISABLE) && flags[i]), "Wrong dialog texture status.\n");
child = GetDlgItem(dialog, 100);
ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
child_hdc = GetDC(child);
lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0);
ok(lr != 0, "WM_ERASEBKGND failed.\n");
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
if (flags[i] == ETDT_ENABLETAB || flags[i] == ETDT_ENABLEAEROWIZARDTAB)
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
else
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = EnableThemeDialogTexture(dialog, flags[j]);
ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
"EnableThemeDialogTexture second flag", TRUE);
ret = IsThemeDialogTextureEnabled(dialog);
/* If the flag is zero, it will have previous dialog texture status */
if (flags[j])
todo_wine_if(flags[j] == ETDT_USETABTEXTURE || flags[j] == ETDT_USEAEROWIZARDTABTEXTURE)
ok(ret == !(flags[j] & ETDT_DISABLE), "Wrong dialog texture status.\n");
else
todo_wine_if((!(flags[i] & ETDT_DISABLE) && flags[i]))
ok(ret == (!(flags[i] & ETDT_DISABLE) && flags[i]), "Wrong dialog texture status.\n");
lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0);
ok(lr != 0, "WM_ERASEBKGND failed.\n");
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
/* Dialog texture is turned on when the flag contains ETDT_ENABLETAB or
* ETDT_ENABLEAEROWIZARDTAB. The flag can be turned on in multiple steps, but you can't
* do things like set ETDT_ENABLETAB and then ETDT_USEAEROWIZARDTABTEXTURE */
if (((flags[j] == ETDT_ENABLETAB || flags[j] == ETDT_ENABLEAEROWIZARDTAB)
|| ((((flags[i] | flags[j]) & ETDT_ENABLETAB) == ETDT_ENABLETAB
|| ((flags[i] | flags[j]) & ETDT_ENABLEAEROWIZARDTAB) == ETDT_ENABLEAEROWIZARDTAB)
&& !((flags[i] | flags[j]) & ETDT_DISABLE)))
&& (((flags[i] | flags[j]) & (ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB)) != (ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB)))
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
else
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
ReleaseDC(child, child_hdc);
EndDialog(dialog, 0);
winetest_pop_context();
}
}
/* Test that the dialog procedure should set ETDT_USETABTEXTURE/ETDT_USEAEROWIZARDTABTEXTURE and
* find out which comctl32 class should set ETDT_ENABLE to turn on dialog texture */
for (i = 0; i < ARRAY_SIZE(class_tests); ++i)
{
winetest_push_context("%s %#x", wine_dbgstr_a(class_tests[i].param.class_name),
class_tests[i].param.style);
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc,
(LPARAM)&class_tests[i].param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
/* GetDlgItem() fails to get the child control if the child is a tooltip */
child = dialog_child;
ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
child_hdc = GetDC(child);
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
ReleaseDC(child, child_hdc);
EndDialog(dialog, 0);
dialog_init_flag = ETDT_ENABLE;
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc,
(LPARAM)&class_tests[i].param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
child = dialog_child;
ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
child_hdc = GetDC(child);
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
ReleaseDC(child, child_hdc);
EndDialog(dialog, 0);
dialog_init_flag = ETDT_USETABTEXTURE;
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc,
(LPARAM)&class_tests[i].param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
child = dialog_child;
ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
child_hdc = GetDC(child);
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
if (class_tests[i].texture_enabled)
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
else
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
ReleaseDC(child, child_hdc);
EndDialog(dialog, 0);
if (LOBYTE(LOWORD(GetVersion())) < 6)
{
dialog_init_flag = 0;
winetest_pop_context();
continue;
}
dialog_init_flag = ETDT_USEAEROWIZARDTABTEXTURE;
dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
test_EnableThemeDialogTexture_proc,
(LPARAM)&class_tests[i].param);
ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
child = dialog_child;
ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
child_hdc = GetDC(child);
brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
if (class_tests[i].texture_enabled)
todo_wine
ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
else
ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
ReleaseDC(child, child_hdc);
EndDialog(dialog, 0);
dialog_init_flag = 0;
winetest_pop_context();
}
/* Test that EnableThemeDialogTexture() is called from child controls for its parent */
hwnd = CreateWindowA(cls.lpszClassName, "parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0,
0, 0, NULL);
ok(hwnd != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
ret = IsThemeDialogTextureEnabled(hwnd);
todo_wine
ok(!ret, "Wrong dialog texture status.\n");
child = CreateWindowA(WC_STATICA, "child", WS_CHILD | WS_VISIBLE, 0, 0, 50, 50, hwnd, 0, 0,
NULL);
ok(child != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
ret = IsThemeDialogTextureEnabled(hwnd);
ok(ret, "Wrong dialog texture status.\n");
/* Test that if you move the child control to another window, it doesn't enables tab texture for
* the new parent */
hwnd2 = CreateWindowA(cls.lpszClassName, "parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0,
0, 0, NULL);
ok(hwnd2 != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
ret = IsThemeDialogTextureEnabled(hwnd2);
todo_wine
ok(!ret, "Wrong dialog texture status.\n");
SetParent(child, hwnd2);
ok(GetParent(child) == hwnd2, "Wrong parent.\n");
ret = IsThemeDialogTextureEnabled(hwnd2);
todo_wine
ok(!ret, "Wrong dialog texture status.\n");
InvalidateRect(child, NULL, TRUE);
flush_events();
ret = IsThemeDialogTextureEnabled(hwnd2);
todo_wine
ok(!ret, "Wrong dialog texture status.\n");
DestroyWindow(hwnd2);
DestroyWindow(hwnd);
UnregisterClassA(cls.lpszClassName, GetModuleHandleA(NULL));
}
START_TEST(system)
{
ULONG_PTR ctx_cookie;
HANDLE ctx;
init_funcs();
init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
......@@ -1568,6 +2219,13 @@ START_TEST(system)
test_GetThemeTransitionDuration();
test_DrawThemeParentBackground();
if (load_v6_module(&ctx_cookie, &ctx))
{
test_EnableThemeDialogTexture();
unload_v6_module(ctx_cookie, ctx);
}
/* Test EnableTheming() in the end because it may disable theming */
test_EnableTheming();
}
/*
* Utility routines for comctl32 v6 tests
*
* Copyright 2006 Mike McCormack for CodeWeavers
* Copyright 2007 George Gov
* Copyright 2009 Owen Rudge for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifdef __i386__
#define ARCH "x86"
#elif defined __x86_64__
#define ARCH "amd64"
#elif defined __arm__
#define ARCH "arm"
#elif defined __aarch64__
#define ARCH "arm64"
#else
#define ARCH "none"
#endif
static const CHAR manifest_name[] = "cc6.manifest";
static const CHAR manifest[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
" <assemblyIdentity\n"
" type=\"win32\"\n"
" name=\"Wine.ComCtl32.Tests\"\n"
" version=\"1.0.0.0\"\n"
" processorArchitecture=\"" ARCH "\"\n"
" />\n"
"<description>Wine comctl32 test suite</description>\n"
"<dependency>\n"
" <dependentAssembly>\n"
" <assemblyIdentity\n"
" type=\"win32\"\n"
" name=\"microsoft.windows.common-controls\"\n"
" version=\"6.0.0.0\"\n"
" processorArchitecture=\"" ARCH "\"\n"
" publicKeyToken=\"6595b64144ccf1df\"\n"
" language=\"*\"\n"
" />\n"
"</dependentAssembly>\n"
"</dependency>\n"
"</assembly>\n";
static void unload_v6_module(ULONG_PTR cookie, HANDLE hCtx)
{
DeactivateActCtx(0, cookie);
ReleaseActCtx(hCtx);
DeleteFileA(manifest_name);
}
static BOOL load_v6_module(ULONG_PTR *pcookie, HANDLE *hCtx)
{
ACTCTX_SECTION_KEYED_DATA data;
DWORD written;
HMODULE hmod;
ACTCTXA ctx;
HANDLE file;
BOOL ret;
/* create manifest */
file = CreateFileA( manifest_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
if (file != INVALID_HANDLE_VALUE)
{
ret = (WriteFile( file, manifest, sizeof(manifest)-1, &written, NULL ) &&
written == sizeof(manifest)-1);
CloseHandle( file );
if (!ret)
{
DeleteFileA( manifest_name );
skip("Failed to fill manifest file. Skipping comctl32 V6 tests.\n");
return FALSE;
}
else
trace("created %s\n", manifest_name);
}
else
{
skip("Failed to create manifest file. Skipping comctl32 V6 tests.\n");
return FALSE;
}
memset(&ctx, 0, sizeof(ctx));
ctx.cbSize = sizeof(ctx);
ctx.lpSource = manifest_name;
*hCtx = CreateActCtxA(&ctx);
ok(*hCtx != 0, "Expected context handle\n");
hmod = GetModuleHandleA("comctl32.dll");
ret = ActivateActCtx(*hCtx, pcookie);
ok(ret, "Failed to activate context, error %d.\n", GetLastError());
if (!ret)
{
win_skip("A problem during context activation occurred.\n");
DeleteFileA(manifest_name);
}
data.cbSize = sizeof(data);
ret = FindActCtxSectionStringA(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
"comctl32.dll", &data);
ok(ret, "failed to find comctl32.dll in active context, %u\n", GetLastError());
if (ret)
{
FreeLibrary(hmod);
LoadLibraryA("comctl32.dll");
}
return ret;
}
#undef ARCH
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment