Commit Graph
4974 Commits
Author SHA1 Message Date
Martín Lucas Golini 9759d2e997 Fix VFS transfer identity checks and eefm archive actions
- Compare connected SSH peers and host keys before treating namespaces
    as disjoint; reject ambiguous sessions before modifying destinations
  - Reject overwrite renames between local hardlinks using native file
    identity on POSIX and Windows
  - Add regressions for hostname aliases, independent SSH servers and
    hardlink moves, and document remote identity limitations
  - Separate external archive opening from browsing inside eefm
  - Cache the eefm icon for the Open in eefm action
  - Resolve shortcut labels throughout eefm from registered keybindings
2026-10-17 21:51:15 -03:00
Martín Lucas Golini 4e45909f8c fix(vfs): guard aliased transfers, invalidate early watch events and bound reads
- Resolve equivalent local and SSH authorities before modifying transfer destinations.
- Reject uncertain cross-authority identity before copying or removing files.
- Emit RescanRequired for early native watch events instead of replaying stale payloads.
- Cap readAll requests at 256 KiB independently of reserved capacity.
- Handle UINT64_MAX read limits without overflow.
- Add regressions for aliases, watch ordering, bounded reads and throttled SFTP transfers.
2026-10-17 21:07:03 -03:00
Martín Lucas Golini cb2b0ec159 Merge branch 'develop' into feature/vfs 2026-10-17 17:17:07 -03:00
Martín Lucas Golini 70daa2141d fix(vfs): harden paths, move safety and watch lifetimes
- Reject embedded NULs and untrusted directory entry names
- Share destination-aware basename validation with eefm
- Preserve changed sources during copy-and-remove moves
- Resolve directory aliases before checking self-copy containment
- Propagate target identity lookup errors
- Report early watch overflow and oversized polling snapshots
- Free stopped watcher channels without closing healthy SFTP sessions
- Add regression tests, including 200 watcher restarts on one SSH connection
2026-10-17 17:16:34 -03:00
Martín Lucas Golini 6bb957f2ca feat(vfs): add runtime libarchive support and eefm extraction
- Add a read-only ArchiveProvider with optional runtime-loaded libarchive 3.x
- Stream archive entries with bounded indexes and backing-file revision checks
- Expose available formats and filters without a build-time dependency
- Extend eefm archive browsing and add extraction context-menu actions
- Merge extraction directories while requiring confirmation before overwriting files
- Add archive, extraction, naming and transfer-conflict regression tests
2026-10-17 16:51:30 -03:00
Martín Lucas Golini 5e633aa44f feat(eefm): browse JAR, APK and EPUB files as ZIP archives
Recognize local .jar, .apk and .epub files alongside .zip using
case-insensitive extensions and the existing ZipProvider.

Centralize archive-location selection, add regression coverage,
and document the supported formats.

Validated: 1935 Linux tests, Windows and Emscripten builds,
and Wine ZIP-location tests.
2026-10-17 15:18:35 -03:00
Martín Lucas Golini 931de3ede9 fix(vfs): reject moves from sources without removal support
Check the source provider's Remove capability before the copy-and-remove
fallback, after attempting a native rename. Moves from zip:// and res://
now return Unsupported without creating or overwriting destinations.

Add regression tests for files, directories, destination preservation,
and native renames without removal support. Document the requirement.
2026-10-17 15:00:44 -03:00
Martín Lucas Golini 37f3137940 Fix emscripten build. 2026-10-17 14:43:26 -03:00
Martín Lucas Golini 3ca7ae7c7e 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.
2026-10-17 14:32:02 -03:00
Martín Lucas Golini cfd39257a0 fix(vfs): preserve data and bound asynchronous operations
- Refuse unsafe SFTP overwrite and POSIX no-replace rename fallbacks.
- Add configurable SFTP operation deadlines and reconnect after timeout.
- Wake all Task waiters and support reentrant directory model dispatch.
- Ignore stale watch results and coalesce large directory listing batches.
- Report partial transfers and preserve skipped symlinks during moves.
- Open remote files as explicit local copies without overwriting prior edits.
- Prevent Xvfb reset crashes and retain server diagnostics.
- Add regression coverage and document the updated behavior.
2026-10-17 02:33:07 -03:00
Martín Lucas Golini 64c75f101c Fix flaky test.
The test assumed one worker guaranteed one connection, but queued requests can reserve additional sockets.

