DEV Community

Building a GUI from scratch in Rust - how IONA OS does compositing, widgets, and applications

Why Build a GUI from Scratch?

Most operating systems use an existing toolkit:

  • Linux โ†’ GTK / Qt / EFL
  • Windows โ†’ Win32 / WPF / UWP
  • macOS โ†’ AppKit / SwiftUI

These toolkits are mature, well-tested, and save time. So why did I build my own? Because I wanted sovereignty over every pixel.

  • No external dependencies - I don't import Qt or GTK.
  • No license restrictions - I own the entire stack.
  • No bloat - I only implement what I need.
  • No legacy - I start from a clean slate.

And because writing a GUI from scratch is one of the most satisfying engineering challenges you can take on.

The Architecture

The GUI in IONA OS has three layers:

Layer 1: The Compositor (src/gui/compositor.rs)

The compositor is the heart of the GUI. It manages windows, handles input, and draws the desktop.

  • Glass compositor - windows are rendered with blur and transparency.
  • Double-buffered - no flicker.
  • Event-driven - input events are dispatched to the active window.

Layer 2: The Widgets (src/gui/widgets/)

Buttons, text inputs, scrollbars, tabs - all are written from scratch. Each widget is a struct that implements a Widget trait:

pub trait Widget {
    fn draw(&self, pixels: &mut [u32], width: usize, height: usize);
    fn handle_event(&mut self, event: &Event) -> bool;
}

This allows me to compose complex UIs from simple building blocks.

Layer 3: The Applications (src/gui/apps/)

Applications are normal Rust code that use the widget system.

  • Browser - simple web view with scrollbar and navigation.
  • Terminal - with scrollback and visual scrollbar.
  • Mail - list of messages, with scroll and selection.
  • Notes - simple text editor.
  • Calendar - month view with navigation.
  • Monitor - system metrics (CPU, RAM, processes).
  • Bluetooth - device management.
  • Clock - with timer and stopwatch.
  • Benchmark - performance testing.

Vector Icons - From Blob to Distinct

Until recently, some icons in the dock and launcher were generic blobs. Now, every application has a distinct vector shape:

Application Icon Description
Notes ๐Ÿ“ Notepad with lines
Backup ๐Ÿ’พ Floppy disk
Vault ๐Ÿ”‘ Key shape
Bluetooth ๐Ÿ”— Connected nodes
Text Editor โœ๏ธ Pencil

The icons are drawn using anti-aliased vector primitives (circles, rings, rectangles, lines). No images, no fonts - just code.

Scrollbars - Finally Real

Several applications had scrollable content but no visual scrollbar. Now they all use a common helper:

pub fn draw_scrollbar_buf(
    pixels: &mut [u32],
    width: usize,
    height: usize,
    scroll: &mut ScrollState,
    total: usize,
    visible: usize,
) {
    // Draw a thumb on the right side
}

This centralises the logic, so every application gets the same visual style, and I don't have to implement scrollbars six times.

Applications That Actually Work

The recent polish session fixed several UI bugs:

  • Monitor - q and r keys now work. Process names are truncated on UTF-8 boundaries, not raw bytes.
  • Shell - keyboard input now reaches the CLI. All screens (dashboard, policy, recovery, services, operator, governor) are now usable.
  • Bluetooth - all commands (1/2/s/p/c/u) now work. Errors are displayed, not silently dropped.
  • Sovereign Apps - the AI chat now accepts keyboard input. MeshRadar now shows real data, not hardcoded numbers.
  • Browser - toolbar now has real icons for Back, Forward, Refresh, Close, Lock, and Unlock.
  • Terminal - now has a real scrollbar for scrollback.

What Makes This GUI Different

  • No external dependencies - every line is written by me.
  • Integrated with the kernel - applications can call kernel syscalls directly.
  • Built for Rust - the entire GUI is written in safe Rust (with minimal unsafe for pixel access).
  • Sovereign - I control the entire stack, from compositor to application.

What's Next

IONA OS is still in active development. The GUI is getting polished, the kernel is stable, and the AI is growing. The first public ISO is scheduled for September 15, 2026.

If you're interested in seeing more:

Comments

No comments yet. Start the discussion.