Open michaelrampl opened 3 weeks ago
If I recall correctly the always on top works(ed) on X11 but didn't on Wayland. My project that uses this features has taken a back sear the past couple of months, but I thought that's what I remember from using it.
When you tested it using X11 was it a full X11 instance, or running under XWayland?
I've had full X11 and XWayland sessions running individually.
When starting the X11 sessions, loginctl show-session 2 -p Type
also shows x11 correctly.
If wayland is not supported (yet), It should be mentioned in the documentation.
If wayland is not supported (yet), It should be mentioned in the documentation.
The documentation does says on Window Managers that support it. I don't know enough about Wayland to know if that's a Wayland issue or lack of Support for a Wayland protocol. One of the actual Slint developers might have more to offer here.
I was testing it on an Arch install under Wayland with Gnome and it didn't work. I thought I remember testing on X11 as well and it did work, but it's been a while.
I'll see if I can load up my system, as well as get a KDE install and maybe some other to try my program on. Might get some more info out of it.
Having a plain simple winit example featuring with_window_level(winit::window::WindowLevel::AlwaysOnTop)
seems to work on X11
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::window::{Window, WindowId};
#[derive(Default)]
struct App {
window: Option<Window>,
}
impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
println!("resumed");
self.window = Some(event_loop.create_window(Window::default_attributes().with_window_level(winit::window::WindowLevel::AlwaysOnTop)).unwrap());
}
fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
match event {
WindowEvent::CloseRequested => {
println!("The close button was pressed; stopping");
event_loop.exit();
},
WindowEvent::RedrawRequested => {
self.window.as_ref().unwrap().request_redraw();
}
_ => (),
}
}
}
fn main() {
let event_loop = EventLoop::new().unwrap();
event_loop.set_control_flow(ControlFlow::Poll);
event_loop.set_control_flow(ControlFlow::Wait);
let mut app = App::default();
let _ = event_loop.run_app(&mut app);
}
Also https://rust-windowing.github.io/winit/winit/window/enum.WindowLevel.html says it's currently unsupported on wayland
Having a plain simple winit example featuring
with_window_level(winit::window::WindowLevel::AlwaysOnTop)
seems to work on X11
Certainly sounds like a Slint issue then. I'll try and test mine and report back. My project is still back on Slint 1.6...although I want to say the last version I tested on X11 was back on v1.2 or 1.4. I wonder if this problem cropped up I'm one of the newer versions.
I try to reproduce this and there is indeed a bug.
With winit, backend, I verified that we do indeed call winit::Window::set_window_level
with the right level.
I also noticed that if you have something like CheckBox { toggled => { root.always-on-top = self.checked; } }
it works. But for some reason, it doesn't work at startup.
With Qt, disabling the always-on-top actually hide the window.
To me, it looks like what we pass to the underlying library (Qt, winit) is correct, and something wrong happens in these library or in the window manager.
I appear to be having some instability issues with X11 on my setup at the moment, but doing some quick testing I am experiencing this bug in the current version of Tomotroid which is using Slint 1.7.2. I checked out an older version compiling with Slint 1.6, and the always on top seemed to be working (as well as I could test with the instability issues).
So it looks like the bug cropped up somewhere between Slint 1.6 and 1.7.2. Hopefully that helps narrow down where the issue might lie.
Maybe this is caused by the update of winit to winit 0.30
I can confirm that the set_window_level
function is also being called correctly in internal/backends/winit/winitwindowadapter.rs
:update_window_properties
(at least the first time)
I also can confirm that the checkbox hack works.
As a dirty workaround one could use a single-shot timer like this:
Timer {
interval: 100ms;
running: true;
triggered => {
root.always-on-top = true;
self.running = false;
}
}
Without the hack the following happens: Upon start, the code
if self.window_level.replace(new_window_level) != new_window_level {
winit_window_or_none.set_window_level(new_window_level);
}
is being called 3 times. The first time the level will be set to the winit::window::Window
object. The second and third time it will not be set because the value stays the same for WinitWindowAdapter
. So i would assume that somewhere after the first call, the level of the underlying winit::window::Window
gets changed without WinitWindowAdapter
noticing it.
Removing the condition, thus always setting the level seems to solve the issue
set_window_level(new_window_level);
This most likely will not be the fix we want as it might affect https://github.com/slint-ui/slint/issues/4225. But for me this confirms the theory that something is happening to the state underneath after the first call.
On Linux (nixos) both under x11 and wayland (tested using KDE), the
always-on-top
property doesn't seem to workCargo.toml
main.slint
main.rs
It looks like SLINT uses the
winit
crate which should support the feature tough https://docs.rs/winit/latest/winit/window/enum.WindowLevel.html#variant.AlwaysOnTop