ReactOS 0.4.17-dev-863-gc5f151a
NcPaintRgn.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API tests
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Test for the WM_NCPAINT update region on frame geometry changes
5 * COPYRIGHT: Copyright 2026 Ahmed Arif <arif.ing@outlook.com>
6 */
7
8#include "precomp.h"
9
10/*
11 * When the frame geometry of a window changes, SetWindowPos copies the bits it
12 * can instead of repainting them. The copied bits carry the old caption along,
13 * so the whole non-client frame has to end up in the WM_NCPAINT update region,
14 * or the caption buttons are left painted at their former position (CORE-20769).
15 */
16
17/* WM_NCPAINT passes this instead of a region when the whole window is to be painted. */
18#define NCPAINT_WHOLE_WINDOW ((HRGN)1)
19
20/* Accumulated non-client update region of the current operation, screen coordinates. */
21static HRGN g_hrgnNcUpdate;
24
25static
26VOID
28{
29 SetRectRgn(g_hrgnNcUpdate, 0, 0, 0, 0);
31 g_cNcPaint = 0;
32}
33
34static
42{
43 if (message == WM_NCPAINT)
44 {
45 HRGN hrgn = (HRGN)wParam;
46
47 g_cNcPaint++;
48
51 else if (hrgn != NULL)
53 }
54
56}
57
58static
59VOID
61{
62 MSG msg;
63
64 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
65 {
68 }
69}
70
71/* Verify that nothing of the non-client frame was left out of the update region. */
72static
73VOID
76 _In_ PCSTR pszStage)
77{
78 RECT rcWindow, rcClient;
79 HRGN hrgnFrame, hrgnClient, hrgnMissing;
80 INT type;
81
82 GetWindowRect(hWnd, &rcWindow);
83 GetClientRect(hWnd, &rcClient);
84 MapWindowPoints(hWnd, NULL, (PPOINT)&rcClient, 2);
85
86 hrgnFrame = CreateRectRgnIndirect(&rcWindow);
87 hrgnClient = CreateRectRgnIndirect(&rcClient);
88 hrgnMissing = CreateRectRgn(0, 0, 0, 0);
89
90 /* The non-client frame is what the window covers but the client area does not. */
91 CombineRgn(hrgnFrame, hrgnFrame, hrgnClient, RGN_DIFF);
92 type = CombineRgn(hrgnMissing, hrgnFrame, g_hrgnNcUpdate, RGN_DIFF);
93
94 ok(g_cNcPaint > 0, "%s: no WM_NCPAINT was sent\n", pszStage);
95
96 if (!g_bWholeWindow)
97 {
98 RECT rcMissing;
99
100 GetRgnBox(hrgnMissing, &rcMissing);
101 ok(type == NULLREGION,
102 "%s: (%ld,%ld)-(%ld,%ld) of the non-client frame is not in the update region\n",
103 pszStage, rcMissing.left, rcMissing.top, rcMissing.right, rcMissing.bottom);
104 }
105
106 DeleteObject(hrgnMissing);
107 DeleteObject(hrgnClient);
108 DeleteObject(hrgnFrame);
109}
110
111START_TEST(NcPaintRgn)
112{
113 WNDCLASSEXW wc;
114 HWND hWnd;
115 ATOM atom;
116
117 ZeroMemory(&wc, sizeof(wc));
118 wc.cbSize = sizeof(wc);
122 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
123 wc.lpszClassName = L"NcPaintRgnTestClass";
124
125 atom = RegisterClassExW(&wc);
126 if (atom == 0)
127 {
128 skip("RegisterClassExW failed with %lu\n", GetLastError());
129 return;
130 }
131
132 g_hrgnNcUpdate = CreateRectRgn(0, 0, 0, 0);
133 if (g_hrgnNcUpdate == NULL)
134 {
135 skip("CreateRectRgn failed with %lu\n", GetLastError());
137 return;
138 }
139
141 wc.lpszClassName,
142 L"NcPaintRgn",
144 100, 100, 400, 300,
145 NULL, NULL, wc.hInstance, NULL);
146 if (hWnd == NULL)
147 {
148 skip("CreateWindowExW failed with %lu\n", GetLastError());
151 return;
152 }
153
154 /* Get the window on screen and fully painted, so that the frame is settled. */
157 PumpMessages();
158
159 ResetNcPaint();
162 PumpMessages();
163 ExpectWholeFrameRepainted(hWnd, "maximize");
164
165 ResetNcPaint();
168 PumpMessages();
170
172 PumpMessages();
173
176}
#define NCPAINT_WHOLE_WINDOW
Definition: NcPaintRgn.c:18
static VOID ExpectWholeFrameRepainted(_In_ HWND hWnd, _In_ PCSTR pszStage)
Definition: NcPaintRgn.c:74
static INT g_cNcPaint
Definition: NcPaintRgn.c:23
static LRESULT CALLBACK NcPaintWndProc(_In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam)
Definition: NcPaintRgn.c:37
static HRGN g_hrgnNcUpdate
Definition: NcPaintRgn.c:21
static BOOL g_bWholeWindow
Definition: NcPaintRgn.c:22
static VOID PumpMessages(VOID)
Definition: NcPaintRgn.c:60
static VOID ResetNcPaint(VOID)
Definition: NcPaintRgn.c:27
static HRGN hrgn
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
#define msg(x)
Definition: auth_time.c:54
HWND hWnd
Definition: settings.c:17
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
WORD ATOM
Definition: dimm.idl:113
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CALLBACK
Definition: compat.h:35
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
pKey DeleteObject()
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
unsigned int UINT
Definition: sysinfo.c:13
#define ZeroMemory
Definition: minwinbase.h:31
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
#define _In_
Definition: no_sal2.h:158
#define WS_OVERLAPPEDWINDOW
Definition: pedump.c:637
LPCWSTR lpszClassName
Definition: winuser.h:3334
HBRUSH hbrBackground
Definition: winuser.h:3332
WNDPROC lpfnWndProc
Definition: winuser.h:3326
UINT cbSize
Definition: winuser.h:3324
HCURSOR hCursor
Definition: winuser.h:3331
HINSTANCE hInstance
Definition: winuser.h:3329
Definition: tftpd.h:60
LONG right
Definition: windef.h:108
LONG bottom
Definition: windef.h:109
LONG top
Definition: windef.h:107
LONG left
Definition: windef.h:106
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
const uint16_t * PCWSTR
Definition: typedefs.h:57
int32_t INT
Definition: typedefs.h:58
const char * PCSTR
Definition: typedefs.h:52
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
HRGN WINAPI CreateRectRgn(_In_ int, _In_ int, _In_ int, _In_ int)
#define RGN_DIFF
Definition: wingdi.h:358
#define NULLREGION
Definition: wingdi.h:361
int WINAPI CombineRgn(_In_opt_ HRGN hrgnDest, _In_opt_ HRGN hrgnSrc1, _In_opt_ HRGN hrgnSrc2, _In_ int fnCombineMode)
#define RGN_OR
Definition: wingdi.h:359
HRGN WINAPI CreateRectRgnIndirect(_In_ LPCRECT)
BOOL WINAPI SetRectRgn(_In_ HRGN, _In_ int, _In_ int, _In_ int, _In_ int)
int WINAPI GetRgnBox(_In_ HRGN, _Out_ LPRECT)
BOOL WINAPI TranslateMessage(_In_ const MSG *)
#define COLOR_WINDOW
Definition: winuser.h:929
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define IDC_ARROW
Definition: winuser.h:695
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2474
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
BOOL WINAPI PeekMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
HWND WINAPI CreateWindowExW(_In_ DWORD dwExStyle, _In_opt_ LPCWSTR lpClassName, _In_opt_ LPCWSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam)
#define PM_REMOVE
Definition: winuser.h:1207
BOOL WINAPI UpdateWindow(_In_ HWND)
ATOM WINAPI RegisterClassExW(_In_ CONST WNDCLASSEXW *)
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define SW_RESTORE
Definition: winuser.h:790
#define SW_SHOW
Definition: winuser.h:786
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
#define SW_MAXIMIZE
Definition: winuser.h:783
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WM_NCPAINT
Definition: winuser.h:1715