aboutsummaryrefslogtreecommitdiff
path: root/wiki
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-06-17 09:16:28 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-06-18 14:01:28 +0300
commit1dae45c58d7eabeda21ef490d712915890bf6cff (patch)
tree62c473ab1662a1161ed522517ea57b7bd8db340c /wiki
parent997119c44338ad96a40b4a1d6e958f77062a37ef (diff)
downloadniri-1dae45c58d7eabeda21ef490d712915890bf6cff.tar.gz
niri-1dae45c58d7eabeda21ef490d712915890bf6cff.tar.bz2
niri-1dae45c58d7eabeda21ef490d712915890bf6cff.zip
Refactor layout to fractional-logical
Lets borders, gaps, and everything else stay pixel-perfect even with fractional scale. Allows setting fractional border widths, gaps, struts. See the new wiki .md for more details.
Diffstat (limited to 'wiki')
-rw-r--r--wiki/Configuration:-Layout.md24
-rw-r--r--wiki/Fractional-Layout.md34
-rw-r--r--wiki/_Sidebar.md1
3 files changed, 59 insertions, 0 deletions
diff --git a/wiki/Configuration:-Layout.md b/wiki/Configuration:-Layout.md
index a16dcb79..e27d0ef7 100644
--- a/wiki/Configuration:-Layout.md
+++ b/wiki/Configuration:-Layout.md
@@ -48,6 +48,10 @@ layout {
Set gaps around (inside and outside) windows in logical pixels.
+<sup>Since: 0.1.7</sup> You can use fractional values.
+The value will be rounded to physical pixels according to the scale factor of every output.
+For example, `gaps 0.5` on an output with `scale 2` will result in one physical-pixel wide gaps.
+
```
layout {
gaps 16
@@ -170,6 +174,22 @@ layout {
}
```
+#### Width
+
+Set the thickness of the border in logical pixels.
+
+<sup>Since: 0.1.7</sup> You can use fractional values.
+The value will be rounded to physical pixels according to the scale factor of every output.
+For example, `width 0.5` on an output with `scale 2` will result in one physical-pixel thick borders.
+
+```
+layout {
+ border {
+ width 2
+ }
+}
+```
+
#### Colors
Colors can be set in a variety of ways:
@@ -227,6 +247,10 @@ They are set in logical pixels.
Left and right struts will cause the next window to the side to always peek out slightly.
Top and bottom struts will simply add outer gaps in addition to the area occupied by layer-shell panels and regular gaps.
+<sup>Since: 0.1.7</sup> You can use fractional values.
+The value will be rounded to physical pixels according to the scale factor of every output.
+For example, `top 0.5` on an output with `scale 2` will result in one physical-pixel wide top strut.
+
```
layout {
struts {
diff --git a/wiki/Fractional-Layout.md b/wiki/Fractional-Layout.md
new file mode 100644
index 00000000..220dc856
--- /dev/null
+++ b/wiki/Fractional-Layout.md
@@ -0,0 +1,34 @@
+There are two main coordinate spaces in niri: physical (pixels of every individual output) and logical (shared among all outputs, takes into account the scale of every output).
+Wayland clients mostly work in the logical space, and it's the most convenient space to do all the layout in, since it bakes in the output scaling factor.
+
+However, many things need to be sized or positioned at integer physical coordinates.
+For example, Wayland toplevel buffers are assumed to be placed at an integer physical pixel on an output (and `WaylandSurfaceRenderElement` will do that for you).
+Borders and focus rings should also have a width equal to an integer number of physical pixels to stay crisp (not to mention that `SolidColorRenderElement` does not anti-alias lines at fractional pixel positions).
+
+Integer physical coordinates do not necessarily correspond to integer logical coordinates though.
+Even with an integer scale = 2, a physical pixel at (1, 1) will be at the logical position of (0.5, 0.5).
+This problem becomes much worse with fractional scale factors where most integer logical coordinates will fall on fractional physical coordinates.
+
+Thus, niri uses fractional logical coordinates for most of its layout.
+However, one needs to be very careful to keep things aligned to the physical grid to avoid artifacts like:
+
+* Border width alternating 1 px thicker/thinner
+* Border showing 1 px off from the window at certain positions
+* 1 px gaps around rounded corners
+* Slightly blurry window contents during resizes
+* And so on...
+
+The way it's handled in niri is:
+
+1. All relevant sizes on a workspace are rounded to an integer physical coordinate according to the current output scale. Things like struts, gaps, border widths, working area location.
+
+ It's important to understand that they remain fractional numbers in the logical space, but these numbers correspond to an integer number of pixels in the physical space.
+ The rounding looks something like: `(logical_size * scale).round() / scale`.
+ Whenever a workspace moves to an output with a different scale (or the output scale changes), all sizes are re-rounded from their original configured values to align with the new physical space.
+2. The view offset and individual column/tile render offsets are *not* rounded to physical pixels, but:
+3. `tiles_with_render_positions()` rounds tile positions to physical pixels as it returns them,
+4. Custom shaders like opening, closing and resizing windows, are also careful to keep positions and sizes rounded to the physical pixels.
+
+The idea is that every tile can assume that it is rendered at an integer physical coordinate, therefore when shifting the position by, say, border width (also rounded to integer physical coordinates), the new position will stay rounded to integer physical coordinates.
+The same logic works for the rest of the layout thanks to gaps, struts and working area being similarly rounded.
+This way, the entire layout is always aligned, as long as it is positioned at an integer physical coordinate (which rounding the tile positions effectively achieves).
diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md
index 5e999194..0e4a8c37 100644
--- a/wiki/_Sidebar.md
+++ b/wiki/_Sidebar.md
@@ -24,3 +24,4 @@
## Development
* [Design Principles](./Design-Principles.md)
* [Developing niri](./Developing-niri.md)
+* [Fractional Layout](./Fractional-Layout.md)