Skip to content

Crash when second window is closed first in multiple_windows example. #19424

Open
@sroauth

Description

@sroauth

Bevy version

0.16.0

Relevant system information

  • Rust version: rustc 1.85.0 (4d91de4e4 2025-02-17)
  • Operating system: macOS Sequoia 15.5 (24F74)
  • Graphics adapter info:
`AdapterInfo { name: "Apple M1", vendor: 0, device: 0, device_type: IntegratedGpu, driver: "", driver_info: "", backend: Metal }`

What I did

Ran the multiple_windows example provided in the bevy repository.

Steps to reproduce:

  1. Run the example.
  2. Close the second window before the primary window.

What went wrong

  • Expected behavior:
    The application should handle the second window closing gracefully and continue running with the first window.
  • Actual behavior:
    The application crashes immediately when the second window is closed first. No crash occurs when the first window is closed before the second.

Additional information

  • After investigation, I tracked the crash down to the AccessKitAdapter removal logic in the window_closed system of the accessibility module in the bevy_winit crate.
  • As a workaround, I delayed the AccessKitAdapter removal in the window_closed system by 1 frame, which prevented the crash. However, this is admittedly a hacky solution and likely not ideal for upstream.
fn window_closed(
    // Removed
    // mut adapters: NonSendMut<AccessKitAdapters>,

    // Added
    mut removal_queue: ResMut<AdapterRemovalQueue>,

    mut handlers: ResMut<WinitActionRequestHandlers>,
    mut events: EventReader<WindowClosed>,
) {
    for WindowClosed { window, .. } in events.read() {
        // Removed
        // adapters.remove(window);

        // Added
        removal_queue.to_remove.push(*window);
        removal_queue.frame_delay = 1;

        handlers.remove(window);
    }
}

impl Plugin for AccessKitPlugin {
    fn build(&self, app: &mut App) {
        app.init_non_send_resource::<AccessKitAdapters>()
            .init_resource::<WinitActionRequestHandlers>()

            // Added
            .init_resource::<AdapterRemovalQueue>()

            .add_event::<ActionRequestWrapper>()
            .add_systems(
                PostUpdate,
                (
                    poll_receivers,
                    update_accessibility_nodes.run_if(should_update_accessibility_nodes),
                    window_closed
                        .before(poll_receivers)
                        .before(update_accessibility_nodes),

                    // Added
                    delayed_adapter_removal.after(window_closed),

                )
                    .in_set(AccessibilitySystem::Update),
            );
    }
}

// Added
#[derive(Resource, Default)]
struct AdapterRemovalQueue {
    to_remove: Vec<Entity>,
    frame_delay: usize,
}

// Added
fn delayed_adapter_removal(
    mut adapters: NonSendMut<AccessKitAdapters>,
    mut removal_queue: ResMut<AdapterRemovalQueue>,
) {
    if removal_queue.frame_delay > 0 {
        removal_queue.frame_delay -= 1;
        return;
    }

    for window in removal_queue.to_remove.drain(..) {
        println!("Removing adapter after delay for {:?}", window);
        adapters.remove(&window);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-WindowingPlatform-agnostic interface layer to run your app inC-BugAn unexpected or incorrect behaviorO-MacOSSpecific to the MacOS (Apple) desktop operating systemS-Needs-ReproductionNeeds an up-to-date or minimal reproduction

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions