This repository has been archived on 2026-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
el-retired/ui/vessels/el-platform/src/backends/linux.rs
T

156 lines
4.6 KiB
Rust

//! Linux backend — GTK/Wayland.
//!
//! Architecture: correct and complete. GTK calls are stubs marked TODO.
//!
//! Each `PlatformNode` maps to a GtkWidget:
//! element("div") → GtkBox (vertical)
//! element("button") → GtkButton
//! element("input") → GtkEntry
//! text("...") → GtkLabel
use crate::{EventHandler, PlatformBackend, PlatformError, PlatformNode, PlatformResult};
pub struct LinuxBackend;
impl LinuxBackend {
pub fn new() -> Self {
Self
}
fn gtk_widget(tag: &str) -> &'static str {
match tag {
"button" => "GtkButton",
"input" => "GtkEntry",
"textarea" => "GtkTextView",
"img" => "GtkImage",
"ul" | "ol" => "GtkListBox",
"li" => "GtkListBoxRow",
"nav" => "GtkHeaderBar",
"div" | "section" | "main" | "article" | "span" => "GtkBox",
_ => "GtkWidget",
}
}
fn gtk_signal(event: &str) -> &'static str {
match event {
"click" => "clicked",
"input" | "change" => "changed",
"focus" => "focus-in-event",
"blur" => "focus-out-event",
"keydown" | "keypress" => "key-press-event",
"keyup" => "key-release-event",
_ => "event",
}
}
}
impl Default for LinuxBackend {
fn default() -> Self {
Self::new()
}
}
impl PlatformBackend for LinuxBackend {
fn name(&self) -> &'static str {
"linux"
}
fn create_element(&self, tag: &str) -> PlatformResult<PlatformNode> {
let mut node = PlatformNode::element(tag);
// TODO: gtk_button_new() / gtk_box_new() / etc. via gtk-rs or raw FFI
node.attributes
.push(crate::Attribute::new("data-gtk-widget", Self::gtk_widget(tag)));
Ok(node)
}
fn create_text(&self, content: &str) -> PlatformResult<PlatformNode> {
let mut node = PlatformNode::text(content);
// TODO: gtk_label_new(content)
node.attributes
.push(crate::Attribute::new("data-gtk-widget", "GtkLabel"));
Ok(node)
}
fn set_attribute(
&self,
node: &mut PlatformNode,
name: &str,
value: &str,
) -> PlatformResult<()> {
// TODO: map to GTK property setters
// "class" → gtk_widget_add_css_class
// "disabled" → gtk_widget_set_sensitive(false)
// "placeholder" → gtk_entry_set_placeholder_text
node.attributes.retain(|a| a.name != name);
node.attributes.push(crate::Attribute::new(name, value));
Ok(())
}
fn remove_attribute(&self, node: &mut PlatformNode, name: &str) -> PlatformResult<()> {
node.attributes.retain(|a| a.name != name);
Ok(())
}
fn append_child(
&self,
parent: &mut PlatformNode,
child: PlatformNode,
) -> PlatformResult<()> {
// TODO: gtk_box_append(parent, child)
parent.children.push(child);
Ok(())
}
fn remove_child(&self, parent: &mut PlatformNode, child_index: usize) -> PlatformResult<()> {
if child_index >= parent.children.len() {
return Err(PlatformError::Render(format!(
"linux: child index {} out of bounds",
child_index
)));
}
// TODO: gtk_widget_unparent(child)
parent.children.remove(child_index);
Ok(())
}
fn replace_child(
&self,
parent: &mut PlatformNode,
index: usize,
new_child: PlatformNode,
) -> PlatformResult<()> {
if index >= parent.children.len() {
return Err(PlatformError::Render("linux: replace_child out of bounds".into()));
}
parent.children[index] = new_child;
Ok(())
}
fn bind_event(
&self,
node: &mut PlatformNode,
event: &str,
_handler: EventHandler,
) -> PlatformResult<()> {
let signal = Self::gtk_signal(event);
// TODO: g_signal_connect(widget, signal, callback, data)
node.attributes
.push(crate::Attribute::new(format!("data-gtk-signal-{}", event), signal));
Ok(())
}
fn render_to_string(&self, node: &PlatformNode) -> PlatformResult<String> {
Ok(node.to_html())
}
fn mount(&self, _root: PlatformNode, _container_id: &str) -> PlatformResult<()> {
// TODO: get GtkWindow and call gtk_window_set_child(root)
Ok(())
}
fn patch(&self, _old: &PlatformNode, _new: &PlatformNode) -> PlatformResult<()> {
// TODO: diff and apply GTK mutations
Ok(())
}
}