WindowRequestApi

WindowRequestApiflor::windows 里的窗口延迟命令接口。它为 WindowId 提供一组 request_* 方法,把窗口操作加入 Flor 事件循环队列,而不是在当前调用栈里直接调用平台窗口 API。

use flor::windows::WindowRequestApi;

window_id.request_set_size((1024, 768));

设计目的

request_* 方法用于避免窗口操作在错误的时机直接重入平台层。

典型风险包括:

  • 窗口消息处理过程中直接改窗口,导致平台消息重入。
  • 响应式更新、布局刷新或绘制过程中直接 set_size / destroy,导致事件循环嵌套执行。
  • 跨线程回调直接控制窗口,造成 UI 线程限制、等待顺序问题、死锁或死循环。

WindowRequestApi 会把操作延后到 Flor 事件循环的统一 flush 点:先结束当前派发,再按 FIFO 顺序执行已入队的窗口命令。

Trait

pub trait WindowRequestApi {
    fn request_update_window(self) -> WindowCommandRequest;
    fn request_show(self) -> WindowCommandRequest;
    fn request_hide(self) -> WindowCommandRequest;
    fn request_set_window_mode(self, mode: WindowMode) -> WindowCommandRequest;
    fn request_set_left(self, left: i32) -> WindowCommandRequest;
    fn request_set_top(self, top: i32) -> WindowCommandRequest;
    fn request_set_position(self, pos: (i32, i32)) -> WindowCommandRequest;
    fn request_set_width(self, width: u32) -> WindowCommandRequest;
    fn request_set_height(self, height: u32) -> WindowCommandRequest;
    fn request_set_size(self, size: (u32, u32)) -> WindowCommandRequest;
    fn request_destroy(self) -> WindowCommandRequest;
    fn request_drag_window(self) -> WindowCommandRequest;
}

当前实现为 WindowId 实现这个 trait。

命令清单

方法作用对应同步 API
request_update_window()请求同步窗口更新。update_window()
request_show()显示窗口。show()
request_hide()隐藏窗口。hide()
request_set_window_mode(mode)设置窗口模式。set_window_mode(mode)
request_set_left(left)设置窗口左侧坐标。set_left(left)
request_set_top(top)设置窗口顶部坐标。set_top(top)
request_set_position((x, y))设置窗口位置。set_position((x, y))
request_set_width(width)设置窗口宽度。set_width(width)
request_set_height(height)设置窗口高度。set_height(height)
request_set_size((width, height))设置窗口尺寸。set_size((width, height))
request_destroy()销毁窗口。destroy()
request_drag_window()触发系统窗口拖动。drag_window()

返回值

所有 request_* 方法都会返回 WindowCommandRequest

pub struct WindowCommandRequest {
    // 内部命令 ID
}

它用于给已入队命令挂接执行结果回调:

window_id.request_show().result(|result| {
    if let Err(err) = result {
        eprintln!("show failed: {err}");
    }
});

回调类型是:

impl FnOnce(Result<(), Error>) + Send + 'static

回调会在 flush_window_commands() 执行命令后调用,不会从 result(...) 里立即调用。

result 的时机

WindowCommandRequest 是单次使用句柄。需要结果时,应在创建请求后立刻调用 .result(...)

window_id
    .request_set_size((800, 600))
    .result(|result| {
        if let Err(err) = result {
            eprintln!("resize failed: {err}");
        }
    });

不要先保存请求,再在很久以后挂回调。事件循环可能已经执行并移除了该命令;如果回调注册晚于命令执行,Flor 会用错误结果调用这个回调。

如果不关心结果,可以直接丢弃返回值:

window_id.request_destroy();

跨线程行为

request_* 方法本身始终可用。是否启用 cross-thread-window-commands,影响的是跨线程提交后的事件循环唤醒行为。

feature行为
未启用 cross-thread-window-commands命令仍会入队,但事件循环要等自然醒来后才会处理。
启用 cross-thread-window-commands命令入队后会调用事件循环唤醒能力,让事件循环线程尽快 flush 命令。

cross-thread-window-commands 会自动启用 event-loop-wakeup。完整使用场景见 跨线程窗口命令

执行顺序

命令按 FIFO 顺序执行。flush_window_commands() 每次只处理当前批次:执行过程中新增的命令会留到后续批次处理,避免递归命令不断扩展当前 flush。

执行完成后,如果命令带有 result(...) 回调,Flor 会把回调排入完成队列,再统一调用。