Allowing the job to fail to avoid failing the pipeline. Some new tests are failing with it, and some are succeeding todo_wine.
-- v4: gitlab: Run user32 32-bit tests with nulldrv driver. user32/tests: Update todos specific to the X11 display driver. user32/tests: Check graphics driver and add todos for nulldrv. win32u: Check GUID_NULL display device if desktop atom is missing. explorer: Use GUID_NULL display device GUID for nulldrv. win32u: Return the current display mode depth with nulldrv. win32u: Map VK_MENU / KBDALT in kbdus_tables pCharModifiers. user32/tests: Test VK_MENU effect on ToUnicode.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/input.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index be41078bf29..c534880679a 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3042,6 +3042,7 @@ static void test_key_map(void)
#define shift 1 #define ctrl 2 +#define menu 4
static const struct tounicode_tests { @@ -3054,6 +3055,9 @@ static const struct tounicode_tests { { 0, 0, 'a', 1, {'a',0}}, { 0, shift, 'a', 1, {'A',0}}, + { 0, menu, 'a', 1, {'a',0}}, + { 0, shift|menu, 'a', 1, {'A',0}}, + { 0, shift|ctrl|menu, 'a', 0, {}}, { 0, ctrl, 'a', 1, {1, 0}}, { 0, shift|ctrl, 'a', 1, {1, 0}}, { VK_TAB, ctrl, 0, 0, {}}, @@ -3142,6 +3146,7 @@ static void test_ToUnicode(void)
state[VK_SHIFT] = state[VK_LSHIFT] = (mod & shift) ? HIGHEST_BIT : 0; state[VK_CONTROL] = state[VK_LCONTROL] = (mod & ctrl) ? HIGHEST_BIT : 0; + state[VK_MENU] = state[VK_LMENU] = (mod & menu) ? HIGHEST_BIT : 0;
ret = ToUnicode(vk, scan, state, wStr, 4, 0); ok(ret == utests[i].expect_ret, "%d: got %d expected %d\n", i, ret, utests[i].expect_ret);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index f768453594f..d7e502a4513 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -135,8 +135,8 @@ static const VK_TO_BIT vk_to_bit[] = static const MODIFIERS modifiers = { .pVkToBit = (VK_TO_BIT *)vk_to_bit, - .wMaxModBits = 3, - .ModNumber = {0, 1, 2, 3}, + .wMaxModBits = 7, + .ModNumber = {0, 1, 2, 3, 0, 1, 0, 0}, };
static const VK_TO_WCHARS2 vk_to_wchars2[] =
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/driver.c | 2 +- dlls/win32u/sysparams.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 1c0708461a1..3f676dc5796 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -761,7 +761,7 @@ static BOOL nulldrv_GetCurrentDisplaySettings( LPCWSTR name, BOOL is_primary, LP
static INT nulldrv_GetDisplayDepth( LPCWSTR name, BOOL is_primary ) { - return 32; + return -1; /* use default implementation */ }
static BOOL nulldrv_UpdateDisplayDevices( const struct gdi_device_manager *manager, BOOL force, void *param ) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index bcdb8c5103b..60b12321953 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2727,6 +2727,7 @@ static unsigned int active_monitor_count(void) INT get_display_depth( UNICODE_STRING *name ) { struct display_device *device; + BOOL is_primary; INT depth;
if (!lock_display_devices()) @@ -2743,8 +2744,16 @@ INT get_display_depth( UNICODE_STRING *name ) return 32; }
- depth = user_driver->pGetDisplayDepth( device->device_name, - !!(device->state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE) ); + is_primary = !!(device->state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE); + if ((depth = user_driver->pGetDisplayDepth( device->device_name, is_primary )) < 0) + { + struct adapter *adapter = CONTAINING_RECORD( device, struct adapter, dev ); + DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}; + + if (!adapter_get_current_settings( adapter, ¤t_mode )) depth = 32; + else depth = current_mode.dmBitsPerPel; + } + unlock_display_devices(); return depth; }
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/desktop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 96673adc254..81eb0d1d01b 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -876,7 +876,7 @@ static BOOL get_default_enable_shell( const WCHAR *name ) return result; }
-static HMODULE load_graphics_driver( const WCHAR *driver, const GUID *guid ) +static HMODULE load_graphics_driver( const WCHAR *driver, GUID *guid ) { static const WCHAR device_keyW[] = { 'S','y','s','t','e','m','\', @@ -921,6 +921,7 @@ static HMODULE load_graphics_driver( const WCHAR *driver, const GUID *guid )
if (!wcscmp( name, L"null" )) { + memset( guid, 0, sizeof(*guid) ); TRACE( "display %s using null driver\n", debugstr_guid(guid) ); wcscpy( libname, L"null" ); null_driver = TRUE;
From: Rémi Bernon rbernon@codeweavers.com
When using nulldrv, there's no module to call __wine_set_user_driver and the user driver is still lazy_load_driver when get_display_driver gets called during desktop windows creation.
Then, load_desktop_driver fails as it cannot find the not-yet-created desktop window atom, and fails later explorer.exe window creations such as the systray window.
Other processes don't suffer from this as they wait for the desktop window to be fully created, and its atom will be eventually set.
This change makes sure that we succeed in the case nulldrv was selected by explorer.exe, while still failing in case of error with another user driver as it would fail to open the right display device GUID. --- dlls/win32u/driver.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 3f676dc5796..eb736de272d 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -923,6 +923,8 @@ static const WCHAR guid_key_suffixW[] = {'}','\','0','0','0','0'};
static BOOL load_desktop_driver( HWND hwnd ) { + static const WCHAR guid_nullW[] = {'0','0','0','0','0','0','0','0','-','0','0','0','0','-','0','0','0','0','-', + '0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0',0}; WCHAR key[ARRAYSIZE(guid_key_prefixW) + 40 + ARRAYSIZE(guid_key_suffixW)], *ptr; char buf[4096]; KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buf; @@ -946,9 +948,15 @@ static BOOL load_desktop_driver( HWND hwnd ) memcpy( key, guid_key_prefixW, sizeof(guid_key_prefixW) ); ptr = key + ARRAYSIZE(guid_key_prefixW); if (NtQueryInformationAtom( guid_atom, AtomBasicInformation, buf, sizeof(buf), NULL )) - return FALSE; - memcpy( ptr, abi->Name, abi->NameLength ); - ptr += abi->NameLength / sizeof(WCHAR); + { + wcscpy( ptr, guid_nullW ); + ptr += ARRAY_SIZE(guid_nullW) - 1; + } + else + { + memcpy( ptr, abi->Name, abi->NameLength ); + ptr += abi->NameLength / sizeof(WCHAR); + } memcpy( ptr, guid_key_suffixW, sizeof(guid_key_suffixW) ); ptr += ARRAY_SIZE(guid_key_suffixW);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/msg.c | 6 ++++ dlls/user32/tests/user32_test.h | 57 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 dlls/user32/tests/user32_test.h
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 6faaa2c2f40..e8a05cf87d7 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -36,6 +36,8 @@
#include "wine/test.h"
+#include "user32_test.h" + #define MDI_FIRST_CHILD_ID 2004
/* undocumented SWP flags - from SDK 3.1 */ @@ -12806,9 +12808,11 @@ static DWORD WINAPI test_edit_ime_messages(void *unused_arg)
himc = ImmGetContext(hwnd); ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0); + todo_wine_if(is_driver( L"null" )) ok(ret, "ImmSetCompositionStringA failed.\n"); flush_sequence(); ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + todo_wine_if(is_driver( L"null" )) ok(ret, "ImmNotifyIME failed.\n"); /* Note that the following message loop is necessary to get the WM_CHAR messages because they * are posted. Same for the later message loops in this function. */ @@ -12828,9 +12832,11 @@ static DWORD WINAPI test_edit_ime_messages(void *unused_arg) ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0); + todo_wine_if(is_driver( L"null" )) ok(ret, "ImmSetCompositionStringA failed.\n"); flush_sequence(); ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + todo_wine_if(is_driver( L"null" )) ok(ret, "ImmNotifyIME failed.\n"); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(edit_eimes_getcompstratonce_seq, diff --git a/dlls/user32/tests/user32_test.h b/dlls/user32/tests/user32_test.h new file mode 100644 index 00000000000..30ef19cdcc1 --- /dev/null +++ b/dlls/user32/tests/user32_test.h @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Rémi Bernon 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 + */ + +#include <stdarg.h> +#include <stddef.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" + +#include "wine/test.h" + +static inline BOOL is_driver( const WCHAR *match ) +{ + static WCHAR *cache; + + WCHAR *tmp = NULL, driver[MAX_PATH] = {0}, path[sizeof("System\CurrentControlSet\Control\Video\{}\0000") + 40]; + DWORD size = sizeof(driver); + UINT guid_atom; + HKEY key; + + if (cache) return !wcscmp( cache, match ); + + guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" ) ); + wcscpy( path, L"System\CurrentControlSet\Control\Video\{" ); + if (GlobalGetAtomNameW( guid_atom, path + wcslen( path ), 40 )) + { + wcscat( path, L"}\0000" ); + if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &key )) + { + if (!RegQueryValueExW( key, L"GraphicsDriver", NULL, NULL, (BYTE *)&driver, &size )) + tmp = wcsdup( driver ); + RegCloseKey(key); + } + } + + if (!tmp) tmp = wcsdup( L"" ); + if ((tmp = InterlockedExchangePointer( (void *)&cache, tmp ))) free( tmp ); + + return !wcscmp( cache, match ); +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/msg.c | 3 ++- dlls/user32/tests/sysparams.c | 4 +++- dlls/user32/tests/win.c | 11 ++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index e8a05cf87d7..f4bdc30f62d 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -16978,7 +16978,8 @@ static DWORD CALLBACK post_rbuttonup_msg( void *arg ) DWORD ret;
ret = WaitForSingleObject( data->wndproc_finished, 500 ); - todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret ); + todo_wine_if(is_driver( L"winex11.drv" )) + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret ); if( ret == WAIT_OBJECT_0 ) return 0;
PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 ); diff --git a/dlls/user32/tests/sysparams.c b/dlls/user32/tests/sysparams.c index 6ed7755b91b..666fa931fd1 100644 --- a/dlls/user32/tests/sysparams.c +++ b/dlls/user32/tests/sysparams.c @@ -30,6 +30,8 @@ #include "winuser.h" #include "winnls.h"
+#include "user32_test.h" + static BOOL (WINAPI *pIsProcessDPIAware)(void); static BOOL (WINAPI *pSetProcessDPIAware)(void); static BOOL (WINAPI *pSetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); @@ -3574,7 +3576,7 @@ static void test_dpi_mapping(void) hdc = GetWindowDC( hwnd ); GetClipBox( hdc, &rect ); SetRect( &expect, 0, 0, 295, 303 ); - todo_wine + todo_wine_if(is_driver( L"winex11.drv" )) ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong clip box win DC %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); ReleaseDC( hwnd, hdc ); diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 1252e046ad3..452c08fbf8a 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -34,6 +34,8 @@
#include "wine/test.h"
+#include "user32_test.h" + #ifndef WM_SYSTIMER #define WM_SYSTIMER 0x0118 #endif @@ -3282,7 +3284,8 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) ret = SetWindowPos(hwnd_child, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_SHOWWINDOW); ok(ret, "Got %d\n", ret); flush_events( TRUE ); - todo_wine check_active_state(hwnd2, hwnd2, hwnd2); + todo_wine_if(is_driver( L"winex11.drv" )) + check_active_state(hwnd2, hwnd2, hwnd2); DestroyWindow(hwnd_child); }
@@ -4034,8 +4037,10 @@ static void test_SetForegroundWindow(HWND hwnd) /* FIXME: these tests are failing because of a race condition * between internal focus state applied immediately and X11 focus * message coming late */ - todo_wine ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow()); - todo_wine ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus()); + todo_wine_if(is_driver( L"winex11.drv" )) + ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow()); + todo_wine_if(is_driver( L"winex11.drv" )) + ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus());
SetForegroundWindow(hwnd); check_wnd_state(hwnd, hwnd, hwnd, 0);
From: Rémi Bernon rbernon@codeweavers.com
--- tools/gitlab/test.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml index 808c825eae9..64f2f62b4e0 100644 --- a/tools/gitlab/test.yml +++ b/tools/gitlab/test.yml @@ -66,6 +66,21 @@ test-linux-32: - export WINETEST_COLOR=1 - wine usr/local/lib/wine/i386-windows/winetest.exe -q -q -o - -t gitlab -u $CI_JOB_URL -n $EXCLUDE_TESTS
+test-linux-32-null: + extends: .wine-test + variables: + INCLUDE_TESTS: user32 + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + needs: + - job: build-linux + script: + - wine reg add HKCU\Software\Wine\Drivers /v Graphics /d null /f + - wineserver -w + - export WINETEST_COLOR=1 + - wine usr/local/lib/wine/i386-windows/winetest.exe -q -q -o - -t gitlab -u $CI_JOB_URL $INCLUDE_TESTS + - wine reg delete HKCU\Software\Wine\Drivers /v Graphics /f + debian-32: extends: .wine-test rules:
This includes fixes from https://gitlab.winehq.org/wine/wine/-/merge_requests/2318 and https://gitlab.winehq.org/wine/wine/-/merge_requests/2319. The only nulldrv specific todo_wine that are added are for imm32 related tests, as we don't have a default IME implementation (and in order to eventually have one, I think we would need to write more tests with an actual IME module, so related to https://gitlab.winehq.org/wine/wine/-/merge_requests/2221 and https://gitlab.winehq.org/wine/wine/-/merge_requests/2266).
Fwiw, I also confirmed that all the tests except for the following list are passing with nulldrv driver:
d3d10core:d3d10core d3d11:d3d11 d3d8:device d3d8:visual d3d9:d3d9ex d3d9:device d3d9:visual amstream comctl32 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 d3drm d3dx9_36 ddraw dxdiagn dxgi dxva2 evr gdi32 imm32 mf mfplat mfreadwrite opengl32 quartz vulkan-1 winmm
Most of the time this is because of the tests not able to create D3D device, or for imm32 case, because of the missing default IME implementation.