Getting the X and Y client space coordinates of a WM_PAINT dirty rect in Win32 API using C++

62 Views Asked by At

I'm trying to design an abstraction layer for windows for various platforms. I decided to add a callback for when a window, or a section of it needs to be redrawn. I'm trying to make it fit into this callback type:

using paint_callback_t = std::function<void(int, int, unsigned int, unsigned int, void*, std::size_t)>;

Where the first 4 parameters are the X, Y coordinates in client space and the width and height of the region that needs to be painted. The problem is in Win32 API there is no obvious way to get the starting X and Y coordinates of a dirty region. When I use BeginPaint in the WM_PAINT case of the WndProc, it returns a device context with it's clipping already set so you can't paint outside the region and the rcPaint member of the PAINTSTRUCT is relative to the clipping space, meaning left and top are 0. GetClipBox also returns the same RECT starting at 0, 0.

Does anyone know how to achieve this? I'm guessing there is some way of maybe creating a Region and then intersecting with the original one to return the original one somehow? I'm really lost on how to achieve this and would appreciate any help.

1

There are 1 best solutions below

0
Alexandre Deus On

It turns out the rcPaint IS in client space. It's just that dragging the window offscreen performs a lot of full redraws of the visible client area. I made this test program to check the values:

#include <iostream>

#include <windows.h>

LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg)
    {
        case WM_PAINT:
        {
            PAINTSTRUCT ps{};
            HDC hdc = BeginPaint(hwnd, &ps);

            std::cout << "Dirty rect: Left=" << ps.rcPaint.left << ", Top=" << ps.rcPaint.top << ", Bottom=" << ps.rcPaint.bottom << ", Right=" << ps.rcPaint.right << "\n";

            EndPaint(hwnd, &ps);

            return 1;
        }
    }

    return DefWindowProcW(hwnd, msg, wparam, lparam);
}

int main(int argc, char* argv[])
{
    HINSTANCE instance = GetModuleHandleW(NULL);

    WNDCLASSW cls{};
    cls.lpfnWndProc = &wndproc;
    cls.hInstance = instance;
    cls.lpszClassName = L"ExampleClass";
    RegisterClassW(&cls);

    HWND hwnd = CreateWindowW(L"ExampleClass", L"Example Window", WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, NULL, NULL, instance, NULL);
    ShowWindow(hwnd, SW_NORMAL);

    MSG msg;
    while (GetMessageW(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return 0;
}

And this is an example of the messages I got:

Dirty rect: Left=0, Top=0, Bottom=283, Right=435
Dirty rect: Left=0, Top=0, Bottom=287, Right=440
Dirty rect: Left=0, Top=0, Bottom=290, Right=444
Dirty rect: Left=0, Top=0, Bottom=292, Right=448
Dirty rect: Left=0, Top=0, Bottom=293, Right=451
Dirty rect: Left=0, Top=0, Bottom=295, Right=453
Dirty rect: Left=0, Top=0, Bottom=296, Right=455
Dirty rect: Left=0, Top=0, Bottom=298, Right=457
Dirty rect: Left=0, Top=0, Bottom=299, Right=460
Dirty rect: Left=0, Top=0, Bottom=301, Right=462
Dirty rect: Left=0, Top=0, Bottom=303, Right=464
Dirty rect: Left=0, Top=0, Bottom=305, Right=466
Dirty rect: Left=0, Top=0, Bottom=306, Right=468
Dirty rect: Left=0, Top=0, Bottom=307, Right=470
Dirty rect: Left=0, Top=0, Bottom=308, Right=471
Dirty rect: Left=471, Top=0, Bottom=308, Right=472
Dirty rect: Left=472, Top=0, Bottom=308, Right=473
Dirty rect: Left=473, Top=0, Bottom=308, Right=474
Dirty rect: Left=0, Top=0, Bottom=309, Right=477
Dirty rect: Left=477, Top=0, Bottom=309, Right=478
Dirty rect: Left=478, Top=0, Bottom=309, Right=479
Dirty rect: Left=479, Top=0, Bottom=309, Right=480

Thank you for the help.