Reputation: 3839
I'm experiencing unexpected behavior when resizing a Windows 10 window while forcing an immediate redraw.
When I use:
RedrawWindow(window, NULL, NULL, RDW_INTERNALPAINT);
inside my main infinite loop, resizing works as expected: I drag the bottom-right corner, resize the window, release the mouse, and I can keep working in the window.
However, when I use:
RedrawWindow(window, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
or alternatively, use RDW_INTERNALPAINT
followed by UpdateWindow()
,
the window gets stuck in resize mode: The mouse remains "glued" to the bottom-right corner. The window keeps resizing as I move the mouse. I cannot exit resize mode, even when I press the escape key (but I don't see why this would be different than releasing the mouse).
Questions:
Why does this happen?
Is it possible to force an immediate redraw while keeping normal resizing behavior? If so, how can I ensure that the window stops resizing once I release the mouse?
Context: I think I understand what RedrawWindow
does—it schedules a WM_PAINT
event, meaning that other events can be processed before the window is actually redrawn(?) Ideally, I would like to force an immediate redraw so that I can process data as a result of that redraw in the main loop after RedrawWindow
is executed. This is why I attempted to switch to RedrawWindow(window, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
however, I then realized that resizing breaks with this change—likely due to my lack of understanding of the Windows API.
Here is a (hopefully) reproducible example that demonstrates this behavior.
// clang -std=c23 -o win_resize_stuck.exe -luser32 -lgdi32 ./win_resize_stuck.c
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <windows.h>
#include <windowsx.h>
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
//DragAcceptFiles(hWnd, TRUE);
break;
case WM_CLOSE:
PostQuitMessage(/* exit code */ 0);
break;
case WM_PAINT:
break;
case WM_SIZE:
break;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
break;
case WM_MOUSEMOVE:
break;
case WM_MOUSEWHEEL:
break;
case WM_KEYDOWN:
break;
case WM_KEYUP:
break;
default:
break;
}
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
//HINSTANCE connection;
HWND window;
#define WIN_CLASS_NAME "tmp"
#define APP_NAME "tmp"
static void create_window() {
WNDCLASSEX win_class;
win_class.cbSize = sizeof(WNDCLASSEX);
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.lpfnWndProc = WndProc;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = 0;
win_class.hInstance = GetModuleHandle(NULL);
win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
win_class.lpszMenuName = NULL;
win_class.lpszClassName = "tmp";
win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
if (!RegisterClassEx(&win_class)) {
fprintf(stderr, "Unexpected error trying to start the application!\n");
fflush(stderr);
exit(1);
}
RECT wr = {0, 0, 500, 500};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
window = CreateWindowEx(0,
WIN_CLASS_NAME,
APP_NAME,
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU,
100, 100,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
GetModuleHandle(NULL),
NULL);
}
int main(int argc, const char** argv) {
(void)argc;
(void)argv;
create_window();
MSG msg;
bool done = false;
while (!done) {
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (msg.message == WM_QUIT) {
done = true;
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
RedrawWindow(window, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); //RDW_INTERNALPAINT);
}
return 0;
}
Upvotes: 2
Views: 57