Skip to content

设计原则

基本原则。#

这里有一些我试图在开发niri时遵循的基本原则。 在特定情况下,如果有正当理由,可以绕过这些程序。

打开一个新窗口的时候不应该影响其他窗口的大小。#

传统平铺布局的主要弊端在于:你想打开一个新窗口,它却会影响现有窗口的大小。 尤其是在你正在查看浏览器或图像编辑器等大窗口时,如果想快速打开一个终端,它会导致大窗口变得非常小,难以使用,或者内容重新排版,甚至裁剪掉窗口的一部分。

平铺式窗口管理器的常用解决方法是使用更多工作区:当需要打开新窗口时,您可以转到空白工作区并在那里打开它(这样,新窗口就可以占据整个屏幕,而不是屏幕的一小部分)。

可滚动平铺提供了一种替代方案:对于临时窗口,您可以直接打开它们,完成所需操作,然后关闭,而无需影响其他窗口或切换到新的工作区。 它还允许您将同一工作区中更多相关的窗口分组在一起,方法是将不常用的窗口滚动到视图之外。

聚焦窗口不应该自行移动。#

具体来说:在焦点窗口左侧打开、关闭和调整窗口大小时,不应导致焦点窗口在视觉上移动。

当前聚焦的窗口就是你正在工作的窗口。 窗口外发生的事情不应该干扰你正在关注的内容。

行为应立即生效。#

这对于合成器的响应速度和可预测性都很重要,同时也能保持代码的合理性,避免出现极端情况和不必要的异步操作。

  • 调整窗口大小或将内容分列显示等操作会立即生效,即使窗口需要一些时间才能跟上。
  • 带动画的工作区切换可让您的输入立即传输到最终的工作区和窗口,无需等待动画结束。
  • 打开概览(带有缩小动画)后,您可以立即选中窗口;关闭概览后,您的输入会立即返回到窗口,无需等待窗口重新放大。

禁用后,视觉特效不应影响性能。#

禁用此功能后,动画和自定义着色器等功能将不会运行,也不会出现在渲染树中。 此外,还会避免额外的离屏渲染。

即使动画被禁用,动画仍然会“开始”,但持续时间为 0(这样,时间一推进,动画就会立即结束)。 这不会影响性能,但有助于避免代码中出现许多极端情况。

视觉效果不应导致不合理的过度渲染。#

  • 例如,在许多情况下,裁剪到几何体会阻止直接扫描输出(因为窗口表面并非完全可见)。但如果表面或次表面完全可见的(完全位于裁剪区域内),则仍然允许直接扫描输出。
  • 例如,动画可能会造成损坏,甚至每帧都离屏绘制,因为它们通常持续时间很短(并且可以被禁用)。然而,像圆角着色器这样的效果不应该每帧都离屏绘制或造成大量的损坏,因为它运行时间长且持续激活。

注意不可见状态。#

这是从屏幕上无法立即察觉的 niri 状态。这本身并非坏事,但您应该仔细考虑如何降低意外发生的可能性。

  • 例如,当一个显示器断开连接时,它的所有工作区都会移动到另一个已连接的显示器上。为了在第一个显示器重新连接后能够恢复这些工作区,这些工作区会保留其原始显示器的信息——这是一个不可见状态的例子,因为您无法通过查看屏幕来判断。这可能会带来意想不到的后果:想象一下,您在家里断开了一个显示器,然后去上班,彻底重新排列了那里的窗口,之后回到家,突然发现一些随机的工作区出现在了您家里的显示器上。为了减少这种意外情况,每当一个新窗口出现在工作区中时,该工作区都会将其原始显示器重置为当前显示器。这样,您正在使用的工作区就会保持在原来的位置。
  • 例如,niri 会在窗口出现或全屏显示时保存视图位置,以便在之后恢复它。这样,处理对话框的打开和关闭或切换全屏等临时操作就变得不那么麻烦了,因为它不会扰乱视图位置。这也是一种不可见的状态,因为您无法通过观察屏幕来判断关闭窗口后视图位置的恢复情况。如果极端情况下(每个打开的窗口都永久保存之前的视图位置),这可能会造成意外,因为关闭长时间运行的窗口会导致视图位置几乎随机移动。为了减少这种意外情况,niri 为每个工作区只记住一个最后的视图位置,并在窗口焦点切换时忘记该位置。

窗口布局#

