# Odin Windowing Library Implementation Plan ## Overview A cross-platform windowing library for Odin with: - **Event-driven architecture** (inspired by winit) - **Minimal API surface** (inspired by GLFW) - **No rendering management** - users bring their own Vulkan/OpenGL - **Single-threaded** event loop on main thread **Initial scope**: Linux (X11 + Wayland), windows, input, monitors, fullscreen --- ## Architecture ### File Structure ``` window/ ├── window.odin # Main package, re-exports public API ├── types.odin # Event union, Control_Flow, handles ├── event_loop.odin # Event_Loop and run procedures ├── window_api.odin # Window struct and operations ├── monitor.odin # Monitor enumeration and info ├── input.odin # Key codes, mouse buttons, modifiers ├── error.odin # Error types │ ├── platform/ │ ├── platform.odin # Platform vtable and dispatch │ ├── backend.odin # Backend selection (X11 vs Wayland) │ │ │ ├── x11/ │ │ ├── x11.odin │ │ ├── x11_window.odin │ │ ├── x11_event_loop.odin │ │ └── x11_monitor.odin │ │ │ └── wayland/ │ ├── wayland.odin │ ├── wayland_window.odin │ ├── wayland_event_loop.odin │ └── wayland_monitor.odin │ └── examples/ ├── basic.odin └── fullscreen.odin ``` --- ## Core Types ### Event System (Discriminated Unions) ```odin // Top-level event Event :: union { Window_Event_Data, // Events for a specific window Device_Event_Data, // Raw input events New_Events, // Start of event batch About_To_Wait, // Before blocking Loop_Exiting, // Event loop shutting down } // Window events Window_Event :: union { Close_Requested, Destroyed, Resized, Moved, Focused, Unfocused, Key_Input, Char_Input, Pointer_Moved, Pointer_Entered, Pointer_Left, Mouse_Button_Input, Mouse_Wheel, Scale_Factor_Changed, Redraw_Requested, } // Control flow (how event loop behaves after processing) Control_Flow :: union { Poll, // Continuous polling (games) Wait, // Block until events (UI apps) Wait_Until, // Block with timeout } ``` ### Handles ```odin Window_Id :: distinct u64 Monitor_Handle :: distinct rawptr Physical_Size :: struct { width, height: u32 } Physical_Position :: struct { x, y: i32 } ``` ### Window Attributes ```odin Window_Attributes :: struct { title: string, size: Physical_Size, min_size: Maybe(Physical_Size), max_size: Maybe(Physical_Size), position: Maybe(Physical_Position), resizable: bool, visible: bool, decorated: bool, maximized: bool, fullscreen: Maybe(Fullscreen_Mode), } ``` --- ## API Design ### Event Loop ```odin // Creation create_event_loop :: proc(allocator := context.allocator) -> (^Event_Loop, Error) destroy_event_loop :: proc(loop: ^Event_Loop) // Running run :: proc(loop: ^Event_Loop, handler: Event_Handler) -> Error poll :: proc(loop: ^Event_Loop, handler: Event_Handler) -> bool exit :: proc(loop: ^Event_Loop) // User callback type Event_Handler :: #type proc(event: Event, loop: ^Event_Loop) -> Control_Flow ``` ### Window ```odin // Lifecycle create_window :: proc(loop: ^Event_Loop, attrs: Window_Attributes) -> (^Window, Error) destroy_window :: proc(win: ^Window) // Size and position surface_size :: proc(win: ^Window) -> Physical_Size request_surface_size :: proc(win: ^Window, size: Physical_Size) outer_position :: proc(win: ^Window) -> Physical_Position set_outer_position :: proc(win: ^Window, pos: Physical_Position) // State set_title :: proc(win: ^Window, title: string) set_visible :: proc(win: ^Window, visible: bool) set_fullscreen :: proc(win: ^Window, mode: Maybe(Fullscreen_Mode)) request_redraw :: proc(win: ^Window) // Raw handle for rendering APIs raw_window_handle :: proc(win: ^Window) -> Raw_Window_Handle ``` ### Monitor ```odin available_monitors :: proc(loop: ^Event_Loop) -> []Monitor_Handle primary_monitor :: proc(loop: ^Event_Loop) -> Maybe(Monitor_Handle) monitor_info :: proc(handle: Monitor_Handle) -> Monitor_Info video_modes :: proc(handle: Monitor_Handle) -> []Video_Mode current_video_mode :: proc(handle: Monitor_Handle) -> Video_Mode ``` --- ## Platform Abstraction ### Vtable Pattern ```odin Platform_Vtable :: struct { // Event loop operations init: proc(loop: ^Platform_Event_Loop) -> Error, terminate: proc(loop: ^Platform_Event_Loop), pump_events: proc(loop: ^Platform_Event_Loop, ...), wait_events: proc(loop: ^Platform_Event_Loop), wake_up: proc(loop: ^Platform_Event_Loop), // Window operations create_window: proc(...) -> Error, destroy_window: proc(...), // ... 20+ window operations // Monitor operations get_monitors: proc(...) -> []Monitor_Handle, // ... monitor operations } ``` ### Backend Selection ```odin select_backend :: proc() -> Backend { if os.getenv("WAYLAND_DISPLAY") != "" { return .Wayland } return .X11 } ``` --- ## Example Usage ```odin package main import "window" main :: proc() { loop, _ := window.create_event_loop() defer window.destroy_event_loop(loop) attrs := window.default_window_attributes() attrs.title = "My App" win, _ := window.create_window(loop, attrs) window.run(loop, proc(event: window.Event, loop: ^window.Event_Loop) -> window.Control_Flow { switch e in event { case window.Window_Event_Data: switch we in e.event { case window.Close_Requested: window.exit(loop) case window.Redraw_Requested: // Render here } } return window.Wait{} }) } ``` --- ## Implementation Phases ### Phase 1: Core Foundation - Package structure with stub files - Core types (Event, Control_Flow, Window_Id) - Basic Event_Loop with X11 backend - Create window, handle close/resize events - **Test**: Window that responds to close button ### Phase 2: Input Events - Key events with scancode mapping - Mouse button/motion/wheel events - Modifier key tracking - **Test**: Print all input events ### Phase 3: Window Operations - Resize, move, size constraints - Visibility, decorations, resizable toggle - Maximize/minimize, focus - **Test**: Interactive window management demo ### Phase 4: Monitor API - Monitor enumeration and properties - Video modes - Borderless and exclusive fullscreen - **Test**: Fullscreen toggle demo ### Phase 5: Event Loop Polish - Wait and WaitUntil control flow - wake_up() for cross-thread signaling - Redraw request batching - **Test**: Benchmark control flow modes ### Phase 6: Wayland Backend - Wayland connection/display - xdg_surface window creation - Port all operations to Wayland - Handle CSD and Wayland quirks - **Test**: All tests pass on Wayland ### Phase 7: DPI/Scale Factor - Scale factor detection - Scale_Factor_Changed events - **Test**: Correct rendering at different DPIs ### Phase 8: Documentation & Examples - API documentation - Examples: basic, input, fullscreen, multi-window, Vulkan - Performance testing --- ## Verification After each phase: 1. Build with `odin build .` 2. Run example programs 3. Test on both X11 and Wayland (after Phase 6) 4. Check for memory leaks with allocator tracking