mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-25 23:57:53 +03:00
Fix eterm startup directories and clarify agent runtime guidance
- Add a default working directory setting, using home when empty. - Keep command-line directory overrides local to the current launch. - Remove the legacy setting that persisted one-off launch paths. - Prefer native hidden windows for tests and benchmarks, and headless execution for ordinary applications and interactive inspector checks. - Keep the secondary dialog test hidden and assert its visibility.
This commit is contained in:
@@ -48,6 +48,16 @@ optimization, benchmarking, or validating runtime speed. Do not reuse a gmake tr
|
||||
The debug/unit-test workflow below is additional correctness validation. It does not replace the
|
||||
release Ninja build required for performance work.
|
||||
|
||||
## Benchmark Runtime
|
||||
|
||||
Run the release benchmark harness with the native runtime on a usable desktop:
|
||||
`EEPP_RUNTIME=native bin/benchmarks/eepp-benchmarks`.
|
||||
The benchmarks that create windows explicitly request `WindowStyle::Hidden`; other benchmarks
|
||||
do not create windows. They can use the native renderer without showing desktop windows or taking
|
||||
focus. Do not switch this harness to headless merely to avoid interrupting the user. Verify the
|
||||
renderer before reporting hardware rendering performance; headless and Xvfb runs can use software
|
||||
rendering and measure a different execution path.
|
||||
|
||||
## Debug and Unit-Test Builds
|
||||
|
||||
All build commands must be executed from the **root project directory**. On macOS, follow the
|
||||
@@ -117,6 +127,13 @@ Run the following command, replacing `<os_name>` with the correct environment:
|
||||
|
||||
## Running GUI Examples Under Xvfb
|
||||
|
||||
For ordinary application/example launches and UI inspector automation, try `EEPP_RUNTIME=headless`
|
||||
first to avoid desktop windows and input interference without requiring Xvfb. This preference does
|
||||
not apply to the unit-test and benchmark harnesses: their windows are already hidden, so use the
|
||||
native runtime on a usable desktop. Use the native/Xvfb paths below for examples only when the
|
||||
required check cannot run with the headless runtime. Verify the renderer before using an offscreen
|
||||
run to assess hardware rendering or performance.
|
||||
|
||||
Xvfb does not support the multisampled OpenGL contexts requested by some eepp examples. In
|
||||
particular, `src/examples/ui_html/ui_html.cpp` normally requests 4x MSAA. Launching that binary
|
||||
through `xvfb-run` or `projects/scripts/xvfb-run-eepp` can therefore fail immediately with
|
||||
|
||||
@@ -23,6 +23,24 @@ not `eTerm`. Its implementation lives under `src/modules/eterm/`.
|
||||
`eeiv` is the repository's image viewer. Its application entry point is
|
||||
`src/tools/eeiv/eeiv.cpp`.
|
||||
|
||||
## AI Agent Runtime Checks
|
||||
|
||||
AI agents should prefer `EEPP_RUNTIME=headless` when launching ordinary applications or examples
|
||||
and when automating their UI with the inspector. This avoids opening desktop windows or interrupting
|
||||
the human's keyboard input and focus. Coordinate interactive checks that require visible native
|
||||
windows with the user before driving them.
|
||||
|
||||
Unit tests and benchmarks are different: run their release binaries with the native runtime on a
|
||||
usable desktop. The unit-test build defines `EE_UNIT_TESTS`, which adds `WindowStyle::Hidden` to
|
||||
the default window style; benchmarks that create windows explicitly request `WindowStyle::Hidden`.
|
||||
These hidden windows preserve native rendering without appearing or taking desktop focus. Keep
|
||||
test and benchmark windows hidden when adding or changing cases. Do not select the headless runtime
|
||||
solely to avoid desktop interruption for these harnesses.
|
||||
|
||||
Use headless tests when no usable display is available, when requested, or when testing the headless
|
||||
runtime itself. Headless rendering can use a software renderer, so verify the renderer before
|
||||
assessing GPU behavior or performance. See `.agents/rules/unit-tests.md` for commands and fallbacks.
|
||||
|
||||
## Documentation & Code References
|
||||
|
||||
When working on this project, rely on the following resources to understand existing implementations:
|
||||
|
||||
+30
-20
@@ -8,44 +8,54 @@ The test binary manages its own current working directory, so you can execute it
|
||||
The required default workflow is:
|
||||
|
||||
1. Build the release unit-test target (use ninja build).
|
||||
2. Run `bin/unit_tests/eepp-unit_tests` directly, without Xvfb.
|
||||
3. If sandbox restrictions prevent access to the host display, retry that same direct command with
|
||||
elevated permissions.
|
||||
4. Use Xvfb only after direct execution has failed outside the sandbox because no usable graphical
|
||||
display is available. Xvfb is the last fallback, not the default headless convenience path.
|
||||
2. On a usable desktop, run `EEPP_RUNTIME=native bin/unit_tests/eepp-unit_tests` directly, without
|
||||
Xvfb. The unit-test build defines `EE_UNIT_TESTS`, making `WindowStyle::Default` include
|
||||
`WindowStyle::Hidden`; native test windows remain hidden and do not take desktop focus.
|
||||
3. If sandbox restrictions prevent access to the host display, retry the same native command with
|
||||
elevated permissions. A sandbox display failure does not establish that the host lacks a display.
|
||||
4. When no usable display is available, use `EEPP_RUNTIME=headless bin/unit_tests/eepp-unit_tests`.
|
||||
Also use it when requested or when checking the headless runtime itself.
|
||||
5. Use Xvfb only if there is no usable desktop display and the required check cannot run with the
|
||||
headless runtime. Keep the explicit runtime selection in fallback commands below.
|
||||
|
||||
Do not infer that a session is headless merely because its first sandboxed command cannot connect to
|
||||
the display. A sandbox can hide or deny access to an otherwise usable host display.
|
||||
The preference for headless application launches and interactive UI inspector checks does not
|
||||
change this harness workflow. Keep all native test windows hidden, including secondary dialog
|
||||
hosts; showing a UI widget inside a hidden host does not require showing the native window.
|
||||
|
||||
* **Use the release test binary during normal development:**
|
||||
When AddressSanitizer or other debug-only diagnostics are not required, build and run `bin/unit_tests/eepp-unit_tests`. The optimized release suite is substantially faster and is the required default for iterative testing. Use `bin/unit_tests/eepp-unit_tests-debug` only when investigating memory safety, assertions, or other behavior that specifically requires the debug configuration.
|
||||
* **Default Execution on a Graphical Linux Desktop:**
|
||||
Unit-test windows are created hidden, so run the release suite directly against the desktop:
|
||||
`bin/unit_tests/eepp-unit_tests`
|
||||
This keeps the windows invisible and unfocused while preserving hardware OpenGL acceleration.
|
||||
* **Default Execution on a Graphical Desktop:**
|
||||
`EEPP_RUNTIME=native bin/unit_tests/eepp-unit_tests`
|
||||
Hidden windows preserve native rendering without appearing or taking desktop focus.
|
||||
Confirm that the renderer log names the real GPU rather than llvmpipe when validating rendering
|
||||
behavior or performance.
|
||||
* **Filtered Tests on a Graphical Linux Desktop:**
|
||||
Use the same direct hardware-backed command for focused runs:
|
||||
`bin/unit_tests/eepp-unit_tests --filter="FontRendering.*Offset*"`
|
||||
* **Last Fallback for Headless CI and Systems Confirmed to Lack a Usable Desktop Display:**
|
||||
Keep `projects/scripts/xvfb-run-eepp` as the fallback when no desktop display is available:
|
||||
`projects/scripts/xvfb-run-eepp bin/unit_tests/eepp-unit_tests`
|
||||
* **Filtered Tests:**
|
||||
Use the same native runtime for focused runs on a usable desktop:
|
||||
`EEPP_RUNTIME=native bin/unit_tests/eepp-unit_tests --filter="FontRendering.*Offset*"`
|
||||
* **Headless Execution:**
|
||||
`EEPP_RUNTIME=headless bin/unit_tests/eepp-unit_tests`
|
||||
Use this when no usable desktop display is available, when requested, or for headless runtime
|
||||
validation. It renders offscreen without Xvfb. It can use a software renderer, so its timings
|
||||
do not necessarily represent hardware GPU performance. Add `--filter` for focused headless runs.
|
||||
* **Last Fallback When the Headless Runtime Cannot Support the Required Check:**
|
||||
Keep `projects/scripts/xvfb-run-eepp` as the fallback when no usable desktop display is available:
|
||||
`EEPP_RUNTIME=native projects/scripts/xvfb-run-eepp bin/unit_tests/eepp-unit_tests`
|
||||
The wrapper provides a race-safe isolated display at `1280x1024x24` and injects
|
||||
`ASAN_OPTIONS=detect_leaks=0`. Xvfb can use llvmpipe, so do not use wrapper timings to evaluate
|
||||
hardware-rendered performance.
|
||||
* **Wrapper Fallback:**
|
||||
If `projects/scripts/xvfb-run-eepp` itself fails before launching the test binary, report that
|
||||
failure and use:
|
||||
`xvfb-run -a -s "-screen 0 1280x1024x24" bin/unit_tests/eepp-unit_tests`
|
||||
`EEPP_RUNTIME=native xvfb-run -a -s "-screen 0 1280x1024x24" bin/unit_tests/eepp-unit_tests`
|
||||
Do not use plain `xvfb-run` as the first headless attempt.
|
||||
* **Non-window Tests:**
|
||||
Tests known not to create windows can run without selecting a video driver:
|
||||
`bin/unit_tests/eepp-unit_tests --filter="NonWindowTest.*"`
|
||||
* **Filtering Tests:**
|
||||
Use the `--filter` parameter to run specific tests (supports glob patterns).
|
||||
Keep the same harness as the full suite: direct execution on a graphical Linux desktop, or the
|
||||
wrapper in a genuinely headless environment.
|
||||
Keep the same runtime as the full suite for the current environment: native on a usable desktop,
|
||||
headless when no usable display is available, or the Xvfb fallback when headless cannot support
|
||||
the required check.
|
||||
|
||||
## Cross-Platform Compatibility (Required)
|
||||
|
||||
|
||||
@@ -779,13 +779,13 @@ UTEST( UIApplication, CreatesSecondaryWindowWithoutChangingAmbientScene ) {
|
||||
const Sizei primaryScreenSize = primaryWindow->getSizeInScreenCoordinates();
|
||||
auto* fileDialog = UIFileDialog::NewInApplicationWindow(
|
||||
app,
|
||||
WindowSettings( 640, 400, "File Dialog UI Context",
|
||||
WindowStyle::Titlebar | WindowStyle::Resize, WindowBackend::Default, 32, {},
|
||||
1, false, true ),
|
||||
WindowSettings( 640, 400, "File Dialog UI Context", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false, true ),
|
||||
UIFileDialog::DefaultFlags, "*", FileSystem::getCurrentWorkingDirectory(),
|
||||
ContextSettings( false, 0, 0, GLv_default, true, false ), true,
|
||||
UIWindow::ApplicationWindowPosition::CenteredOnPrimary );
|
||||
ASSERT_TRUE( fileDialog != nullptr );
|
||||
EXPECT_FALSE( fileDialog->getUISceneNode()->getWindow()->isVisible() );
|
||||
EXPECT_EQ( app.getWindowCount(), 3u );
|
||||
EXPECT_NE( fileDialog->getUISceneNode(), app.getUI() );
|
||||
EXPECT_NE( fileDialog->getUISceneNode(), secondaryUI );
|
||||
|
||||
@@ -22,8 +22,9 @@ void AppConfig::load() {
|
||||
terminal.shell = mIni.getValue( "terminal", "shell", terminal.shell );
|
||||
terminal.shellArguments =
|
||||
mIni.getValue( "terminal", "shell_arguments", terminal.shellArguments );
|
||||
terminal.workingDirectory =
|
||||
mIni.getValue( "terminal", "working_directory", terminal.workingDirectory );
|
||||
// The legacy working_directory key also captured one-off command-line paths.
|
||||
terminal.defaultWorkingDirectory =
|
||||
mIni.getValue( "terminal", "default_working_directory", terminal.defaultWorkingDirectory );
|
||||
terminal.executeInShell =
|
||||
mIni.getValue( "terminal", "execute_in_shell", terminal.executeInShell );
|
||||
terminal.historySize = mIni.getValueU( "terminal", "scrollback", terminal.historySize );
|
||||
@@ -99,7 +100,8 @@ bool AppConfig::savePreferences() {
|
||||
mIni.deleteValue( "window", "max_fps" );
|
||||
mIni.setValue( "terminal", "shell", terminal.shell );
|
||||
mIni.setValue( "terminal", "shell_arguments", terminal.shellArguments );
|
||||
mIni.setValue( "terminal", "working_directory", terminal.workingDirectory );
|
||||
mIni.deleteValue( "terminal", "working_directory" );
|
||||
mIni.setValue( "terminal", "default_working_directory", terminal.defaultWorkingDirectory );
|
||||
mIni.setValue( "terminal", "execute_in_shell", terminal.executeInShell );
|
||||
mIni.setValueU( "terminal", "scrollback", terminal.historySize );
|
||||
mIni.setValue( "terminal", "cursor_style",
|
||||
|
||||
@@ -25,7 +25,7 @@ enum class NewTerminalBehavior { CurrentTabBar, VerticalSplit, HorizontalSplit }
|
||||
struct TerminalConfig {
|
||||
std::string shell;
|
||||
std::string shellArguments;
|
||||
std::string workingDirectory;
|
||||
std::string defaultWorkingDirectory;
|
||||
std::string executeInShell;
|
||||
size_t historySize{ 10000 };
|
||||
size_t initialTabs{ 1 };
|
||||
|
||||
@@ -701,7 +701,8 @@ int App::run( int argc, char* argv[] ) {
|
||||
parser, "prefers-color-scheme",
|
||||
"Set the preferred color scheme (\"light\", \"dark\" or \"system\")",
|
||||
{ 'c', "prefers-color-scheme" } );
|
||||
args::Positional<std::string> wd( parser, "wording-dir", "Working Directory / executable" );
|
||||
args::Positional<std::string> wd( parser, "working-dir",
|
||||
"Working directory / executable for this launch only" );
|
||||
args::Flag closeOnExit( parser, "close-on-exit",
|
||||
"close the application when the executable exits",
|
||||
{ "close", "close-on-exit" } );
|
||||
@@ -770,8 +771,6 @@ int App::run( int argc, char* argv[] ) {
|
||||
}
|
||||
config->theme.uiColorScheme = ColorSchemePreferences::fromStringExt( scheme );
|
||||
}
|
||||
if ( wd )
|
||||
config->terminal.workingDirectory = wd.Get();
|
||||
config->terminal.executeInShell = executeInShell.Get();
|
||||
config->theme.colorScheme = colorScheme.Get();
|
||||
config->window.maxFPS = maxFPS.Get();
|
||||
@@ -938,9 +937,14 @@ int App::run( int argc, char* argv[] ) {
|
||||
resourceScope.getFontService().addFallbackFont( std::move( fallback ) );
|
||||
}
|
||||
|
||||
const std::string launchPath = config->terminal.workingDirectory.empty()
|
||||
? initialWorkingDirectory
|
||||
: config->terminal.workingDirectory;
|
||||
std::string launchPath = FileSystem::expandTilde( config->terminal.defaultWorkingDirectory );
|
||||
if ( wd ) {
|
||||
launchPath = wd.Get();
|
||||
} else if ( launchPath.empty() || !FileSystem::isDirectory( launchPath ) ) {
|
||||
if ( !launchPath.empty() )
|
||||
Log::warning( "Default working directory does not exist: %s", launchPath );
|
||||
launchPath = Sys::getUserDirectory();
|
||||
}
|
||||
FileInfo launchFile( launchPath );
|
||||
const bool launchExecutable = launchFile.isRegularFile() && launchFile.isExecutable();
|
||||
terminalConfig.program = launchExecutable ? launchFile.getFilepath() : config->terminal.shell;
|
||||
|
||||
@@ -307,6 +307,27 @@ UIWindow* SettingsPanel::create( App& app ) {
|
||||
return true;
|
||||
},
|
||||
true );
|
||||
panel->addText(
|
||||
{ "terminalDefaultWorkingDirectory", "terminal.behavior",
|
||||
app.i18n( "default_working_directory", "Default Working Directory" ),
|
||||
app.i18n( "default_working_directory_desc",
|
||||
"Set the starting directory for new terminals. Leave empty to use your home "
|
||||
"directory. A command-line directory overrides it for that launch." ) },
|
||||
[&app] { return app.config->terminal.defaultWorkingDirectory; },
|
||||
[&app]( const std::string& value ) {
|
||||
auto directory = FileSystem::expandTilde( value );
|
||||
if ( !directory.empty() ) {
|
||||
if ( !FileSystem::isDirectory( directory ) )
|
||||
return false;
|
||||
directory = FileSystem::getRealPath( directory );
|
||||
}
|
||||
app.config->terminal.defaultWorkingDirectory = directory;
|
||||
app.terminalConfig.workingDirectory =
|
||||
directory.empty() ? Sys::getUserDirectory() : std::move( directory );
|
||||
app.savePreferences();
|
||||
return true;
|
||||
},
|
||||
true );
|
||||
panel->addInteger(
|
||||
{ "terminalScrollback", "terminal.behavior",
|
||||
app.i18n( "terminal_scrollback", "Terminal Scrollback" ),
|
||||
|
||||
Reference in New Issue
Block a user