Commit Graph
2293 Commits
Author SHA1 Message Date
Martín Lucas Golini 67660d4c13 Add accessible text, relations and live regions; keep dormant a11y free
Text:
- Ranged text access in code points (length, range, line bounds) that
  never copies more than requested, plus a text revision (document UUID
  and modification) so UIA and macOS cache their UTF-16 copies.
- Report document edits as exact change records, up to four per widget
  and frame, then collapse to one whole-text change. Resets, loads and
  document swaps report a whole-text change.
- The removed text is available only while an edit is being notified
  (TextDocument::getNotifiedRemovedText()); DocumentContentChange stays
  { range, text }, so queued records (LSP) copy nothing extra.
- Suppressed text changes are keyed by node ref, so a document shared
  with another window still reports its edits.
- UITextView reports NameChanged; UITextInput overrides onTextChanged()
  to report ValueChanged.

Relations, live regions and shortcuts:
- aria-labelledby, aria-describedby and aria-live (API and CSS). Ids a
  client has read are remembered; renaming, adding or removing their
  widgets notifies the dependents. setId() copies the old id only when
  it is remembered.
- Live regions and UISceneNode::announceForAccessibility(). A newer
  change from the same widget replaces its pending announcement, and
  hidden sources are dropped.
- Menu item shortcuts (std::string text and key) exposed as AT-SPI key
  bindings, the UIA accelerator key and macOS command characters.
- ScrollTo for anything inside a scroll view
  (UIScrollView::scrollIntoView()). Icon-only buttons are named from
  their tooltip.

Dormant path (no client attached):
- Widget notifications are inline: one relaxed atomic load of a
  process-wide count of active root scenes, no call.
- Scene destruction and scene or host changes never create a manager.
  Without a client, notify() queues nothing and widget deletion does
  not register parents to announce it. While only the root has an
  identity, deletion skips the ancestor walk unless a remembered
  relation target may be affected.
- When the last client disconnects, model-view sources release their
  queried rows. Persistent handles count their registrations, so
  handles held elsewhere survive (PersistentModelIndex::release()).
- Spin boxes no longer hide their input explicitly, and
  AccessibilityProperties shrinks from 144 to 136 bytes.

Backends:
- AT-SPI: object:announcement, word and line granularity, ranged
  reads, SetTextContents reported as its minimal diff. Watch
  disconnects per client (NameOwnerChanged arg0 plus a non-blocking
  NameHasOwner check) instead of for every bus name. Without a scene
  thread pool, initialize on a detached thread that shares ownership,
  so teardown never waits on D-Bus timeouts.
- UIA: notification events (resolved at runtime, Windows 10 1709+),
  text ranges served from the revision cache, and a per-frame provider
  drain that skips the lock when nothing is queued.
- macOS: announcements, a UTF-16 text cache per revision, and command
  key attributes.
- EEPP_ACCESSIBILITY_TRACE=1 logs client activity transitions.

Fixes:
- UICodeEditor::isType() no longer dispatches to a subclass's
  getType(), so a UITextEdit is a code editor again.
- ecode: dropped files open only in document editors, not in other
  code editors such as a commit message box.

Tools, tests and docs:
- Widget inspector: role names, shortcut, relation and live rows, and
  an accessibility audit (unnamed controls, broken relations).
- Accessibility example: live status, an icon-only button, and edit and
  reset actions that test_atspi.py checks end to end.
- Regression tests for text records, relations, live regions,
  disconnect and reconnect, scene lifecycle and id changes.
- Add the AccessibilityDormant benchmark (C++ new/new[] counted on the
  measuring thread) and benchmark_accessibility_dormant.py, which fails
  on missing measurements and compares against other builds with
  --compare LABEL=PATH.
- Document the dormant-path rules, what survives a disconnection, and
  the remaining platform limitations.
2026-10-10 02:01:52 -03:00
Martín Lucas Golini 1dd0870187 Harden accessibility review fixes and make macOS de-dup linear
macOS:
- Check each notification against a hash set of (event, element,
  related element) instead of scanning the whole pending queue. The
  ordered queue still drives delivery, so a burst of distinct events
  (e.g. 10,000 label changes) stays linear. Created/Destroyed are never
  de-duplicated.
- Track the pending focus change by its index instead of scanning for it.

Core:
- SceneManager::update: also bound the loop by the live scene count, so
  a scene removed during the pass can't cause an out-of-range read.
- Accessibility setters (role, label, description, hidden) return early
  on unchanged values. Re-applying CSS no longer allocates the
  properties block or notifies clients.

API cleanup:
- Remove AccessibilityRelation, AccessibilityRelationInfo and
  AccessibilityNodeInfo::relations. Nothing populated them. Remove the
  inspector row and the macOS linked-elements attribute that read them.
  AT-SPI GetRelationSet still answers with an empty set.
- Drop unused includes in uiroot.cpp and accessibility.hpp.

Docs:
- Architecture guide: UIA and macOS queue events until update(); AT-SPI
  emits right away except for per-frame text diffs. Describe each
  backend's per-frame batching, including the macOS de-dup.

Tests:
- Add UnchangedAccessibilityPropertiesStaySilent.
2026-10-09 10:47:43 -03:00
Martín Lucas Golini d27eae5927 Harden accessibility lifecycle, events and native backends
Teardown and identity:
- Detach native backends before scene children are destroyed and clear
  mRoot afterwards, fixing a use-after-free when an AT-SPI client is
  connected while a window closes.
- Invalidate a deleted widget's subtree once, top-down, before OnClose
  handlers run (NODE_FLAG_DESTROYING). Descendants never walk into
  destroyed parents, and deleted identities cannot be re-registered.
- Closing scenes expose no accessibility manager through either accessor.
- Deleting widgets no client has seen allocates no identity and emits no
  events.
- Ignore events from widgets not yet attached to a scene.

Events:
- Keep the order of state and structural events; coalesce only adjacent
  query-again hints.
- Stop emitting per-widget BoundsChanged; bounds are queried on demand.
- Report the Focused state and keyboard focus only on the projected focus
  owner, through a shared helper used by both paths.

Model views:
- Lazy child count and child queries, cached sibling indexes, selection
  and hit testing without enumerating rows.
- Row identities follow inserted and removed rows; removed rows are
  pruned from native wrapper caches.
- Expose the active cell editor as the child of the row or cell it edits.

AT-SPI:
- Correct state bits (EXPANDABLE/EXPANDED, SENSITIVE, CHECKABLE,
  SELECTABLE, READ_ONLY, SINGLE/MULTI_LINE, SELECTABLE_TEXT) and the
  password-text and panel roles.
- Emit text-changed insert/delete, caret-moved and selection-changed
  events, diffed once per frame. Support line granularity,
  SetCaretOffset and selection editing.
- Track clients by bus name so the active flag clears on disconnect.
- Fix the I/O thread busy-spin and stranded dispatch backlog, flush
  queued signals, and type-check Properties.Set values.

UIA:
- Raise focus only for the focused element.
- Defer UiaDisconnectProvider out of widget destruction.
- Keep providers alive for in-flight cross-thread requests.
- Reject unknown interfaces without a UI-thread round trip.
- Require window-specific client activity.

macOS:
- Avoid repeated full node info builds.
- Use sibling indexes and lazy child access.
- Fix label/value deduplication for list items.

Tests and docs:
- Add regression tests for focus ownership, teardown, event ordering,
  lazy model identities, nested scenes and cell editors.
- Extend the AT-SPI validation scripts and document the current
  performance characteristics and limitations.
2026-10-09 00:06:36 -03:00
Martín Lucas Golini 51b1059996 Fix accessibility ownership and native backend lifecycle
- Prevent dense-map iterator invalidation during widget deletion.
- Invalidate widget and model references when scene ownership changes.
- Expose nested-scene controls through the host accessibility manager.
- Preserve identities when reparenting within the same host.
- Synchronize AT-SPI state access with asynchronous initialization.
- Wake the shared SDL event loop without retaining window-owned Input pointers.
- Add lifecycle regression tests and hidden multi-window AT-SPI validation.
- Ensure test-bus failures cannot skip child-process cleanup.
2026-10-08 21:20:14 -03:00
Martín Lucas Golini 5a4fb936f0 Merge branch 'develop' into feature/a11y 2026-10-08 10:04:08 -03:00
Martín Lucas Golini 9d8ec467cf Modernize UI Editor with isolated previews and UIApplication
- Reimplement previews using nested UISceneNodes with isolated styles
  and resources.
- Preserve live XML/CSS editing, unsaved buffer previews, external file
  watching, and project resource loading.
- Use UIApplication for initialization, font resolution, and offscreen
  rendering support.
- Enable Breeze by default, add a menu toggle, and replace
  --use-app-theme with --disable-app-theme.
- Automatically preserve declared project viewport dimensions, with
  an optional override to use the preview split size.
- Support embedded HTML documents inside WebView XML elements.
- Fix fading window shadows and shutdown with visible modal dialogs.
- Update documentation and add regression coverage.
2026-10-07 14:02:56 -03:00
Martín Lucas Golini 8a3fbb6719 Replace select() with poll()/WSAPoll() in SocketSelector
SocketSelector used fd_set + select() on every platform. On POSIX,
descriptors >= FD_SETSIZE (1024) were rejected and only logged, so a
UI inspector listener or client opened that high was never serviced.
On Windows, the selector held at most 64 sockets (Winsock's default
FD_SETSIZE).

SocketSelector:
- Use a shared pollfd implementation on every platform: poll() on
  POSIX and WSAPoll() on Windows. This removes both FD_SETSIZE limits.
  Store descriptors in a SmallVector<pollfd, 16>, which covers the
  inspector's peak without heap allocations.
- Report POLLIN | POLLERR | POLLHUP as ready to match select()'s read
  readiness, so a peer disconnect still triggers the receive() that
  discovers it. Windows reports a graceful shutdown as POLLHUP.
- Treat negative timeouts as an immediate check instead of an infinite
  wait.
- Clear revents when poll() fails, so isReady() never reports readiness
  left over from an earlier wait.
- An empty selector sleeps for a finite timeout and returns false;
  with an infinite timeout it returns immediately. WSAPoll() rejects
  empty sets, and nothing could ever become ready anyway.
- Remove sockets by swapping with the last entry instead of shifting.
- Raise the Winsock target to Vista (0x0600), the minimum for WSAPoll().

UI inspector:
- Stop watching the listener while the 16-client limit is reached. A
  pending connection kept it readable, so every wait() returned
  immediately and the network thread spun.

