rust-windowing / winit

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

Pop-up menus #403

Open Shookbelf opened 6 years ago

Shookbelf commented 6 years ago

Hi, is there any way to create pop-ups like for right click menus with winit? Since right-click menus can also go across the borders of a window, I suppose they need to have their own window and surface.

It would be nice if functionality like this could be included.

paulirotta commented 6 years ago

This is done as a higher level function of glutin or other UI lib that creates the windows and text on them.

Unless an extension binds to the native UI. React Native without the HTML garbage. It would be a most excellent direction but not a small mandate/extension. As a consultant I see a lot of wasted money and lives porting the same app to many platforms just to get the native components.

Shookbelf commented 6 years ago

I am not talking about the drawing of the menu content. My current understanding is that those are basically specialized windows. If I want to spawn a window like that it's currently not possible with winit, because it will behave like a regular window.
Perhaps it would be enough to make it possible to hide windows from the task manager.

Please correct me if my understanding is wrong.

Osspial commented 6 years ago

Do you mean having some way to create windows that aren't placed on the taskbar?

paulirotta commented 6 years ago

I believe that is correct- small "windows" without edge decoration or appearing in the taskbar for things like menus. It is then up to a higher level lib (out of scope- you choose what to do) to populate these.

Shookbelf commented 6 years ago

@paulirotta Unfortunately I don't know exactly how it is done on different platforms.
This could be enough if the following features are supported:

Most things can probably be handled by users of winit if the basics work.

There might be more subtle behaviour on different platforms though.

In xdg_shell there is a protocol xdg_popup for exactly this type of windows.

Osspial commented 6 years ago

Borderless window handling is already supported. As far as the other two features go, implementing them on Windows seems to be pretty easy, and I've done so in these two branches: focus and taskbar.

I don't know how it would be handled on other platforms, but I can't imagine it's too much of a challenge.

francesca64 commented 6 years ago

This would be straightforward for me to implement on X11. I'm in favor of moving forward on this, provided it's viable to implement on macOS as well.

Osspial commented 6 years ago

It looks like, on OSX, windows can be excluded from the dock with this flag, and focus can be handled with modal windows. I'd need to actually test those, but that should be fairly easy to do.

Osspial commented 6 years ago

Something worth noting is that Wayland doesn't let you specify where a window will be placed on-screen, which complicates right-click menu creation - it's expected that a menu would be created at the mouse pointer, but there's currently no way to ensure that happens on Wayland.

@vberger Does Wayland provide any way to work around this?

elinorbgr commented 6 years ago

Wayland provides a special kind of surfaces that are made exactly for this use-case (popup tooltips and menus, that are positioned relative to a parent window), so we can absolutely do popup surfaces.

In this case, my preferred way forward would be to first introduce the proper abstraction for popups in Smithay's Client Toolkit and then use it in winit.

But API-wise, would popups be represented by regular winit Window or some other type?

Osspial commented 6 years ago

Somewhat of a necropost, but I feel like popups should be represented as regular windows. AFAIK the only major difference happens during the creation process, after which they can be safely treated the same way as a normal window would.

Shookbelf commented 5 years ago

Just for clarification: in the #695 there are two concepts, popup and tooltip windows. According to the examples, this issue is not about popups, but about something more like tooltips.

When I looked into it, I realized that context menu windows usually have very specific behaviour: they exist only as long as they or some further child have focus and have to have exact placement.

I am absolutely sure this is a concept all platforms share (even Android has them), so winit should support this in some way. If it's only exposed in the platform specific implementation, so be it.

I agree that most of the logic could be implemented by the user, but having the according settings for such windows implemented in a cross platform way should not be more effort than other settings, most is even already possible. Since they are so ubiquitous, it should be possible to create them without calling platform specific functions.
On the other hand, the Wayland positioning situation makes it impossible to do this in a good way, since the window would have to be created with platform specific code anyway.

I'd be okay with closing this issue if the implementation is possible with what is exposed in the platforms, but that has already been discussed over at #695.

dhardy commented 4 years ago

More than a year later... where does this stand? Do we have an API design or at least a list of requirements?

It was decided in #695 to support pop-up windows. From that a + this thread we have a few requirements:

To expand on the latter:

ArturKovacs commented 4 years ago

I think we should be careful not to confuse this with "tooltips" or "pop-up windows".

It seems that this is something that has a specific API on both Windows (CreatePopupMenu) and MacOS (popUp(positioning:at:in:)). I haven't used any of these APIs but they really seem to be exactly for what @Shookbelf described in the original post.

