
Bevy 0.20 macOS 应用激活行为迁移指南Window::focused如何控制前台聚焦【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy本文围绕 Bevy 当前仓库中macos_app_activation.md迁移指南展开在 macOS 上Bevy 应用何时请求应用激活成为最前台应用现在由Window::focused字段决定。读完本文你能理解启动时与运行时两条激活路径的源码实现并知道如何通过设置focused: false避免应用抢占用户焦点同时确认默认配置的兼容性不受影响。背景什么是 macOS 上的应用激活macOS 的焦点模型与其他平台不同一个 App 必须先是激活active/frontmost状态它的窗口才有资格接收键盘输入和处于聚焦状态。winit 在构建EventLoop时提供了一个 macOS 专属开关with_activate_ignoring_other_apps(bool)用于决定启动时是否请求 App 激活。在此之前Bevy 应用在 macOS 上启动时会无条件请求激活这意味着即使你的程序只是想后台静默运行或作为多窗口工具的一部分也会把焦点从用户正在使用的应用抢走。本次迁移对应上游 pull request #24702见文档 front matter 中的pull_requests字段把这一行为改为跟随Window::focused配置。行为变更的三条规则原迁移指南给出了三条明确的行为约定全部可以直接在当前仓库源码中验证启动时应用只有在WindowPlugin::primary_window或在WinitPlugin::build之前已存在的任何Window实体带有focused: true时才会请求激活。设置focused: false即可避免启动时抢占焦点。运行时新建窗口启动后创建的可见Window若focused: true会请求激活希望应用保持非激活状态时将其设为focused: false。默认配置不变只使用默认WindowPlugin::primary_window的应用不受影响因为Window::default()中focused初始为true。源码验证一启动时的激活决策在 bevy_winit 的插件构建逻辑 中WinitPlugin::build有一段 macOS 专属代码#[cfg(target_os macos)]// Dont request app activation on startup if all its windows should // start unfocused. Otherwise, app activation would focus one of the // windows. let mut initial_windows_state SystemState::Query(Entity, Window)::new(app.world_mut()); let initial_windows initial_windows_state.get(app.world()).unwrap(); let initially_focused initial_windows.iter().any(|(_, window)| window.focused); event_loop_builder.with_activate_ignoring_other_apps(initially_focused);从源码结构看这里的关键点是在事件循环构建之前用一次性SystemState::get快照查询当前 World 里所有已存在的Window组件。这正是文档中在WinitPlugin::build之前可用的Window实体的判定来源——如果你的插件在WinitPlugin之前注册并预创建了窗口例如通过WindowPlugin::primary_window其focused值会被计入。决策采用iter().any(...)只要任意一个初始窗口focused true就会请求激活全部为false时应用以非激活状态启动。注释也解释了原因若所有窗口本应未聚焦启动却仍请求激活激活动作本身就会聚焦其中某个窗口与预期矛盾。源码验证二运行时新建窗口的聚焦请求第二条规则启动后创建可见窗口时按focused决定是否激活实现于窗口创建系统 bevy_winit 的 system.rs#[cfg(target_os macos)] { // Request app activation via focus_window() if the window should start focused. if window.focused { winit_window.focus_window(); } }即在 winit 窗口实际创建完成之后仅当window.focused为true才调用focus_window()。winit 在 macOS 上以该调用触发 App 激活因此运行期新建窗口抢占前台的开关同样就是这一个字段。实操如何配置避免抢占焦点结合 Window 组件的字段文档focused: bool说明窗口创建后不能被设为未聚焦典型用法如下。启动时不抢占焦点主窗口通过WindowPlugin覆盖主窗口属性把focused置为falseuse bevy::prelude::*; fn main() { App::new() .add_plugins( DefaultPlugins .set(WindowPlugin { primary_window: Some(Window { focused: false, // macOS 启动时不再请求应用激活 ..default() }), ..default() }) .set(WinitPlugin { // 可选事件循环任意线程运行与激活行为无关 ..default() }), ) .add_systems(Startup, setup) .add_systems(Update, my_update) .run(); }其中WindowPlugin::primary_window的默认值是Some(Window::default())见 bevy_window 的 lib.rs而Window::default()的focused为true所以默认行为保持原样——这与迁移指南第三条仅使用默认主窗口的应用不变完全一致。运行时创建的窗口启动后动态spawn的Window实体同样按各自的focused字段处理fn create_secondary_window(mut commands: Commands) { commands.spawn(Window { title: 辅助窗口.to_string(), focused: false, // 创建后不请求 macOS 应用激活 ..default() }); }只要该窗口的focused为true创建时就会触发focus_window()请求激活设为false则应用保持非激活状态适合工具类、后台面板类场景。Window::focused的语义边界与平台限制在使用该字段控制激活行为前需要注意 Window 文档 中明确的约束It cannot be set unfocused after creation窗口创建后不能再把它从聚焦改为未聚焦。也就是说focused: false只能在窗口创建时声明不能在运行期把已聚焦窗口取消聚焦来实现放弃前台。平台差异文档注明 iOS / Android / X11 / Wayland 上未聚焦创建不受 winit 支持iOS / Android / Web / Wayland 上创建后设置 focused不受支持。本迁移指南本身仅针对 macOS 行为但如果你跨平台部署focused的实际生效范围以 winit 的平台支持为准。从 bevy_winit 的 system.rs 中的注释还可看到Window::focused在窗口创建后手动改为false是不支持的用法与本迁移的创建时声明语义一致。验证清单与适用前提适用版本当前仓库Cargo.toml中 Bevy 版本为0.20.0-dev该迁移行为适用于此版本及之后集成 PR #24702 的构建。验证要点主窗口focused: false→ 启动后 macOS 菜单栏中你的应用不应处于高亮激活态也不应抢走用户当前应用的焦点运行期spawn一个focused: true的窗口 → 该窗口创建瞬间应用被激活到前台完全不配置WindowPlugin→ 行为与旧版本一致Window::default()即focused: true。相关路径迁移指南_release-content/migration-guides/macos_app_activation.md、启动决策crates/bevy_winit/src/lib.rs、窗口创建聚焦crates/bevy_winit/src/system.rs、字段定义crates/bevy_window/src/window.rs。小结这次迁移把 macOS 上应用何时成为前台激活应用的决策权交给了Window::focused这一个显式字段启动时由所有初始窗口聚合判定任一聚焦即激活运行时按每个新建窗口单独判定聚焦才调用focus_window()而默认配置因Window::default()本身focused: true保持向后兼容。对需要后台运行或多应用协作的场景只需在建窗口时声明focused: false即可获得不抢占用户焦点的行为——这是当前仓库源码中完整可验证的迁移路径。【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考