feat(infra): auto-commit con 10 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 16:56:53 +02:00
parent fa09ff9866
commit 516db8efc0
10 changed files with 138 additions and 12 deletions
+32
View File
@@ -23,6 +23,7 @@
#include <atomic>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <string>
@@ -647,6 +648,25 @@ static void draw_header_badge_on_floating_panels(const AppConfig& cfg) {
}
}
// Resuelve si la ventana GLFW debe crearse oculta (GLFW_VISIBLE=FALSE).
// default_hidden : politica base del path de entrada (apps reales = false,
// tests de UI = true).
// config_headless: AppConfig.headless explicito de la app.
// El entorno FN_HEADLESS gana sobre ambos: "0"/"false" fuerza visible,
// cualquier otro valor no vacio fuerza oculta. Sin la variable, se respeta
// default_hidden || config_headless.
static bool resolve_headless(bool default_hidden, bool config_headless) {
bool hidden = default_hidden || config_headless;
if (const char* e = std::getenv("FN_HEADLESS")) {
if (std::strcmp(e, "0") == 0 || std::strcmp(e, "false") == 0) {
hidden = false;
} else if (e[0] != '\0') {
hidden = true;
}
}
return hidden;
}
int run_app(AppConfig config, std::function<void()> render_fn) {
// Logger primero para capturar fallos del propio init (GLFW, ventana, GL).
if (config.log.file_path != nullptr) {
@@ -672,6 +692,11 @@ int run_app(AppConfig config, std::function<void()> render_fn) {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Apps reales: ventana visible por defecto. Solo se oculta si la app pide
// headless o el entorno FN_HEADLESS lo fuerza (smoke/capture sin parpadeo).
const bool hidden = resolve_headless(/*default_hidden=*/false, config.headless);
glfwWindowHint(GLFW_VISIBLE, hidden ? GLFW_FALSE : GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(config.width, config.height, config.title, nullptr, nullptr);
if (!window) {
fprintf(stderr, "Failed to create GLFW window\n");
@@ -1178,6 +1203,13 @@ int run_app_test(AppConfig config,
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Tests de frontend: ventana OCULTA por defecto (headless) para no parpadear
// en la pantalla del desarrollador ni robar foco mientras el Test Engine
// ejercita la UI. El contexto GL real se crea igual, asi que el render sigue
// siendo fiel. Opt-out para depurar visualmente: FN_HEADLESS=0.
const bool hidden = resolve_headless(/*default_hidden=*/true, config.headless);
glfwWindowHint(GLFW_VISIBLE, hidden ? GLFW_FALSE : GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(
config.width, config.height,
config.title ? config.title : "fn_test", nullptr, nullptr);
+15
View File
@@ -101,6 +101,21 @@ struct AppConfig {
int height = 720;
bool vsync = true;
bool viewports = true; // Multi-viewport ON por defecto: ventanas ImGui arrastrables fuera del main window
// Headless: si true, la ventana GLFW se crea oculta (GLFW_VISIBLE=FALSE).
// El contexto OpenGL real se sigue creando y el render ocurre offscreen,
// por lo que las pruebas visuales y de UI siguen siendo fieles, pero la
// ventana nunca se mapea en pantalla (cero parpadeo, no roba foco).
//
// Politica por path:
// - run_app (apps reales): default visible (headless = false).
// - run_app_test (Dear ImGui Test Engine): default OCULTA. Los tests de
// frontend corren headless salvo opt-out explicito para debug visual.
//
// Override por entorno (gana sobre el default del path y sobre este flag):
// FN_HEADLESS=1 / true -> fuerza ventana oculta.
// FN_HEADLESS=0 / false -> fuerza ventana visible (ej. ver un test).
bool headless = false;
ThemeMode theme = ThemeMode::FnDark; // Identidad visual unificada por defecto
float bg_r = 0.102f; // fn_tokens::colors::bg (dark.7 #1A1B1E)
float bg_g = 0.106f;