AvengeMedia / AvengeMedia/DankMaterialShell

Keyboard layout widget: allow a custom label per layout/variant (follow-up to #2679)

Open
#3,351 1 comment 0 reactions 0 assignees View on GitHub
feature request
Dominant language
QML
Stars
8.1k
Forks
515
Avg merge
1d 8h
Merged PRs (30d)
102

Description

### Feature Description

Add an official, persistent setting to the `keyboard_layout_name` bar widget that lets the user
define a **custom label per layout/variant**, instead of only being able to toggle the built-in
compact/full formatting.

Something like a user-defined map:

| layout | desired label |
|-----------|---------------|
| `us` | `US` |
| `us-intl` | `US-Intl` |
| `ara` | `AR` |

This is a follow-up to #2679 ("Is it possible to change the name of keyboard layout?"), which was
closed without a built-in option. The need is still present in DMS 1.6.0, and the workaround that
issue landed on no longer works at all (see below).

### Use Case

**The label style is inconsistent between layouts, and there is no supported way to normalise it.**

On this machine niri reports exactly two layouts:

```console
$ niri msg --json keyboard-layouts
{"names":["English (US)","Arabic"],"current_idx":1}
```

In compact mode DMS 1.6.0 renders those as **`en-US`** and **`AR`** — one layout gets a
`lang-VARIANT` label, the other a bare 2-letter code, purely because the xkb description for one
happens to carry a parenthesised variant and the other does not. I would like both to read the same
way (`US` / `AR`), which is also the shortest unambiguous label for a two-layout setup.

Turning compact mode off is not an alternative: it swaps `en-US` for the full `English (US)`, which
is longer still. So today there is **no setting that produces a short, consistent label**.

The current formatting is the deliberate behaviour of `Modules/DankBar/Widgets/KeyboardLayoutName.qml`:

```js
if (match[2]) {
const variant = match[2].trim();
const isValid = validVariants.some(v => variant.toUpperCase().includes(v.toUpperCase())) || variant.length <= 3;
if (isValid)
return code + "-" + variant;
}
return code.toUpperCase();
```

That is a reasonable default — this request is only for a way to override it without editing DMS.

### Why the previous workaround is no longer viable

#2679 concluded with users hand-editing `KeyboardLayoutName.qml` in the installed tree, and the
reporter there already hit the obvious problem:

> A recent update overwrote my changes and reverted my implementation back to the default behavior.

In **DMS 1.6.0 it is worse than fragile — it is silently inert.** The Quickshell UI is now embedded
in the `dms` binary, and `dms.service` runs `dms run --session` with no `-c` and no `DMS_SHELL_DIR`,
so `/usr/share/quickshell/dms/` is never read. That directory is still present on disk and still
contains a `KeyboardLayoutName.qml` with the matching source, so an edit (or a patch script) applied
there **succeeds, verifies, and changes nothing at runtime** — with no error to indicate it had no
effect. DMS itself says as much:

> The shell is embedded in the dms binary. `~/.config/quickshell/dms` is no longer auto-discovered,
> pass `-c` or set `DMS_SHELL_DIR` to override it

That leaves only two options for a label change today: fork the whole UI via `DMS_SHELL_DIR` and
freeze on it, giving up all future UI updates for a cosmetic tweak, or reimplement the entire widget
as a plugin. Both are disproportionate, which is why a first-class setting seems worth having.

### Compositor(s)

All compositors. The examples above are from niri, but the same label formatting is applied on the
Hyprland path (`layouts[i] + "-" + variants[i]`), so a per-layout label map would apply there too.

### Proposed Solution

The widget already reads per-widget overrides that fall back to global settings:

```js
property bool compactMode: widgetData?.keyboardLayoutNameCompactMode !== undefined ? widgetData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode
property bool showIcon: widgetData?.keyboardLayoutNameShowIcon !== undefined ? widgetData.keyboardLayoutNameShowIcon : SettingsData.keyboardLayoutNameShowIcon
```

A third setting in the same shape would fit naturally — e.g. `keyboardLayoutNameLabels`, a
`{ "": "" }` map consulted at the top of `displayLabel()`, falling
through to the existing compact/full logic when a layout has no entry. Being an ordinary setting, it
would persist in `settings.json` and survive package updates like any other, and it would work for
the Hyprland code path too.

Whether the key should be the compositor-reported name (`English (US)`) or the xkb layout/variant
pair (`us` / `us,intl`) is yours to decide; the xkb pair is more stable across locales, the reported
name is what the widget already has in hand.

If a full map is more than you want to carry, a narrower option would still solve it: a toggle that
makes compact mode emit the **bare variant** (`US`) rather than `code + "-" + variant`, leaving
variant-less layouts on their existing 2-letter code.

I'm happy to open a PR for whichever shape you prefer.

### Alternatives/Existing Solutions

- **Compact mode off** — gives `English (US)`, longer than `en-US`; does not solve it.
- **Editing the QML in `/usr/share/quickshell/dms/`** — the #2679 workaround; inert in 1.6.0, as
described above.
- **`DMS_SHELL_DIR` fork** — works, but freezes the UI at the forked revision.
- **A custom plugin widget** — supported and update-safe, but means reimplementing the whole widget
to change one string.
- Waybar's `hyprland/language` module solves the same problem with a `format-` map, and
niri/Sway status bars commonly expose a similar per-layout alias.

### Environment

- DMS **1.6.0** (`dms-1.6.0-1.fc44`, COPR `avengemedia/dms`)
- niri **26.04**
- Fedora Linux **44**
- Layouts: `us,ara` with `grp:alt_shift_toggle`

Contributor guide

Open the contributing guide

Research direction

Start with Modules/DankBar/Widgets/KeyboardLayoutName.qml, especially displayLabel() and the existing compactMode, showIcon, and per-widget override handling. Trace the corresponding settings definitions and settings.json persistence, then verify that custom labels fall back to the existing formatting and work through both niri and Hyprland paths.

Written by the indexing model from the issue text.

Assessment

Domain
desktop
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.