Skip to content

Wayland, Windows, MacOS: Popup Implementation#4543

Open
Murmele wants to merge 19 commits into
rust-windowing:masterfrom
Murmele:popup
Open

Wayland, Windows, MacOS: Popup Implementation#4543
Murmele wants to merge 19 commits into
rust-windowing:masterfrom
Murmele:popup

Conversation

@Murmele

@Murmele Murmele commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Implement proper decorationless popups by specifying the type of the child window with with_type()

With this PR different kind of child windows can be created

  • Popups: Special windows without any decoration which can be positioned relative to the parent
  • Window: Normal window with a parent or not

The type can be specified during creation of the Window using the window_attributes and the with_type() function. As default a normal Window is used. If Popup is choosen a parent must be specified, otherwise the Popup creation fails with an Error returned by the new() function.

Related issues: #403 and #4256

  • Tested on all platforms changed
  • Added an entry to the changelog module if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality

Platforms

  • Wayland
  • Windows
  • MacOs
  • X11

Wayland:

Bildschirmaufzeichnung.vom.2026-06-04.13-18-16.mp4

This work is sponsored by the NLnet foundation

@madsmtm madsmtm added DS - wayland Affects the Wayland backend, or generally free Unix platforms S - platform parity Unintended platform differences labels Mar 26, 2026
Comment thread winit-wayland/src/window/state.rs
Comment thread winit-wayland/src/window/state.rs Outdated
@Murmele Murmele marked this pull request as ready for review May 18, 2026 08:06
@Murmele Murmele requested a review from kchibisov as a code owner May 18, 2026 08:06
Comment thread winit-wayland/src/state.rs Outdated
Comment thread winit-wayland/src/state.rs Outdated
Comment thread winit-core/src/window.rs
Comment thread winit-core/src/window.rs Outdated
Comment thread winit-core/src/window.rs Outdated
Comment thread winit-wayland/src/popup.rs Outdated
Comment thread winit-wayland/src/popup.rs Outdated
Comment thread winit-wayland/src/state.rs Outdated
Comment thread winit-wayland/src/popup.rs Outdated
Comment thread winit-win32/src/window.rs
@Murmele Murmele requested a review from madsmtm as a code owner May 28, 2026 15:09
@Murmele Murmele force-pushed the popup branch 2 times, most recently from facdfde to 87f6327 Compare June 4, 2026 12:59
Murmele added 15 commits June 4, 2026 15:07
Reason: Because a normal window can have a parent window as well, like a Dialog
Reason: otherwise the child surface is anchored to the center
Reason: otherwise the height of the client side decoration is not considered and therefore the location is shifted
Reason: There are multiple pointers to the smithay popup. Once in state.windows and one time in the popup object it self. Just dropping the popup object releases only one pointer but we have to notify the state to release also the other
…he position

Reason: Much easier in the resize handle
Reason: we have to call resize to initialize the viewport to map to correct window size
@Murmele Murmele changed the title Wayland: Popup Implementation Wayland, Windows, MacOS: Popup Implementation Jun 4, 2026
@Murmele

Murmele commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@kchibisov Just in case you have time. This is ready for review

@CryZe

CryZe commented Jun 8, 2026

Copy link
Copy Markdown

I'd like to review it too. I've been using an earlier version of this branch for my own project and I had some local bugfixes (various panics, protocol violations and commented out / unimplemented code). I'll try to rebase and see if your PR now contains all of them.

@Murmele

Murmele commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

I'd like to review it too. I've been using an earlier version of this branch for my own project and I had some local bugfixes (various panics, protocol violations and commented out / unimplemented code). I'll try to rebase and see if your PR now contains all of them.

Thanks for testing, just let me know if you have any problems

Comment thread winit-core/src/window.rs Outdated
///
/// See [`WindowType::Popup`] for the per-platform behavior, including how to obtain a
/// rounded, native-looking popup on macOS.
pub fn with_type(mut self, window_type: WindowType) -> Self {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm inclined to suggest to call this with_window_type. That would also make it symmetric to window_type().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks I changed it

Comment thread winit-core/src/window.rs
/// tooltip. Requires a parent set via [`WindowAttributes::with_parent_window`], and its
/// position is interpreted relative to that parent.
///
/// ## Platform-specific

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be the place to mention that this is for example not supported on X11 (as opposed to just with with_type())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread winit-core/src/window.rs Outdated
Comment thread winit-wayland/src/event_loop/mod.rs Outdated
let popup = crate::Popup::new(self, window_attributes)?;
Ok(Box::new(popup))
},
_ => panic!("Not implemented"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the function returns a Result, wouldn't it perhaps make sense to return Err instead of a panic?

Alternatively, unimplemented!() perhaps?

(sucks that non_exhaustive doesn't kick in here - I wonder if there's a way?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread winit-wayland/src/window/state.rs Outdated
Comment on lines +61 to +62
Window((Window, Option<WindowConfigure>)),
Popup((Popup, XdgPositioner, Option<PopupConfigure>)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tuples are tempting, but .1 and .2 aren't super readable. I'd lean towards anonymous structs inside the enum.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, makes it much more readable :)

Comment thread winit-win32/src/window.rs Outdated
// If we have a popup the position is relative to the parent window and not
// relative to the screen. Therefore we have to translate it from the parent
// coordinate system to the display coordinate system
fn translate_outer_position(&self, position: Position) -> (i32, i32) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should return a PhysicalPosition instead of a tuple, to reduce changes of mixing this up?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Murmele added 2 commits June 10, 2026 16:55
Reason: So it is clear which kind of position it is
@CryZe

CryZe commented Jun 12, 2026

Copy link
Copy Markdown

Alright, so far I've confirmed 2 out of 3 bugs:

  1. Popups need to be closed in reverse order (children before parents), otherwise you get a protocol violation:
xdg_wm_base#14: error 2: destroyed popup not top most popup

Fix here: CryZe@a157156

  1. This may be unrelated to this PR a bit, but I noticed this when popups get closed, sometimes the compositor updates still get processed by the event loop and it panics on a None unwrap because the window no longer exists:
thread 'main' (26750) panicked at vendor/winit/winit-wayland/src/event_loop/mod.rs:361:58:
called `Option::unwrap()` on a `None` value

Fix here: CryZe@3d03cab

Both of these fixes are quickly put together, there's possibly a better way to do it. I'm still looking into the third bugfix, at least so far it doesn't seem to do anything anymore on your branch (as in, you probably already fixed it).

@kchibisov

kchibisov commented Jun 12, 2026

Copy link
Copy Markdown
Member

I think the idea with those pop-ups were to have a separate type other than glue to window, because as you said, they are very restricted on some platforms and on some platform it's indeed just a Window.

so in top-level API I would have them, as a separate type with its own restrictions, and what not, I'm also not sure if those things can be owned by the user, really, I think popups should be more like something you create from e.g. Window so Window::create_popup type of API call, that may take an ActiveEventLoop or ActiveEventLoop. EventLoop having an api like ActiveEventLoop::create_pop(&dyn Window, PopupProperties) as generally better in my opinion.

Popups need to be closed in reverse order (children before parents), otherwise you get a protocol violation:

Exactly why I want to have them owned by Parent, whether it's window or some other thing.

Generally, I think the initial plan was to have some kind of trait Surface and then for event loop to have ActiveEventLoop::create_popup(&mut dyn Surface, so it adds popup for the Surface so API is a bit more future proof.

@tronical would like to hear your opinion here since you're representing ui toolkit side 😅

I just want to account for other special surfaces Wayland people can create which has their own popup type that is certainly not different than standard popup.

@tronical

Copy link
Copy Markdown
Contributor

I think the idea with those pop-ups were to have a separate type other than glue to window, because as you said, they are very restricted on some platforms and on some platform it's indeed just a Window.

so in top-level API I would have them, as a separate type with its own restrictions, and what not, I'm also not sure if those things can be owned by the user, really, I think popups should be more like something you create from e.g. Window so Window::create_popup type of API call, that may take an ActiveEventLoop or ActiveEventLoop. EventLoop having an api like ActiveEventLoop::create_pop(&dyn Window, PopupProperties) as generally better in my opinion.

Popups need to be closed in reverse order (children before parents), otherwise you get a protocol violation:

Exactly why I want to have them owned by Parent, whether it's window or some other thing.

That's indeed an interesting constraint (reverse order required).

Generally, I think the initial plan was to have some kind of trait Surface and then for event loop to have ActiveEventLoop::create_popup(&mut dyn Surface, so it adds popup for the Surface so API is a bit more future proof.

@tronical would like to hear your opinion here since you're representing ui toolkit side 😅

I just want to account for other special surfaces Wayland people can create which has their own popup type that is certainly not different than standard popup.

I see the discrepancy, but I also see that - wayland aside - popups have more in common with Window than not. Another surface abstraction is tempting indeed, but my feeling is that it may be worthwhile to go with this approach first and learn from it.

(disclaimer: I'm biased though as I'm Martin's colleague :)

@kchibisov

Copy link
Copy Markdown
Member

The problem with Wayland, is that if you randomly use it wrongly, it really likes killing applications with protocol errors, so my suggestion is mostly to try solve it on type system level, or at least make it less likely, so users won't have to debug Wayland when it breaks in their cross platform app.

I also remember that popups can be discarded/removed on user behalf and winit window is kind of persistent now.

@HigherOrderLogic

Copy link
Copy Markdown

For Wayland: shouldnt we also use the xdg-dialog-v1 protocol to mark it as dialog? This implementation doesnt seems to use that protocol atm.

@kchibisov

Copy link
Copy Markdown
Member

I think dialog protocol serves a different purpose, and also not widely available?

@HigherOrderLogic

Copy link
Copy Markdown

I think dialog protocol serves a different purpose

Ah right, I didnt read the PR description carefully, my bad. Originally thought it was popup dialog.

and also not widely available?

All 3 most popular compositors right now, KWin, Mutter and Hyprland, implement it so I dont think it's a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DS - wayland Affects the Wayland backend, or generally free Unix platforms S - platform parity Unintended platform differences

Development

Successfully merging this pull request may close these issues.

7 participants