Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2021
- 78 participants
- 2529 messages
Re: [PATCH v8 1/2] user32: Retrieve the work rect for placements in a helper function.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=96897
Your paranoid android.
=== debiant2 (32 bit report) ===
user32:
menu.c:2337: Test failed: test 25
Aug. 31, 2021
[PATCH] avicap32: Partially implement capCreateCaptureWindowW.
by Gijs Vermeulen
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38011
Signed-off-by: Gijs Vermeulen <gijsvrm(a)gmail.com>
---
dlls/avicap32/Makefile.in | 1 +
dlls/avicap32/avicap32_main.c | 72 ++++++++++++++++++++++++++---------
2 files changed, 56 insertions(+), 17 deletions(-)
diff --git a/dlls/avicap32/Makefile.in b/dlls/avicap32/Makefile.in
index 8f5a1089d5c..f320a58f04b 100644
--- a/dlls/avicap32/Makefile.in
+++ b/dlls/avicap32/Makefile.in
@@ -1,4 +1,5 @@
MODULE = avicap32.dll
IMPORTLIB = avicap32
+IMPORTS = user32
C_SRCS = avicap32_main.c
diff --git a/dlls/avicap32/avicap32_main.c b/dlls/avicap32/avicap32_main.c
index 9e2a99d4c7c..6ed8db1d552 100644
--- a/dlls/avicap32/avicap32_main.c
+++ b/dlls/avicap32/avicap32_main.c
@@ -56,36 +56,74 @@
WINE_DEFAULT_DEBUG_CHANNEL(avicap);
+static ATOM registered_class = 0;
+static WCHAR class_nameW[] = {'W','i','n','e','A','v','i','C','a','p','C','l','a','s','s',0};
+
+static LRESULT CALLBACK avicap_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch(msg)
+ {
+ /* FIXME: handle WM_CAP_* messages */
+ default:
+ return DefWindowProcW(hwnd, msg, wparam, lparam);
+ }
+}
+
+static ATOM register_class(void)
+{
+ WNDCLASSEXW class;
+
+ class.cbSize = sizeof(WNDCLASSEXW);
+ class.style = 0;
+ class.lpfnWndProc = avicap_wndproc;
+ class.cbClsExtra = 0;
+ class.cbWndExtra = 0;
+ class.hInstance = GetModuleHandleW(NULL);
+ class.hIcon = NULL;
+ class.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
+ class.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+ class.lpszMenuName = NULL;
+ class.lpszClassName = class_nameW;
+ class.hIconSm = NULL;
+
+ return RegisterClassExW(&class);
+}
/***********************************************************************
* capCreateCaptureWindowW (AVICAP32.@)
*/
-HWND VFWAPI capCreateCaptureWindowW(LPCWSTR lpszWindowName, DWORD dwStyle, INT x,
- INT y, INT nWidth, INT nHeight, HWND hWnd,
- INT nID)
+HWND VFWAPI capCreateCaptureWindowW(const WCHAR *window_name, DWORD style, INT x,
+ INT y, INT width, INT height, HWND hWnd, INT id)
{
- FIXME("(%s, %08x, %08x, %08x, %08x, %08x, %p, %08x): stub\n",
- debugstr_w(lpszWindowName), dwStyle, x, y, nWidth, nHeight, hWnd, nID);
- return 0;
+ FIXME("(%s, %08x, %08x, %08x, %08x, %08x, %p, %08x): semi-stub\n",
+ debugstr_w(window_name), style, x, y, width, height, hWnd, id);
+
+ if (!registered_class && !(registered_class = register_class()))
+ {
+ ERR("Failed to register class!\n");
+ return NULL;
+ }
+
+ return CreateWindowExW(style, class_nameW, window_name, style, x, y, width, height,
+ hWnd, NULL, GetModuleHandleW(NULL), NULL);
}
/***********************************************************************
* capCreateCaptureWindowA (AVICAP32.@)
*/
-HWND VFWAPI capCreateCaptureWindowA(LPCSTR lpszWindowName, DWORD dwStyle, INT x,
- INT y, INT nWidth, INT nHeight, HWND hWnd,
- INT nID)
-{ UNICODE_STRING nameW;
- HWND retW;
+HWND VFWAPI capCreateCaptureWindowA(const char *window_name, DWORD style, INT x,
+ INT y, INT width, INT height, HWND hWnd, INT id)
+{ UNICODE_STRING window_nameW;
+ HWND ret;
- if (lpszWindowName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszWindowName);
- else nameW.Buffer = NULL;
+ if (window_name) RtlCreateUnicodeStringFromAsciiz(&window_nameW, window_name);
+ else window_nameW.Buffer = NULL;
- retW = capCreateCaptureWindowW(nameW.Buffer, dwStyle, x, y, nWidth, nHeight,
- hWnd, nID);
- RtlFreeUnicodeString(&nameW);
+ ret = capCreateCaptureWindowW(window_nameW.Buffer, style, x, y, width, height,
+ hWnd, id);
+ RtlFreeUnicodeString(&window_nameW);
- return retW;
+ return ret;
}
#ifdef HAVE_LINUX_VIDEODEV2_H
--
2.33.0
Aug. 31, 2021
Re: [PATCH 4/5] d3d10/effect: Support stream output declaration when creating geometry shaders.
by Nikolay Sivov
On 8/31/21 4:32 PM, Matteo Bruni wrote:
> On Mon, Aug 30, 2021 at 7:07 AM Nikolay Sivov <nsivov(a)codeweavers.com> wrote:
>> Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
>> ---
>> dlls/d3d10/effect.c | 172 ++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 166 insertions(+), 6 deletions(-)
> Patch is okay, a few notes below.
>
>> diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c
>> index 113125e9cbd..c3c98a0da31 100644
>> --- a/dlls/d3d10/effect.c
>> +++ b/dlls/d3d10/effect.c
>> @@ -566,6 +592,127 @@ static HRESULT get_fx10_shader_resources(struct d3d10_effect_variable *v, const
>> return S_OK;
>> }
>>
>> +struct d3d10_effect_so_decl
>> +{
>> + D3D10_SO_DECLARATION_ENTRY *entries;
>> + SIZE_T capacity;
>> + SIZE_T count;
>> + unsigned int stride;
>> + char *decl;
>> +};
>> +
>> +static void d3d10_effect_cleanup_so_decl(struct d3d10_effect_so_decl *so_decl)
>> +{
>> + heap_free(so_decl->entries);
>> + heap_free(so_decl->decl);
>> + memset(so_decl, 0, sizeof(*so_decl));
>> +}
>> +
>> +static HRESULT d3d10_effect_parse_stream_output_declaration(const char *decl,
>> + struct d3d10_effect_so_decl *so_decl)
>> +{
>> + static const char * allmask = "xyzw";
> Usually in HLSL you can use "rgba" in place of "xyzw" for swizzles /
> writemasks, it might be worth checking if those also work (and are
> passed through to the effect bytecode unchanged).
Yes, "rgba" also works apparently. Compiler preserves string as is, does
not convert to coordinate mask names. I'll add a test for that.
>
>> + char *p, *ptr, *end, *next, *mask, *m, *slot;
>> + unsigned int len = strlen(decl);
>> + D3D10_SO_DECLARATION_ENTRY e;
>> +
>> + memset(so_decl, 0, sizeof(*so_decl));
>> +
>> + if (!(so_decl->decl = heap_alloc(len + 1)))
>> + return E_OUTOFMEMORY;
>> + memcpy(so_decl->decl, decl, len + 1);
>> +
>> + p = so_decl->decl;
> I think it would be nice to have a small comment showing the expected
> syntax of a stream out declaration (entry) somewhere around here. Just
> something to quickly glance at while reading the following code.
Okay.
>
>> +
>> + while (p && *p)
>> + {
>> + memset(&e, 0, sizeof(e));
>> +
>> + end = strchr(p, ';');
>> + next = end ? end + 1 : p + strlen(p);
>> +
>> + len = next - p;
>> + if (end) len--;
>> +
>> + /* Remove leading and trailing spaces. */
>> + while (len && isspace(*p)) { len--; p++; }
>> + while (len && isspace(p[len - 1])) len--;
>> +
>> + p[len] = 0;
>> +
>> + /* Output slot */
>> + if ((slot = strchr(p, ':')))
>> + {
>> + *slot = 0;
>> +
>> + ptr = p;
>> + while (*ptr)
>> + {
>> + if (!isdigit(*ptr))
>> + {
>> + WARN("Invalid output slot %s.\n", debugstr_a(p));
>> + goto failed;
>> + }
>> + ptr++;
>> + }
>> +
>> + e.OutputSlot = atoi(p);
>> + p = slot + 1;
>> + }
>> +
>> + /* Mask */
>> + if ((mask = strchr(p, '.')))
>> + {
>> + *mask = 0; mask++;
>> +
>> + if (!(m = strstr(allmask, mask)))
>> + {
>> + WARN("Invalid component mask %s.\n", debugstr_a(mask));
>> + goto failed;
>> + }
>> +
>> + e.StartComponent = m - allmask;
>> + e.ComponentCount = strlen(mask);
> Did you verify that it's illegal to have a wrongly ordered mask (e.g.
> something like .wzyx)?
> I expect that to be invalid but better to be sure.
> Likewise for other assumptions involved here, like repeating the same
> component twice.
Yes, it is disallowed to break the order. API manifestation is that you
specify start and count, which assumes it's always forward looking.
Regarding error, it won't pass compiler check first, complaining about
"invalid mask declaration". As far as I can tell that's the only thing
that compiler checks in this string, you can have non-existent semantics
as much as you like. That will break effect creation later though,
presumably because shader object can't be created with invalid declaration.
>
> In general, some more tests with interesting stream out declarations
> would be nice. I guess you have more planned after the test in patch
> 5/5.
I can think of adding more variations with spaces around, and maybe with
multiple entries. Do you have other ideas?
>> + }
>> + else
>> + {
>> + e.StartComponent = 0;
>> + e.ComponentCount = 4;
>> + }
>> +
>> + /* Semantic index and name */
>> + len = strlen(p);
>> + while (isdigit(p[len - 1]))
>> + len--;
>> +
>> + if (p[len])
>> + {
>> + e.SemanticIndex = atoi(&p[len]);
>> + p[len] = 0;
>> + }
>> +
>> + e.SemanticName = p;
>> +
>> + if (!d3d_array_reserve((void **)&so_decl->entries, &so_decl->capacity, so_decl->count + 1,
>> + sizeof(*so_decl->entries)))
>> + goto failed;
>> +
>> + so_decl->entries[so_decl->count++] = e;
>> +
>> + if (e.OutputSlot == 0)
>> + so_decl->stride += e.ComponentCount * sizeof(float);
> This looks weird, but that's probably because the API for
> ID3D10Device_CreateGeometryShaderWithStreamOutput() is confusing (just
> one stride for up to 4 output buffers? What does it even mean?) and
> neither the documentation nor our tests seem to clarify that. Any clue
> what's supposed to happen with multiple output buffers?
>
> FWIW that function's signature makes a lot more sense in d3d11.
My understanding is that in d3d10 you can specify stride only when you
use one SO buffer. And if you use multiple buffers runtime will use
default strides for all. For d3d11 you can set each explicitly.
Aug. 31, 2021
[tools] testbot: Pids can have more than 5 digits.
by Francois Gouget
Pids used to be a 16-bit value but that's no longer the case. Assume
they are an unsigned 32-bit value now.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
This is needed on Debian 11 because without it the TestBot ORM (Object
Relational Mapper) rejects pids with more than 5 digits. But in Debian
11 'sysctl -n kernel.pid_max' returns 4194304 (probably because of the
newer kernel, 5.10 vs 4.19 for Debian 10).
So the important part is the VMs.pm patch but it's better to keep the
database schema consistent with it by applying update46.sql.
---
testbot/ddl/update46.sql | 4 ++++
testbot/ddl/winetestbot.sql | 2 +-
testbot/lib/WineTestBot/VMs.pm | 2 +-
3 files changed, 6 insertions(+), 2 deletions(-)
create mode 100644 testbot/ddl/update46.sql
diff --git a/testbot/ddl/update46.sql b/testbot/ddl/update46.sql
new file mode 100644
index 000000000..f24130b06
--- /dev/null
+++ b/testbot/ddl/update46.sql
@@ -0,0 +1,4 @@
+USE winetestbot;
+
+ALTER TABLE VMs
+ MODIFY ChildPid INT UNSIGNED NULL;
diff --git a/testbot/ddl/winetestbot.sql b/testbot/ddl/winetestbot.sql
index 3b5cda757..2d085247c 100644
--- a/testbot/ddl/winetestbot.sql
+++ b/testbot/ddl/winetestbot.sql
@@ -52,7 +52,7 @@ CREATE TABLE VMs
MissionCaps VARCHAR(512) NOT NULL,
Status ENUM('dirty', 'reverting', 'sleeping', 'idle', 'running', 'off', 'offline', 'maintenance') NOT NULL,
Errors INT(2) NULL,
- ChildPid INT(5) NULL,
+ ChildPid INT UNSIGNED NULL,
ChildDeadline DATETIME NULL,
VirtURI VARCHAR(64) NOT NULL,
VirtDomain VARCHAR(32) NOT NULL,
diff --git a/testbot/lib/WineTestBot/VMs.pm b/testbot/lib/WineTestBot/VMs.pm
index 2cc6c678d..0b11d8170 100644
--- a/testbot/lib/WineTestBot/VMs.pm
+++ b/testbot/lib/WineTestBot/VMs.pm
@@ -760,7 +760,7 @@ my @PropertyDescriptors = (
CreateBasicPropertyDescriptor("MissionCaps", "Mission Capabilities", !1, !1, "A", 512),
CreateEnumPropertyDescriptor("Status", "Current status", !1, 1, ['dirty', 'reverting', 'sleeping', 'idle', 'running', 'off', 'offline', 'maintenance']),
CreateBasicPropertyDescriptor("Errors", "Errors", !1, !1, "N", 2),
- CreateBasicPropertyDescriptor("ChildPid", "Child process id", !1, !1, "N", 5),
+ CreateBasicPropertyDescriptor("ChildPid", "Child process id", !1, !1, "N", 10),
CreateBasicPropertyDescriptor("ChildDeadline", "Child Deadline", !1, !1, "DT", 19),
CreateBasicPropertyDescriptor("VirtURI", "LibVirt URI of the VM", !1, 1, "A", 64),
CreateBasicPropertyDescriptor("VirtDomain", "LibVirt Domain for the VM", !1, 1, "A", 32),
--
2.30.2
Aug. 31, 2021
Re: [PATCH 3/3] dbghelp: fix failing SymInitialize for a live 32bit target from a 64bit caller in WOW64
by Gabriel Ivăncescu
On 31/08/2021 12:53, Alexandre Julliard wrote:
> Eric Pouech <eric.pouech(a)gmail.com> writes:
>
>> When:
>> - caller of dbghelp is a 64bit process,
>> - invoking SymInitialize on a 32bit live target running under WOW64
>>
>> SymInitialize fails because:
>> - check_live_target() erroneously reads the 64bit PEB of the target,
>> while it actually wants the 32bit PEB.
>> - as the ELF base header address isn't set (hidden in CloudFileFlags)
>> in the 64bit PEB, hence causing the failure
>>
>> So ensure that check_live_target() actually reads the 32bit PEB when
>> handling a 32bit process.
>>
>>
>> ----
>>
>> I couldn't find a simpler way to fix it :-(
>> (offsetting PEB address by 0x1000 works but is way too hacky)
>
> Offsetting by 0x1000 is fine.
>
> But I'd say that the ELF data should be stored in the 64-bit PEB. Also
> note that once the new Wow64 architecture is enabled, all ELF data
> inside 32-bit processes is going to be 64-bit.
>
Sorry for the off topic remark, but is there some brief documentation on
how this is going to work posted anywhere? Will it be optional? (i.e. if
the host supplies 32-bit libs, wine will still use them).
I'm mainly concerned about it adding too much overhead, mostly for stuff
that relies on heavy library usage for performance (probably graphics
API related, like 32-bit games)... But maybe I misunderstand the whole
thing.
Aug. 31, 2021
[PATCH v8 2/2] user32: Don't save maximized position for toplevel windows covering the entire work area.
by Gabriel Ivăncescu
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51672
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/user32/tests/win.c | 54 ++++++++++++++++++++++++++++++++---------
dlls/user32/winpos.c | 50 +++++++++++++++++++++++++++++++++++++-
2 files changed, 91 insertions(+), 13 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 228395e..e23ab81 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -11624,8 +11624,9 @@ static void test_IsWindowEnabled(void)
static void test_window_placement(void)
{
- RECT orig = {100, 200, 300, 400}, orig2 = {200, 300, 400, 500}, rect;
+ RECT orig = {100, 200, 300, 400}, orig2 = {200, 300, 400, 500}, rect, work_rect;
WINDOWPLACEMENT wp = {sizeof(wp)};
+ MONITORINFO mon_info;
HWND hwnd;
BOOL ret;
@@ -11633,6 +11634,10 @@ static void test_window_placement(void)
orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, 0, 0, 0, 0);
ok(!!hwnd, "failed to create window, error %u\n", GetLastError());
+ mon_info.cbSize = sizeof(mon_info);
+ GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mon_info);
+ work_rect = mon_info.rcWork;
+
ret = GetWindowPlacement(hwnd, &wp);
ok(ret, "failed to get window placement, error %u\n", GetLastError());
ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd);
@@ -11675,7 +11680,6 @@ static void test_window_placement(void)
ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11693,6 +11697,42 @@ todo_wine
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
wine_dbgstr_rect(&wp.rcNormalPosition));
+ SetWindowPos(hwnd, 0, work_rect.left, work_rect.top, work_rect.right - work_rect.left,
+ work_rect.bottom - work_rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ ret = GetWindowPlacement(hwnd, &wp);
+ ok(ret, "failed to get window placement, error %u\n", GetLastError());
+ ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd);
+ ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
+ "got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
+ ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
+ "got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
+ ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
+ wine_dbgstr_rect(&wp.rcNormalPosition));
+
+ SetWindowPos(hwnd, 0, work_rect.left, work_rect.top, work_rect.right - work_rect.left - 1,
+ work_rect.bottom - work_rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ ret = GetWindowPlacement(hwnd, &wp);
+ ok(ret, "failed to get window placement, error %u\n", GetLastError());
+ ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd);
+ ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
+ "got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
+ ok(wp.ptMaxPosition.x == work_rect.left && wp.ptMaxPosition.y == work_rect.top,
+ "got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
+ ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
+ wine_dbgstr_rect(&wp.rcNormalPosition));
+
+ SetWindowPos(hwnd, 0, work_rect.left, work_rect.top, work_rect.right - work_rect.left,
+ work_rect.bottom - work_rect.top - 1, SWP_NOZORDER | SWP_NOACTIVATE);
+ ret = GetWindowPlacement(hwnd, &wp);
+ ok(ret, "failed to get window placement, error %u\n", GetLastError());
+ ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd);
+ ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
+ "got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
+ ok(wp.ptMaxPosition.x == work_rect.left && wp.ptMaxPosition.y == work_rect.top,
+ "got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
+ ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
+ wine_dbgstr_rect(&wp.rcNormalPosition));
+
ShowWindow(hwnd, SW_MINIMIZE);
ret = GetWindowPlacement(hwnd, &wp);
@@ -11701,7 +11741,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11714,7 +11753,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11727,7 +11765,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11745,7 +11782,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == 100 && wp.ptMinPosition.y == 100,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig2), "got normal pos %s\n",
@@ -11761,7 +11797,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig2), "got normal pos %s\n",
@@ -11783,7 +11818,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11804,7 +11838,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == 100 && wp.ptMinPosition.y == 100,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11825,7 +11858,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11839,7 +11871,6 @@ todo_wine
ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
@@ -11854,7 +11885,6 @@ todo_wine
ok(wp.showCmd == SW_NORMAL, "got show cmd %u\n", wp.showCmd);
ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000,
"got minimized pos (%d,%d)\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
-todo_wine
ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
"got maximized pos (%d,%d)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n",
diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c
index 33a7de5..c0ef0b8 100644
--- a/dlls/user32/winpos.c
+++ b/dlls/user32/winpos.c
@@ -1285,6 +1285,47 @@ UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
}
+static RECT get_maximized_work_rect( HWND hwnd )
+{
+ RECT work_rect = { 0 };
+
+ if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_MINIMIZE | WS_MAXIMIZE)) == WS_MAXIMIZE)
+ {
+ if (!get_work_rect( hwnd, &work_rect ))
+ work_rect = get_primary_monitor_rect();
+ }
+ return work_rect;
+}
+
+
+/*******************************************************************
+ * update_maximized_pos
+ *
+ * For top level windows covering the work area, we might have to
+ * "forget" the maximized position. Windows presumably does this
+ * to avoid situations where the border style changes, which would
+ * lead the window to be outside the screen, or the window gets
+ * reloaded on a different screen, and the "saved" position no
+ * longer applies to it (despite being maximized).
+ *
+ * Some applications (e.g. Imperiums: Greek Wars) depend on this.
+ */
+static void update_maximized_pos( WND *wnd, RECT *work_rect )
+{
+ if (wnd->parent && wnd->parent != GetDesktopWindow())
+ return;
+
+ if (wnd->dwStyle & WS_MAXIMIZE)
+ {
+ if (wnd->window_rect.left <= work_rect->left && wnd->window_rect.top <= work_rect->top &&
+ wnd->window_rect.right >= work_rect->right && wnd->window_rect.bottom >= work_rect->bottom)
+ wnd->max_pos.x = wnd->max_pos.y = -1;
+ }
+ else
+ wnd->max_pos.x = wnd->max_pos.y = -1;
+}
+
+
/***********************************************************************
* GetWindowPlacement (USER32.@)
*
@@ -1293,6 +1334,7 @@ UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
*/
BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
{
+ RECT work_rect = get_maximized_work_rect( hwnd );
WND *pWnd = WIN_GetPtr( hwnd );
if (!pWnd) return FALSE;
@@ -1350,6 +1392,7 @@ BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
{
pWnd->normal_rect = pWnd->window_rect;
}
+ update_maximized_pos( pWnd, &work_rect );
wndpl->length = sizeof(*wndpl);
if( pWnd->dwStyle & WS_MINIMIZE )
@@ -1421,6 +1464,7 @@ static void make_point_onscreen( POINT *pt )
static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
{
DWORD style;
+ RECT work_rect = get_maximized_work_rect( hwnd );
WND *pWnd = WIN_GetPtr( hwnd );
WINDOWPLACEMENT wp = *wndpl;
@@ -1438,7 +1482,11 @@ static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT f
if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
if (flags & PLACE_MIN) pWnd->min_pos = point_thread_to_win_dpi( hwnd, wp.ptMinPosition );
- if (flags & PLACE_MAX) pWnd->max_pos = point_thread_to_win_dpi( hwnd, wp.ptMaxPosition );
+ if (flags & PLACE_MAX)
+ {
+ pWnd->max_pos = point_thread_to_win_dpi( hwnd, wp.ptMaxPosition );
+ update_maximized_pos( pWnd, &work_rect );
+ }
if (flags & PLACE_RECT) pWnd->normal_rect = rect_thread_to_win_dpi( hwnd, wp.rcNormalPosition );
style = pWnd->dwStyle;
--
2.31.1
Aug. 31, 2021
[PATCH v8 1/2] user32: Retrieve the work rect for placements in a helper function.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/user32/winpos.c | 45 ++++++++++++++++++++++++++++----------------
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c
index 6e96a4b..33a7de5 100644
--- a/dlls/user32/winpos.c
+++ b/dlls/user32/winpos.c
@@ -675,6 +675,33 @@ BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
}
+/*******************************************************************
+ * get_work_rect
+ *
+ * Get the work area that a maximized window can cover, depending on style.
+ */
+static BOOL get_work_rect( HWND hwnd, RECT *rect )
+{
+ HMONITOR monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
+ MONITORINFO mon_info;
+ DWORD style;
+
+ if (!monitor) return FALSE;
+
+ mon_info.cbSize = sizeof(mon_info);
+ GetMonitorInfoW( monitor, &mon_info );
+
+ style = GetWindowLongW( hwnd, GWL_STYLE );
+ *rect = mon_info.rcMonitor;
+ if (style & WS_MAXIMIZEBOX)
+ {
+ if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
+ *rect = mon_info.rcWork;
+ }
+ return TRUE;
+}
+
+
/*******************************************************************
* WINPOS_GetMinMaxInfo
*
@@ -683,8 +710,8 @@ BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
MINMAXINFO WINPOS_GetMinMaxInfo( HWND hwnd )
{
DPI_AWARENESS_CONTEXT context;
+ RECT rc_work, rc_primary;
MINMAXINFO MinMax;
- HMONITOR monitor;
INT xinc, yinc;
LONG style = GetWindowLongW( hwnd, GWL_STYLE );
LONG adjustedStyle;
@@ -738,22 +765,8 @@ MINMAXINFO WINPOS_GetMinMaxInfo( HWND hwnd )
/* if the app didn't change the values, adapt them for the current monitor */
- if ((monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY )))
+ if (get_work_rect( hwnd, &rc_work ))
{
- RECT rc_work, rc_primary;
- MONITORINFO mon_info;
-
- mon_info.cbSize = sizeof(mon_info);
- GetMonitorInfoW( monitor, &mon_info );
-
- rc_work = mon_info.rcMonitor;
-
- if (style & WS_MAXIMIZEBOX)
- {
- if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
- rc_work = mon_info.rcWork;
- }
-
rc_primary = get_primary_monitor_rect();
if (MinMax.ptMaxSize.x == (rc_primary.right - rc_primary.left) + 2 * xinc &&
MinMax.ptMaxSize.y == (rc_primary.bottom - rc_primary.top) + 2 * yinc)
--
2.31.1
Aug. 31, 2021
[tools 3/3] winetest/build-patterns: Add dark cyan instead of substituting it for cyan.
by Francois Gouget
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
winetest/build-patterns | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/winetest/build-patterns b/winetest/build-patterns
index 72291401e..386bf9784 100755
--- a/winetest/build-patterns
+++ b/winetest/build-patterns
@@ -903,7 +903,7 @@ sub compute_set_colors($)
{
# Start from a 'darker cyan' for increased contrast
# when many colors are needed.
- $keycolors[0] = [0, 179, 179] if ($count > 10);
+ unshift @keycolors, [0, 179, 179] if ($count > 10);
# Convert the key colors to the Luv colorspace where the distance
# between colors is roughly representative of the perceptual difference
--
2.30.2
Aug. 31, 2021
[tools 2/3] winetest/build-patterns: Use the Luv colorspace for interpolating colors.
by Francois Gouget
Interpolation works best in a colorspace where the distance between
colors is representative of their perceptual difference. That's
roughly the case in the Luv colorspace and much less so in the RGB
one.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
This introduces a dependency on the Graphics::ColorObject perl module
which is provided by the libgraphics-colorobject-perl Debian package.
Note that on Debian 11 this package is missing a dependency on
libgraphics-colornames-www-perl.
---
winetest/build-patterns | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/winetest/build-patterns b/winetest/build-patterns
index ff72516f6..72291401e 100755
--- a/winetest/build-patterns
+++ b/winetest/build-patterns
@@ -22,6 +22,7 @@ use open ':utf8';
use CGI qw(:standard);
use POSIX; # ceil()
+use Graphics::ColorObject;
use Text::CSV::Encoded;
use Time::Piece;
@@ -860,15 +861,15 @@ if (open(my $fh, "-|", $cmd))
sub color2html($)
{
my ($c) = @_;
- return sprintf "#%02x%02x%02x", $c->[0], $c->[1], $c->[2];
+ return "#". $c->as_RGBhex();
}
-sub blend($$$)
+sub interpolate($$$)
{
my ($p, $start, $end) = @_;
- my $r = [int($start->[0] * (1 - $p) + $end->[0] * $p + 0.5),
- int($start->[1] * (1 - $p) + $end->[1] * $p + 0.5),
- int($start->[2] * (1 - $p) + $end->[2] * $p + 0.5)];
+ my $r = [$start->[0] * (1 - $p) + $end->[0] * $p,
+ $start->[1] * (1 - $p) + $end->[1] * $p,
+ $start->[2] * (1 - $p) + $end->[2] * $p];
return $r;
}
@@ -896,7 +897,7 @@ sub compute_set_colors($)
my $count = @values;
if ($count == 1)
{
- $set->{$values[0]} = color2html($keycolors[0]);
+ $set->{$values[0]} = color2html(Graphics::ColorObject->new_RGB255($keycolors[0]));
}
else
{
@@ -904,6 +905,12 @@ sub compute_set_colors($)
# when many colors are needed.
$keycolors[0] = [0, 179, 179] if ($count > 10);
+ # Convert the key colors to the Luv colorspace where the distance
+ # between colors is roughly representative of the perceptual difference
+ # between them. This allows linear interpolation to produce relatively
+ # uniform gradients (which is not the case in the RGB colorspace).
+ map { $_ = Graphics::ColorObject->new_RGB255($_)->as_Luv() } @keycolors;
+
# Compute the total length of the path traced by the key colors through
# the colorspace. This is necessary so the gradient remains uniform
# even if two key colors are close to each other. This does assume that
@@ -929,8 +936,8 @@ sub compute_set_colors($)
}
# And blend
- my $Rgb = blend(($pos - $keypos[$k]) / ($keypos[$k+1] - $keypos[$k]), $keycolors[$k], $keycolors[$k+1]);
- $set->{$values[$_]} = color2html($Rgb);
+ my $Luv = interpolate(($pos - $keypos[$k]) / ($keypos[$k+1] - $keypos[$k]), $keycolors[$k], $keycolors[$k+1]);
+ $set->{$values[$_]} = color2html(Graphics::ColorObject->new_Luv($Luv));
}
}
}
--
2.30.2
Aug. 31, 2021
[tools 1/3] winetest/build-patterns: Take the distance between key colors into account.
by Francois Gouget
To get a uniform color gradient, fewer colors should be squeezed between
close key colors than between distant ones.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
There are two issues with the current pattern colors:
* We have lots of blue/green colors which are hard to distinguish.
* We have few colors in the yellow/red range despite those being easier
to distinguish.
This is in part because we don't take the space between key colors into
account, but mainly because interpolating in the RGB colorspace does not
yield good results.
So the goal of this patchset is to make it easier to distinguish the
pattern colors by fixing these two issues.
---
winetest/build-patterns | 35 ++++++++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/winetest/build-patterns b/winetest/build-patterns
index 2ee5d5bdd..ff72516f6 100755
--- a/winetest/build-patterns
+++ b/winetest/build-patterns
@@ -872,6 +872,13 @@ sub blend($$$)
return $r;
}
+sub distance($$)
+{
+ my ($a, $b) = @_;
+ return sqrt(($b->[0] - $a->[0])**2 +
+ ($b->[1] - $a->[1])**2 +
+ ($b->[2] - $a->[2])**2);
+}
# Use colors to differentiate the set values. Each unique value is assigned
# a color (in HTML format) picked along a series of gradients passing by the
@@ -897,19 +904,33 @@ sub compute_set_colors($)
# when many colors are needed.
$keycolors[0] = [0, 179, 179] if ($count > 10);
+ # Compute the total length of the path traced by the key colors through
+ # the colorspace. This is necessary so the gradient remains uniform
+ # even if two key colors are close to each other. This does assume that
+ # the path does not zigzag too much: (0,0,0)->(255,0,0)->(1,0,0) cannot
+ # produce a meaningful gradient.
+ my @keypos = (0);
+ for (my $i = 1; $i < @keycolors; $i++)
+ {
+ my $d = distance($keycolors[$i - 1], $keycolors[$i]);
+ $keypos[$i] = $keypos[$i - 1] + $d;
+ }
+
my $k = 0;
- my ($start, $end) = (-1, 0);
for (0..$count-1)
{
- while (!$end or $_ > $end)
+ # Compute the position of the current item on the path
+ my $pos = $_ / ($count - 1) * $keypos[-1];
+
+ # Figure out which segment of the path this corresponds to
+ while ($pos > $keypos[$k+1] and $k+1 < @keycolors-1)
{
$k++;
- $start = $end;
- $end = ($count-1) * $k / (@keycolors-1);
}
- $set->{$values[$_]} = color2html(blend(($_-$start)/($end-$start),
- $keycolors[$k-1],
- $keycolors[$k]));
+
+ # And blend
+ my $Rgb = blend(($pos - $keypos[$k]) / ($keypos[$k+1] - $keypos[$k]), $keycolors[$k], $keycolors[$k+1]);
+ $set->{$values[$_]} = color2html($Rgb);
}
}
}
--
2.30.2
Aug. 31, 2021