Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jgcodes2020 opened this issue Sep 21, 2024 · 8 comments
Open

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

jgcodes2020 opened this issue Sep 21, 2024 · 8 comments
Labels
S - enhancement Wouldn't this be the coolest?

Comments

@jgcodes2020
Copy link

jgcodes2020 commented Sep 21, 2024

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:

  • the ability to grab input (usually upon user action)
  • the ability to be visually transparent or translucent
  • the ability to blur their background if transparent
  • the ability to be resized
  • the ability to request a repaint

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:

  • Windows: HWND
  • MacOS: NSView?
  • X11: XID
  • Wayland: wl_surface

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:

  • decorations and/or frame
  • the ability to be modal to another window
  • the ability to trigger the system move/resize handles
  • the ability to be repositioned (on some WMs: Windows, macOS, X11 (not advised))
  • an icon (on some WMs: Windows, macOS, X11)
  • a window class (on some WMs: X11, Wayland)
  • the ability to request activation

Platform equivalents:

  • Windows: WS_OVERLAPPEDWINDOW
  • MacOS: NSWindow
  • X11: ??
  • Wayland: xdg_toplevel

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:

  • the ability to be repositioned

  • the ability to steal focus from its parent window

  • Windows: WS_POPUPWINDOW

  • MacOS: NSWindow, with additional settings: [window setDecorated:NO]; [window setExcludedFromWindowsMenu:YES]; [window setLevel:NSPopUpMenuWindowLevel];

  • X11: override-redirect/save-under window, no decorations

  • Wayland: xdg_popup

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. Functions and properties unique to subviews include:

  • the ability to be repositioned
  • the ability to be restacked relative to other subviews

Platform equivalents:

  • Windows: WS_CHILD
  • MacOS: Subclass NSView
  • X11: just parent the window and don't request decoration
  • Wayland: wl_subsurface, use wp_viewporter protocol to clip output

Structure

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 existing WindowId class would be renamed to SurfaceId for consistency, though it could exist as a deprecated alias during a transition period.

The trait hierarchy would look something like this:

trait Surface: HasWindowHandle {
    fn id() -> SurfaceId

    // 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.

Event handling

  • Subviews cannot receive keyboard focus on Wayland.
    • Subviews will not receive keyboard focus by default, instead passing it to their parent window.
  • On MacOS and X11, subviews can automatically bubble events up to their ancestors, whereas on Windows and Wayland, they don't.
    • Subviews will handle all pointer events they receive unless they have explicitly been made invisible to cursor hit test. Further testing will be needed to ensure consistency between platforms.

Changelog

  1. Added plan for event bubbling
  2. Specified how subviews will catch events

Relevant platforms

Windows, macOS, Wayland, X11

@jgcodes2020 jgcodes2020 added the S - enhancement Wouldn't this be the coolest? label Sep 21, 2024
@jgcodes2020 jgcodes2020 changed the title RFC: Window redesign RFC: Window redesign to allow for other surface roles Sep 21, 2024
@kchibisov
Copy link
Member

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.

@madsmtm
Copy link
Member

madsmtm commented Sep 23, 2024

And I'll add that what you define as "surface" here is closer to a "widget" in other UI frameworks (for example Gtk.Widget or QWidget), since you also want it to do event handling, including user input, focus and bubbling of events.

So I'd probably prefer that name.

@jgcodes2020
Copy link
Author

jgcodes2020 commented Sep 24, 2024

And I'll add that what you define as "surface" here is closer to a "widget" in other UI frameworks (for example Gtk.Widget or QWidget), since you also want it to do event handling, including user input, focus and bubbling of events.

So I'd probably prefer that name.

Wayland and Vulkan use "surface" in that sense, so that's where I took the name from. A widget, to me, implies a rectangular area within a window, managed by the UI framework and not the window manager.

@kchibisov
Copy link
Member

I also don't like Widget and wanted to use Surface, since logically Widget doesn't imply that it consists only from one surface, surface is a more clear thing here, but on the other hand you can argue that surface has subsurfaces...

One could also use the word View though.

@jgcodes2020
Copy link
Author

jgcodes2020 commented Sep 30, 2024

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.

The simplest solution would just be to pass each event to the relevant Surface - as far as I know, this is what Wayland does. Do other operating systems bubble events from subviews and popups automatically?

@kchibisov
Copy link
Member

yeah, some do bubling, like macOS.

@jgcodes2020
Copy link
Author

yeah, some do bubling, like macOS.

Edited the proposal to account for this. We can simply disable it on MacOS/X11 where it is supported; those platforms could eventually have this re-enabled on a platform basis.

@jgcodes2020
Copy link
Author

I started a draft PR on the initial part of this redesign (splitting trait Window to trait Surface and trait Window: Surface. It's still a work-in-progress, but I'd like feedback on the design, particularly as I don't have much experience developing for mobile or web in Rust.

jgcodes2020 added a commit to jgcodes2020/winit that referenced this issue Oct 24, 2024
This PR splits some methods of Window into a new supertrait Surface, laying groundwork for the implementation of rust-windowing#3928.

As stated there, this split is needed because popups and subsurfaces may not necessarily allow the same operations as windows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S - enhancement Wouldn't this be the coolest?
Development

No branches or pull requests

3 participants