显示器选择与边界计算

基本信息

属性 值
核心方法 ClientProxy#getAppropriateScreenBounds(Rectangle, int)
监视器索引基数 1 起(findScreenDimensionsByID 用 screens[monitorID - 1])
自动选择哨兵 Reference.AUTOMATIC_MONITOR_SELECTION = 0
取显示器信息的方式 java.awt.GraphicsEnvironment#getScreenDevices(),不是 LWJGL

分支优先级

方法是一条 if / else-if 链,先到先得:

顺序 条件 结果
1 advanced 且 onlyRemoveDecorations 直接用 currentCoordinates,不 resize 也不移动
2 advanced 且 customFullscreenDimensions 且 H > 256 且 W > 256 自定义矩形
3 desiredMonitor < 0 或 == 0 按窗口中心点落在哪块屏来选
4 其余(指定了 ≥ 1 的屏号) 按屏号取;取不到则退回分支 3

分支 1 因 onlyRemoveDecorations 恒为 false 而是死代码, 详见 配置项 的"第 10 个配置项从未写入"。

自动模式:按窗口中心点判断

findCurrentScreenDimensionsAndPosition(x, y) 遍历 getScreenDevices(), 返回第一个 bounds.contains(x, y) 的显示器。传入的 (x, y) 是当前窗口矩形中心:

Point centerCoordinates = new Point(
    (int) (currentCoordinates.getMinX() + currentCoordinates.getWidth() / 2),
    (int) (currentCoordinates.getMinY() + currentCoordinates.getHeight() / 2));

全部 GraphicsDevice 都不含该点时(Java 报告不出匹配屏),退回 LWJGL 的 Display.getDesktopDisplayMode() 宽高,并假定原点为 (0, 0)。

自定义尺寸:X/Y 是相对偏移

分支 2 生效需要同时满足四项:advanced 总开关开、自定义总开关开、 W > 256 且 H > 256。只有宽高都过 256 才生效,缺一不可。

选中屏号(desiredMonitor > 0)时,X/Y 会被解释为相对该屏原点的偏移:

screenBounds.setLocation(actualScreenBounds.x + screenBounds.x,
                         actualScreenBounds.y + screenBounds.y);

desiredMonitor == 0(自动)时则直接用配置里的 X/Y 绝对值。 语言文件的描述与此一致:X 为"主显示器最左像素列"或"所选显示器最左像素列"。

屏号取不到时的降级

findScreenDimensionsByID 有三重保护,任一命中返回 null:

  • monitorID < 1 → null(所以屏号 0 和负数都进不了这条路径);
  • screens == null || screens.length == 0 → null;
  • screens.length < monitorID → null(越界)。

null 会让分支 4 退到分支 3 的自动选择——即"指定了但没接上,就当成自动"。

与分支 2 的交互盲点

desiredMonitor > 0 才会走"取实际屏原点做偏移"这一步,但取原点的 findScreenDimensionsByID(desiredMonitor) 可能返回 null; 源码对这里的 null 做了判断(if (actualScreenBounds != null)), 只是不施加偏移——窗口会落在绝对 X/Y 上,语义与注释里的"相对偏移"不符。

相关条目

  • 全屏切换流程 - 本方法产出的 screenBounds 在第 3 步被消费
  • 配置项 - fullscreenMonitor 与 5 个 customFullscreenDimensions* 的默认值
  • 启动初始化 - 启动时也走同一套边界计算