Tests:
- Add SocketSelector tests for listener and data readiness, removal,
  duplicate adds, disconnect readiness, negative timeouts and empty
  selectors, plus a POSIX run with every descriptor above FD_SETSIZE.
- Add HighFileDescriptorReservation, shared with
  Http.tcpConnectTimeoutHandlesFdAboveFdSetSize. It raises the soft
  RLIMIT_NOFILE when needed, so the high-fd tests run under common
  defaults (1024 on Linux, 256 on macOS) instead of being skipped.
- Fix UIHTML.AttributeSelectorsMatchWidgetIds on Windows: it compared
  c_str() of a temporary that was destroyed before the check.
- Fix UIHTML.StylesheetsDoNotPaintRawTextNodes on Windows: read the
  frame before display(), because Windows drivers don't preserve the
  back buffer after a buffer swap.
2026-10-07 01:07:03 -03:00
Martín Lucas Golini be17af3da0 Fix CSS selector backtracking, union style dependencies and bind libeepp calls directly
Selector matching (Selectors Level 4 §17.3):
- Retry other candidates for descendant and general-sibling combinators
  instead of rejecting after the first failed path. Checkpoints use a
  fixed array of one entry per checkpoint-saving rule (16 on the stack,
  32/64 in out-of-line helpers, heap beyond), with failure pruning so
  exhausted searches stop early.
- Handle <html> as a style-sheet parent boundary whose siblings stay
  visible: failed parent steps at an <html> with element siblings retry
  instead of rejecting, and a ~ candidate that is such an <html> resumes
  its search without a checkpoint.
- Reject the subject before sizing storage for long selectors.

Style dependencies:
- getRelatedElements() now returns the union of tracked elements over
  every matching path, so state changes on any eligible ancestor or
  sibling restyle the subject. Strategies are chosen per selector:
  immediate exit, fixed-prefix walk, single candidate scan (with a
  shared suffix for ~ candidates), an ancestor-path DP, and a memoized
  collector. All are linear and allocation-free for common selectors.

Other fixes:
- Exclude raw text nodes from matched author styles; their widget
  backgrounds painted over glyphs drawn by the parent rich text.
- Report widget ids from getPropertyString() so [id=...] selectors match.
- Add StyleSheetSelectorRule::hasAnyPseudoClasses() and
  UIStyle::getRelatedWidgets() (inline, ABI-compatible additions).

Build:
- Link libeepp with -Wl,-Bsymbolic-functions on Linux, BSD and Haiku so
  internal calls skip the PLT (11,314 -> 619 PLT entries). Measured:
  Markdown load -25%, selector matching -11%, attribute matching -14%.

Tests and benchmarks:
- Regression tests for backtracking, <html> boundaries, subscription
  union and cleanup, operation-count bounds, long selectors and id
  attribute selectors, plus a differential test against an exhaustive
  reference matcher.
- Add Benchmark.CSSSelectorCombinators and Benchmark.CSSStateDependencies
  and create all benchmark windows hidden.
2026-10-07 00:03:22 -03:00
Martín Lucas Golini d49fe3fdc8 Add date and time pickers with calendar popups and HTML mappings
- Add CalendarDate, TimeOfDay, LocalDateTime and DateRange with Gregorian
  arithmetic, locale-aware formatting/parsing, ISO serialization and Unix
  timestamp conversions with explicit UTC offsets.
- Add UIDateTimeEdit, UIDatePicker, UITimePicker, UIDateTimePicker and
  standalone UICalendar, with XML/CSS registration and data binding.
- Support segmented keyboard editing, numeric entry, ISO paste, configurable
  steps, bounds, empty values and independent seconds/milliseconds display.
  Default time display to hours and minutes while preserving stored precision.
- Add day/month/year calendar navigation and a combined date-time popup with
  time steppers, live configuration updates and scoped event connections.
- Add Breeze and fallback theme styles with CSS-defined SVG icons, dp sizing,
  font-aware calendar dimensions and muted read-only/disabled controls.
- Map HTML date, time and datetime-local inputs to native controls with strict
  value sanitization, min/max/step/required/readonly/disabled handling,
  constraint validation and normalized form serialization.
- Provide private light HTML control defaults and intrinsic temporal sizing;
  prevent author CSS from styling anonymous implementation parts.
- Share popup placement and visibility helpers across pickers, dropdowns and
  trigger/cursor menus while retaining cascading-menu placement rules.
- Fix fractional grid wrapping and input cursor bubbling over child buttons;
  notify and refresh styles when editing permission changes.
- Reduce CSS registration allocations with string_view parameters and
  heterogeneous name lookup; inline frequently used node and CSS getters.
- Align CodeEditor default font sizing with text widgets without overriding
  application preferences.
- Add HTML form margin defaults and update the affected rendering baseline.
- Upgrade Windows ecode nightly builds to Ubuntu 24.04 and newer MinGW.
- Add picker documentation, an example and regression coverage for date math,
  locales, editing, popup placement/lifetime, HTML controls and pixel density
2026-10-06 01:13:44 -03:00
Martín Lucas Golini e9f074b1d2 Fix baseline alignment when rendering mixed rich-text fonts + Fix image diff button hit-testing and native pixel sizing
- Compensate for the difference between font ascent used by RichText layout
  and the character-size baseline used by Text rendering. Cache the natural
  baseline in each text span while preserving background and selection boxes.

