tao

repository·dev·Indexed 24 days ago

https://github.com/tauri-apps/tao

A cross-platform application window creation library written in Rust, maintained by the Tauri team. It supports Windows, macOS, Linux, iOS, and Android. Tao provides a central EventLoop for managing application lifecycles, window manipulation, and input handling, including support for custom events via EventLoopProxy and raw hardware input through DeviceEvents.

Tokens
12.7K
Snippets
17
Records
72
Agent score
79%

What's inside tao

  1. Install Linux dependencies for Tao

    dev

    Tao uses GTK and its related libraries for Linux support. You must install the GTK3 development packages on your system before building.

    • Arch Linux / Manjaro: Use pacman to install gtk3.
    • Debian / Ubuntu: Use apt to install libgtk-3-dev.
    # Arch Linux / Manjaro
    sudo pacman -S gtk3
    
    # Debian / Ubuntu
    sudo apt install libgtk-3-dev
  2. Explore Window and Input examples

    dev

    The following examples demonstrate window manipulation and input handling:

    Window Management:

    • window: A basic example of creating a window.
    • multiwindow: Demonstrates creating multiple windows.
    • multithreaded: A multithreaded version of the multiwindow example.
    • parentwindow: Shows how to create a window inside another window.
    • min_max_size: Demonstrates setting the minimum and maximum zoomable window sizes.
    • resizable: Shows how to enable or disable window resizing.
    • minimize: Demonstrates how to minimize a window.
    • transparent: Shows how to create a transparent window.
    • window_icon: Demonstrates how to add a window icon.
    • drag_window: Shows how to allow dragging the window by holding the left mouse button and moving.
    • fullscreen: Demonstrates configuring different screen sizes and video modes.
    • video_modes: Lists all available video modes for the primary monitor.

    Input and Cursor Control:

    • cursor: Demonstrates setting different cursor icons.
    • cursor_grab: Shows how to prevent the cursor from leaving the window boundaries.
    • mouse_wheel: Demonstrates how to retrieve the difference in scrolling state (MouseScrollDelta) in either pixels or lines.
    • set_ime_position: Shows how to set the IME (Input Method Editor) position upon clicking.

    System and Monitor interaction:

    • monitor_list: Lists all available monitors.
    • reopen_event: Demonstrates handling clicks on the dock icon on macOS.
  3. Explore Event Loop and Lifecycle examples

    dev

    The following examples demonstrate how to manage the application lifecycle and event loop:

    • control_flow: Demonstrates how to tell the event loop what to do in the next iteration after the current one finishes.
    • custom_events: Shows how users can create, emit, and listen to custom events through tao.
    • handling_close: Demonstrates how to intercept a close request and show a warning before closing the window.
    • request_redraw: Shows how to handle the event emitted when a redraw is needed (e.g., during window resizing).
    • request_redraw_threaded: A multithreaded version of the request_redraw pattern.
    • timer: Demonstrates creating a timer that suspends the thread for a specific duration.
    • window_run_return: An alternative to the standard EventLoop run function that accepts non-move closures and returns control flow to the caller upon exit.
    • window_debug: A utility example for debugging using eprintln.
  4. Set up Tao for Android development

    dev

    Tao uses the ndk-rs crates for Android support. To run Tao on an Android device, you must configure your crate as a dynamic system library and include the native activity glue.

    1. In your Cargo.toml, set the crate-type to ["cdylib"] for your target.
    2. Use the ndk_glue::main attribute on your main function with backtrace = "on".
    3. Run the application using cargo apk run.
    [[example]]
    name = "request_redraw_threaded"
    crate-type = ["cdylib"]
    #[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
    fn main() {
        ...
    }
    cargo apk run --example request_redraw_threaded
  5. Run Tao examples

    dev

    You can explore the capabilities of tao by running any of the provided examples using Cargo. Use the following command format, replacing <file_name> with the name of the specific example you wish to run:

    cargo run --example <file_name>
  6. How event handling works in Tao

    dev

    Tao uses an event-driven model where an EventLoop manages and dispatches events. You start the loop by calling EventLoop::run.

    Event Types

    • WindowEvent: Specific to a window (e.g., CloseRequested, cursor movement, key presses). In multi-window apps, check the WindowId to identify which window sent the event.
    • DeviceEvent: Unfiltered input data from devices (e.g., mouse movement) that is not tied to a specific window.
    • UserEvent: Custom events you can define and trigger.

    Control Flow

    Inside the run closure, you control how the loop behaves using ControlFlow:

    • ControlFlow::Poll: The loop runs continuously even if no events are pending. Best for games.
    • ControlFlow::Wait: The loop pauses until the OS dispatches a new event. Best for power-efficient, non-game applications.
    • ControlFlow::Exit (or ExitWithCode): Terminates the event loop and the program.
    ```rust
    use tao::{
        event::{Event, WindowEvent},
        event_loop::{ControlFlow, EventLoop},
        window::WindowBuilder,
    };
    
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();
    
    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;
    
        match event {
            Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
                *control_flow = ControlFlow::Exit
            },
            Event::MainEventsCleared => {
                window.request_redraw();
            },
            Event::RedrawRequested(_) => {
                // Perform rendering here
            },
            _ => ()
        }
    });
    ```埋
  7. Manage event loop behavior with ControlFlow

    dev

    Inside the run closure, you can modify the ControlFlow enum to determine how the loop behaves after the current iteration finishes.

    Variants:

    • Poll: (Default) Immediately start a new iteration regardless of whether new events are available.
    • Wait: Suspend the thread until a new event arrives.
    • WaitUntil(Instant): Suspend the thread until an event arrives or the specified Instant is reached.
    • ExitWithCode(i32): Stop the event loop and exit with the provided code. This variant is sticky; once set, it cannot be changed.
    • Exit: A constant alias for ExitWithCode(0).
  8. Understand the Tao event loop lifecycle

    dev

    The EventLoop::run closure processes events in a specific approximate order. Understanding this order helps you decide where to place state updates and rendering logic.

    1. Event::NewEvents(StartCause): Emitted when new events arrive from the OS. Use this for timing updates or checking if a ControlFlow::WaitUntil timer has elapsed.
    2. Window, User, and Device Events: The loop processes all pending WindowEvent, UserEvent, and DeviceEvents.
    3. Event::MainEventsCleared: Emitted after all input events are processed but before redrawing. This is the ideal place for 'main body' logic (calculations, state updates). Games can also use this for continuous rendering.
    4. Event::RedrawRequested(WindowId): Emitted after MainEventsCleared when a window needs to be redrawn (e.g., due to OS invalidation or an explicit Window::request_redraw call). Non-game GUIs should perform rendering here to avoid unnecessary work.
    5. Event::RedrawEventsCleared: Emitted after all RedrawRequested events are handled. Use this for cleanup or bookkeeping after rendering.
    6. Event::LoopDestroyed: The final event emitted when the loop is shutting down. Treat this as your 'on quit' hook.
    let mut control_flow = ControlFlow::Poll;
    let mut start_cause = StartCause::Init;
    
    while control_flow != ControlFlow::Exit {
        event_handler(NewEvents(start_cause), ..., &mut control_flow);
    
        for e in (window events, user events, device events) {
            event_handler(e, ..., &mut control_flow);
        }
        event_handler(MainEventsCleared, ..., &mut control_flow);
    
        for w in (redraw windows) {
            event_handler(RedrawRequested(w), ..., &mut control_flow);
        }
        event_handler(RedrawEventsCleared, ..., &mut control_flow);
    
        start_cause = wait_if_necessary(control_flow);
    }
    
    event_handler(LoopDestroyed, ..., &mut control_flow);
  9. How the EventLoop works in Tao

    dev

    The EventLoop is the central context of a Tao application. It retrieves system events and events from registered windows.

    Key constraints:

    • Thread Safety: EventLoop is neither Send nor Sync and must be created on the main thread. Attempting to create it on a different thread will cause a panic.
    • Cross-thread Communication: While the EventLoop itself cannot be shared across threads, you can send Window instances to other threads, and you can use an EventLoopProxy to wake up or send custom events to the loop from other threads.
    • Lifecycle: You start the loop by calling .run(), which hijacks the calling thread and executes a provided closure for the duration of the application.
  10. How to draw graphics on a Tao window

    dev

    Tao does not provide built-in drawing APIs. Instead, it provides access to the raw window and display handles via the platform module and methods like raw_window_handle() and raw_display_handle().

    You can use these handles to initialize a graphics context for APIs such as OpenGL, Vulkan, DirectX, or Metal.

  11. Handle window fullscreen modes

    dev

    The set_fullscreen(Option<Fullscreen>) method allows switching between windowed and fullscreen modes.

    Platform-specific behavior for macOS:

    • Fullscreen::Exclusive: Provides true exclusive mode with a video mode change. Note that macOS does not provide task switching (Spaces) while in this mode.
    • Fullscreen::Borderless: Provides a borderless fullscreen window on a separate space. This is the recommended way for fullscreen games on macOS.