以下是窗口布局逻辑的一些设计考虑因素。

  1. 如果窗口或弹出窗口大于屏幕,则应将其对齐到左上角。

    窗口左上角区域更有可能包含重要内容,因此应该始终可见。

  2. 将窗口宽度或高度设置为固定像素大小(例如 set-column-width 1280default-column-width { fixed 1280; })将设置窗口本身的大小,而设置为比例大小(例如 set-column-width 50%)将设置平铺单元的大小,包括 niri 添加的边框。

    • 当使用比例时,用户的意图是在屏幕上平铺多个窗口,因此尺寸计算中应当包含窗口边框。
    • 当使用固定尺寸时,用户的目的是测试某个特定客户端窗口的大小,或截取指定尺寸的截图,因此这时尺寸设置应直接作用于窗口内容本身(不包括边框)。
    • 设置窗口大小后,为了保证代码的合理性,窗口大小始终会转换为包含边框的值。也就是说,先设置 set-column-width 1000,然后再更改 niri 的边框宽度,窗口大小就会相应调整。
  3. 全屏窗口是滚动布局的正常组成部分。

    这是一个很棒的创意,而可滚动平铺技术恰好能完美实现这一点。 全屏窗口并非位于覆盖整个屏幕的“特殊”图层上;相反,它们只是普通的平铺单元,您可以随时切换,而不会影响全屏状态。

    当然,当焦点集中在一个全屏窗口时,您肯定希望它覆盖整个显示器。 这是在逻辑中明确硬编码的:当视图固定在一个已聚焦的全屏窗口上时,顶层外壳层和浮动窗口都会隐藏起来。

    这也是为什么将浮动窗口全屏显示后,它会进入滚动布局的原因。

默认配置#

默认配置旨在为niri新用户提供熟悉、便捷且不会过于突兀的体验。 需要注意的是,这并非“推荐的Rice配置”;我们不想用过于炫酷的彩虹边框和花哨的着色器吓到用户。

由于我们并非一个完整的桌面环境(而且也没有足够的贡献者群体来发展成为一个完整的桌面环境),因此我们无法提供完全集成的体验——发行版在这方面更有优势。 因此,我们希望新的 niri 用户能够阅读并调整 niri 的默认配置。

因此,默认配置包含详尽的注释,并附有指向相关 wiki 章节的链接。 为了避免用户感到信息过载,我们并未在默认配置中包含所有可能的选项;任何过于具体或不常用的选项都可以保留在 wiki 中。 一般原则是,默认配置仅包含用户理应想要更改或知道如何操作的内容。 当然,我们也会宣传一些更独特的功能,例如屏幕录制屏蔽。

我们默认使用 CSD(prefer-no-csd 已被注释掉)。 这为新用户提供了一种简单而熟悉的方式,可以通过标题栏移动和关闭窗口,尤其考虑到 niri 目前还没有服务器端标题栏(至少到目前为止是这样)。

默认情况下,焦点环会完全绘制在窗口后面。 虽然这会影响窗口的透明度,这也是一个常见的误解来源,但如果默认只在窗口周围绘制焦点环,情况会更糟,因为这样会在客户端的圆角处留下空隙。 理想的解决方案是提出一个 Wayland 协议,让窗口向合成器报告其圆角半径(这通常有助于不同合成器中的服务器端装饰)。

默认的焦点环宽度为 4 像素,与客户端装饰的窗口搭配使用效果很好,而且非常醒目;默认的间隙也为 16 像素,与默认的焦点环宽度搭配使用效果很好。

默认输入设置例如触摸板点击和自然滚动等是我认为大多数人使用他们电脑的方式。

阴影默认是关闭的,因为阴影是一种性能消耗较大的着色器,而且许多客户端装饰窗口已经绘制了自己的阴影。

默认屏幕截图路径与 GNOME Shell 一致。

默认窗口规则仅限于修复已知的严重问题(WezTerm)以及执行绝大多数人可能想要的操作(使 Firefox 画中画播放器浮动——它目前无法自行实现这一点,也许 pip 协议会改变这一点)。

默认的快捷键配置主要来源于我自己使用 PaperWM 和其他合成器时的经验。 这些快捷键默认假设使用 QWERTY 键盘布局。 它们的排列方式旨在循序渐进地引导你理解不同的快捷键配置概念。

整体的快捷键设计逻辑如下:如果某个快捷键用于切换位置,那么在此基础上加上 Ctrl,就会变成移动焦点窗口或列到该位置。 加上 Shift 则会触发替代操作:对于焦点或移动类快捷键,它会跨显示器移动或切换;对于调整大小类快捷键,它会从控制宽度改为控制高度,依此类推。 工作区切换的快捷键 ModU / I,位于用于窗口切换的 ModJ / K 的上一排键,这样排列是为了方便记忆和连贯操作。

由于 Alt 是嵌套 niri 中的修饰符,因此带有显式 Alt 的绑定主要只在主机上有用,例如生成屏幕锁定程序。