- Add pixel-level coverage for proportional and monospace fonts at matching
  and different sizes, with default and explicit line heights. Refresh the
  affected rendering reference images.

- Keep diff view select buttons last in the child list so lazily created
  image viewers cannot intercept their clicks.

- Display source images and generated diffs at native pixel dimensions,
  independent of UI density, scaling down only to fit the viewport. Avoid
  rounding twice at fractional densities.

- Add regression coverage for mode switching and sizing at densities
  1, 1.5, and 2. Use portable temporary paths.
2026-10-05 00:57:39 -03:00
Martín Lucas Golini 98e9213f4d Add local Markdown navigation and persistent ecode previews and fix terminal selection bounds and vertical auto-scroll
- Follow local Markdown links relative to each document, including
  relative file:// paths, with configurable handling and async loading.
- Add validated subtree navigation interceptors and custom link flows.
- Introduce UIScrollableMarkdownView with XML support and scroll reset
  after successful navigation.
- Add opt-in Back/Forward history, localized context menu actions, and
  mod+[ / mod+] shortcuts; enable history in ecode previews.
- Restore preview tabs between sessions and preserve live editor binding
  and unsaved source content when navigating back.
- Refresh the README around eepp's GUI framework and document the new APIs.
- Remove the fixed Markdown code font size and add regression coverage
- Clamp selection coordinates independently so horizontal dragging preserves
  the selected row. Use the mouse event's Y coordinate against the terminal's
  vertical bounds, including padding, and retain unclamped coordinates during
  periodic updates outside the window.
2026-10-05 00:12:07 -03:00
Martín Lucas Golini af273c08a4 Avoid redundant layout invalidation from inline fragment sizing
Track when the formatting owner assigns fragment bounds and suppress
layout feedback from text-node and inline-span size changes. Preserve
size events and invalidation from callback-driven text or style changes.

Add regression coverage for content reuse and table sizing after size
callbacks. Preserve class sizes and existing member offsets.

Adjust browser toolbar padding and remove the URL bar's right margin.
2026-10-01 01:41:18 -03:00
Martín Lucas Golini e4801afab9 Reduce rich-text rebuilds and normalize browser addresses
- Reuse unchanged inline content and fragment lookups.
- Share plain-text min/max intrinsic measurements without copying
  existing shaped layout state.
- Preserve content invalidation during active measurements.
- Default URL bar and CLI addresses to HTTPS while preserving
  explicit URLs and local file paths.
- Fix Windows header macro conflicts and eproc signal declarations.
- Add regression coverage for reuse, rewrapping, and invalidation
2026-10-01 00:45:25 -03:00
Martín Lucas Golini ddc9112f13 Reduce redundant HTML table layout work. Add browser shortcuts and keybinding inspection.
- Skip dirty-descendant scans for leaf layouts during document construction.
- Treat table-assigned cell sizes as computed output, avoiding repeated measurement and intrinsic-size invalidation.
- Defer descendant changes until table traversal completes, preserving content updates and propagating completed intrinsic contributions.
- Add regressions for dirty-root coalescing, cell measurement, nested table reflow, and content changes during size events.
- Register tab, address-bar, reload, and history navigation commands in ui_html
- Route toolbar actions through the registered commands
- Add read-only ui.keybindings queries for scenes and supported widgets
- Extend the inspector CLI, documentation, and regression tests
2026-09-30 23:53:18 -03:00
Martín Lucas Golini 2613ec0921 Fix remaining DPI inconsistencies and expand regression coverage
Correct checkbox and radio autosizing, submenu padding, scrollbar skin
sizing, and nested menu-bar popup coordinates.

Preserve resolved stroke widths through CSS serialization and transitions,
including HTML's special px scaling.

Add high-density regressions for these fixes and the preceding DPI cleanup
commits, covering padding and margin setters, widget defaults, dialog
dimensions, table padding, editor spacing, and diff gutters.
2026-09-30 12:19:40 -03:00
Martín Lucas Golini d04a6ad279 Fix cursor jump when clicking a scrolled editor split
Preserve the viewport when restoring a pane's selection on mouse focus,
so click hit testing uses the visible text. Keep scrolling to the restored
cursor for keyboard and programmatic focus changes.

Refs SpartanJ/ecode#958
2026-09-30 11:18:58 -03:00
Martín Lucas Golini f8f5627f77 Add clipboard change events and configurable split tab bars in eterm and fixed scrolling tests.
- Translate SDL2 and SDL3 clipboard updates into ClipboardChanged events.
- Expose Unknown, Self, and External clipboard ownership metadata.
- Add regression tests for event dispatch and ownership defaults.
- Add a persisted eterm setting controlling tab bars in split panes.
- Fixed both scrolling tests. SDL2 starts text input automatically on desktop, so the first Space waited for a text event the key-only test never sent.
2026-09-29 19:38:19 -03:00
Martín Lucas Golini a8eb1834eb Add tabbed HTML browsing and extend eepp navigation and input support
eepp framework:
- Add shared cookie jars to UISceneNode and UIWebView, plus versioned
  CookieManager persistence, domain clearing, and locking in hasCookie().
