slint-ui / slint

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

Right click on title bar causes event loop to hang #5720

Open dstric-aqueduct opened 1 month ago

dstric-aqueduct commented 1 month ago

<-- Please mention your platform and the programming language you are using Slint with -->

Windows x86-64 with Rust

<-- For bugs, please give steps on how to reproduce. What is the expected behavior and what do you see instead. -->

Right clicking on the Window title bar seems to pause the event loop. Maximizing the window by making it full screen restarts the loop and updates resume.

We followed the bridge pattern from an example app to handle updating a global parameter:

// The following line ensures that, in release mode, the application does not spawn a console window in Windows.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

// Include Slint UI modules. Slint is used for creating the graphical interface.
slint::include_modules!();

mod bridge;
mod worker;

fn main() {
    // Initialize the main UI from the `Ui` component defined in Slint.
    let ui = Ui::new().expect("Failed to create UI");

    let stream_dialog = StreamControlsDialog::new().expect("Failed to Stream Controls Dialog");

    bridge::init(&ui);

    // Create a worker thread that will handle background tasks without blocking the UI.
    let worker_h = worker::Worker::new(&ui, &stream_dialog);

    // Bind UI events to their respective handlers.
    bridge::bind_events(&ui, &worker_h);

    ui.global::<SystemDisplayEvents>().on_show_settings(move || {
        stream_dialog.show().expect("Failed to show Stream Controls Dialog");
    });

    // Display the UI window.
    ui.show().expect("Failed to show UI");

    // Run the Slint event loop to keep the UI responsive.
    slint::run_event_loop().expect("Failed to run event loop");

    // Ensure the worker thread is properly joined back before exiting.
    worker_h.join().expect("Worker thread failed to join");
}

Relevant part of worker.rs update logic.

/// Renders UI updates.
#[inline(always)]
fn render_ui_updates<const N: usize>(
    handle: &slint::Weak<Ui>,
    controls_handle: &slint::Weak<StreamControlsDialog>,
    state: &mut State<N>,
    window_size: &Arc<RwLock<PhysicalSize>>,
) {
    let stream_data: Vec<UiStreamData> = state.data.iter().map(|s| s.into()).collect();
    let ws = window_size.read_recursive().clone();
    let chart_image = match state.create_chart(ws) {
        Ok(image) => Some(image),
        Err(e) => {
            log::debug!("Error generating chart: {:?}", e);
            None
        }
    };

    // Update the window size
    let ws = window_size.clone();

    let steam_data_clone = stream_data.clone();

    if let Err(e) = handle.clone().upgrade_in_event_loop(move |h| {
        let mut ws = ws.write();
        *ws = h.window().size();

        let stream_data: VecModel<UiStreamData> = VecModel::from(steam_data_clone);

        h.global::<DataState>()
            .set_streams(ModelRc::from(Rc::new(stream_data)));

        if let Some(image) = chart_image {
            let image = slint::Image::from_rgb8(image);
            h.global::<DataState>().set_chart0(image);
        }
    }) {
        log::error!("{e:?}");
    }

    if let Err(e) = controls_handle.clone().upgrade_in_event_loop(move |h| {
        let stream_data: VecModel<UiStreamData> = VecModel::from(stream_data);

        h.global::<DataState>()
            .set_streams(ModelRc::from(Rc::new(stream_data)));
    }) {
        log::error!("{e:?}");
    }
}

I can provide a movie of the issue if that's helpful.

Finally, thank you for this wonderful framework!

Vadoola commented 1 month ago

I have an issue that may or may not be related. I hadn't posted my issue yet since I was trying to determine if it was something I was doing wrong first (since I'm manually creating the "title bar").

In Tomotroid on my frameless window with manually recreated title bar. When clicking on the Title bar (say to move the window) the active timer pauses. As soon as you release the title bar it starts again.

I only observe this issue on Windows, in both Win 10 and Win 11, release and debug builds. This issue does not occur on Linux (under X11 or Wayland)

ogoffart commented 1 month ago

Thanks for filling a bug

I can provide a movie of the issue if that's helpful.

Yes please, that'd be helpfull

dstric-aqueduct commented 1 month ago

Hi Olivier -

Here's a link to a video of the issue: https://youtu.be/C1vquIm46DA

I couldn't capture the title bar in the video; the displays stop updating immediately after the right click on the title bar (this is Windows 10). Double clicking to make the window full screen restarts the updates.

Vadoola commented 1 month ago

After doing a quick look back at my issue I'm not sure it's related. As already mentioned I'm manually recreating a "title bar", but also after checking again the timer does not stop when I click on the title bar but only when I start moving the window.

If you feel it could be relevant I've captured some videos, if not I can keep digging into the issue on my end and perhaps open another issue. In the Linux video you can see the timer never stops. In Windows I've included a mouse capture overlay you can see when I click the title bar the timer keeps running, but as soon as I start moving the window the timer pauses.

https://github.com/user-attachments/assets/e65b7c98-9ad8-454d-8805-ad9f05cac55d

https://github.com/user-attachments/assets/291b31ec-d7f1-428b-a2aa-394ffd189426

Vadoola commented 1 month ago

So I don't want to upload while tethering so I'll have to come back and upload the code to Github and some videos later. But I now have a small sample app that demonstrates both the right click on the tool bar as well as left click and dragging the window using a normally framed window. So it would appear that perhaps these issues are related and not something I'm doing to move my frameless window around.

Vadoola commented 1 month ago

I haven't had a chance to take a video yet. I've only had a chance to test this on Windows 11, not 10 yet, but this repo is a minimum example that demonstrates the issue @dstric-aqueduct and I are both having.

If I get a chance I can try and dig into it more later, and upload some videos. in the mean time here is the repo: https://github.com/Vadoola/win_slint_event_loop_issue

XiongDa457 commented 1 month ago

I have a similar problem, and from what I can see the event loop hangs from moving the window, drag resizing or right clicking the title bar, just anything that has to do with the Windows window manager in general.

ogoffart commented 1 month ago

This seems to be a bug in winit: https://github.com/rust-windowing/winit/issues/3272