rust-windowing / winit

Window handling library in pure Rust
https://docs.rs/winit/
Apache License 2.0
4.75k stars 892 forks source link

RFC: `Window` redesign to allow for other surface roles #3928

Open jgcodes2020 opened 21 hours ago

jgcodes2020 commented 21 hours ago

Description

This proposal addresses #159, #343, and #3506.

Definitions

The below model of surfaces, windows, etc. is heavily inspired by Wayland; though it maps well to other platforms.

Window manager

For the purpose of this design proposal, the window manager (abbreviated WM) is software that handles the positioning, compositing, and display of surfaces. This is equivalent to X11 server and window manager on X11 and the compositor on Wayland.

Surface

A surface is a rectangular buffer owned by the window manager that can be drawn to, and is usually displayed on screen in some fashion. Not all surfaces can be positioned programmatically; for some window managers this is purely by design (i.e. Wayland). Functions and properties common to most surfaces include:

Generally, window managers support different roles for surfaces, which govern their lifetime and purpose. Most window managers can define the roles of window, popup, and subview.

Platform equivalents:

Window

A window is a long-lived surface that can be positioned by the user. They can also be stacked or tiled as the window manager deems appropriate. Functions and properties unique to windows include:

Platform equivalents:

Popup

A popup is a short-lived surface bound to a window that disappears when unfocused. They are generally used to implement context menus and tooltips. Functions and properties unique to popups include:

Subview

A subview is a long-lived surface bound to some other surface, be it a window, popup, or even another subview. They are generally clipped to their parent surface. They generally serve as a separate render target for such things as a video player or browser engine. Functions and properties unique to subviews include:

Platform equivalents:

Implementation

The existing Window trait should be split into two separate traits: Surface representing the common functionality, and Window representing functionality specific to top-level windows. This opens up room for traits like Popup or Subview.

The trait hierarchy would look something like this:

trait Surface: HasWindowHandle {
    // surface operations

    // Downcast to the corresponding "common" role, if it is one
    fn as_role(&self) -> Option<SurfaceRole>;
    fn as_role_mut(&mut self) -> Option<SurfaceRoleMut>;
    // Upcast to Surface
    fn as_surface(&self) -> &dyn Surface;
    fn as_surface_mut(&mut self) -> &dyn mut Surface;
}

trait Window: Surface {
    // window operations
}

trait Popup: Surface {
    // popup operations
}

trait Subview: Surface {
    // subview operations
}

enum SurfaceRole {
    Window(&dyn Window),
    Popup(&dyn Popup),
    Subview(&dyn Subview),
}
enum SurfaceRoleMut {
    Window(&dyn mut Window),
    Popup(&dyn mut Popup),
    Subview(&dyn mut Subview),
}

Ideally, the Surface::as_surface/Surface::as_surface_mut are obsoleted once trait upcasting is stabilized.

Relevant platforms

Windows, macOS, Wayland, X11

kchibisov commented 20 hours ago

I'd add that the suggested design was iterated multiple times and kind of how it'll be with 0.31(though thanks for writing rough idea of it down), but there's still a long way to go.

The main issue as of now, is not how to structure, but how event routing should work, which is not entirely clear and re-using WindowId might be not the greatest way forward with some designs.

Anyway, this is all actionable after the split is done, since all of the ID/monitor types are not general enough.

I'm also not sure whether to keep this open given that it's a meta issue based on other issues we have around, but I guess I keep for now.