Fixed the test (src/tests/unit_tests/uiwebview_tests.cpp:3845) by explicitly limiting its pool to one connection. The strict reuse assertions remain unchanged.
2026-10-17 02:30:11 -03:00
Martín Lucas Golini 8afc62557f Fix headless GL context lifecycle in SDL2 and SDL3
- Give offscreen worker contexts a separate EGL surface.
- Reset and configure GL attributes before creating windows.
- Retain EGL for process lifetime to prevent reload crashes on Linux.
- Keep the initializing window current during framebuffer creation.
- Avoid recreating the batch renderer during framebuffer teardown.
- Test shared texture uploads and worker exit after Engine shutdown.
2026-10-17 02:20:25 -03:00
Martín Lucas Golini 5f2c9677d6 feat(vfs): add ZIP browsing and optional shared module builds
- Add a read-only ZipProvider with streaming reads, cached metadata,
  change notifications, and zip:///archive.zip!/member URIs.
- Support ZIP navigation and copying files out of archives in eefm.
- Extend Zip with explicit read-only access, optional resource
  registration, and improved stream, CRC, and error handling.
- Add EE_VFS_API exports and --with-shared-vfs support; reject
  combining shared VFS with static eepp.
- Fix polling watcher teardown from its own thread.
- Add regression tests and document ZIP and shared module behavior.
2026-10-17 01:50:55 -03:00
Martín Lucas Golini c1b609ed42 Add eeiv settings and fix font preferences across applications
- Add eeiv's searchable settings panel, welcome-screen button, and Ctrl/Cmd+, shortcut.
- Persist image filtering and info visibility in state.cfg.
- Backport eterm's font fixes and add matching font controls to eproc.
- Apply font changes to existing widgets and handle UI density correctly.
- Fix rejected-font cleanup to prevent font-picker crashes.
2026-10-17 01:42:18 -03:00
Martín Lucas Golini aeca4cd4ce feat(vfs): keep unresponsive network mounts from blocking the I/O pool + refactor: rename VFS::FileInfo to VFSFileInfo
When its server stops answering, a hard NFS mount (or SMB, SSHFS...) blocks every call on it, and
the blocked thread can't be interrupted. One dead mount used to take over the I/O pool, and
with it every local folder and the eefm UI waiting on them.

LocalIOScheduler (VirtualFileSystem::localIO()):
- Calls on local disks run on the I/O pool. Calls under a network mount run on that mount's own
  lane of two threads. Mounts come from the mount table (/proc/self/mountinfo, getfsstat,
  getvfsstat, UNC and mapped drives on Windows), which never blocks.
- A call that takes longer than Config::networkMountTimeout (15 s by default) fails with
  TimedOut ("server:/export is not responding"), and so does every call queued behind it. Until
  the stuck call returns, further calls on that mount fail at once; when it returns, its result
  is discarded and the mount works again. Timeouts are delivered on their own thread, so they
  never wait for a free pool worker.
- A path through a symbolic link into a mount runs on that mount's lane. While any network
  mount is mounted, the links are read on the I/O pool, stopping where the path enters a mount.
  Renames, opens and watches route the same way. On Windows, links are not followed yet.
- A timed-out read never writes into the caller's buffer afterwards: it reads into its own
  buffer, which is copied only while the caller still waits. A network write works from a copy.
  Closing a directory whose read is stuck doesn't wait; the read closes it when it ends.
- The scheduler holds the pool weakly. Once the pool is released, every call, network ones
  included, fails with Cancelled. Destroying the scheduler, a lane or the watchdog on one of
  their own threads detaches that thread instead of joining it.
- submit(), submitResolved( path, followLast ), submitOnSameRoute() and submitCommitted()
  let applications run their own blocking work on a path with the same protection.

LocalProvider:
- Runs its calls through the scheduler. Listing a local folder never asks a mount's server: a
  network mount inside it is listed as a folder without metadata, and a link into a mount
  without its target's type. A rename across mounts fails with Unsupported, so a move copies
  and removes instead. localpath.hpp is replaced by FileSystem helpers.
- LocalWatchBackend watches directories on network mounts by polling through the VFS
  (PollingWatchBackend), whose calls time out, instead of with efsw.

eefm:
- Header checks when opening files, trash operations and the trash's .trashinfo cleanup run
  through localIO(). Each opened file is routed by its own path.
- A timed-out or lost location shows "(F5 to retry)".

Rename: VFS::FileInfo is now VFSFileInfo, as with VFSTask and VFSError. It no longer clashes
with System::FileInfo, so sources can use `using namespace EE::System;`.

Fix: DataDrop is EE_API. eefm's arkdrop.cpp failed to link DataDrop::find() on MSVC.

Docs: vfs.md documents network mounts and localIO().
Tests: LocalIOScheduler unit tests cover routing, timeouts, fail-fast, links into a mount,
caller memory, teardown from lane threads and a released pool.
2026-10-17 00:37:14 -03:00
Martín Lucas Golini f0ba17818a Merge branch 'develop' into feature/vfs 2026-10-16 13:36:52 -03:00
Martín Lucas Golini 74dc6e9fdd feat(window): receive X11 drags without files + feat(eefm): drops from Ark and XDS, run programs
Some applications drag things that only become files when they are dropped: an archive manager
drags entries it has not extracted, a browser an image it has not saved. These drags carry no file
list, so SDL's XDND support refuses them.