- Follow HTTP 303 redirects and merge same-host redirect cookies as
  name/value pairs without forwarding Set-Cookie attributes.
- Include Cookie headers in document cache keys while preserving static
  resource reuse as cookies change.
- Submit HTML forms with an empty action to the current document URL.
- Extend NavigationRequest with source, mouse buttons, modifiers, and
  navigation target; anchors forward this context to the scene.
- Emit OnLinkOpenRequested for middle-click, platform-modifier click,
  and explicit new-tab requests, with current-view fallback if unhandled.
- Install the WebView navigation interceptor during construction.
- Dispatch middle clicks to the hovered node without moving keyboard focus.
- Add the clicked target to ContextMenuEvent so applications can extend
  context menus through existing events.
- Parse HTML titles, emit TitleEvent, and fix onTitleChanged's payload cast.
- Load declared favicons through the shared image cache, emit
  OnFaviconChanged, and ignore responses from superseded navigation.
- Add optional UITabWidgetSplitter tab-bar visibility while split;
  keep it disabled by default and respect explicitly hidden tab bars.
- Add Space/Shift+Space scrolling and viewport-sized Page Up/Down steps
  to UIScrollView, shared by WebView and Markdown content.
- Implement setEnableDefaultKeybindings() and preserve text-input
  priority through normal bubbling without control-type checks.
- Report inserted UICodeEditor text as handled.
- Add UITextView::onFontColorChanged() and synchronize password-mask color.
- Support validated left, middle, and right clicks in the inspector
  server and Python client.

ui_html example:
- Use UITabWidgetSplitter for tabs and user-controlled splits.
- Share cookies and the resource cache across tabs; persist cookies
  between sessions and open new tabs blank.
- Add Inspect, Clear Domain Cookies, Clear All Cookies, and contextual
  Open Link in New Tab actions through menu event subscriptions.
- Open requested links in background tabs and synchronize navigation UI.
- Use document titles and 16dp favicons for tabs, cap width at 200dp,
  and truncate long titles with ellipsis.
- Enable tab-bar visibility across split panes.
- Fixed: the selection rectangle now uses the visible password symbols instead of the original text.

Update HTML compatibility and inspector documentation and add regression
coverage for persistence, redirects, cache isolation, navigation, menus,
titles, favicons, password colors, split visibility, and scrolling.
2026-09-29 18:58:51 -03:00
Martín Lucas Golini a090d1a666 Fix CSS state rollback for transient properties. eproc: add keyboard navigation between search and process views, fix Send Signal menu events.
Store native and inherited fallback values outside local styles, then restore them when state rules stop matching. Handle indexed properties across overlapping states and retain a serialized value when an inherited source disappears. Add rollback regression tests and update the CSS documentation

Focus and select the first process row when pressing Down in the search input. Pressing Up from the first row returns focus to search in both table and tree views.
2026-09-29 14:56:01 -03:00
Martín Lucas Golini 850f33c336 Polish app icon sizing and bump eepp and ecode versions
Generate size-aware macOS icons and separate runtime Dock PNGs for ee,
ecode, eterm, eeiv, and eproc. Keep shared PNGs sized for small Linux
icons, and package ecode's macOS runtime icon.

Bump eepp to 5.0.0 (Kittima-attā) and ecode to 0.9.0 (Yanta-lekhā).
2026-09-29 01:02:07 -03:00
Martín Lucas Golini ee0d9378ad Expand UI documentation and refine link context menus
Add guides for native UI authoring, layouts, application CSS, and HTML
compatibility. Update the CSS reference, rename article files consistently,
and point README links to the local guides.

Add Copy Link for HTML and Markdown anchors when no text is selected.
Resolve relative links against the document URI before copying, and cover
Markdown and WebView behavior with tests.

Fix layout width policy serialization to use the widget's width.
2026-09-28 19:20:34 -03:00
Martín Lucas Golini fd5a3718d4 Renamed UIStackLayout to UIFlowLayout throughout the engine and its usages, including the header and source files, XML tag, runtime type, widget factory, docs, and typed lookups. The layout behavior is unchanged. Separate UIStackWidget and debugger stack views retain their names. 2026-09-28 15:25:56 -03:00
Martín Lucas Golini 5db8d78725 - SocketSelector::isReady() (src/eepp/network/socketselector.cpp:111) no longer treats a Windows socket handle as an FD_SETSIZE index. That check prevented the inspector server from responding.
- Token generation (src/eepp/ui/tools/uiinspectorserver.cpp:67) now uses `BCryptGenRandom` on Windows, including for screenshot filenames.
- Split basic HTML defaults from document and form styles
- Load only structural defaults for Markdown views, leaving document colors and form-control styles to full HTML documents. Add Breeze styling for Markdown horizontal rules and HTML textareas.
2026-09-28 11:45:35 -03:00
Martín Lucas Golini 542075cca6 **fix(ui): prevent MSVC from generating UIInspector copy operations**
`UIInspector` owns move-only event connections. Explicitly delete its copy constructor and assignment operator so MSVC does not instantiate invalid copies of the handle maps. Restore the dense map implementation
2026-09-28 10:51:16 -03:00
Martín Lucas Golini 27bfbb4b3a * UIInspector now stores move-only event connections in a node-based map, avoiding the MSVC vector copy error.
* Batch results now initialize as a JSON object. The previous initialization created an array, causing both reported Linux and macOS test failures.
2026-09-28 10:10:44 -03:00
Martín Lucas Golini 4ffba20d07 feat(ui): add runtime inspector and fix HTML layout regressions
Add an opt-in TCP/NDJSON inspector for running eepp applications. It
provides authenticated, UI-thread-safe access to windows, scenes, and
widgets, including nested WebView documents. The v1 protocol supports
queries, trees, properties, focus, input actions, watches, screenshots,
and composed batches with result references and deferred execution.

