aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/posts/notch-support/index.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/notch-support/index.md')
-rw-r--r--content/posts/notch-support/index.md368
1 files changed, 368 insertions, 0 deletions
diff --git a/content/posts/notch-support/index.md b/content/posts/notch-support/index.md
new file mode 100644
index 0000000..be3ebd6
--- /dev/null
+++ b/content/posts/notch-support/index.md
@@ -0,0 +1,368 @@
++++
+authors = ["Guido Günther"]
+title = "Avoiding notches"
+date = "2023-07-11"
+tags = [ "phosh",
+ "development",
+ ]
+series = [
+ "Phosh internals"
+]
++++
+
+The following gives an overview on how the Phone Shell (phosh) and the
+Phone Comppositor (phoc) get information about a device's display
+notches and how you can add support for new devices.
+
+Disclaimer: I'm a Librem 5 user so I don't have to worry about notches
+and cutouts at all. I basically wrote the initial notch
+implementations to make it easier to use phosh on non Linux first
+devices. It's also possible that future Librem 5 iterations might use
+more available screen estate and hence might also have notches so it's
+good to be prepared.
+
+A notch is a (usually non rectangular) area of a display without any
+usable pixels. It's often a cutout that e.g. contains the
+camera. They're usually at the top of the display and hence would
+partially overlay phosh's top bar. Here's some examples showing the
+shape of notches on some common devices:
+
+![Shape display notches](./cutouts.png)
+
+Notches are frequently found on phones but also on tablets and
+also some laptops have display cutouts. So in the following by
+*device* we mean the device with the cutout independent from it's form
+factor.
+
+As of [0.29.0](/releases/rel-0.29.0/) phosh automatically tries to
+avoid a notch if it has the necessary information about the device it
+runs on. If so it tries to move UI elements around to not overlap with
+the notch. This mode of operation is on by default and can be disabled
+via
+
+```sh
+gsettings set sm.puri.phosh shell-layout none
+```
+
+To reenable this feature use either one of:
+
+```sh
+gsettings reset sm.puri.phosh shell-layout
+```
+
+or
+
+```sh
+gsettings set sm.puri.phosh shell-layout device
+```
+
+In order to get the needed information phosh uses a small library
+called [gmobile][] that contains classes to represent a display and
+it's cutouts and also the information for various devices. The code
+is split out into a libarary so other projects (e.g. Wayland
+compositors) can reuse it.
+
+Shouldn't this information be provided by the kernel? That would be
+nice (discussion around this [stalled a while back][]) but having it
+in userspace for all devices also has an upside: we can easily use it
+in tests to emulate different devices by just telling a Wayland
+compositor or phosh that it should assume a certain device type and
+hence it's notches. This is possible with phoc already, more on that
+below.
+
+## Looking at existing device information
+
+Here's how to see what device information is already available in
+gmobile, how it's structured and how to preview it:
+
+First clone the gmobile library and it's data:
+
+```sh
+git clone https://gitlab.gnome.org/guidog/gmobile
+cd gmobile
+```
+
+You can then see for devices there's display panel information:
+
+```sh
+$ ls -1 data/devices/display-panels/
+oneplus,enchilada.json
+oneplus,fajita.json
+purism,librem5.json
+xiaomi,beryllium.json
+```
+
+The information is stored in JSON files describing the display panel, it's notches
+and (possibly) rounded corners. Looking at one specific file
+`data/devices/display-panels/oneplus,fajita.json`:
+
+```json
+{
+ "name": "Oneplus 6T",
+ "x-res": 1080,
+ "y-res": 2340,
+ "border-radius": 120,
+ "width": 68,
+ "height": 145,
+ "cutouts" : [
+ {
+ "name": "notch",
+ "path": "M 355,0
+ h 368.34
+ c -9.77,0.44 -19.57,0.08 -29.28,1.24
+ c -20.33,1.14 -41.18,5.17 -58.62,16.24
+ c -16.9,10.79 -29.44,26.78 -43.44,40.81
+ a 72.73,72.73 0 0 1 -38.29 19.58
+ c -16.53,2.51 -34,1 -49.09,-6.62
+ c -9.85,-4.62 -17.88,-12.24 -25.21,-20.18
+ c -10.46,-11.27 -20.9,-22.75 -33.53,-31.66
+ c -11.49,-8 -24.9,-12.78 -38.53,-15.42
+ c -17.27,-3.18 -34.86,-3.6 -52.35,-3.99
+ Z"
+ }
+ ]
+}
+```
+
+The file name of the JSON file is the device-tree compatible you want
+to match on (we'll see how to get that in a moment). `x-res` and
+`y-res` are th devices maximum resolution and `cutouts` is an array of
+cutouts each described via a closed SVG path. In the above `M` is a
+movement, the `c`s indicate Cubic Béziers curves, `h` is an horizontal
+line and `Z` closes the path. Mozilla has a good
+[introduction](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths)
+on how SVG paths work.
+
+We take the display panels top left corner as `0,0` of the coordinate
+system. Each SVG path should describe exactly one cutout as closely as
+possible.
+
+How the cutouts look is easy to test. First we build gmobile:
+
+```sh
+meson setup _build
+```
+
+We can then use the `gm-panel-preview` tool to preview cutouts and the cutouts
+bounding boxes (the area that shouldn't be used by UI elements) for a certain device
+(here a `oneplus,fajita`):
+
+```sh
+_build/examples/gm-display-panel-preview -c oneplus,fajita -o oneplus,fajita.html
+```
+
+The generated HTML file contains an SVG of the display's boundaries and it's
+notches. To display it you can use any web browser:
+
+```sh
+epiphany oneplus,fajita.html
+```
+
+![The display panel rendered as html](./panel-as-html.png)
+
+While the HTML rendering has the advantage of showing us the *exact*
+cutout path we don't see how UI elements would be laid out.
+
+For this we can run phosh and phoc nested and see how phosh looks with the
+given information. For that you need phosh and phoc on your laptop or
+PC (as explained [here](../phosh-dev-part-0/)). As there's a bunch of
+environment variables needed for things to work right gmobile wraps
+this in a single command:
+
+```sh
+_build//examples/gm-display-panel-run-phosh -s 3 -c oneplus,fajita
+```
+
+So what happens in that command is that we
+
+- build a phoc.ini with the device's resolution for the given
+ device compatible and the scaling given on the command line
+- tell phoc and phosh to assume they're running on a `oneplus,fajita`
+- tell phoc to render the display cutouts and rounded edges in semi transparent purple so that we can
+ see easily if UI elements overlap with the notch or corners
+- tell phosh to use it's layout-manager although it's running on a emulated device
+
+The result should look like this:
+
+![The display panel in a nested phosh session](./panel-phosh.png)
+
+Note how the clock was moved from the default center to the right.
+
+But what if we want to add a new device? Do we need to
+rebuild things so phosh and phoc know about it? Fortunately no, we can
+use glib's [`G_RESOURCE_OVERLAYS`](https://docs.gtk.org/gio/struct.Resource.html) for testing
+and hence don't need to rebuild anything. We can also do most of the
+development in the nested session before moving to the actual device.
+
+## Adding a new device
+
+To add a new device we need to know
+
+1. The device tree compatible string to determine the target file name
+2. The device panels maximum resolution to fill in the `x-res` and `y-res` properties
+3. Information about the cutouts as SVG path to fill in the cutout `path`.
+
+### The compatibles string
+
+*compatible*s are used in the Linux kernel to figure out which drivers to bind
+for a bit of hardware and of the form `<manufacturer>,<model>`.
+The base compatible that identifies the device itself
+is exported by the kernel at `/sys/firmware/devicetree/base/compatible`. Let's assume our
+device is from manufacturer `mycorp` and the model is `fantastic` so this could look like:
+
+```sh
+$ sed -z 's/$/\n/' /sys/firmware/devicetree/base/compatible
+mycorp,fantastic-r3
+mycorp,fantastic
+fsl,imx8mq
+```
+
+`mycorp,fantastic-r3` would be very specific as it would only match the
+3rd revision. Since all Fantastic's so far have the same panel we'd pick
+`mycorp,fantastic`. This gives us the filename of the file we'd put the display
+panel information: `data/devices/display-panels/mycorp,fantastic.json`.
+
+### The display resultion
+
+We can get the display resolution via `wlr-randr` and have the first bits of
+the display-panel information filled in:
+
+```json
+{
+ "name": "Mycorp Librem 5",
+ "x-res": 720,
+ "y-res": 1440
+}
+```
+
+### Information about the cutouts
+
+If you want to add a device that formerly ran Android
+have a look at the device overlay's config.xml
+([example](https://github.com/LineageOS/android_device_oneplus_fajita/blob/lineage-19.1/overlay/frameworks/base/core/res/res/values/config.xml#L388)). There
+you should find an SVG path that is pretty close to what you need. You
+just need to shift it right by half the display width. If you can't find such
+a file you can construct the SVG path with a vector graphics program
+that handles SVG like Inkscape.
+
+For our made up device we just make up some notch information. Let's
+assume there's a small notch in the middle for the camera:
+
+```json
+{
+ "name": "Mycorp Fantastic",
+ "x-res": 720,
+ "y-res": 1440,
+ "cutouts" : [
+ {
+ "name": "notch",
+ "path": "M 336 0
+ A 24 24 0 0 0 384 0
+ Z"
+ }
+ ]
+}
+```
+
+You can check at any time if your file is parseable via
+
+```sh
+json-glib-validate data/devices/display-panels/mycorp,fantastic.json
+```
+
+With that passing we can again render the display panel as HTML and run a nested
+phosh session for testing. As we don't want to rebuild and commit our changes yet we
+use the above mentioned `GResource` overlay:
+
+```sh
+export G_RESOURCE_OVERLAYS=/org/gnome/gmobile/devices/display-panels=$PWD/data/devices/display-panels
+_build/examples/gm-display-panel-preview -c mycorp,fantastic -o mycorp,fantastic.html
+epiphany mycorp,fantastic.html
+```
+
+`G_RESOURCE_OVERLAYS=/org/gnome/gmobile/devices/display-panels=` is
+fixed and `$PWD/data/devices/display-panels` is the path to the
+directory where you put the `mycorp,fantastic.json`.
+
+The result should look like this (The screenshot only shows the interesting top part):
+
+![Panel cutout of our fictuous device as html](./panel-mycorp-fantastic.png)
+
+And if we want to check in our nested phosh session:
+
+```sh
+export G_RESOURCE_OVERLAYS=/org/gnome/gmobile/devices/display-panels=$PWD/data/devices/display-panels
+_build//examples/gm-display-panel-run-phosh -s 2 -c mycorp,fantastic
+```
+
+The result should look like:
+
+![Panel cutout of our fictuous device](./panel-mycorp-fantastic2.png)
+
+
+Finally we can check the changes the "Mycorp Fantastic" device itself. For that we copy
+the *mycorp,fantastic.json* onto the device (e.g. via scp) and use `GResource` overlay again.
+Let's assume we put `mycorp,fantastic.json` at
+`/tmp/mycorp,fantastic.json` on the device for testing purposes. We'd
+then want to put
+
+```sh
+G_RESOURCE_OVERLAYS=/org/gnome/gmobile/devices/display-panels=/tmp
+```
+
+into phosh's environment so it can find and use that file. How that
+works exactly depends a bit on your distribution and display
+manager. If you're using the systemd unit to start phosh (e.g. on
+PureOS) you can just add an override:
+
+```sh
+mkdir -p /etc/systemd/system/phosh.service.d/
+cat <<EOF > /etc/systemd/system/phosh.service.d/override.conf
+[Service]
+Environment=PHOC_DEBUG=cutouts
+Environment=G_RESOURCE_OVERLAYS=/org/gnome/gmobile/devices/display-panels=/tmp
+EOF
+systemctl daemon-reload
+systemctl restart phosh
+```
+
+On pmOS using [tinydm](https://gitlab.com/postmarketOS/tinydm#tinydm) you'd put that information into
+`/etc/tinydm.d/env-wayland.d`:
+
+```sh
+mkdir -p /etc/tinydm.d/env-wayland.d
+cat <<EOF /etc/tinydm.d/env-wayland.d/cutout-test
+G_RESOURCE_OVERLAYS=/org/gnome/gmobile/devices/display-panels=/tmp
+export G_RESOURCE_OVERLAYS
+PHOC_DEBUG=cutouts
+export PHOC_DEBUG
+EOF
+service tinydm restart
+```
+
+You can drop `PHOC_DEBUG=cutouts` if you don't want phoc to render the
+bounding box of the notch. Your device should now shift the clock to
+avoid the notch.
+
+Once you have tested on device that the cutouts are at the intended
+locations you can add your newly added file and add an entry to
+`data/gmobile.gresources.xml`. Now you could submit a merge request
+against [gmobile][] so it can be included to benefit other users as
+well.
+
+## Summary / Outlook
+
+With the above we can have notches work out of the box when using phosh. However while shell and
+Wayland compositor have the necessary bits of information fullscreen applications don't know about this
+yet. For that we need a Wayland protocol. Discussions around this
+[have already started](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/87#note_1733891).
+We need to yet work out how represent that information to clients.
+
+In the future we want to add support for display panels with curved
+screen edges (aka waterfalls) and areas for under display cameras by
+adding a `type` field to the cutout's JSON. If you have such a device
+feel free to submit a merge request or comment in the related
+[issue](https://gitlab.gnome.org/guidog/gmobile/-/issues/2).
+
+[gmobile]: https://gitlab.gnome.org/guidog/gmobile
+[stalled a while back]: https://lore.kernel.org/dri-devel/f8747f99-0695-5be0-841f-4f72ba5d5da3@connolly.tech/