openrazer (the official driver, daemon and library), polychromatic (the AUR tray, kept as found; its i3 line moves out of the i3 module into its own node-display-session contribution), forticlient (the AUR VPN client: its service declared, its configuration never read) and nm-applet (the desktop half of NetworkManager, apart from the server-side module). The openrazer daemon fails on both workstations because the account is not in the openrazer group; openrazer_check names it and the README carries the one-off step, since the account's user resource is zsh's. desktop.go learns to tell a program from another sharing its 15-character command name, so polychromatic's tools never count or end themselves, and a copies test holds the six carriers to one text.
193 lines
13 KiB
Markdown
193 lines
13 KiB
Markdown
# xdg
|
|
|
|
The workstations' XDG desktop conventions as a module (novox/hq ADR 0208, ADR 0182): the account's
|
|
folders, the default applications, and a view of what starts at login. It claims no seat: nothing
|
|
calls "the conventions" as a role. It needs no display; every tool reads files, asks xdg-mime and gio,
|
|
or reads `/proc`. It is for the two workstations only.
|
|
|
|
- **Packages:** `xdg-user-dirs` and `xdg-utils` (`xdg-open`, `xdg-mime`, which the tools use).
|
|
`dex`, which runs the autostart entries, is `i3`'s. `desktop-file-utils` and `shared-mime-info` come
|
|
as other packages' dependencies and are held as found.
|
|
- **No contribution, no session code.** The window manager's `dex --autostart --environment i3` line
|
|
is `i3`'s, and stays there.
|
|
|
|
## What it owns
|
|
|
|
| path | class (ADR 0182) | from |
|
|
|---|---|---|
|
|
| `~/.config/user-dirs.dirs` | owned, the found file kept once | [`config/user-dirs.dirs`](config/user-dirs.dirs), three folders from settings |
|
|
| `~/.config/user-dirs.locale` | owned, the found file kept once | [`config/user-dirs.locale`](config/user-dirs.locale) |
|
|
| `~/.config/user-dirs.conf` | owned, new | [`config/user-dirs.conf`](config/user-dirs.conf): `enabled=False` |
|
|
| `/etc/xdg/mimeapps.list` | owned, new | [`config/mimeapps.list`](config/mimeapps.list): the machine's default applications |
|
|
|
|
## What it does not own, and why
|
|
|
|
| | whose | why |
|
|
|---|---|---|
|
|
| `~/.config/mimeapps.list` | the person's, held as found | every program offering "always open with" rewrites it, and so does `xdg-mime default` (below) |
|
|
| the folders themselves (`~/Downloads`, …) | the person's, held as found | they hold the person's files. Declaring a directory would make its mode the mesh's (ADR 0182), and on one workstation `~/Desktop` is a file, not a folder |
|
|
| `~/.config/autostart/*`, `/etc/xdg/autostart/*` | each application's | an autostart entry belongs to the module of the application it starts (below) |
|
|
| `~/.config/xdg-desktop-portal/portals.conf` | `adwaita` | the portal's backends are the theme's business |
|
|
| `~/.local/share/applications/*.desktop` | the person's and their installers' | Steam, Telegram and the agent write their own launchers and handlers there |
|
|
|
|
## The folders
|
|
|
|
`user-dirs.dirs` is owned whole, with the operator's own values. Three folders differ between the
|
|
workstations, so they are settings; the rest are the same on both.
|
|
|
|
| setting | the mesh's layer | the laptop | the desktop machine |
|
|
|---|---|---|---|
|
|
| `desktop-dir` | `$HOME/Desktop` | as the mesh's | `$HOME/` |
|
|
| `publicshare-dir` | `$HOME/Public` | as the mesh's | `$HOME/` |
|
|
| `videos-dir` | `$HOME/Videos` | as the mesh's | `$HOME/` |
|
|
|
|
A value is written into the file as it is, in xdg-user-dirs' format: `"$HOME/yyy"` or `"/yyy"`. `$HOME/`
|
|
is the home itself, xdg-user-dirs' way of saying the folder is not wanted. The settings have no
|
|
default, so the mesh's layer is set before the first assignment (as `power`'s are). They land in this
|
|
one file: the module has no merged file and no contribution, so issue 168 cannot carry them anywhere
|
|
else.
|
|
|
|
**Why `xdg-user-dirs-update` is disabled.** It runs at every login, from its XDG autostart entry, which
|
|
`dex` starts. Measured on xdg-user-dirs 0.20 against a copy of the folders:
|
|
|
|
- enabled, it reassigns a folder it cannot find to the home (`Videos was removed, reassigning VIDEOS to
|
|
homedir`), adds a line and creates the folder for every default it knows that the file lacks
|
|
(`PROJECTS` arrived this way), and rewrites the file with its own header. Every login would undo
|
|
the mesh's file, and every push would undo the login;
|
|
- disabled by `enabled=False` in the account's `user-dirs.conf`, it does nothing, even with `--force`.
|
|
Only an explicit `--set` still writes.
|
|
|
|
The package's systemd user unit `xdg-user-dirs.service` is enabled by preset but never runs: it is
|
|
wanted by `graphical-session-pre.target`, which the xinit session does not reach. Disabled, it would
|
|
do nothing either way, so it is left as found.
|
|
|
|
`user-dirs.locale` (`en_US` on both) only tells xdg-user-dirs-gtk, which neither workstation has,
|
|
which language the folders were named in. It is owned so the account's xdg-user-dirs files are one
|
|
set.
|
|
|
|
## Default applications: the mesh's list is the last one read
|
|
|
|
**Decision.** The mesh owns `/etc/xdg/mimeapps.list`, the system's list, and never writes the
|
|
person's `~/.config/mimeapps.list`. An application reads the person's list first and the system's
|
|
after it (the XDG MIME Applications specification), so every choice the person makes wins, and the
|
|
mesh's list answers only what the person has not chosen. `xdg_default` gets and sets a default, and
|
|
setting writes the person's list through `xdg-mime default`, as any program would.
|
|
|
|
**Why not own the person's file, or a block in it.** Measured on 2026-10-05 with xdg-utils 1.2.1 and
|
|
GLib's `gio`, against copies:
|
|
|
|
1. **Owned whole** fights the person: Firefox's "make default", a file manager's "always open with" and
|
|
`xdg-mime default` all rewrite that file, and the next push would take each choice back.
|
|
2. **A mesh block at its start** (`into: block`, as `zsh` and `xorg` do) breaks three ways, because a
|
|
mimeapps list is a key file and not a script:
|
|
- the block's `[Default Applications]` and the person's are one group written twice. **xdg-mime reads
|
|
the first and GLib the last**, so `xdg-open` and every GTK or Electron program answered differently
|
|
for the same type;
|
|
- `gio mime` (what GTK programs do on "always open with") **rewrote the file as one merged group and
|
|
dropped the block's markers**: the next push would find no block and add a second;
|
|
- `xdg-mime default` **wrote the person's choice into the first group, inside the mesh's block**,
|
|
where the next push removes it.
|
|
3. **The system's list** has none of this: nothing but the mesh writes it, each reader reads one group
|
|
per file, and a person's choice in their own file is never touched. A default naming an
|
|
application that is not installed is passed over, to the next list.
|
|
|
|
**What the mesh's list holds.** The operator's own defaults, adopted from both workstations' lists of
|
|
2026-10-05 (the two were byte-identical), except entries naming an application installed on neither:
|
|
|
|
- dropped: 55 types for `code-oss.desktop` (no Code-OSS on either machine; plain text opens in
|
|
Fleet, from its own declaration), `jetbrains-rider.desktop`, `org.kde.korganizer.desktop`,
|
|
`Postman.desktop`, and a Fleet launcher whose name is the id one machine's JetBrains Toolbox
|
|
generated (a different one on the other machine);
|
|
- kept: Firefox for the web, HTML and PDF; Thunar for folders; ghostwriter for Markdown; Plexamp, Slack,
|
|
Telegram for their own links; and mpv, mplayer, vlc for MP4.
|
|
|
|
The person's list keeps every line as found, the dropped ones included. `xdg_check` names them.
|
|
|
|
## Autostart: listed, not owned
|
|
|
|
An XDG autostart entry belongs to the module of the application it starts, as `picom` does: picom's
|
|
package entry is its one starter. `nextcloud-client` holds `Nextcloud.desktop` as its start (the client
|
|
writes it itself), and `blueman`, `nm-applet` and `forticlient` hold their packages' entries as theirs.
|
|
`polychromatic`'s helper entry is that module's too, though the tray's start is its window-manager line.
|
|
Slack's and JetBrains Toolbox's entries would be their modules'. Two entries on the desktop have no
|
|
module and are left as found: the print applet's (the `cups` README says why) and geoclue's demo
|
|
agent (`/usr/lib/geoclue-2.0/demos/agent`). geoclue is there as a dependency of an application of the
|
|
operator's, not as a choice; the agent is what answers geoclue's question "may this program know
|
|
where the machine is" outside GNOME, whose own shell answers it there. It is a dependency's piece, so
|
|
it belongs to whoever installs geoclue on purpose, and nobody does yet.
|
|
This module only says what is there, and what the session does with it.
|
|
|
|
The session's starter is `i3`'s `dex --autostart --environment i3`. `xdg_autostart` decides each
|
|
entry by dex's own rules (dex 0.10):
|
|
|
|
- a user entry hides the system entry of the same name;
|
|
- `Hidden=true` keeps an entry from starting;
|
|
- an `OnlyShowIn` without `i3` keeps it from starting, and so does a `NotShowIn` with it;
|
|
- a `TryExec` that is not installed keeps it from starting;
|
|
- `X-GNOME-Autostart-enabled=false` and `AutostartCondition` are GNOME's, and **dex ignores them**: the
|
|
entry still starts.
|
|
|
|
## Tools
|
|
|
|
| tool | | what |
|
|
|---|---|---|
|
|
| `xdg_user_dirs` | r | each folder as written, the path it resolves to, whether it exists as a directory or points at the home, the folder xdg-user-dirs would have made; whether the update may rewrite the file, and from which file that is decided; the locale |
|
|
| `xdg_default` | r/a | the default for a MIME type or a URL scheme (`https`, `mailto`): what `xdg-open` uses (xdg-mime) and what GTK programs use (gio), flagged when they differ; which list decided it and which named applications were passed over as not installed; the application and whether its program is installed. `set` makes an installed desktop file the default through `xdg-mime default`, in the person's list |
|
|
| `xdg_open_handlers` | r | the same for http, https, mailto, HTML, folders, plain text, Markdown, PDF, PNG, JPEG, MP4, MP3 and any types given; every mimeapps list in reading order and whose it is; every default naming an application that is not installed; every installed handler whose program is missing |
|
|
| `xdg_autostart` | r | every autostart entry, the account's and the system's: what it runs and whether that is installed, Hidden, OnlyShowIn/NotShowIn, whether dex starts it (and if not, why), whether the window manager's configuration starts the same program too, and how many of the account's processes run it now |
|
|
| `xdg_check` | r | the folders file is the mesh's, every folder it names exists, the update cannot rewrite it; the mesh's list is in place, every list parses with no group or key written twice, no default names a missing application, no handler's program is missing; no program has two starters at login, every program dex starts is installed |
|
|
|
|
From `/proc` only the account's own processes are read, and of each only its command line and name.
|
|
|
|
## What it leaves found
|
|
|
|
The person's `~/.config/mimeapps.list`; the folders; every autostart entry; every desktop file under
|
|
`~/.local/share/applications`, including its `mimeinfo.cache`; `/etc/xdg/user-dirs.conf` and
|
|
`user-dirs.defaults` (the package's); and the `xdg-user-dirs.service` user unit.
|
|
|
|
## The one-off migration (ADR 0182)
|
|
|
|
**Before the first assignment,** set the three settings on the mesh's layer (`$HOME/Desktop`,
|
|
`$HOME/Public`, `$HOME/Videos`) and on the desktop machine's layer (`$HOME/` for all three).
|
|
|
|
**Once `xdg` is assigned, on the laptop:**
|
|
|
|
1. Delete `~/.local/share/applications/mimeapps.list` and `~/.local/share/applications/defaults.list`.
|
|
Both are links the retired predecessor made into its own tree, which is gone; they point at nothing.
|
|
2. `~/.config/autostart/slack.desktop` is the predecessor's too (its comment says so). It still starts
|
|
Slack, and is left until a Slack module owns it.
|
|
|
|
**On the desktop machine:** nothing to remove. `~/Desktop` is a text file, not a folder, which is why
|
|
`desktop-dir` is the home there; move it aside and change the setting if a Desktop folder is wanted.
|
|
|
|
## What changes when it is assigned
|
|
|
|
| | the laptop | the desktop machine |
|
|
|---|---|---|
|
|
| packages | none (both present) | the same |
|
|
| `user-dirs.dirs` | the found file kept once, then the module's: the same eight folders, and `PROJECTS` becomes `~/projects` instead of the home | the found file kept once, then the module's: the same eight folders, and a `PROJECTS` line (`~/projects`) where there was none |
|
|
| `user-dirs.conf` | new: the update stops rewriting the file at login | new: the update, which `dex` starts here since `i3` installed it, would otherwise have added `PROJECTS` and created `~/Projects` at the next login |
|
|
| `/etc/xdg/mimeapps.list` | new; changes no answer today, because the person's list says the same | the same |
|
|
| running programs, the person's list, autostart | nothing | nothing |
|
|
|
|
**The one visible change is `PROJECTS`:** `xdg-user-dir PROJECTS` answers `~/projects`, the folder
|
|
where the operator's repositories are, on both machines. GLib knows only the eight older folders, so
|
|
GTK programs see no change at all.
|
|
|
|
## What `xdg_check` will say at first
|
|
|
|
Measured on the laptop before assignment, and expected on both: the defaults naming applications that
|
|
are not installed (the 55 Code-OSS types and the four others above) fail "every default names an
|
|
installed application", until the person removes them from their list or installs the editor. On the
|
|
laptop, the predecessor's two dead links fail "the mimeapps lists are sane" until migration step 1. It
|
|
also showed that `audio/mpeg` opens in Audacity from `xdg-open` and in mpv from GTK programs, because
|
|
no list names a default for it: one `xdg_default` with `set` settles it.
|
|
|
|
## Blockers
|
|
|
|
- The three settings must be set before the first assignment (above).
|
|
|
|
|
|
**JetBrains removed (2026-10-05).** The operator retired JetBrains: its link handler left the mesh's list, and
|
|
the Toolbox, its IDEs and launchers were moved off both workstations.
|