eepp (X11 with SDL3, getCapabilities().dataTarget):
- DragAndDrop::setFileSaveDropHandler(): drags using the XDS direct save protocol
  (XdndDirectSave0), such as Engrampa and Xarchiver. The callback picks a local folder for the
  drop position; the source then saves into it. XDS takes priority over a file list offered with it,
  which such sources only fill with temporary copies.
- DragAndDrop::setDataDropHandler(): drags offering application-defined MIME types and no file
  list. The callback receives each registered type's contents and the drop position.
- X11DropTarget takes over only the drags it accepts through the existing SDL3 X11 event hook,
  which stays installed while a window has a handler. Callbacks run from DragManager::poll(),
  outside native hooks, and may replace or remove handlers.
- Each drop receives its data in its own property, and replies must match its timestamp: a late
  reply to an abandoned drop never completes a newer one. Queued drops belong to their data
  handler registration (a never-reused generation), so a removed or replaced handler never
  receives them. INCR, oversized or unreadable replies fail the drop instead of delivering empty
  data.
- XErrorScope moves to x11errorscope.hpp, shared by the X11 drag source and drop target.
- Fix a use-after-free in the X11 drag source: destroying the drag preview pumps X events, which
  could re-enter the source and destroy the same preview window again (the intermittent
  "free(): invalid pointer" of eepp-native-dnd-tests). The preview is detached before it is reset,
  in the X11 source and in both SDL preview backends.
- Wayland is unchanged: SDL owns its data device and refuses these offers.

eefm:
- Entries dragged out of Ark are extracted where they are dropped. Ark's drag only names a D-Bus
  object; ArkDrop asks it to extract into the folder (org.kde.ark.DndExtract, as Dolphin does).
  libdbus is loaded at runtime, and the drag's name, path and the destination are validated before
  the call, since libdbus aborts on invalid ones.
- XDS drops save into the pane, or the folder row, under the pointer. Both kinds of drop refuse
  remote folders, which the source cannot write to.
- Opening a local executable runs it in its folder: native programs (ELF / Mach-O) directly,
  scripts ("#!") after a confirmation. The execute permission alone is not enough (FAT and NTFS
  mounts set it on every file), and remote files are only opened.

Tests: eepp-native-dnd-tests --automated adds the drop target checks on X11 (data drop, INCR
reply, late reply, XDS save and refusal, removed and replaced handlers) from a scripted source.
The "skipped" exit code 77 is now named TestSkipped.

Docs: native_drag_and_drop.md describes receiving drags without files.
2026-10-16 13:36:22 -03:00
Martín Lucas Golini 726aeaa254 Ups. 2026-10-16 12:57:56 -03:00
Martín Lucas Golini 6639101262 eproc: stabilize the first frame and speed up startup collection
- Restore saved columns and sorting before publishing process data.
- Apply final cell styles before their first paint, avoiding redundant reloads.
- Publish ready startup snapshots on the next UI update.
- Overlap initial Linux process and socket-ownership scans.
- Skip DRM descriptor scans on NVIDIA-only systems, preserving mixed-GPU
  and unknown-driver handling.
2026-10-16 12:57:41 -03:00
Martín Lucas Golini 259b7bf32e refactor(vfs, eefm, ui): organize the pre-merge review's architecture, DRY and API items
Architecture and file organization:
- VFS: TransferEngine moves to transferengine.hpp/.cpp; the blocking write steps shared by
  writeAll() and transfers become detail::FileWriter (writeFully, makeDirs, resolveTarget,
  replace). FileInfo code moves from error.cpp to fileinfo.cpp; InlineExecutor to
  core/executor.cpp.
- SFTP: sshsession.hpp/.cpp is split into one file per class (SSHOperation, SSHChannelPump,
  SSHIOContext, SSHConnection, SSHTransport and SSHSocketTransport / SSHChannelTransport /
  SSHProcessTransport); the socket free functions become SSHSocket statics and WakeSignal is
  SSHWakeSignal. SFTPProviderImpl is implemented in sftpproviderimpl.cpp. Watch backend headers
  and SFTPProvider::impl() are no longer public.
- LocalProvider: the POSIX and Win32 implementations live in localproviderposix.cpp and
  localproviderwin.cpp.
- UISystemIconTheme: the #if-switched backend becomes SystemIconBackend with
  FreedesktopIconBackend, WindowsIconBackend and MacOSIconBackend; systemicons.hpp is gone.
- UIAbstractTableView owns focus-on-selection (backed by TableFlagFocusOnSelection), shared by
  UITableView and UITreeView; UITableView's rubber band state reads its table flag.
- New UISceneNode::applyDefaultFont() / setFontRendering() and FontTrueType::filePathOf()
  replace the copies in eefm, eterm and ecode.
- eefm: App is the shared context (as in ecode) owning PaneManager, FileOperations,
  PlacesController, TerminalPanel and SettingsActions; Pane/FileTab live in pane.hpp, location
  text helpers in Location. trash/dialogs/icons free functions become the Trash, Dialogs and
  Icons classes; SSHPrompts has its own file; currentFileDrag() is FileTableView::currentDrag().
  Deleting from the trash drops its .trashinfo through Trash::forget() on the pool.

Duplicates:
- URI: defaulted copy operations, shared authority copy, new hasSameAuthority().
- Sys::getDataPath() / getDataSearchPaths() replace six XDG_DATA_HOME/XDG_DATA_DIRS lookups;
  FileSystem::fileNameSplitExtension() replaces two base/extension splits; lowerExtension and
  toWide use FileSystem::fileExtension and String::toWideString; SSH authentication prompts
  share requestExternal() bookkeeping.

Removed unused API: FileCursor, VFSProvider::nativeCopy and VFSCapability::NativeCopy,
Transfer::progress(), Task::onCompleteOn(), SmallUniqueFunction::fitsInline(), the Result
combinators, CancellationToken::canBeCancelled(), IOStreamVFS, VFS::instance() and the
deprecated System::VirtualFileSystem / System::VFS.

Mechanical: braces on multi-line control bodies added by the branch, struct field order without
interior padding, the debug.hpp include in task.hpp, doc comment fixes. Sources wrapped entirely
in a platform guard include only eepp/config.hpp before it, and their headers inside it.

Task API, for readability: Task<T>::create( resolve ) returns a pending task and fills a
copyable TaskResolver<T>, called as resolve( value ), which replaces the move-only TaskSource and
its task()-once rule (the last copy destroyed unresolved still abandons the task).
thenOn( executor, fn ) is now then( executor, fn ); then( fn ) keeps running on the resolving
thread.
onComplete( fn ) passes std::optional<T> (nullopt when abandoned) instead of the task.
TaskDiagnostic::TaskRetrievedTwice is gone.
SSHTaskOperation receives its resolver in its constructor instead of exposing task(), and the
polling watch backend no longer creates a task it immediately abandons while stopping.
2026-10-16 11:30:43 -03:00
Martín Lucas Golini 379dbd26ba Fix macOS build. 2026-10-16 10:42:54 -03:00
Martín Lucas Golini 0e7e12ba76 fix(vfs): data safety, SSH policy and liveness fixes from the pre-merge review
Data safety (VFS):
- Copies write a temporary sibling and replace the destination only
  once it is complete (as writeAll() already did): a failed overwrite
  kept nothing of the old destination, and copying onto a hard link to
  the source truncated the source itself. A destination symlink is
  written through, and one that resolves to the source fails as the
  same file.
- Moving a symlink to another file system is refused: the fallback copy
  followed it and then removed the copied entries through the link,
  emptying its target.
- Saves keep the exact mode of the file they replace: the temporary was
  created with it, but filtered through the umask.

Deadlocks and blocking:
- writeAll( createParents ) waited on makeDirs() queued on its own
  orchestration pool: one thread deadlocked at once, two with two
  concurrent saves. Orchestration jobs now create parents directly.
- Copies and moves run on their own pool (Config::transferThreads), so
  long transfers no longer delay saves, reads and recursive removals.
- Local watches are registered and removed on the I/O pool: efsw and the
  directory checks touch the filesystem, which blocked the UI thread on
  slow mounts.

SSH security:
- "@revoked" known_hosts keys are rejected; they were skipped as
  unknown, so StrictHostKeyChecking accept-new trusted them.
- Sessions are shared only between configurations with the same
  security policy (known hosts, host key checking, algorithms,
  authentication settings), not just the same destination: a strict
  alias reused a session a permissive one had accepted.
- A configured algorithm restriction that permits nothing this libssh2
  supports fails the connection instead of using libssh2's defaults.

SSH liveness:
- Operations submitted to a failed or closed connection fail with
  ConnectionLost instead of staying pending forever.
- ssh-agent requests run on a worker thread (SSHAgent, Unix-domain
  sockets), with libssh2_userauth_publickey() and a sign callback that
  waits without blocking: an agent waiting for a hardware key touch no
  longer stalls every other session. Windows keeps libssh2's agent.
- Connecting no longer holds a helper thread while the user answers a
  host key or password prompt: the setup continues from the session's
  ready task, one ProxyJump hop at a time. Jump hosts only need to
  authenticate, not to offer SFTP.
- Idle connections close after SFTPProviderConfig::idleTimeout. The old
  check compared use_count() with 1 and never passed: connections now
  track their users (open handles, pumps, jump children).
- A remote watch agent that never answers falls back to polling after
  5 seconds; the directory listing waited for it indefinitely.

Core:
- CancellationSource::cancel() keeps the shared state alive while its
  callbacks run: a callback destroying the source freed it mid-cancel
  (heap use after free under AddressSanitizer).
- MainThreadExecutor::shutdown() detaches the executor from its
  dispatcher node and drops queued and later functions.
- String::icompare(): case-insensitive comparison without allocations.

VFSDirectoryModel (UI thread):
- Names compare with String::icompare() instead of lowercased copies,
  which made every sort, merge and insertion allocate (about 2x slower
  when sorting).
- Sorting by type asks the type provider once per entry instead of
  twice per comparison.
- The case-insensitive plain text filter keeps a search table instead
  of lowercasing every name on each row rebuild.
- Watch events update the visible rows in place instead of rebuilding
  them from every entry per event.

Drag and drop:
- The X11 drag source showed the pending badge over the source window
  for every application, which broke the X11 drag and drop integration
  tests in CI. DragOffer::sourceHandlesDrops now asks for it; eefm sets
  it, since it completes those drops as its own drag.

eefm:
- Shutdown destroyed the main thread executor before the VFS and the
  thread pool while continuations still held it: closing during a
  transfer could dispatch through freed memory. Transfers are cancelled,
  the VFS is destroyed, the executor is detached, and only then are the
  scene, its pool and the executor destroyed.
- Remote files opened locally were downloaded to
  /tmp/eefm/<scheme>/<host>/<name>: files with the same name from other
  folders, users or ports overwrote each other, in a directory shared by
  every user. They now go to a per-file folder (a hash of the complete
  URI) in the user's cache.

Every fix comes with a regression test.
2026-10-15 20:33:13 -03:00
Martín Lucas Golini 8827f8de86 feat(window): report X11 drags released over their source window +
feat(eefm): drag files to other applications

X11 never offers a native drag to its source window, so a release over
it ended as a plain cancellation. DragResult::releasedOverSource now
tells the application, which can complete it as its own internal drop.
That lets applications start the native drag as soon as their own drag
begins (as file managers do: the files can then go to any window, even
one switched to with Alt+Tab mid-drag) and still handle drops on
themselves. The preview shows the pending badge over the source window
instead of the rejected one.

A drag of local files starts the system drag at once, along with eefm's
own, so the files can be dropped on any window, also after switching to
it with Alt+Tab mid-drag (starting it only once the window had lost
focus was refused on X11). eefm's drag keeps highlighting targets while
it sees the pointer, and waits for the system drag to end instead of
dropping on release:

- Released over eefm on X11 (releasedOverSource), it drops as eefm's
  drag: panes, folders, tabs and places, with the Move/Copy menu.
- On Wayland, macOS and Windows that drop arrives as a file drop; being
  eefm's own drag, it is resolved the same way (Move/Copy menu).
- Escape cancels both. Remote files keep the internal drag only.

The system drag shows eefm's drag label, which now has an icon (folders
tinted as in the rows) and the name or the item count. For several items
the icon is that of their most common type, the pressed row's on a tie. It
is rendered alone into the back buffer once, read back and handed to the
system as the preview image. It is cleared with the theme's background,
so the label's rounded corners match it where the preview is opaque
(X11).

Drops from other applications are still copied, now skipping files
already in the destination folder instead of duplicating them as
"(copy)".
2026-10-15 16:17:40 -03:00
Martín Lucas Golini a52eaa3926 Merge branch 'develop' into feature/vfs 2026-10-15 16:16:42 -03:00
Martín Lucas Golini bec24db054 Fix flaky HTTP socket-budget wakeup regression test
Replace the 50 ms sleep and 200 ms deadline with a synchronized
condition-wait handshake and a generous transfer deadline.

Add a scoped budget-wait hook to keep fallback polling beyond the test
deadline. Use the budget change counter as the wait predicate so spurious
wakeups cannot hide a missing notification.

Confirmed the test fails when the idle-socket notification is removed.
2026-10-15 16:00:08 -03:00
Martín Lucas Golini 5268a83e07 Merge branch 'develop' into feature/vfs 2026-10-15 14:10:04 -03:00
Martín Lucas Golini f0065b65ea Merge branch 'develop' of github.com:SpartanJ/eepp into develop 2026-10-15 13:51:36 -03:00
Martín Lucas Golini f80b44a778 Merge branch 'feature/dragndrop' into develop 2026-10-15 13:48:05 -03:00
Martín Lucas Golini b33c0ec7f9 Run native drag-and-drop integration tests in Linux CI
- Run X11 and Weston tests at 1x and 2x scale.
- Accept both libwayland object ID log formats.
- Preserve test failures through logging pipelines.
- Add shell32 to Windows dependencies in both Premake scripts.
- Update SDK platform support and linking documentation.
2026-10-15 12:54:27 -03:00
Martín Lucas Golini 7f9c6d2153 New eefm icon. Improvements in nanosvg to read correctly colors when in stylesheet. 2026-10-15 11:03:49 -03:00
Martín Lucas Golini ee8f560bde Add native Wayland file dragging for SDL2 and SDL3
- Load Wayland APIs dynamically and track genuine pointer press serials.
- Serve file URI lists on a dedicated queue and transfer thread.
- Render native drag icons with Copy, rejected and pending feedback.
- Use memfd_create on Linux with a portable temporary-file fallback.
- Suppress synthetic gesture releases and clean up on cancellation,
  window destruction and process exit.
