7 releases

new 0.3.2 Oct 27, 2025
0.3.1 Oct 18, 2025
0.2.0 Sep 13, 2025
0.1.2 Jul 17, 2025

#1882 in GUI

Download history 146/week @ 2025-07-13 49/week @ 2025-07-20 7/week @ 2025-07-27 2/week @ 2025-08-03 1/week @ 2025-08-10 6/week @ 2025-08-17 4/week @ 2025-08-24 19/week @ 2025-08-31 96/week @ 2025-09-07 92/week @ 2025-09-14 27/week @ 2025-09-21 15/week @ 2025-09-28 206/week @ 2025-10-05 120/week @ 2025-10-12 121/week @ 2025-10-19 151/week @ 2025-10-26

598 downloads per month
Used in winio

MIT license

155KB
4K SLoC

Rust 3.5K SLoC C++ 430 SLoC

Winio

Winio is a single-threaded asynchronous GUI runtime. It is based on compio, and the GUI part is powered by Win32, WinUI 3, Qt 5/6, GTK 4 or AppKit. All IO requests could be issued in the same thread as GUI, without blocking the user interface!

Example

Read the examples and learn more!

Backend Light Dark
Win32 Win32 Light Win32 Dark
WinUI 3 WinUI Light WinUI Dark
Qt 6 Qt Light Qt Dark
GTK 4 GTK Light GTK Dark
AppKit macOS Light macOS Dark

Quick start

Winio follows ELM-like design, inspired by yew and relm4. The application starts with a root Component:

use winio::prelude::*;

fn main() {
    App::new("rs.compio.winio.example").run::<MainModel>(());
}

struct MainModel {
    window: Child<Window>,
}

enum MainMessage {
    Noop,
    Close,
}

impl Component for MainModel {
    type Event = ();
    type Init<'a> = ();
    type Message = MainMessage;

    fn init(_init: Self::Init<'_>, _sender: &ComponentSender<Self>) -> Self {
        // create & initialize the window
        init! {
            window: Window = (()) => {
                text: "Example",
                size: Size::new(800.0, 600.0),
            }
        }
        window.show();
        Self { window }
    }

    async fn start(&mut self, sender: &ComponentSender<Self>) -> ! {
        // listen to events
        start! {
            sender, default: MainMessage::Noop,
            self.window => {
                WindowEvent::Close => MainMessage::Close,
            }
        }
    }

    async fn update_children(&mut self) -> bool {
        // update the window
        self.window.update().await
    }

    async fn update(&mut self, message: Self::Message, sender: &ComponentSender<Self>) -> bool {
        // deal with custom messages
        match message {
            MainMessage::Noop => false,
            MainMessage::Close => {
                // the root component output stops the application
                sender.output(());
                // need not to call `render`
                false
            }
        }
    }

    fn render(&mut self, _sender: &ComponentSender<Self>) {
        let csize = self.window.client_size();
        // adjust layout and draw widgets here
    }

    fn render_children(&mut self) {
        self.window.render();
    }
}

Dependencies

~0.9–18MB
~205K SLoC