Skip to content

Probably a small bug in the x11 visibility tree related to XWayland #331

Closed

Description

@baltobor

Hello everyone,

we talked for a short time on Discord. As promised I file a short issue here.

Platform:

  • Arch linux
  • Cosmic dm
  • DAW: Bitwig Studio 6, installed from flatpak. A 30 day trial is available.
  • AMD x86_x64

My small synth project which is creating an embedded gui using baseview could be found by the DAW,
could always load the plugin and play sounds. It is based on clack. But when opening the GUI window it stayed black.

By reading the logs of the DAW (which is stored in a hidden folder in the home directory) I could trace down the
location: on_frame() was not called.

In commit 13ccd15 in file
'src/platform/x11/visibility_tree.rs' at line 306 I added:

let is_ancestor = ancestry.own_window_id().is_some_and(|id| id != current_window);
let finally_mapped = mapped || is_ancestor;

// All checks succeeded, now register the current window info and fetch info from the parent.
ancestry.push(Ancestor { id: current_window, mapped: finally_mapped.into() });

Here is what probably happened:

Wayland-native plugin hosts (?) probably create XEmbed container windows via XWayland (and never truly map them to X11)? This is just a guess. The window content then is composited by the Wayland compositor instead of X11.

In this case treating an unmapped parent window as “invisible” would permanently block “on_frame()” calls. And unmapped parent windows should be impossible in native X11. For parent windows (not our own window), we force “mapped=true” even if X11 (XWayland) reports that the window is “UNMAPPED.” If the host later hides its window, we receive “UnmapNotify” events via the “SubstructureNotify” mask registered above, which correctly sets “own_window_is_viewable” to “false” then.

I know, this is “hack-like”, but made my synth work as plugin in that situation.

Maybe this patch helps to understand XWayland issues or point to an exception of some DAW's. At my system this patch made baseview work perfectly in my dm and BitwigStudio. I'm not sure if this is a bug of my systems configuration or baseview. But I wanted to share this observation in case it's helpful.

Activity

  1. BillyDM commented on Sep 19, 2026

    @BillyDM
    Contributor

    This might be affecting nice-plug too: https://codeberg.org/RustAudio/nice-plug/issues/95

  2. prokopyl commented on Sep 23, 2026

    @prokopyl
    Member

    #340 should fix this issue, can you give it a try?

  3. baltobor commented on Sep 23, 2026

    @baltobor
    Author

    I can approve: Pull request 340 fixes this issue!

    In my synth I use a scope. There I can see the GUI only being drawn on mouse and keyboard events. Which is perfectly working and saving unneeded extra render loops.

    The scope is a special use case. I've seen there is a WakeHandle. Probably this is the right way to wakeup the GUI for this kind of purposes. But generally speaking: This fix is working. Consider this issue to be closed.

  4. justinas commented on Sep 25, 2026

    @justinas

    Seems like #340 fixes it!

    Tested plugin_clack_femtovg, it doesn't exhibit the problem anymore.

    Tested with gain_egui from nice_plug by adding this in nice-plug/Cargo.toml:

    [patch.crates-io]
    baseview = { git = "https://github.com/RustAudio/baseview.git", rev = "9cdee50d1dd3e8b7d4c751cd818d621956a55a9f" }
    egui-baseview = { path = "../egui-baseview" }

    and applying this to my local copy egui-baseview:

    diff --git a/src/window.rs b/src/window.rs
    index 8ee52ed..53d1614 100644
    --- a/src/window.rs
    +++ b/src/window.rs
    @@ -533,7 +533,7 @@ fn update_modifiers(
     }
     
     impl<A: App> WindowHandler for EguiWindow<A> {
    -    fn on_frame(&self) -> Result<(), HandlerError> {
    +    fn draw(&self) -> Result<(), HandlerError> {
             let mut do_repaint_now = if let Some(repaint_notifier) = &self.repaint_notifier {
                 repaint_notifier.repaint_requested()
             } else {

    it works as expected now too.

  5. ark-ain commented on Oct 8, 2026

    @ark-ain

    I had a similar bug when developping a vst with nice-plug in bitwig studio. tried building the gain_iced example and also got the bug. Here is the bug and my config :

    Environment: Fedora 44 with Wayland,
    host Bitwig Studio 6.1.3,
    baseview 0.3.7 via iced_baseview 0.5.2 / nice-plug-iced 0.4.1

    Steps: Compile and load the nice-plug gain_iced example in Bitwig, play audio, stop moving the mouse.

    Expected: the peak meter keeps updating.
    Actual: the peak meter stop updating after about one second; the GUI freezes
    until the window receives input. with_always_redraw(true) does not help.
    The meter keeps updating only if the mouse is place above the window and the mouse keeps moving.

    Suspected cause: in platform/x11/event_loop.rs, a PresentCompleteNotify with
    e.msc <= last_received_msc updates last_received_present but does not set
    draw_now, so handle_redraw never runs, present_notify_requested is never
    set again, and no further NotifyMSC request is sent. The frame chain dies.

    Workaround: always using setup_fallback_frame_timer() on MapNotify and skipping
    handle_present_notify restores continuous frames.

  6. prokopyl commented on Oct 9, 2026

    @prokopyl
    Member

    iced_baseview has not yet been updated to baseview v0.4.0, which is the first version that has the fix (#340).

    When iced_baseview gets updated, it should fix that issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions