First commit. Version 0.1.0

This commit is contained in:
2026-05-10 09:58:23 +02:00
parent af105b7f7d
commit bbab5e238d
635 changed files with 53627 additions and 175 deletions
Executable
+429
View File
@@ -0,0 +1,429 @@
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
// Inside `unsafe fn` bodies, every unsafe op must still be wrapped in
// its own `unsafe { ... }` block. Without this lint the compiler treats
// the whole body as one implicit `unsafe` scope and a SAFETY: comment
// per call site becomes impossible to enforce — the kind of drift that
// hides UB in renderer code where every glow::* call is `unsafe fn`.
#![ deny( unsafe_op_in_unsafe_fn ) ]
//! # ltk — Liberux ToolKit
//!
//! A lightweight Wayland UI toolkit built on top of
//! [smithay-client-toolkit](https://crates.io/crates/smithay-client-toolkit),
//! [tiny-skia](https://crates.io/crates/tiny-skia) and
//! [fontdue](https://crates.io/crates/fontdue).
//!
//! ltk is the UI toolkit for the Liberux desktop. The Liberux compositor (Forge)
//! handles window management, decorations, and positioning — ltk focuses on
//! rendering the content of each Wayland surface.
//!
//! `ltk` is also a public library for third-party developers building native
//! Wayland applications. If you are approaching the crate through `cargo doc`,
//! the API is grouped conceptually into three navigation modules:
//!
//! - [`window`] — the basic application window path most apps should start with
//! - [`shell`] — layer-shell and overlay APIs for shell-like surfaces
//! - [`runtime`] — advanced runtime hooks, invalidation, channels, and
//! runtime-free embedding via [`core::UiSurface`]
//!
//! ## Quick start
//!
//! ```rust,no_run
//! use ltk::{App, Element, column, text, button, spacer, Color, ButtonVariant};
//!
//! #[derive(Clone)]
//! enum Msg { Quit }
//!
//! struct MyApp;
//!
//! impl App for MyApp
//! {
//! type Message = Msg;
//!
//! fn view( &self ) -> Element<Msg>
//! {
//! column()
//! .push( text( "Hello, ltk!" ).size( 32.0 ).color( Color::WHITE ) )
//! .push( spacer() )
//! .push( button( "Quit" ).on_press( Msg::Quit ) )
//! .into()
//! }
//!
//! fn update( &mut self, msg: Msg )
//! {
//! match msg { Msg::Quit => std::process::exit( 0 ) }
//! }
//! }
//!
//! fn main() { ltk::run( MyApp ); }
//! ```
//!
//! ## Architecture
//!
//! - **[`App`]** trait — implement this to define your application.
//! - **[`Element`]** enum — the widget tree returned by [`App::view`].
//! - Widgets, layouts and primitive types are listed below in their own
//! sidebar sections; the [`widgets`], [`layouts`] and [`types`] modules
//! are concept-oriented landing pages that `cargo doc` exposes for the
//! same set, grouped by category.
//!
//! ## Widgets
//!
//! The interactive and decorative leaves of the [`Element`] tree:
//!
//! - **Buttons / activations** — [`button()`], [`icon_button`],
//! [`pressable`], [`window_button`], [`list_item()`].
//! - **Stateful binary controls** — [`toggle()`], [`checkbox()`],
//! [`radio()`].
//! - **Continuous controls** — [`slider()`], [`vslider()`],
//! [`progress_bar()`].
//! - **Text** — [`text()`], [`text_edit()`].
//! - **Decoration** — [`container()`], [`separator()`], [`img_widget()`].
//! - **Clipping wrappers** — [`scroll()`], [`viewport()`], [`flex()`].
//! - **Modal overlays** — [`dialog()`] (centered confirmation card with
//! optional title, subtitle, custom body and action row; built-in
//! scrim, ESC-to-cancel, and tap-outside-to-dismiss for the
//! non-modal variant).
//!
//! See [`widgets`] for the grouped landing page and
//! `docs/widgets.md` for the per-widget catalogue.
//!
//! ## Layouts
//!
//! Composable arrangers for [`Element`] trees:
//!
//! - [`column()`] — vertical flow.
//! - [`row()`] — horizontal flow.
//! - [`stack()`] — z-order overlay with per-child alignment.
//! - [`grid()`] — fixed-column-count wrapping grid.
//! - [`spacer()`] — invisible flexible filler.
//!
//! See [`layouts`] for the grouped landing page.
//!
//! ## Types
//!
//! Geometry and primitive values that flow through every builder:
//!
//! - [`Color`], [`Rect`], [`Point`], [`Size`], [`Corners`], [`WidgetId`].
//!
//! See [`types`] for the full module with `//!` description.
//!
//! ## Runtime-free embedding
//!
//! Use [`core::UiSurface`] when you need ltk's layout, drawing and
//! hit-testing without [`run()`] — typically for compositor-side
//! decorations, embedding ltk widgets in another render loop, or
//! offscreen rendering / previews.
//!
//! ## Licence and third-party assets
//!
//! `ltk` itself is distributed under `LGPL-2.1-only`. The default
//! theme bundles two third-party asset sets that travel under their
//! own licences and must be credited when the toolkit (or a binary
//! that embeds the default theme) is redistributed:
//!
//! - **Symbolic icons** under `themes/default/icons/catalogue/` —
//! Streamline's *Core Line Free* set, [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/),
//! © Streamline. Some files modified for the symbolic-tinting
//! pipeline; details in `themes/default/icons/catalogue/LICENSE.md`.
//! Upstream: <https://www.streamlinehq.com/icons/core-line-free>.
//! - **Sora Regular** (`src/theme/fallback/Sora-Regular.otf`) — the
//! embedded font fallback, [SIL OFL 1.1](https://scripts.sil.org/OFL),
//! © The Sora Project Authors, Jonathan Barnbrook, Julián Moncada.
//!
//! The remaining artwork in the default theme (wallpapers, lockscreens,
//! launcher logo, brand-mark variants, per-application icons) is
//! original to Liberux Labs and travels under the toolkit's own
//! `LGPL-2.1-only` licence. The full Debian-style declaration lives in
//! `debian/copyright` of the source tree.
// Load YAML locale files from `ltk/locales/*.yaml`. The `t!()` macro is
// re-exported (see below) so consuming applications can also use it; their
// own `i18n!()` invocations merge into the same runtime registry. The
// fallback locale is English — built-in widget strings always have an
// English entry.
rust_i18n::i18n!( "locales", fallback = "en" );
pub mod types;
pub( crate ) mod render;
pub( crate ) mod system_fonts;
pub( crate ) mod widget;
pub( crate ) mod layout;
pub( crate ) mod app;
pub mod theme;
pub mod wallpaper;
pub( crate ) mod tree;
pub( crate ) mod draw;
pub( crate ) mod input;
pub( crate ) mod event_loop;
pub( crate ) mod secure_mem;
pub mod gles_render;
pub mod egl_context;
pub mod core;
pub use app::
{
Anchor, App, ChannelSender, ShellMode, Layer, OverlayId, OverlaySpec,
InvalidationScope, SurfaceTarget,
};
pub use theme::
{
Palette, ThemeMode, ThemePreference, ThemeError,
ThemeDocument, Mode, SlotStore,
WallpaperSpec, WallpaperFit, LauncherSpec, WindowControlsSpec,
active_document, active_mode, active_theme_id,
is_fallback_active,
set_active_document, set_active_mode,
tint_symbolic,
};
pub use theme::{ color as theme_color, color_or as theme_color_or };
pub use theme::{ paint as theme_paint, shadows as theme_shadows };
pub use theme::{ surface as theme_surface, text_style as theme_text_style };
pub use theme::resolve_surface as theme_resolve_surface;
pub use theme::palette as theme_palette;
pub use theme::window_controls as theme_window_controls;
pub use theme::wallpaper as theme_wallpaper;
pub use theme::lockscreen as theme_lockscreen;
pub use theme::app_icon as theme_app_icon;
pub use theme::app_default_icon as theme_app_default_icon;
pub use theme::launcher_icon as theme_launcher_icon;
pub use theme::logo as theme_logo;
pub use theme::logo_square as theme_logo_square;
pub use theme::logo_horizontal as theme_logo_horizontal;
pub use theme::branding_asset as theme_branding_asset;
pub use theme::branding_raster as theme_branding_raster;
pub use theme::branding_image as theme_branding_image;
pub use theme::{ decode_svg_bytes, icon_path as theme_icon_path, icon_rgba as theme_icon_rgba };
pub use gles_render::{ BorrowedGlesTexture, GlesVersion };
pub use render::is_software_render;
pub use wallpaper::{ WallpaperBundle, ImageData };
pub use types::{ Color, Corners, CursorShape, Point, Rect, Size, WidgetId };
pub use widget::{ Element, button, icon_button, text_edit, image as img_widget, text, container };
pub use widget::button::ButtonVariant;
pub use widget::slider::{ Slider, slider, SliderAxis };
pub use widget::vslider::{ VSlider, vslider };
pub use widget::text::TextAlign;
pub use widget::toggle::{ Toggle, toggle };
pub use widget::separator::{ Separator, separator };
pub use widget::progress_bar::{ ProgressBar, progress_bar };
pub use widget::checkbox::{ Checkbox, checkbox };
pub use widget::radio::{ Radio, radio };
pub use widget::list_item::{ ListItem, list_item };
pub use widget::window_button::{ WindowButton, WindowButtonKind, window_button, window_controls };
pub use widget::pressable::{ Pressable, pressable };
pub use widget::flex::{ Flex, flex };
pub use widget::combo::{ Combo, ComboState, combo };
pub use widget::spinner::{ Spinner, spinner };
pub use widget::tab_bar::{ TabBar, tabs };
pub use widget::toast::{ Toast, toast };
pub use widget::tooltip::{ Tooltip, tooltip };
pub use widget::notebook::{ Notebook, NotebookPage, notebook };
pub use widget::external::{ External, ExternalSource };
pub use widget::external as widget_external;
pub use widget::date_picker::
{
Date, DatePicker, Locale as DateLocale, date_picker,
is_leap_year, days_in_month, day_of_week, add_months,
};
pub use widget::time_picker::{ Time, TimePicker, time_picker };
pub use widget::color_picker::
{
ColorPicker, color_picker, color_to_hex, parse_hex,
};
pub use widget::dialog::{ Dialog, dialog };
pub use layout::spacer::{ Spacer, spacer };
pub use layout::column::{ Column, column };
pub use layout::row::{ Row, row };
pub use layout::stack::{ Stack, stack, HAlign, VAlign };
// push_aligned_margin is available as a method on Stack — no separate re-export needed.
pub use layout::wrap_grid::{ WrapGrid, grid };
pub use widget::scroll::scroll;
pub use widget::viewport::{ Viewport, viewport };
pub use app::run;
pub use app::{ try_run, RunError };
pub use smithay_client_toolkit::seat::keyboard::Keysym;
/// Widgets — the interactive and decorative leaves of the [`Element`]
/// tree.
///
/// Concept-oriented sidebar entry: every widget the toolkit ships is also
/// available at the crate root (`ltk::button`, `ltk::toggle`, …); this
/// module groups them so `cargo doc` shows a single landing page when you
/// are looking for "what controls can I draw".
///
/// See [`docs/widgets.md`](https://github.com/liberux/ltk/blob/master/docs/widgets.md)
/// for the per-widget catalogue with usage notes and minimal examples.
pub mod widgets
{
pub use crate::
{
// Buttons / activations
button, icon_button,
Pressable, pressable,
WindowButton, WindowButtonKind, window_button, window_controls,
ListItem, list_item,
// Stateful binary controls
Toggle, toggle,
Checkbox, checkbox,
Radio, radio,
// Continuous controls
Slider, slider, SliderAxis,
VSlider, vslider,
ProgressBar, progress_bar,
// Composite picker
Combo, ComboState, combo,
// Activity / hint indicators
Spinner, spinner,
// Segmented selector + paginated tabs
TabBar, tabs,
Notebook, NotebookPage, notebook,
// Date / time / color pickers
Date, DatePicker, DateLocale, date_picker,
Time, TimePicker, time_picker,
ColorPicker, color_picker, color_to_hex, parse_hex,
// Transient overlays (return OverlaySpec)
Toast, toast,
Tooltip, tooltip,
// Modal / non-modal centered overlays
Dialog, dialog,
// Text input and display
text, text_edit, TextAlign,
// Decoration and chrome
container, Separator, separator,
img_widget,
// Clipping wrappers
scroll,
Viewport, viewport,
Flex, flex,
// Button styling token
ButtonVariant,
};
}
/// Layouts — composable arrangers for [`Element`] trees.
///
/// Concept-oriented sidebar entry. Each layout has a free constructor
/// (`column()`, `row()`, …) and a builder-style API for spacing, padding
/// and alignment. Layouts and [widgets] share the same `Element<Msg>`
/// tree.
pub mod layouts
{
pub use crate::
{
Column, column,
Row, row,
Stack, stack, HAlign, VAlign,
WrapGrid, grid,
Spacer, spacer,
};
}
/// Basic application-window API.
///
/// Start here if you are building a normal Wayland client window.
///
/// This module is documentation-first: it re-exports the common entry points
/// that most applications need so `cargo doc` presents a smaller and more
/// approachable surface before the user gets into overlays, gestures, and
/// shell-specific features.
///
/// The default path is:
///
/// 1. implement [`App`]
/// 2. return an [`Element`] tree from [`App::view`]
/// 3. mutate state in [`App::update`]
/// 4. start the event loop with [`run`]
///
/// If you are looking for layer-shell, overlays, or advanced runtime hooks,
/// move on to [`crate::shell`] or [`crate::runtime`].
pub mod window
{
pub use crate::
{
App, ButtonVariant, Color, Element, Keysym, Point, Rect, Size,
Column, Row, Stack, WrapGrid, Spacer,
button, icon_button, text, text_edit, img_widget,
container, checkbox, radio, toggle, separator,
progress_bar, list_item, slider, vslider, scroll, viewport,
column, row, stack, grid, spacer,
TextAlign, SliderAxis,
run,
};
}
/// Shell and layer-surface API.
///
/// Use this module when you are building shell-like surfaces rather than a
/// plain application window:
///
/// - panels
/// - docks
/// - homescreens
/// - greeters
/// - lock screens
/// - transient overlays
///
/// These items are also available at the crate root; this module exists so
/// `cargo doc` exposes a concept-oriented entry point for layer-shell users.
pub mod shell
{
pub use crate::
{
Anchor, App, Layer, OverlayId, OverlaySpec, ShellMode,
SurfaceTarget, InvalidationScope,
WindowButton, WindowButtonKind, window_button, window_controls,
};
}
/// Advanced runtime and embedding API.
///
/// This module groups the hooks that are useful once the basic app-window flow
/// is no longer enough:
///
/// - external wakeups via [`ChannelSender`]
/// - redraw narrowing via [`InvalidationScope`]
/// - surface-level invalidation targets via [`SurfaceTarget`]
/// - runtime-free embedding with [`crate::core::UiSurface`]
/// - direct theme/runtime state access
///
/// Most applications do not need to start here.
pub mod runtime
{
pub use crate::
{
ChannelSender, InvalidationScope, SurfaceTarget,
Palette, ThemeDocument, ThemeError, ThemeMode, ThemePreference,
WallpaperBundle, ImageData,
active_document, active_mode, active_theme_id,
is_fallback_active,
set_active_document, set_active_mode,
theme_color, theme_color_or, theme_paint, theme_palette,
theme_resolve_surface, theme_shadows, theme_surface, theme_text_style,
theme_wallpaper, theme_lockscreen, theme_window_controls,
theme_branding_asset, theme_branding_raster, theme_branding_image,
tint_symbolic,
};
pub use crate::core::{ RenderOptions, RenderOutput, UiSurface };
}
/// Internal helpers re-exported for the integration tests under `tests/` and
/// the criterion benches under `benches/`. The items themselves are `pub` but
/// live inside `pub(crate)` modules, so the only path that reaches them from
/// outside the crate is `ltk::test_support::*` — which is exactly what test
/// crates (and benches, which are also external) need.
///
/// **Not part of the stable public API.** Anything in here may change between
/// patch releases without notice. Hidden from generated docs via
/// `#[doc(hidden)]` for the same reason.
#[ doc( hidden ) ]
pub mod test_support
{
pub use crate::tree::{ find_widget_at, find_widget, find_handlers, next_focusable_index };
pub use crate::widget::{ LaidOutWidget, WidgetHandlers };
pub use crate::widget::slider::{ value_from_x_in_rect, value_from_pos_in_rect, SliderAxis };
pub use crate::widget::vslider::value_from_y_in_rect;
pub use crate::event_loop::diff_overlay_ids;
}