rust-windowing / winit

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

window.with_maximized ineffective on X11 #2360

Open John-Nagle opened 2 years ago

John-Nagle commented 2 years ago

Creating a window with .with_maximized() works fine on Windows (Wine 7) but does not generate a maximized window on Linux (x86_64, 20.04 LTS, X (not Wayland)).

Reproduce with

https://github.com/John-Nagle/ui-mock

Build with

cargo build ui-mock --examples or

cargo build ui-mock --examples --target x86_64-pc-windows-gnu

Run ./ui-mock or ./ui-mock.exe in target directory as indicated. Will open full screen on Windows, small window on Linux.

(Ui-mock is a mockup of a game-type user interface, exercising winit, egui, rend3, and rfd. It's a test program to wring out problems in those subsystems before integration into a larger program.)

kchibisov commented 2 years ago

I think X11 doesn't allow that? At least it was stated like that. I'd suggest to call set_maximized shortly after creating the window and making it visible, though, it's indeed strange why it doesn't work.

maroider commented 2 years ago

I think X11 doesn't allow that?

Shouldn't it depend on the WM?

kchibisov commented 2 years ago

I mean maximizing on startup, it can maximize right after without issues.

At least in alacritty we have a special case for X11 to maximize its window after we draw into it or something like that.

John-Nagle commented 2 years ago

Re: "Right after".

Current startup code:

    let app = Ui::new();
    rend3_framework::start(
        app,
        winit::window::WindowBuilder::new()
            .with_title("UI mockup")
            .with_maximized(true),
    )
}

Re: window manager:

wmctrl -m
Name: GNOME Shell
Class: N/A
PID: N/A
Window manager's "showing the desktop" mode: OFF
John-Nagle commented 1 year ago

Tried, after the window was open, calling

window.set_maximized(true)

No effect on Linux 20.04 LTS with GNOME/X11.

kchibisov commented 1 year ago

Could you try with the code we have for maximized for X11 in alacritty, I'm pretty sure it works. https://github.com/alacritty/alacritty/blob/694a52bcffeffdc9e163818c3b2ac5c39e26f1ef/alacritty/src/display/mod.rs#L511

I'm pretty sure I'd need set_visible(true) before.

John-Nagle commented 1 year ago

OK, that does

        #[cfg(not(windows))]
        match config.window.startup_mode {
            #[cfg(target_os = "macos")]
            StartupMode::SimpleFullscreen => window.set_simple_fullscreen(true),
            #[cfg(not(target_os = "macos"))]
            StartupMode::Maximized if is_x11 => window.set_maximized(true),
            _ => (),
        }

which, on Linux/x11, is just window.set_maximized(true) (Which I've already tried with winit.)

What's "window"?

use crate::display::window::Window
...
let window = Window::new(
            event_loop,
            config,
            identity,
            estimated_size,
            #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
            wayland_event_queue,
        )?;

That's Acrility's own Window struct, from here. That has special cases for each platform, and eventually calls WindowBuilder from glutin::window

Further down the rabbit hole into glutin, there's a case for X11, and it finally uses winit's WindowBuilder. I think.

More later. But it's not a simple call to winit.

John-Nagle commented 1 year ago

OK, if I modify the example "window" from glutin, using

    let wb = WindowBuilder::new()    
        .with_title("A fantastic window!")
        .with_maximized(true);

I get a maximized window.

In my program which uses Rend3 and egui, I call

    let app = Ui::new();
    rend3_framework::start(
        app,
        winit::window::WindowBuilder::new()
            .with_title("UI mockup")
            .with_maximized(true),
    )

and do not get a maximized window. So, what's different? More later.

kchibisov commented 1 year ago

Have you made it set_visible(true)?

John-Nagle commented 1 year ago

Have you made it set_visible(true)?

Yes, I tried that.

The glutin window example gets a full screen without doing that. And it's not using Acrility code. So this is some difference between the Rend3->egui->winit chain (which is using Vulkan, not OpenGL) and the gultin->winit chain.

John-Nagle commented 1 year ago

OK, so now I tried the simplest Rend3 example: "cube".

pub fn main() {
    let app = CubeExample::default();
    rend3_framework::start(
        app,
        winit::window::WindowBuilder::new()
            .with_title("cube-example")
            .with_maximized(true),
    );
}

Window is not maximized on Linux.

Built with cargo build --target x86_64-pc-windows-gnu and run under Wine, the window is maximized.

So, the problem is not in egui, or in my code. It's some difference between rend3 and glutin. Both use winit. The problem can be reproduced with standard examples from both those packages. What's different?

kchibisov commented 1 year ago

So, the problem is not in egui, or in my code. It's some difference between rend3 and glutin. Both use winit. The problem can be reproduced with standard examples from both those packages. What's different?

The window must be mapped on X11 to make it maximized. So maximize on startup doesn't work, so what you need to do is to map a window and then maximize it.

Also, are you sure that your window manager supports maximization?

I've just modified the default window example and it works for me on GNOME.

I basically added

.with_visible(true)
.with_maximized(true)

And the window got maximized.

The thing is that on X11 the window can't be maximized unless it's mapped. And mapping a window means that it must be set_visible(true) before calling set_maximized(true), otherwise it won't work and will be ignored.

John-Nagle commented 1 year ago

OK. I'm able to get maximization to work on Linux/X11, but I have to wait until the window is fully initialized small. So, now I have

    let app = Ui::new();
    rend3_framework::start(
        app,
        winit::window::WindowBuilder::new()
            .with_title("UI mockup")
            .with_visible(true)    
            .with_maximized(true)   // this is not effective on Linux/X11
    )

and, separately, in later initialization

        window.set_visible(true);
        window.set_maximized(true);

On Wine/Microsoft Windows, the first is sufficient by itself. On Linux/X11, the second is sufficient by itself, although the window starts out small and then expands to maximum size. Both used together work on both platforms.

This is usable, but needs to be documented. Or WindowBuilder needs to take care of this case automatically.

kchibisov commented 1 year ago

Likely should document how X11 works.

Though in general I wonder if we can enqueue maximized state and apply it on window map notify event.

Also, have you tested the window example from winit with the 2 lines I've mentioned? Does it start maximized for you that way?

LoganDark commented 1 year ago

(AFAIK) X11 has no concept of maximized windows. "Maximization" is a concept introduced by the window manager, as it may have things like a taskbar on-screen that maximized windows shouldn't overlap. Fullscreen is fully defined, maximized not so.

John-Nagle commented 1 year ago

I tried the "fullscreen" example from winit. That was very strange. I got things such as two copies of the window. Screenshot from 2022-07-13 18-18-11 Both F (fullscreen) and X (maximize) commands produce something like that.

After too many mode switches, and the window manager hung and I had to log out.

kchibisov commented 1 year ago

@John-Nagle that's kind of expected since winit doesn't draw anything. I was suggesting to use maximize though. not sure why you've went fullscreen.

John-Nagle commented 1 year ago

Oh, OK. I was just trying all the options suggested by "fullscreen".

As requested, I tried changing Winit's "window" example to

    let window = WindowBuilder::new()
        .with_title("A fantastic window!")
        ////.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
        .with_visible(true)    
        .with_maximized(true)   // this is not effective on Linux/X11
        .build(&event_loop)
        .unwrap();

    event_loop.run(move |event, _, control_flow| {
...

The window is not maximized. Linux X11, same specs as before. Anything else you want me to try?

kchibisov commented 1 year ago

So you don't see a button the right corner? Like it's not that visible. If not, don't think there's anything left to try. Not that I care about X11 here, since it doesn't have a maximimized window as a real concept.

John-Nagle commented 1 year ago

Screenshot from 2022-07-13 18-18-11 Screenshot which was supposed to go with previous message.