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
+102
View File
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Surface chrome: the client-side title bar and the Wayland input
//! region. Both are backend-agnostic — the software and GPU draw
//! paths call them with a `&mut Canvas` / a `&WlSurface` and get back
//! the geometry they need for hit testing + commit.
use smithay_client_toolkit::compositor::{ CompositorState, Region };
use smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface;
use crate::render::Canvas;
use crate::types::{ Color, Rect };
/// Paint the client-side title bar (close button, divider, title text).
///
/// Returns the close button rect in physical pixels so the caller can
/// store it for hit testing. Returns `Rect::default()` when `tb_h <=
/// 0` — overlays / layer-shell surfaces have no title bar.
pub( crate ) fn draw_titlebar( canvas: &mut Canvas, title: &str, pw: u32, tb_h: f32, sf: f32 ) -> Rect
{
if tb_h <= 0.0 { return Rect::default(); }
let tb_rect = Rect { x: 0.0, y: 0.0, width: pw as f32, height: tb_h };
canvas.fill_rect( tb_rect, Color::rgb( 0.15, 0.15, 0.18 ), 0.0 );
let title_size = 15.0;
// `Canvas::draw_text` interprets `y` as the baseline. Match the
// vertical-centring formula used by `Button::draw_text_button` so
// chrome and content text lines line up at the same optical height.
let title_y = ( tb_h + title_size * sf ) / 2.0 - 2.0;
let title_w = canvas.measure_text( title, title_size );
let title_x = ( pw as f32 - title_w ) / 2.0;
canvas.draw_text( title, title_x, title_y, title_size, Color::WHITE );
let btn_size = tb_h - 8.0 * sf;
let btn_x = pw as f32 - btn_size - 8.0 * sf;
let btn_y = 4.0 * sf;
let close_rect_phys = Rect { x: btn_x, y: btn_y, width: btn_size, height: btn_size };
canvas.fill_rect( close_rect_phys, Color::rgba( 1.0, 1.0, 1.0, 0.1 ), 4.0 * sf );
let cx = btn_x + btn_size / 2.0;
let cy = btn_y + btn_size / 2.0;
let arm = btn_size * 0.25;
canvas.draw_line( cx - arm, cy - arm, cx + arm, cy + arm, Color::WHITE, 2.0 * sf );
canvas.draw_line( cx + arm, cy - arm, cx - arm, cy + arm, Color::WHITE, 2.0 * sf );
canvas.draw_line( 0.0, tb_h - 0.5, pw as f32, tb_h - 0.5, Color::rgba( 1.0, 1.0, 1.0, 0.15 ), 1.0 );
close_rect_phys
}
/// Stamp a red warning banner at the top of the surface when the
/// active theme came from the in-memory B/W fallback (i.e.
/// [`crate::theme::is_fallback_active`] returned `true`). Gives the
/// user a clear visual cue that `ltk-theme-default` is missing.
///
/// Paints a thin red strip across the top of the surface (24 px
/// logical) with the install-instruction text. When the fallback is
/// not active this is a no-op.
pub( crate ) fn draw_fallback_banner(
canvas: &mut Canvas,
pw: u32,
sf: f32,
)
{
if !crate::theme::is_fallback_active() { return; }
let banner_h = 24.0 * sf;
let rect = Rect { x: 0.0, y: 0.0, width: pw as f32, height: banner_h };
canvas.fill_rect( rect, Color::rgb( 0.75, 0.10, 0.10 ), 0.0 );
let msg = "ltk: fallback theme — install `ltk-theme-default`";
let size = 12.0;
let msg_w = canvas.measure_text( msg, size );
let x = ( ( pw as f32 - msg_w ) / 2.0 ).max( 6.0 * sf );
let y = ( banner_h - size * sf ) / 2.0;
canvas.draw_text( msg, x, y, size, Color::WHITE );
}
/// Apply or clear the surface's input region (set by
/// `App::input_region`). `None` restores the default of "receive
/// input everywhere"; `Some(&[])` makes the surface pointer-through.
pub( crate ) fn apply_input_region(
wl_surface: &WlSurface,
compositor: &CompositorState,
input_region: Option<&[Rect]>,
)
{
if let Some( regions ) = input_region
{
if let Ok( region ) = Region::new( compositor )
{
for r in regions
{
region.add( r.x as i32, r.y as i32, r.width as i32, r.height as i32 );
}
wl_surface.set_input_region( Some( region.wl_region() ) );
}
} else {
wl_surface.set_input_region( None );
}
}