Add a standard-library Python CLI, protocol documentation, build
entries, and integration tests. The listener remains disabled unless
explicitly enabled.

Fix HTML compatibility issues found while debugging NewsBlur:
- Let explicit flex minimums, including min-width: 0, replace the
  automatic content minimum.
- Measure flex lines against the container content box when padding
  and explicit dimensions are present.
- Keep promoted positioned descendants of hidden ancestors out of
  the paint list.
2026-09-28 01:15:39 -03:00
Martín Lucas Golini 1174e97911 Add optional filled areas to UI chart lines
Allow each LineSeries to fill down to the plot’s bottom edge, using a translucent version of its line color by default or a custom fill color. Render overlapping fills beneath the strokes, document the new API, and demonstrate it in the charts example. Add coverage for blending, data gaps, and toggling fills.
2026-09-26 23:59:19 -03:00
Martín Lucas Golini 2d7623c5fa Fix Windows build. 2026-09-26 23:30:00 -03:00
Martín Lucas Golini ec7c3c45dd Add document-level text selection to HTML and Markdown views
Introduce UITextSelectionController to coordinate selection across independent
RichText owners while retaining RichText hit testing and painting. Support
forward and reverse dragging, nested content, gap hit testing, autoscroll,
plain-text copy, select-all, and context menus.

Enable UIRichText and UITextSpan selection by default. Add CSS user-select
semantics and the -webkit-user-select alias, while preserving the separate
text-selection capability flag.

Clear selection safely when owners or documents are destroyed, suppress link
activation after a selection drag, and add regression tests, documentation,
and an updated rich-text example.
2026-09-26 22:11:32 -03:00
Martín Lucas Golini de040ef17e Add eproc settings and macOS/FreeBSD per-core CPU metrics
- Add persistent eproc settings for refresh interval, appearance, fonts,
    and renderer options, with a settings button in the main window.
  - Collect per-core CPU usage on macOS and FreeBSD for Performance charts.
  - Keep the settings search focused in eproc and eterm, and wrap long
    setting names.
  - Share macOS theme-colored titlebar handling across ecode, eproc,
    and eterm.
  - Stabilize fixed-size UI tests on Retina displays and prevent macOS
    build scripts from starting unlimited jobs when sysctl fails.
2026-09-26 01:44:10 -03:00
Martín Lucas Golini 8df1298470 eepp: add UI environment overrides and theme-aware eproc colors
Use Breeze theme colors for eproc's process table and Performance charts,
while preserving the translucent Username colors. Keep process icons
visible in the light theme with a white tint.

Add eproc CLI options for font hinting, font antialiasing, and color scheme.
Add -c/--prefers-color-scheme to eterm and retain close-on-exit through
its long options.

Support EEPP_FONT_HINTING, EEPP_FONT_ANTIALIASING, and EEPP_COLOR_SCHEME
across eepp UI apps, with valid environment values taking precedence
over application settings. Document and test the overrides.
2026-09-25 22:59:58 -03:00
Martín Lucas Golini 1de732962d Add eproc Performance view and family memory metrics
- Add CPU, memory, GPU, and network charts with ten-minute history,
  a 60-second view, clickable cards, and overall or per-core CPU views.
- Add Family Memory and Family Memory % to both process views. Use
  proportional memory on Linux, count zero-memory zombies correctly,
  and collect the data after the first frame without delaying it.
- Add column tooltips, rename Total Memory to Resident Memory, keep
  Command last by default, and migrate saved column layouts.
- Enable sorting within each tree level and preserve selection.
- Improve eepp chart margins and sorting behavior, and document UIChart.
2026-09-25 16:22:00 -03:00
Martín Lucas Golini f2ab50f2d8 Add chart grids, smoothing, and rotated tick labels
- Add configurable vertical and horizontal grids with axis tick, data,
  and screen spacing modes.
- Add monotone cubic line smoothing and angled X-axis tick labels.
- Return references for chart APIs that always have a result, and document
  model ownership and borrowed references.
- Prevent empty tooltips and refresh chart hover when live data changes
  under a stationary cursor.
- Update the charts example and add rendering and tooltip regression tests.
2026-09-25 12:26:11 -03:00
Martín Lucas Golini b3e6ea559d Add pixel-density default and improve chart rendering
- Honor EEPP_PIXEL_DENSITY when an app has not specified a scale,
  without resizing its window.
- Scale chart measurements in dp, expose chart styling, and resolve
  default colors through the UI theme.
- Fix gaps at miter joins and round chart text to device pixels.
- Use inline storage for common chart axis, series, and label counts.
- Add density and rendering regression tests.
2026-09-25 10:51:55 -03:00
Martín Lucas Golini 7a66563114 Add eepp charts module and interactive example
Implement chart axes, line series, data sources, pixel-bucket reduction,
tooltips, and pan, zoom, fit, and live-follow interactions. Register Chart
as a default UI widget and expose the new APIs through ui.hpp.

Add a responsive four-chart example, benchmarks, and unit tests. Reuse
rendering buffers and fix ring-buffer rendering and hover tooltip behavior.
2026-09-24 21:16:52 -03:00
Martín Lucas Golini d551ac170c Expand eproc and improve eepp table and tree views
Add process columns, GPU metrics, tree mode, multi-process actions,
GUI and tray detection, and persistent filter and table settings.

Add optional column header reordering to eepp table and tree views.
Keep dragged headers in place during refresh and draw them above other
headers. Preserve row selection when sorting and when opening context
menus, and support application items in header context menus.

Refresh eepp and tool icons and add the icon generation script.
Add tests for the process views, icon decoding, and GUI table behavior.
2026-09-23 20:57:34 -03:00
Martín Lucas Golini 61ca3844ba Fix splitter widget callbacks being dropped on tab moves
* Fix UICodeEditorSplitter dropping its widget listeners on tab moves:
    UITabWidget reports drag & drop transfers as OnTabClosed + OnTabAdded,
    so treating OnTabClosed as "left the splitter" permanently unhooked the
    moved widget and left mCurEditor/mCurWidget tracking nothing
    (SpartanJ/ecode#958).
  * Tie splitter-owned callbacks to splitter membership: attach on
    OnTabAdded of managed tab widgets, detach on OnTabClosed. Creation and
    transfer now share one registration path; moves to external tab
    widgets stay detached.
  * Keep mEditorSelections for the editor lifetime instead of the tab
    membership lifetime: it survives split moves and is cleared from the
    editor OnClose callback, which is disconnected in the splitter
    destructor so outliving editors cannot call into a destroyed splitter.
  * Apply the same ownership model to UITabWidgetSplitter, which had the
    inverse bug: widgets dragged out kept notifying the splitter through
    stale connections; drop the duplicated closeTab() cleanup.
  * Store listeners as Scene::EventConnection/List (RAII disconnect)
    instead of std::vector<Uint32> + removeEventListener bookkeeping.
  * Add regression tests covering editor and generic widget moves between
    splits, in and out of the splitter, focus/title tracking after each
    transition, selection cache survival, and editor destruction cleanup.
2026-09-22 14:00:11 -03:00
Martín Lucas Golini 7a63e13070 Fix eproc not displaying the full command. Fix UITableHeaderColumn mist-firing a sort after drag. 2026-09-22 01:30:27 -03:00
Martín Lucas Golini f200850941 Fix eterm tab closing and macOS menu integration
* Serialize tracked realloc and free bookkeeping to prevent cross-thread
    address reuse from corrupting the memory tracker during tab teardown.
  * Add concurrent allocation and terminal close/resize regression coverage.
  * Install a macOS-only File, Edit, and Window menu that mirrors eterm
    keybindings without binding Cmd+W.
  * Keep the native menu outside the splitter layout and document the canonical
    macOS build workflow.
2026-09-21 21:39:39 -03:00
Martín Lucas Golini e2174aa044 feat(ecode): add Git diff gutter and minimap indicators
Compute document line changes asynchronously against the repository
baseline and render added, modified, and removed markers in the editor
gutter and minimap.

Keep diff indicators disabled by default to avoid unexpected background
work. Add settings for enabling them and configuring the debounce delay,
with translations for all supported locales.

Handle fully added files, stale asynchronous results, document lifetime,
repository changes, and unsaved edits. Add focused Git diff and document
serialization regression coverage.

Vendor a reduced simdutf build and use it to accelerate String UTF-8 and
UTF-32 conversion and codepoint counting. Preserve efficient scalar and
cached-ASCII paths while reusing output storage for document snapshots.
Add simdutf to the Premake 4, Premake 5, and Android builds.

Fix UIConsole wheel and keyboard scrolling, and repair its text cache by
hashing log entries before moving their strings. Initialize cache hashes
and add regression coverage for scrolling and moved log entries.

Preserve debugger response data when notifying multiple listeners by
copying for all but the final listener. Remove an evaluation-order hazard
when capturing and submitting URIs for asynchronous document loading.

Refs SpartanJ/ecode#955.
2026-09-21 18:05:23 -03:00
Martín Lucas Golini 53f1fe6045 perf(ui): store Variant values inline
Replace Variant's heap-owned payloads with manually managed inline
  storage while preserving its return-by-value API.

  - inline std::string, String, DrawablePtr, Vector2f, and Rectf
  - add move construction and capacity-preserving assignment
  - add explicit borrowed std::string support and string views
  - avoid redundant conversions in table and tree hot paths
  - borrow stable process fields in eproc
  - eliminate per-frame eproc class allocation churn
  - focus the eproc search input on startup
  - add comprehensive Variant lifecycle and ownership tests
2026-09-21 02:37:11 -03:00
Martín Lucas Golini 51b88fa125 fix(ui): harden asynchronous document search
Snapshot document search state before dispatching highlight workers and
retain the searched document for the duration of each job.

Publish results through MainThreadLifetime and reject results when the
editor has changed document or search parameters. Remove the obsolete
worker counter and destructor wait used for editor lifetime management.

Use atomic cancellation flags in TextDocument::findAll() and protect
active-search map inspection during destruction.

Add regression coverage for concurrent cancellation, stale highlight
results, rapid backtick searches after a large multiline paste, and
editor destruction during active search.

Refs SpartanJ/ecode#956.
2026-09-21 01:55:58 -03:00
Martín Lucas Golini d885c6b31a Update svector and unordered_dense to its latest releases. 2026-09-19 21:52:07 -03:00
Martín Lucas Golini b838a42fee Fix lTrim/rTrim asymmetry with trim. Fix readBySeparator on an empty buffer.
Reuse RegEx match data and bound the pattern cache.

lTrim and rTrim returned an all-separator string unchanged where trim() returns empty;
all sixteen overloads now drop everything when no non-separator is left.
readBySeparator handed the callback one empty chunk for an empty buffer; it hands none
now, as the UTF-32 overloads already did.

RegEx::matches allocated its match data per call, four allocations per row while
filtering over a table. It is created once per object now, held by a unique_ptr whose
deleter knows the engine, so the destructor no longer repeats that split. RegEx is
movable but not copyable: it was implicitly copyable while owning that block, and a
copy taken after a match released it twice. syntaxtokenizer.cpp was copying its
std::variant temporary because the user-declared destructor suppressed the implicit
move; it moves now.

RegExCache held two unordered_maps, hash to pattern and hash to options, and never
evicted. It is one DynamicLRU<8192, size_t, shared_ptr<void>> now: the engine lives in
each pattern's deleter so the options map is gone, and values own the pattern, because
an eviction must not free one a live RegEx is still matching with. That also fixes a
racing insert that leaked the loser's pattern. The bound leaves ample room over the
working set and cache hits stay allocation-free (0 new, 0 malloc per 1000
constructions). New tests: lTrimAndRTrim, readBySeparator, splitCb, cacheIsBounded.
Release and AddressSanitizer suites pass 1216 tests each.
2026-09-18 17:12:13 -03:00
Martín Lucas Golini c100d93896 Fix String::trim on all-separator input. Fix RegEx freeing Oniguruma patterns.
String::trim: when the input consisted only of separators, both find_first_not_of
and find_last_not_of returned npos and the pos2 fallback computed length() - 1, so
trim("  ") returned " " and every all-separator value came back one character
shorter instead of empty, making an all-whitespace value look non-empty to callers.
All eight overloads were affected: std::string, std::string_view, String and
String::View, in their char and separator-set forms. Return an empty result when
there is no non-separator, and compute the trimmed range as
substr(pos1, pos2 - pos1 + 1).

RegEx: mCompiledPattern stores whichever engine compiled the pattern, a pcre2_code*
or an OnigRegex, but the destructor released it with pcre2_code_free() whenever
RegExCache did not own it. With useCache = false that freed an Oniguruma pattern as
a PCRE2 block, which corrupts the heap: constructing and destroying such a RegEx
crashes with SIGSEGV, a path snippetparser.cpp reaches by passing Utf |
AllowFallback with useCache = false. Release the pattern with the deallocator of the
engine recorded in Options::UseOniguruma, the predicate matches(), getCaptureCount()
and RegExCache::clear() already use, and remove the mOnigEngine flag, which was
never set or read anywhere.

Both fixes come with regression tests. String.trim covers the all-separator boundary
and the trimmed range of every overload. RegExEngines.uncachedPatternIsFreedByItsOwnEngine
destroys uncached patterns from both engines; it crashed the test binary before the fix.
2026-09-18 15:51:39 -03:00
Martín Lucas Golini 128abc692e Fix UIDropDown listbox mis-positioning.
Fix sort indicator in UIAbstractTableView not displaying when sorted.
2026-09-18 13:59:11 -03:00
Martín Lucas Golini c530e4bd6e feat: add cross-platform file association management
Add an EE::System::FileAssociation abstraction with XDG, Windows,
and macOS implementations.

Expose extensions from syntax predefinitions and add custom widget
support to UISettingsPanel. Add an ecode settings page for selecting
file associations and installing an XDG desktop entry.

Apply changes asynchronously with lifecycle-safe UI handling, disable
controls while applying, and avoid redundant XDG database updates.

Add translations and coverage for the new functionality.

Implements SpartanJ/ecode#192
2026-09-17 11:04:25 -03:00
Martín Lucas Golini 75ebe22a02 fix(accessibility): stabilize inactive backend benchmark timing
- expose whether native backend initialization has completed
  - distinguish completed initialization from backend availability
  - wait up to one second for asynchronous initialization in benchmark mode
  - exclude AT-SPI registration activity from notification timing
  - report backend readiness latency in benchmark results
  - verify disabled backends complete initialization immediately
2026-09-16 21:05:20 -03:00
Martín Lucas Golini 7866c27381 Merge branch 'develop' into feature/a11y 2026-09-16 20:14:46 -03:00
Martín Lucas Golini 4e3c2d966f ecode: allow deleting untracked files from Git status
- Add a Delete action for untracked files and the Untracked section, with
  confirmation before permanently removing the selected paths.

  - Decode Git-quoted status paths using new byte-oriented std::string
  String::escape() and String::unescape() overloads, preventing quoted or
  octal-escaped filenames from breaking deletion.

  - Add translations and regression tests for string escaping and quoted
  untracked paths.
2026-09-15 13:19:24 -03:00