9ddcab14b1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.4 KiB
6.4 KiB
name, lang, domain, description, tags, uses_functions, uses_types, framework, entry_point, dir_path, repo_url, icon
| name | lang | domain | description | tags | uses_functions | uses_types | framework | entry_point | dir_path | repo_url | icon | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| altsnap_jitter_test | cpp | tools | Regression test for multi-viewport window jitter + iconified survival + Alt+RMB resize + Alt+LMB move. Six phases: p1 main-window sync, p2 AltSnap on main HWND, p3 AltSnap on secondary viewport HWND, p4 iconify+restore preserves floating panels, p5 Alt+RMB consumed by WndProc, p6 Alt+LMB consumed by WndProc. |
|
imgui | main.cpp | apps/altsnap_jitter_test |
|
altsnap_jitter_test
Headless C++ harness para validar el subclass anti-jitter del framework
(cpp/framework/app_base.cpp): movimiento/redimensionado externos sin
temblor en la ventana principal y en viewports secundarios, iconified main
no pierde paneles flotantes, Alt+RMB resize anywhere, Alt+LMB move anywhere.
Que hace
Seis fases en una sola sesion de fn::run_app:
- p1.sync (cross-platform). Warmup 8 frames, mueve la ventana principal via
glfwSetWindowPosun step por frame durante 60 frames. Muestrea pos OS (glfwGetWindowPos) vs pos ImGui (GetMainViewport()->Pos). Tolerancia 1px. Cuenta divergencias =bad_sync. - p2.altsnap (Windows). Worker thread fakea
WM_ENTERSIZEMOVE+ burst de 30SetWindowPos(SWP_ASYNCWINDOWPOS)+WM_EXITSIZEMOVEsobre el HWND principal. Asertarenders_during==0(subclass del WndProc principal y gate del main loop activos). - p3.secondary (Windows). Fuerza creacion de un viewport secundario (panel flotante,
ConfigViewportsNoAutoMerge=true), localiza su HWND enpio.Viewportsviafind_secondary_viewport_hwnd, y repite el bracket sobre el. Valida que el subclass per-frame cubre tambien el HWND secundario. - p4.minimize (Windows). State machine 4 steps con
kP4SettleFrames=20entre cada uno. CapturaIsWindow(secondary_hwnd)antes/durante/despues deglfwIconifyWindow+glfwRestoreWindow. Asserta los 3 estados vivos ANDrenders_iconified > 0(frame loop sigue activo durante iconify para que los flotantes no se pierdan). - p5.alt_rmb (Windows).
fn::internal::set_force_alt_for_test(true)+SendMessageW(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(40,40))sincrono mismo-hilo. Assertafn::internal::alt_rmb_resize_count()incrementa en 1. En test mode el handler salta elPostMessage SC_SIZEpara no atrapar al harness en modal. - p6.alt_lmb (Windows). Mismo patron para
WM_LBUTTONDOWN. Assertafn::internal::alt_lmb_move_count()incrementa en 1.
PASS = todas las fases con sus deltas positivos. SKIP en Linux para p2-p6.
Run
WSL/Linux (sanity build; p2-p6 skipped):
cd cpp && cmake -B build/linux -DFN_BUILD_TESTS=OFF
cmake --build build/linux --target altsnap_jitter_test -j4
xvfb-run -a -s "-screen 0 1280x800x24" \
env LIBGL_ALWAYS_SOFTWARE=1 GALLIUM_DRIVER=llvmpipe \
build/linux/apps/altsnap_jitter_test/altsnap_jitter_test
echo "EXIT: $?"
Windows (cross-compile + Desktop deploy + run):
source bash/functions/infra/e2e_run_cpp_windows.sh
e2e_run_cpp_windows altsnap_jitter_test
Output esperado (PASS, Windows)
[p1.sync] DONE frames=60 max_sync=0px max_clamp=0px bad_sync=0 bad_clamp=0
[p2.altsnap] DONE renders before=N during=0 after=M
[p3.secondary] DONE renders before=N during=0 after=M
[p4.minimize] DONE alive(before=1 during=1 after=1) renders_iconified=20
[p5.alt_rmb] DONE alt_resize delta=1 (after=1) sizemove_enter delta=0 (after=2)
[p6.alt_lmb] DONE alt_move delta=1 (after=1)
[altsnap_jitter] p1=PASS p2=PASS p3=PASS p4=PASS p5=PASS p6=PASS overall=PASS
En Linux/xvfb p2-p6 reportan SKIPPED. P1 puede mostrar lag pre-existente bajo xvfb por como X procesa SetWindowPos; no es un fallo del fix.
Criterio de fallo
p1_bad_sync > 0: ImGui viewport->Pos quedo fuera de sincronia con la pos OS. Roto el callback GLFW + per-frame sync.p2_renders_during > 0: la app sigue dibujando durante un bracket AltSnap en el HWND principal. Roto el subclass del WndProc principal o la gate del main loop.p3_renders_during > 0: la app sigue dibujando durante un bracket AltSnap en un HWND secundario (panel flotante). Roto el escaneo per-frame depio.Viewportsque instala el subclass en cada platform window.p4 alive(during)=0: floating panel se cierra/desaparece al minimizar el main. Regresion del fix iconified+secondary.p4 renders_iconified == 0: el iconified-gate volvio aglfwWaitEvents+continueglobal sin chequear secondaries. Floating panels se congelarian.p5 alt_resize delta == 0: Alt+RMB no se consume. Subclass no esta en el chain (ImGui_ImplGlfw_WndProccapturo nuestra WndProc como prev y no chainea bien) o flagforce_alt_for_testno se aplica.p6 alt_move delta == 0: misma raiz que p5 pero para LMB.
Donde vive el fix
cpp/framework/app_base.cpp:
- GLFW pos/size callbacks (anti-jitter capa 1).
- Per-frame viewport sync (capa 2).
unordered_map<HWND, WNDPROC> g_subclassed+ per-frameinstall_sizemove_subclass_hwndsobrepio.Viewports(capa 3, multi-HWND).- Iconified gate detecta secondary viewports y fall-through si existen.
WM_LBUTTONDOWN/WM_RBUTTONDOWNAlt-held →WM_SYSCOMMAND, SC_MOVE|HTCAPTION/SC_SIZE|dir.io.ConfigWindowsMoveFromTitleBarOnly = true(floating panels respetan header-only).fn::internal::*counters expuestos para tests headless.
cpp/framework/app_base.h:
namespace fn::internal { sizemove_enter_count(); alt_rmb_resize_count(); alt_lmb_move_count(); rbuttondown_seen_count(); set_force_alt_for_test(bool); }.
Notas
keybd_event(VK_MENU)NO es fiable para drivearGetAsyncKeyStatedesde tests headless cross-compilados — la sesion de input del proceso no esta foreground. Usaset_force_alt_for_test(true)+SendMessageWsincrono mismo-hilo. Bypassa kernel-input filter (que dropea silenciosamentePostMessage(WM_RBUTTONDOWN)sintetizado).- ImGui_ImplGlfw subclassea el HWND despues que nosotros (vendor
cpp/vendor/imgui/backends/imgui_impl_glfw.cpplinea ~820, capturabd->PrevWndProc = our_subclass). Por eso ImGui llama a nuestro WndProc viaCallWindowProc(prev_wndproc, ...)y todos los mensajes nos llegan en orden correcto. No re-subclassear (provoca recursion infinita via cycle). - Test mode (
set_force_alt_for_test(true)) hace que el WndProc cuente pero NO posteeSC_SIZE/SC_MOVE— evita quedarse atrapado en modal sizemove. La parte "entrar al modal" se valida por p2/p3 fakeandoWM_ENTERSIZEMOVEdirectamente.