Skip to content

Conversation

joshua-holmes
Copy link
Contributor

@joshua-holmes joshua-holmes commented Jun 11, 2025

After removing !Send resources, GILRS and WINIT_WINDOWS were not made public, which is a breaking change. This was brought up in a comment on that PR. This PR makes them public.

Fixes #19540.

@alice-i-cecile alice-i-cecile added this to the 0.17 milestone Jun 11, 2025
Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a small note, but other than that LGTM

Thank you

@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events A-Windowing Platform-agnostic interface layer to run your app in C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it P-Regression Functionality that used to work but no longer does. Add a test for this! labels Jun 11, 2025
@alice-i-cecile
Copy link
Member

Waiting a bit for the response on the comment above, but I won't block on it :)

@joshua-holmes
Copy link
Contributor Author

Thanks for the suggestion @IceSentry! I added to the document

@alice-i-cecile
Copy link
Member

Great stuff :) Let me know when you've got the Markdown nag bot happy and I'll merge this!

@joshua-holmes
Copy link
Contributor Author

Looks like the linting job is passing @alice-i-cecile

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 12, 2025
Merged via the queue into bevyengine:main with commit 8010185 Jun 12, 2025
31 of 32 checks passed
});
```

If a borrow is attempted while the data is borrowed elsewhere, the method will panic.
Copy link

@TeamDman TeamDman Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any guidance on how to borrow WINIT_WINDOWS without panicking? I have a system in a custom schedule running after Last using NonSendMarker that's getting a panic for RefCell already borrowed

use bevy::app::MainScheduleOrder;
use bevy::ecs::schedule::ExecutorKind;
use bevy::ecs::schedule::ScheduleLabel;
use bevy::ecs::system::NonSendMarker;
use bevy::prelude::*;
use bevy_winit::WINIT_WINDOWS;
use std::any::type_name;

pub struct WindowIconPlugin;

impl Plugin for WindowIconPlugin {
    fn build(&self, app: &mut App) {
        app.register_type::<WindowIcon>();
        app.add_message::<AddWindowIconWithRetry>();
        app.add_systems(Update, emit_window_icon_requests);

        // Set up a custom schedule to run the window icon update as an exclusive system.
        // We want to avoid `RefCell already borrowed` issues.
        let mut custom_update_schedule = Schedule::new(UpdateWindowIconsSchedule);
        custom_update_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
        app.add_schedule(custom_update_schedule);

        let mut main_schedule_order = app.world_mut().resource_mut::<MainScheduleOrder>();
        main_schedule_order.insert_after(Last, UpdateWindowIconsSchedule);

        app.add_systems(UpdateWindowIconsSchedule, set_window_icon);
    }
}

#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
struct UpdateWindowIconsSchedule;

#[derive(Debug, Component, Reflect)]
pub struct WindowIcon {
    pub image: Handle<Image>,
}

#[derive(Debug, Clone, Reflect, Message)]
pub struct AddWindowIconWithRetry {
    pub image: Handle<Image>,
    pub window: Entity,
}

impl WindowIcon {
    pub fn new(image: Handle<Image>) -> Self {
        Self { image }
    }
}

// Sends an AddWindowIconWithRetry message for any entity that just received WindowIcon
fn emit_window_icon_requests(
    mut q: Query<(Entity, &WindowIcon), Added<WindowIcon>>,
    mut writer: MessageWriter<AddWindowIconWithRetry>,
) {
    for (entity, icon) in &mut q {
        debug!("Detected new WindowIcon on {:?}", entity);
        writer.write(AddWindowIconWithRetry {
            image: icon.image.clone(),
            window: entity,
        });
    }
}

fn set_window_icon(
    mut events: ParamSet<(
        MessageReader<AddWindowIconWithRetry>,
        MessageWriter<AddWindowIconWithRetry>,
    )>,
    assets: Res<Assets<Image>>,
    _main_thread_marker: NonSendMarker,
) {
    if events.p0().is_empty() {
        return;
    }
    WINIT_WINDOWS.with_borrow_mut(|windows| { info!("Ahoy!") });
    // let outgoing = WINIT_WINDOWS.with_borrow_mut(|windows| {
    //     let mut outgoing = Vec::new();
    //     for event in events.p0().read() {
    //         debug!(?event.window, ?windows, "Handling {}", type_name::<AddWindowIconWithRetry>());

    //         // Identify window
    //         let target_window = windows.get_window(event.window);
    //         let Some(window) = target_window else {
    //             warn!(
    //                 ?windows,
    //                 "Window {:?} does not exist, retrying later...",
    //                 event.window
    //             );
    //             outgoing.push(event.clone());
    //             continue;
    //         };

    //         // Fetch the image asset
    //         let Some(image) = assets.get(&event.image) else {
    //             error!(
    //                 "Image handle {:?} not found in assets, the window will not have our custom icon",
    //                 event.image
    //             );
    //             continue;
    //         };

    //         // Acquire pixel data from the image
    //         let Some(image_data) = image.data.clone() else {
    //             error!(
    //                 "Image handle {:?} has no data, the window will not have our custom icon",
    //                 event.image
    //             );
    //             continue;
    //         };

    //         // Convert between formats
    //         let icon = match winit::window::Icon::from_rgba(
    //             image_data,
    //             image.texture_descriptor.size.width,
    //             image.texture_descriptor.size.height,
    //         ) {
    //             Ok(icon) => icon,
    //             Err(e) => {
    //                 error!("Failed to construct window icon: {:?}", e);
    //                 continue;
    //             }
    //         };

    //         // Set the window icon
    //         info!(image_size = ?image.size(), "Setting window icon");
    //         window.set_window_icon(Some(icon));
    //     }
    //     outgoing
    // });

    // for event in outgoing {
    //     events.p1().write(event);
    // }
}

EDIT: just going to create a discussion post for this question

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #21250 where I demonstrate my problem and I identified the solution:

The real problem was that I was using with_borrow_mut when with_borrow is sufficient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events A-Windowing Platform-agnostic interface layer to run your app in C-Usability A targeted quality-of-life change that makes Bevy easier to use P-Regression Functionality that used to work but no longer does. Add a test for this! S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing migration guide for WINIT_WINDOWS
5 participants