Skip to content

gui_toolkit 0.50.0

Choose a tag to compare

@sachahjkl sachahjkl released this 28 Oct 07:11
· 301 commits to master since this release
v0.50.0
e63e86f

Added

  • font.glyph_outline and a neutral font.color_renderable: glyph_outline(state, face, gid, tolerance, out) hands a 2D canvas (or any glyph-path consumer) a glyph outline through the active backend (DirectWrite or the native Fontations backend) rather than a DirectWrite-only entry point, and color_renderable now answers on every system (off Windows the built-in COLR / CPAL interpreter draws colour faces). Both let an application draw glyph paths and build colour-font cascades the same way on every platform.
  • platform.raise_window(window) and platform.is_window_visible(window): bring an already-shown window to the front (Win32 SetForegroundWindow; X11 _NET_ACTIVE_WINDOW; a no-op on Wayland, where the compositor owns focus), and whether a window is on screen (mapped and not minimized). An application no longer calls Win32 for the "switch to this window" and "is this window visible" it needs around multi-window and capture flows.
  • Linux accessibility, IME and smaller desktop services (platform): a minimal AT-SPI 2 accessibility bridge over D-Bus (a11y_send / a11y_state / a11y_take_request expose the toolkit's neutral tree — roles, names, states, bounds, Invoke / Focus — to screen readers when one connects); input-method composition through Wayland zwp_text_input_v3 (ime_set_enabled, ime_set_cursor_rect, ime_preedit; committed text arrives as .Text events, and X11 composes dead keys through libxkbcommon); keeping the screen awake (idle_inhibit / idle_uninhibit through org.freedesktop.ScreenSaver); the recent-files list (add_recent_file to the freedesktop recently-used.xbel); and Wayland cursor shapes drawn by the compositor through wp_cursor_shape_v1.
  • Linux file dialogs, open-URL and live theme through the XDG portals (platform): open_file_dialog / save_file_dialog / pick_folder_dialog now use org.freedesktop.portal.FileChooser first (filters, multiple selection, a suggested name; it works under a sandbox), falling back to zenity / kdialog; open_url / open_path use org.freedesktop.portal.OpenURI; dark_mode_preferred reads the appearance portal's color-scheme and the new watch_color_scheme(cb) reports a live light / dark switch (the SettingChanged signal).
  • Linux tray icon and notifications (platform): tray_create / tray_notify and the rest of the tray API now work on Linux through the StatusNotifierItem specification over D-Bus, with its menu as a com.canonical.dbusmenu tree and notifications through org.freedesktop.Notifications (clicks, chosen menu items and notification results come back as Tray_Events). Same public API as the Windows backend; tray_create returns nil when there is no status-notifier host, as Windows does when the shell refuses an icon.
  • Linux cross-process clipboard and drag-and-drop (platform): the clipboard owner is now complete on both backends — a full Wayland wl_data_source offering text / HTML / PNG / text/uri-list (and reading a foreign owner over wl_data_offer.receive), the zwp_primary_selection_v1 primary selection, and an X11 SelectionRequest server with TARGETS / TIMESTAMP / MULTIPLE and INCR for large images; clipboard_get_image / _get_html / _get_files read whatever another process owns. Drag and drop works both ways with the same API as Windows (drop_target_enable, drop_data, drag_start, drop_inject): Wayland wl_data_device and X11 XDND version 5.
  • D-Bus client (dbus package): a small, pure-Odin D-Bus client for the toolkit's Linux desktop services, with no libdbus link (a binary starts on a machine without it and reports the bus unreachable). It connects to the session or system bus (connect_bus / connect_bus_address), authenticates with SASL EXTERNAL, does the Hello handshake, marshals and unmarshals the whole type system (basic types, strings, object paths, signatures, arrays, structs, dicts, variants, with the spec's alignment and byte order), calls methods synchronously (call) or asynchronously (call_async), subscribes to signals (subscribe), exports objects (export_object, request_name) and folds its socket into a program's own poll(2) loop (conn_fd, dispatch). dbus/*.odin, docs/dbus.md.
  • Test building blocks (testkit.Ports, testkit.process_state): a new package with the parts of a test harness that are pure Odin and not tied to any one application. Ports gives each test run its own block of test-server ports (an application sets a base-port environment variable, a default base and a span): the tests write the default ports and url / port move every address to the run's block so several worktrees test side by side, interning the results. process_state reads the process's resident and private memory, its open handle count and (on Windows) its GDI and USER object counts for endurance and leak tests, and memory_split (Windows) shows where the private bytes are — the heaps' allocated against committed, and the private committed pages outside the heaps split read-write vs executable. testkit/ports.odin, testkit/process_<os>.odin, tests/testkit, docs/testkit.md.
  • Single-instance mechanism (instance.acquire): a new package so an application can keep one running copy per named resource. The first process to start with a name owns it; a second start hands an opaque message to the first and comes forward instead of opening a second copy on the same state. The interface is platform-neutral — a name (key(prefix, path)), an optional identity token the owner checks so only a copy it trusts hands over, an opaque []byte message the package never reads, and a handler the owner runs while it pumps messages — with no window handle, executable semantics or OS type crossing it. Under it: a named mutex and a message-only window (WM_COPYDATA) on Windows, a flock lock file and a Unix socket in $XDG_RUNTIME_DIR on POSIX (instance_windows.odin, instance_linux.odin, instance_other.odin). An owner that is starting or closing is waited for; a silent one does not hold the second start. acquire, send, owner_start / owner_closing / owner_stop, pump_messages, raise_window, is_elevated. tests/instance, docs/instance.md.
  • Lifetime and ownership primitives (arena.Scope, arena.Pool): a new pure-Odin package with the two primitives an application builds its object graph on. A Scope owns a growing virtual-memory arena plus a reverse-order cleanup list and may have child scopes, so closing a scope closes its children, runs its cleanups and frees the arena in one go — an application is a tree of scopes and "close the view" frees everything without any subsystem keeping a list of what it owns (scope_make, scope_allocator, on_close, forget_cleanup, rebind_cleanup, run_cleanup, scope_close). A generational Pool gives fixed-address slots addressed by a Handle (a distinct u64, generation + index) that can never dangle: removing an object bumps the slot's generation so an old handle fails to resolve instead of reaching whatever reused the slot (pool_insert, pool_get, pool_valid, pool_remove, pool_handle_at, pool_next, pool_destroy). arena/scope.odin, arena/pool.odin, in-package tests, docs/arena.md.
  • Typed preference registry (config.Prefs): a new pure-Odin package — an about:config for any application. Every tunable is a named, typed, documented preference with a default, optional bounds or a choices list, a unit, and a layered source (default < user file < command line < policy, where a policy value also locks it). The registry validates every change, resolves a name to a Ref once so hot-path reads never hash a string, notifies observers by name prefix (config.watch, apply without a restart), persists only the user's changes atomically (save_user / load_file, values read before their definition applied later and surviving a round trip), snapshots and restores the whole set (snapshot / restore), and derives readable titles, a first-sentence summary and a word search for a settings UI (title_of, summary_of, matches). config/config.odin, config/snapshot.odin, config/titles.odin, in-package tests, docs/config.md.
  • platform.monitor_size(window): the pixel size of the monitor a window is on, neutral across systems (Win32 MonitorFromWindow + GetMonitorInfoW, the Wayland wl_output mode, or the X11 root screen). An application that wants a fixed surface the size of the screen (render.set_fixed_surface) no longer needs its own Win32 call.
  • Linux desktop services (platform): file dialogs (open_file_dialog / save_file_dialog / pick_folder_dialog) through zenity or kdialog; open_url / open_path / reveal_in_folder through xdg-open; known_folder_path from the XDG user directories; light / dark (dark_mode_preferred) and reduce-motion (os_animations_enabled) from the GTK settings; the rich clipboard (clipboard_set / clipboard_get_*) with text carried over the X11 CLIPBOARD selection and the Wayland wl_data_device, and HTML / image / files kept by the owner. render/wgpu_surface_linux.odin builds the wgpu surface from Surface_Handles (Wayland / XCB) for the renderer's Linux path.
  • wgpu is the renderer's Linux backend: on a non-Windows target render builds the WebGPU backend only (TOOLKIT_RENDER is ignored there and USE_WGPU is forced on). The Direct3D 11 backend (render_d3d.odin, frame.odin, the canvas, slug, video, app-shader and damage files) is now built only for the Direct3D backend (when !USE_WGPU, Windows); the shared types (Renderer, Texture_Data, the frame description) and the backend-agnostic procedures build on every system. The wgpu surface comes from platform.Surface_Handles (Wayland wl_display + wl_surface, or XCB connection + window); present pacing on Linux is the FIFO vblank (there is no DWM timing or waitable-timer latency object). wgpu-native must be built for Linux (libwgpu_native.a).
  • Linux window backend (platform): platform.open_window and the whole window / input API now run on Linux, over Wayland (xdg-shell, wl_seat with an xkbcommon keymap, wl_output scale for DPI, zxdg-decoration or a client-side title bar) and X11 (XCB, xkbcommon, Xft.dpi, _NET_WM_STATE, Motif hints), chosen at open from WAYLAND_DISPLAY / DISPLAY. Every window library is loaded with dlopen (libwayland-client, libxcb, libxkbcommon), so a binary starts on a system missing one and names it; nothing is hard-linked. The same Window, Event, Key, Cursor, Placement types as the Win32 backend — an application written against platform does not change.
  • Text catalogue (i18n.tr): a new pure-Odin package so an application can be translated without going through its code again. tr is a procedure group with three forms — tr(text), tr(context, text) (a translator's context for two meanings of one English word) and tr(count, one, other) (count-dependent forms, the choice left to the language). The English literal is the key; today each call returns its argument (same bytes, no lookup, no allocation), so a call in an interface drawn every frame is free, and a language can later swap in one flat pointer-keyed table without any other change. i18n/i18n.odin, tests/i18n, docs/i18n.md.
  • Partial redraw (damage regions) (render.set_partial_redraw, draw.damage): the renderer can now repaint and present only the part of the window that changed since the last frame (a caret, a hover, a progress bar, a video, a local animation) instead of the whole window. The application opens a region with damage_begin and marks changed boxes with damage_add / damage (and damage_scroll for a scrolled view); the region is the bounded union of the boxes (near ones merged). The renderer clips every frame-target batch to the region, clears only the region, and presents it: Direct3D 11 with Present1 dirty rectangles and a buffer-age redraw for the flip swap chain's un-kept back buffers; WebGPU composes into a persistent target and copies it to the surface (wgpu-native has no present-with-damage yet, a documented limit). A frame that marks nothing draws and presents nothing. render.damage.verify (set_damage_verify, or TOOLKIT_DAMAGE_VERIFY=1) renders every frame in full too and reports the first pixel that differs. Off by default (the whole window every frame, as before). render/damage.odin, render/damage_d3d.odin, render/damage_wgpu.odin, render/damage_verify.odin, draw/damage.odin; docs/draw.md, docs/webgpu.md.
  • font.color_glyph_rgba, font.glyph_is_color, font.Color_Glyph: rasterize one color glyph (COLR / CPAL, sbix, CBDT, SVG) to a straight-alpha RGBA bitmap at an exact em size, with the offset from the pen to the bitmap, outside the glyph atlas and the draw layer, for a caller that composites it itself (a 2D canvas drawing emoji in fillText). It reuses the COLR interpreter for the glyphs it owns and Direct2D otherwise; fg colors foreground / text-color layers. The signature is platform-neutral; off Windows the functions compile and report no color glyph until a portable rasterizer lands. See docs/text.md.
  • font.cascade language: a cascade now carries the content's BCP 47 language (cascade(s, entries, features, no_system_fallback, language)), and the shaper passes it to the backend as the shaping locale (DirectWrite's GetGlyphs / GetGlyphPlacements locale name, HarfRust's buffer language). Faces then apply their language-specific forms (locl): Serbian and Macedonian Cyrillic, Han unification of CJK ideographs, Romanian ș/ț, and so on. Empty keeps the previous default (no locale), and two cascades differing only in language are distinct Font_Ids, so the word cache tells them apart. See docs/text.md.
  • Frame capture on WebGPU (render.capture_request / render.capture_poll): reading a frame back without the screen now works with the WebGPU backend, not only Direct3D 11. Before the present, frame_end copies the frame target (surface or offscreen, in whole or in part) into a mappable buffer; capture_poll maps it without waiting (Pending until the GPU is done) and returns straight RGBA8 with sRGB values and alpha forced to 255, the same picture the Direct3D path gives. It costs nothing until a capture is asked for, and works with the window covered, off the screen, hidden or minimized (render/capture.odin).
  • render.surface_* on WebGPU: a second window drawn by the same renderer now works with the WebGPU backend, not only Direct3D 11. surface_init / surface_use / surface_destroy create a per-window WebGPU surface (with its own present and latency state, and the DirectComposition visual for a translucent window) and swap it with the renderer's window state, mirroring the Direct3D path. The device, queue and pipelines stay shared (wgpu_surface.odin).

Changed

  • platform API made system-neutral: platform.wake_handle now returns an opaque rawptr (paired with the new platform.wake_signal) instead of a Win32 HANDLE, and the new platform.native_surface_handles hands a renderer the window's native handles through a neutral Surface_Handles (Windows HWND, Wayland wl_display + wl_surface, or X11 connection + window) so render can make a surface on any system without a Win32 type in the signature.
  • render.init takes a neutral surface, not an HWND: render.init(&r, surface: platform.Surface_Handles, size, transparent, space) opens the renderer on the native handles the platform package fills (platform.native_surface_handles(window)), the HWND on Windows and the Wayland or XCB handles on Linux; render.init_window(&r, window, size, ...) is the convenience form. surface_init / surface_create (second windows) take the same neutral handles. No Direct3D, DXGI or Win32 type appears in the renderer's public signatures.