In my opinion winit should expose an API that's specific to these "pop-up menus". To me it would feel over-engineered to expose them as regular windows.

dhardy commented 4 years ago

@ArturKovacs as I understand it, everyone else in this thread is talking about general-purpose (client-drawn) pop-up "windows" / surfaces, not one where the OS provides the menu model. I mean, that would satisfy some uses of this, but it's really a different topic.

ArturKovacs commented 4 years ago

Hmm well the wording of the original post by @Shookbelf supports what I'm proposing (pop-up menus) but immediately afterwrads @Shookbelf wrote

[...] My current understanding is that those are basically specialized windows.

which supports the "pop-up window" route.

To me this post is rather ambigous. I think it's necesarry to edit the original text and make it obvious what this issue is about. If this is indeed about "pop-up windows" (generic windows without a border that don't show up on the taskbar) then I'll just create another issue for what I would like to achieve. I would also be willing to implement what I proposed.

Shookbelf commented 4 years ago

IMO it's more sensible to provide generic surfaces that the client can draw to.

Not every platform provides native menus and custom windows would be far more flexible. They just need special "modal" logic to behave correctly. But this could be emulated by the client observing window events.

However, after more than 2 years this issue does not really affect me anymore, so feel free to exclude me from the discussion.

notgull commented 1 year ago

This is what I was trying to implement in #2693 and with the menubar crate

ids1024 commented 1 year ago

This generally seems like important/expected functionality if winit is used for a UI toolkit. (See https://github.com/slint-ui/slint/issues/2375, https://github.com/iced-rs/iced/issues/30)

Looking at how GTK4 implements GdkPopup:

Presumably the feature wouldn't exist on non-desktop platforms, but the toolkit/application would then fallback to rendering the popup as part of the main surface. If it wished to support such platforms.

Jumping into the discussion from a few years ago:

I feel like popups should be represented as regular windows. AFAIK the only major difference happens during the creation process, after which they can be safely treated the same way as a normal window would.

"Treated the same way as normal windows" seems to be mostly true on Wayland, X11, and macOS. On Wayland, though, an xdg_popup is a fundamentally different thing from an xdg_toplevel. So if this were used with Window, various methods would have to have a note saying that on Wayland they have an effect with toplevels but not popups.

The other API consideration is that a parent toplevel/window is required to create a popup at least on Wayland, and positioning has to be relative to that and not absolute.

ids1024 commented 1 year ago

@notgull I seem to have forgotten that you began implementing this. :laughing:

Anyway, I'm familiar with how this works on Wayland, somewhat familiar with how X does it, and used to mucking around in GDK's code to see how it does things, so I have some thoughts to add here at least.

jgcodes2020 commented 8 months ago

GDK deals with the Popup != Window problem by making both classes inherit from a common Toplevel class. In Rust, you could simply have a TopLevel trait and have both Window and Popup implement it, though since there is a lot of code to share between them, I have no idea if this is the right path.

notgull commented 8 months ago

Generally, in Rust we do composition rather than inheritance. So there would be a common Toplevel struct that both Window and Popup are built around, in this hypothetical view.

jgcodes2020 commented 8 months ago

Looking again, I think popups can simply be Windows. Generally speaking, popups are positioned relative to the parent, so we can just add a method in WindowBuilder similar to with_parent_window, but for popups.

The Wayland implementation would then just maintain an enum for surface roles (either xdg_surface or xdg_popup), which could later be extended to child windows (with wl_subsurface).

kchibisov commented 8 months ago

it's really not that simple as you might thing since there're special rules, etc for all of that and special semantics, like popup can be dismissed at any time, etc.

it's generally planned after 0.31.0 release.

kchibisov commented 8 months ago

And child windows are also not the same as subsurfaces in general, they do intersect, but there're cases where child windows can do way more. There's also parent/child relationship for toplevels on wayland.

LinusDikomey commented 4 months ago

I would also be interested in this, what is the current status on this?

I think a good first step would be to provide a platform-specific API on wayland to at least make it possible to position child windows/subsurfaces. I tried implementing a context menu (right-click menu) with winit's existing APIs and it roughly works on X11, Windows and MacOS with some visual inconsistencies with shadows, so that would also be something to look into in the future.

jgcodes2020 commented 3 months ago

I believe for Wayland, we're blocked by https://github.com/Smithay/client-toolkit/issues/5; as @elinorbgr mentioned above.

kchibisov commented 3 months ago

We're not blocked on anything in client-toolkit, since we can implement everything ourselves and already do for a lot of parts. And I'm pretty sure it's all present in sctk nowadays and the issue just obsolete.