- Add isolated Weston integration tests and document API requirements.
2026-10-15 10:58:58 -03:00
Martín Lucas Golini 88e816f4d9 feat(eefm): tab moves, middle click tabs, visual polish and fixes
eefm:
- Tabs can be dragged between the panes. When a pane's last tab moves
  out, the pane gets a new tab on the same folder, so the split view
  stays.
- A middle click on a folder opens it in a new background tab; with
  Ctrl (Cmd on macOS) the new tab is selected and focused.
- Item context menus list Create New after the open actions.
- Open Terminal Here prefers eterm (in PATH or next to eefm), else the
  default terminal: $TERMINAL, xdg-terminal-exec, the desktop's own
  (KDE's setting, GNOME, Xfce, MATE, LXQt), x-terminal-emulator, then
  the common ones. On Windows it opens PowerShell (else cmd.exe) in a
  new console, so it shows in the default terminal; it used to start
  as a detached process with no console.
- Tab close buttons work: the focus handoff to the files took the
  focus from them, and the click goes to the focused node. Their hover
  color shows again.
- Visual polish: long cell text ends in an ellipsis, dates are shorter,
  and the name gets more room. Hover and selection are soft accent
  tints with an outline; the inactive pane's view is a little dimmer,
  with a grey selection. The location bar highlights on hover. The
  filter bar is one framed field and starts hidden (Ctrl+I). Places
  share the row tints, usage bars are softer, scrollbars are grey until
  used, unselected tabs dim their close button, and folders are tinted
  when eefm's own icons are used.
- Crashes print a stack trace (backward).

eefm and eterm:
- The font picker opens centered and preselects the font in use when
  none is configured. A picked fallback font replaces the previous one,
  so it applies at once. The UI scene gets a thread pool, as in ecode,
  so the picker lists fonts in the background.

eepp:
- UIPushButton: with an expanded text view, the content size is the
  whole text, so auto sized table columns still fit their content.
- VFSDirectoryModel: folder name cells get the vfs_folder class.

build:
- backward stack traces for more tools (texture atlas editor, map
  editor, UI editor, eterm, texture packer, eeiv, eproc, eefm); libdw
  is linked by the backward module.
2026-10-15 02:30:30 -03:00
Martín Lucas Golini f0a21c3f9f Added backward to all eepp tools in both Premake configurations, including eterm, eproc, eeiv, and the editors/texture packer. Optional Linux libdw support now lives in the shared helper. 2026-10-15 01:37:19 -03:00
Martín Lucas Golini 00999e26c3 Queue HTTP connection waits, add a socket budget and cancel on shutdown
Requests that hit a connection limit used to wait inside their worker,
polling every 10 ms, and an async request's timeout included that wait.
On a page with many resources from one origin, later requests timed out
while queued, and waiting requests tied up shared thread-pool workers
that other origins needed.

Connection queue:
- Serve blocking and async requests from one first-come, first-served
  queue per pool. Requests waiting on one origin's limit never block
  requests to other origins.
- In shared thread-pool mode, an async request runs on a worker only
  after it has been granted a connection. Grants are handed to the
  executor from a service thread, never from the thread releasing a
  connection, which could be inside the executor's own lock.
- Requests hold their executor only weakly, so a request can never be
  the last owner of the thread pool running it.
- Start an async request's timeout once it holds a connection. A
  blocking call's timeout still covers the wait plus the transfer, and
  a resumed download keeps its deadline across the HEAD probe.
- Wait on a condition variable instead of polling. Cancelling by ID,
  shutdown() and Pool::close() release queued requests immediately.
- Let running requests and blocking callers take over a slot reserved
  for queued work that has not started; that work queues again, first
  in line. Without this, a redirect, retry or resumed download on a
  busy executor could wait forever on slots reserved behind it.
- When queued work starts, switch to a connection that went idle while
  it waited, instead of opening a new one.
- Replace an idle connection the server has closed in place, keeping
  its slot.

Process-wide limit and idle expiry:
- Limit open sockets across all pools with
  Http::setMaxOpenConnections() (default 256). At the limit, close the
  least recently used idle socket in any pool, then a socket held for
  queued work, and only wait while every socket is in active use.
- Wake waiters on the limit when a socket goes idle, and recheck a
  change counter so a wake-up just before waiting is never missed.
- Only inspect a socket for reclaim once its connection is known to be
  idle or reserved, never while a request is using it.
- Close idle connections from a background timer when idleTimeout
  elapses, instead of only when a connection is next requested in the
  same pool.
- The budget and its service thread are intentionally never destroyed,
  so the thread is never joined during static destruction, which would
  deadlock under the Windows loader lock.

Shutdown:
- Add Http::cancelAllRequests(), which cancels every queued and running
  request in every pool and closes idle connections. A per-pool
  generation counter makes running requests stop at their next check,
  and the pools stay usable afterwards.
- Add Http::waitForConnectionsToClose().
- Engine cancels all requests as it starts shutting down. Once its
  windows are closed, it waits up to 100 ms for sockets to close before
  ending TLS.
- Check for cancellation every 25 ms instead of 100 ms while reading, so
  requests stop within that wait.

TLS:
- SSLSocket::end() now waits while TLS sockets exist: the last socket
  destroyed releases the backend, and a socket created in the meantime
  keeps it.
- Set up the backend and register a new socket a
  lock, so a concurrent end() cannot release the backend in between.
- Add SSLSocket::isInitialized() and a testing h
  socket construction.
2026-10-15 00:36:56 -03:00
Martín Lucas Golini ad69ee977e Fix project encoding test scanning downloaded SDL3 SDKs
Skip versioned SDL2 and SDL3 SDK directories before recursing,
preventing bundled libraries and debug symbols from being treated
as project text files.
2026-10-15 00:07:27 -03:00
Martín Lucas Golini 0b182de93e Fix Windows MSVC build. 2026-10-14 22:01:18 -03:00
Martín Lucas Golini 0bd6c9e85c fix(eefm): include a lean windows.h in the terminal panel
The full windows.h pulls in the RPC headers, whose UUID clashed with
EE::System::UUID brought into the global namespace by eterm's headers
(MSVC C2872). The terminal only needs kernel32 and the toolhelp API, so
define WIN32_LEAN_AND_MEAN as trash.cpp and apps.cpp already do.
2026-10-14 21:43:05 -03:00
Martín Lucas Golini bb83e47fe4 fix(vfs): match FSEvents' resolved paths in local watches on macOS
FSEvents reports events under the watched directory's real path
(/private/var/... for a root under /var, such as the temporary
directory), so local watch events kept absolute paths instead of paths
relative to the watched root. Keep the resolved root when it differs and
strip whichever prefix the event path starts with. Update efsw for the
same fix in efsw-agent.
2026-10-14 21:38:39 -03:00
Martín Lucas Golini a7ca505229 Add bounded HTTP/1.1 connection pooling for browser sessions
Replace thread-local connections with owned pools shared across workers.
Bound total and per-origin connections, expire idle sockets, and check
idle connections before reuse. Retry safe requests after stale-connection
races without replaying POST requests.

Fix response framing, chunk trailers, decompression completion, empty
compressed bodies, and handling of bytes beyond completed responses.

Give each WebResourceCache partition its own transport, preserving
connections across navigation and shared tabs. Close session transports
without blocking the UI thread. This substantially improves browsing
performance in the ui_html example.

Preserve every Set-Cookie field and attribute redirect cookies to the
client that received the response. Prevent rejected redirects from
assigning cookies to their destination.

Add regression coverage for pooling, framing, cancellation, TLS policy
isolation, browser sessions, and redirect cookie attribution
2026-10-14 21:05:40 -03:00
Martín Lucas Golini b53ea69258 Fixed the missing SDL3 startup wrappers. Premake now adds sdl3_main.cpp (src/eepp/main/sdl3_main.cpp) once per MSVC executable to supply main/WinMain, while preserving the accessibility harness’s own wmain. 2026-10-14 20:38:57 -03:00
Martín Lucas Golini 345bfd2c26 fix(ui): delete FreedesktopIconLookup copies for MSVC exports
MSVC instantiates the implicit copy operations of dllexport classes, and
FreedesktopIconLookup's unique_ptr theme list cannot be copied (C2280).
The lookup is never copied, so delete them explicitly.
2026-10-14 20:35:27 -03:00
Martín Lucas Golini a152a5427d fix(ui): open model rows once on Enter; link efsw frameworks for eefm
- UITableCell: leave Enter to the model view instead of clicking the cell.
  With focus on the selected row's cell, single-click navigation opened
  the row twice: once from the cell click and once from the view's Enter
  handler. Affected UITreeView, and UITableView/UIListView since they
  follow focus-on-selection.
- Add a regression test for list, table and tree views in both click
  modes.
- Link CoreFoundation and CoreServices in eepp_module_vfs_add(): efsw's
  FSEvents watcher needs them, which broke the eefm link on macOS.
2026-10-14 20:05:48 -03:00
Martín Lucas Golini c148becc64 feat(eefm): add settings, terminal panel, system icons and in-place rename
UI:
- Add UISystemIconTheme: colored file, folder and place icons from the
  freedesktop icon theme, the Windows shell or macOS, loaded asynchronously
  with glyph fallbacks. Platform helpers live in src/eepp/ui/icons/.
- UITableView: rubber band selection (tableview::rubberband, styled in
  breeze.css), Shift range selection from an anchor, type-to-select by a
  configurable column, and focus following the selection.
- UISpinBox: keep partial text while typing; clamp and normalize on Enter or
  focus loss, and detach the input listeners on destruction.
- InputEvent: report the window position of file drops (SDL3).
- Image: detect SVG documents preceded by comments, a DOCTYPE or XML
  declarations.

eefm:
- Add a settings window (theme, fonts, rendering, files, terminal),
  persisted in config.cpp.
- Add a terminal panel (F4) whose shell follows the active pane while it
  waits at its prompt.
- Show platform icons for files and places, cached per MIME type.
- Rename in place, select created or renamed items, and copy files
  dropped from other applications into the pane or folder under the drop.
- Fix MIME descriptions and icons for exact names, multi-dot extensions and
  globs; cache unknown types negatively.

eterm:
- Apply UI font, size, hinting and anti-aliasing settings live.
2026-10-14 19:34:02 -03:00
Martín Lucas Golini 60f025fde2 Fix SDL backend isolation in platform helpers
Include only the selected backend in Engine and guard both platform helper
classes and the SDL2 implementation. This prevents MSVC SDL3 builds from
exporting SDL2 vtables and failing with unresolved helper methods.
2026-10-14 19:16:26 -03:00
Martín Lucas Golini 45f11f6816 Add native file dragging on macOS
- Implement a Cocoa drag source on NSDraggingSession for SDL2 and SDL3.
- Use the offered snapshot as the drag image, or each file's Finder icon,
  with AppKit's own count badge and copy cursor.
- Offer Generic alongside Copy only within the application, so SDL2's
  Cocoa windows accept drops while other apps still see a copy-only offer.
- Report cancellation immediately and refuse the drop, since AppKit cannot
  abort a running session.
- Fix macOS SDL3 builds: use pkg-config instead of the removed sdl3-config
  and keep EE_SDL3_FROM_ROOTPATH for framework builds only.
- Build the native drag tests on macOS, add the Android drag sources, and
  avoid the windows.h max macro in the Win32 source.
- Document macOS behavior and platform support.
2026-10-14 18:37:08 -03:00
Martín Lucas Golini f809e84b53 test(a11y): stabilize inactive performance benchmark and CI coverage
- Warm the notification workload before timing one million calls
- Collect ten fixed enabled/disabled pairs with alternating order
- Preserve the 1.01x ratio-of-medians guard without conditional retries
- Validate reported measurements and retain JSON diagnostics on failure
- Prevent D-Bus service output from contaminating benchmark artifacts
- Run native AT-SPI checks after timing failures without masking CI failure
- Add deterministic runner tests and document the measurement protocol
2026-10-14 18:12:23 -03:00
Martín Lucas Golini 6e38945211 Add native file dragging on X11 and Windows
- Introduce DragAndDrop with capability queries, copy-only file offers,
  image previews, cancellation, and completion callbacks.
- Implement XDND and OLE sources with safe input recovery and window teardown.
- Keep SDL2 and SDL3 presentation and input handling in their own backends.
- Load X11 dynamically without adding a link dependency.
- Reuse Image, URI, and timing APIs; fix Image::fillWithColor().
- Add a manual playground, integration tests, and consumer documentation.
- Migrate SDK builds and packaging to SDL3 and fix bundled runtime lookup.
2026-10-14 17:24:56 -03:00
Martín Lucas Golini 110a9d46f0 Fix numeric cleanup stripping significant trailing zeros
Only trim zeros from fractional digits, preserving integers and
scientific notation. Fixes the universal locator calculator displaying
14 instead of 140 for 86504-86364.
2026-10-14 14:48:35 -03:00
Martín Lucas Golini ea40c532a7 Fix Fish startup warnings from placeholder terminal dimensions
Use an 80×24 grid when a terminal view has fewer than two rows or
columns, preventing placeholder and collapsed layouts from creating
a one-row PTY. Resize normally once usable layout dimensions exist.

Add regression coverage for startup sizing and resizing after layout.

Refs: SpartanJ/ecode#969
2026-10-14 11:34:54 -03:00
Martín Lucas Golini 3999df7043 Fix emscripten build. 2026-10-13 16:09:31 -03:00