slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.55k stars 601 forks source link

Slint apps constantly steal focus on Linux using winit on X11 #4678

Closed hunger closed 8 months ago

hunger commented 8 months ago

While showing the live preview in VSCode, each keypress in the editor makes the Slint preview window focus. That makes the live preview pretty unusable in combination with VSCode.

This happens on Linux using winit. WAYLAND_DISPLAY is unset, DISPLAY is set, so it should use X11.

It does not happen in these setups:

Disabling the accessibility layer in the winit backend does not fix the issue either.

I think this is a upstream bug, but have not found any matching issue in winit.

tronical commented 8 months ago

Does commenting out the code in the body of fn input_method_request in winitwindowadapter.rs help?

tronical commented 8 months ago

Does this happen with any kind of slint code you're previewing (say just a Rectangle {}) or does this happen in particular when there are focusable elements present?

hunger commented 8 months ago

I see the focus stealing with this example:

export component T inherits Rectangle {}
tronical commented 8 months ago

Ok, what about fn input_method_request?

Can you reproduce this also with slint-viewer and --auto-reload?

ogoffart commented 8 months ago

I have the feeling this might be related to the recent maximise/minimise feature. We might call too often to winit when the window attributes changes, even if it didn't change

ogoffart commented 8 months ago

I cannot reproduce the issue on plasma (with the nightly build of our vscode extension). What are the step to reproduce? Does it also happen with the viewer?

hunger commented 8 months ago

I build the slint-lsp and the Slint VSCode extension and start that. I open the preview for anything... and as long as the preview is open, it steals focus from VSCode whenever I type any character into VSCode.

The exact command line I use is this:

cd ~/<SLINT_REPO>/editors/vscode && cargo build -p slint-lsp && npm run build:wasm_lsp && npm run compile && npm run lint && RUST_BACKTRACE=full DISPLAY=:0 WAYLAND_DISPLAY="" SLINT_ENABLE_EXPERIMENTAL_FEATURES=1 code --extensionDevelopmentPath=$PWD ../../examples/

The npm run build:wasm_lsp is not necessary for the native preview, but I keep that around to cover both building native and in WASM mode :-)

I can reproduce this with DISPLAY=:0 WAYLAND_DISPLAY="" cargo run -p slint-viewer -- some.slint --auto-reload: Whenever I edit and save some.slint, the slint-viewer steals focus from the editor.

I am on Linux using Gnome and wayland by default with no Qt being installed on the system. I then set DISPLAY=:0 WAYLAND_DISPLAY="" before starting vscode or the viewer to force the SLint UI into X11 as I can not close the preview window on wayland.

ogoffart commented 8 months ago

I can reproduce the problem. This is only on Gnome Xwayland (wayland compositor, but using X11 from Slint) As I suspected, this is related to minimize, as the problem disappear when commenting this line: https://github.com/slint-ui/slint/blob/3969e09d5bb15f9593ab3e1b9c5cb005c29d078a/internal/backends/winit/winitwindowadapter.rs#L492

Maybe we want to do something like this to workaround:

let value = properties.is_minimized();
if winit_window.is_minimized() != value {
    winit_window.set_minimized(value);
}

And the same for maximized.

This is a shame.

Alternative would be to remember in the winitwindowadapter which value was sent.

tronical commented 8 months ago

This is a shame.

That's true :(

Alternative would be to remember in the winitwindowadapter which value was sent.

I think that we may have to do that.

I noticed two things on the Wayland side here (from reading the winit code):

  1. On wayland, you can't programmatically un-minimize a window.
  2. On wayland, fn is_minimized() always returns None, to indicate that it's not know to the client if the compositor changed the state.

This is also mentioned in the protocol docs at https://wayland.app/protocols/xdg-shell#xdg_toplevel:request:set_minimized:

There is no way to know if the surface is currently minimized, nor is there any way to unset minimization on this surface.

All this leads me to believe that the primary use of the programmatic API for these states is to set them once on startup. After that all bets are off in a cross-platform environment.