Files
raven/testdata/native_loader/frame_hover_client.c
T
Raymond Bennett e1fef47bd6 fix: redraw only the frame when the pointer crosses the caption
Every pointer move over a caption or border recalculated the client
area and erased and repainted the window and all its controls, so a
dialog flickered while the pointer moved over its title. Only a caption
button changes there, and only the frame is drawn again for it.

Fixes #123

Assisted-by: Claude Code:claude-opus-5-5
AI-Scope: reproduction under Xvfb, the fix to hover_frame, the native_frame_hover test and fixture
2026-11-02 11:25:54 -07:00

72 lines
2.6 KiB
C

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// A window with a caption and a close button over one control, as a dialog without WS_CLIPCHILDREN is. Once both have painted, the
// pointer crossing the caption and lighting the close button changes only the frame: neither window hears WM_NCCALCSIZE, WM_ERASEBKGND
// or WM_PAINT again. The host moves the pointer, then posts WM_APP, and the counts come back as the exit code.
static unsigned frames,erases,paints,child_paints;
static LRESULT CALLBACK child_procedure(HWND window,UINT message,WPARAM wparam,LPARAM lparam)
{
if (message==WM_PAINT) {
PAINTSTRUCT paint;
HDC dc=BeginPaint(window,&paint);
FillRect(dc,&paint.rcPaint,(HBRUSH)GetStockObject(BLACK_BRUSH));
EndPaint(window,&paint);
++child_paints;
return 0;
}
return DefWindowProcW(window,message,wparam,lparam);
}
static LRESULT CALLBACK procedure(HWND window,UINT message,WPARAM wparam,LPARAM lparam)
{
if (message==WM_NCCALCSIZE) ++frames;
if (message==WM_ERASEBKGND) ++erases;
if (message==WM_PAINT) {
PAINTSTRUCT paint;
HDC dc=BeginPaint(window,&paint);
FillRect(dc,&paint.rcPaint,(HBRUSH)GetStockObject(WHITE_BRUSH));
EndPaint(window,&paint);
++paints;
return 0;
}
if (message==WM_APP) {
PostQuitMessage(frames ? 10 : erases ? 11 : paints ? 12 : child_paints ? 13 : 0);
return 0;
}
return DefWindowProcW(window,message,wparam,lparam);
}
int raven_entry(void)
{
WNDCLASSW definition={0};
definition.lpfnWndProc=procedure;
definition.hInstance=GetModuleHandleW(NULL);
definition.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
definition.lpszClassName=L"raven.frame.hover";
if (!RegisterClassW(&definition)) return 1;
definition.lpfnWndProc=child_procedure;
definition.hbrBackground=NULL;
definition.lpszClassName=L"raven.frame.hover.child";
if (!RegisterClassW(&definition)) return 2;
HWND window=CreateWindowExW(0,L"raven.frame.hover",L"frame hover",WS_POPUP | WS_CAPTION | WS_SYSMENU,40,50,300,200,NULL,NULL,
definition.hInstance,NULL);
if (!window) return 3;
HWND child=CreateWindowExW(0,L"raven.frame.hover.child",NULL,WS_CHILD | WS_VISIBLE,20,20,100,40,window,NULL,definition.hInstance,NULL);
if (!child) return 4;
ShowWindow(window,SW_SHOW);
UpdateWindow(window);
UpdateWindow(child);
RECT pending;
if (GetUpdateRect(window,&pending,FALSE) || GetUpdateRect(child,&pending,FALSE) || !paints || !child_paints) return 5;
frames=erases=paints=child_paints=0;
MSG message;
while (GetMessageW(&message,NULL,0,0)>0) {
TranslateMessage(&message);
DispatchMessageW(&message);
}
DestroyWindow(window);
return (int)message.wParam;
}