Skip to content

[Bug] 多显示器变更后,窗口可能启动在屏幕外且无法恢复 #298

Description

@KurisuRakko

关联问题

Follow-up:#161

#161 曾因被认为属于 Windows 多显示器问题而关闭。对当前窗口恢复代码复核后,可以确认应用层仍缺少保存坐标的可见性校验,因此在显示器拓扑变化后能够稳定出现该问题。

已在 #161 补充代码分析;由于无权限重开他人创建的 issue,新建此 issue 跟踪修复。

问题现象

AUTO-MAS 会保存主窗口的位置。如果上次退出时窗口位于副屏,之后断开副屏再启动,主窗口仍可能恢复到旧副屏坐标,导致:

  • 任务栏和托盘图标正常出现;
  • 主窗口完全不可见;
  • 点击任务栏图标也无法把窗口恢复到当前屏幕;
  • 部分环境下 Win + Shift + ←/→ 同样无法找回窗口。

复现步骤

  1. 连接两个显示器。
  2. 将 AUTO-MAS 主窗口移动到副屏。
  3. 正常退出应用,保存副屏窗口坐标。
  4. 断开副屏,只保留主屏。
  5. 再次启动 AUTO-MAS。

也可以把 config/frontend_config.json 中的 UI.location 设置为远超当前桌面范围的坐标进行验证。

实际结果

窗口使用已失效的旧坐标创建,完全位于所有当前显示器工作区之外。

期望结果

启动时检测保存的窗口 bounds 是否仍与任一显示器工作区有效相交。如果窗口不可操作,应自动移回主显示器可见区域。

根因定位

问题位于 frontend/electron/main.tscreateWindow() 及窗口边界更新逻辑:

  • config.UI.location 读取 cfgX/cfgY
  • screen.getDisplayNearestPoint({ x: cfgX, y: cfgY }) 只用于获取显示器缩放和工作区尺寸。
  • 创建 BrowserWindow 时仍原样传入 x: cfgX, y: cfgY,没有约束到目标显示器的 workArea
  • recomputeMinSize() 仅修正宽高,不修正 x/y
  • 未监听 screen.on('display-removed') 对现有窗口进行恢复。

因此这不仅是 Windows 自身行为,应用当前确实会恢复未经校验的失效坐标。

修复建议

增加统一的窗口可见性校验函数,在启动恢复和显示器变化时使用:

  1. 通过 screen.getAllDisplays() 获取所有显示器 workArea
  2. 检查待恢复 bounds 是否与至少一个工作区存在足够的有效相交,建议至少保证一段标题栏可见并可拖动。
  3. 若与所有工作区均无有效相交,则将窗口居中放到 screen.getPrimaryDisplay().workArea
  4. 将窗口宽高限制在目标工作区内,并保存修正后的 bounds。
  5. 监听 display-removeddisplay-metrics-changed,显示器布局变化后重新校验。
  6. 正确支持位于主屏左侧或上方显示器的合法负坐标,不能简单限制 x/y >= 0
  7. 最大化窗口可先修正其 normal bounds,再执行 maximize()

验收标准

  • 从已断开的副屏坐标启动时,窗口自动恢复到主屏可见区域。
  • 更改显示器排列、分辨率或缩放后,窗口仍保留可操作区域。
  • 左侧/上方显示器产生的合法负坐标不会被误判。
  • 保存窗口尺寸超过当前工作区时会被合理收缩。
  • 修正后的 bounds 被持久化,后续启动无需重复恢复。
  • 单显示器、双显示器、最大化及非最大化状态均正常。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions