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

Pop-up menus #403

Open
Shookbelf opened this issue Feb 8, 2018 · 28 comments
Open

Pop-up menus #403

Shookbelf opened this issue Feb 8, 2018 · 28 comments
Labels
C - needs discussion Direction must be ironed out D - average Likely as difficult as most tasks here DS - macos DS - wayland DS - windows DS - x11 H - help wanted Someone please save us P - low Nice to have S - api Design and usability S - enhancement Wouldn't this be the coolest?

Comments

@Shookbelf
Copy link

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.

@tomaka tomaka added the S - enhancement Wouldn't this be the coolest? label Feb 8, 2018
@paulirotta
Copy link
Contributor

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
Copy link
Author

Shookbelf commented Feb 10, 2018

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
Copy link
Contributor

Osspial commented Feb 21, 2018

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

@paulirotta
Copy link
Contributor

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
Copy link
Author

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

  • The window should not show up in task bars or similar
  • It should not have borders
  • Focus should be handled correctly

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
Copy link
Contributor

Osspial commented Feb 27, 2018

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
Copy link
Member

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
Copy link
Contributor

Osspial commented Apr 3, 2018

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.

@francesca64 francesca64 added H - help wanted Someone please save us S - api Design and usability C - needs discussion Direction must be ironed out D - average Likely as difficult as most tasks here P - low Nice to have labels May 6, 2018
@Osspial
Copy link
Contributor

Osspial commented May 11, 2018

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
Copy link
Contributor

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
Copy link
Contributor

Osspial commented Sep 14, 2018

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
Copy link
Author

Shookbelf commented Jan 26, 2019

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
Copy link
Contributor

dhardy commented Mar 6, 2020

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:

  • optionally, no decorations (already possible)
  • skip the taskbar
  • optionally, able to block interaction with parent window
  • optionally, able to close self if focus is lost (for menus & tooltips) — with e.g. Qt on X11 these even capture the next click anywhere on the screen, meaning it takes two clicks to activate a different window
  • precise positioning

To expand on the latter:

  • things like file-open dialogs don't matter too much but should be over the parent
  • menus are usually aligned to one side of a target box, flipping to the other side if there is insufficient space (and the app may want to know which side)
  • since multi-screen set-ups are not always a simple rectangle and since winit's users only use coordinates relative to the window, the user can do no more than specify a target rect in window-coordinates and a preferred alignment direction

@ArturKovacs
Copy link
Contributor

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
Copy link
Contributor

dhardy commented Jun 24, 2020

@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
Copy link
Contributor

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
Copy link
Author

Shookbelf commented Jul 20, 2020

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
Copy link
Member

notgull commented May 2, 2023

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

@ids1024
Copy link
Member

ids1024 commented May 2, 2023

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

Looking at how GTK4 implements GdkPopup:

  • Wayland: uses xdg_popup, which is created with a parent window or popup, and is positioned relative to it.
  • X11: uses an override-redirect, save-under window (save-under seems to be an optional optimization here)
  • Windows: Uses the WS_POPUP style, and sets the "owner" of the window to the parent window
  • macOS: sets a few properties:
    [window setDecorated:NO];                                                                                                  
    [window setExcludedFromWindowsMenu:YES];                                                                                   
    [window setLevel:NSPopUpMenuWindowLevel];

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
Copy link
Member

ids1024 commented May 2, 2023

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

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
Copy link

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
Copy link
Member

notgull commented Feb 5, 2024

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
Copy link

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
Copy link
Member

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
Copy link
Member

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
Copy link

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
Copy link

I believe for Wayland, we're blocked by Smithay/client-toolkit#5; as @elinorbgr mentioned above.

@kchibisov
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C - needs discussion Direction must be ironed out D - average Likely as difficult as most tasks here DS - macos DS - wayland DS - windows DS - x11 H - help wanted Someone please save us P - low Nice to have S - api Design and usability S - enhancement Wouldn't this be the coolest?
Development

No branches or pull requests