summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorsommerfeld <sommerfeld@sommerfeld.dev>2026-09-18 17:55:17 +0100
committersommerfeld <sommerfeld@sommerfeld.dev>2026-09-18 17:55:17 +0100
commit2bd04514ab37d15e81d0a3b2c44b277482a825fe (patch)
treec5489c02e14fc823b58dadb3cd19afdee405409b
parent786632c25db3c2ad89312ad07dcc6d89fe4f6429 (diff)
downloaddotfiles-2bd04514ab37d15e81d0a3b2c44b277482a825fe.tar.gz
dotfiles-2bd04514ab37d15e81d0a3b2c44b277482a825fe.tar.bz2
dotfiles-2bd04514ab37d15e81d0a3b2c44b277482a825fe.zip
Use O-Tiling and simplify the corporate desktopHEADmaster
-rw-r--r--KEYBINDS.md6
-rw-r--r--docs/canonical-laptop.md32
-rw-r--r--dot_local/lib/dotfiles/canonical_desktop.py71
-rw-r--r--meta/canonical/extensions.txt2
-rw-r--r--scripts/canonical-vm-guest.sh4
-rw-r--r--tests/test_canonical_desktop.py46
6 files changed, 118 insertions, 43 deletions
diff --git a/KEYBINDS.md b/KEYBINDS.md
index a5794f1..ee60159 100644
--- a/KEYBINDS.md
+++ b/KEYBINDS.md
@@ -423,7 +423,7 @@ in `~/.XCompose`. Press and release Compose, then the sequence.
# Canonical GNOME Role
-These keys apply only to the `canonical` role with PaperWM. Company-locked
+These keys apply only to the `canonical` role with O-Tiling. Company-locked
settings remain unchanged.
| Keys | Action |
@@ -434,6 +434,8 @@ settings remain unchanged.
| Super+T | Thunderbird, normal window |
| Super+Shift+Q | Close window |
| Super+F | Fullscreen |
+| Super+Shift+Space | Toggle floating |
+| Super+Period | Emoji picker |
| Super+H/J/K/Right | Focus left/down/up/right |
| Super+Shift+H/J/K/L | Move window left/down/up/right |
| Super+I | Toggle dictation; copy text to clipboard |
@@ -443,7 +445,7 @@ settings remain unchanged.
| Caps Lock | Escape |
| Right Ctrl | Compose |
-Use GNOME's screenshot UI and Emoji Copy's configured shortcut. PaperWM's
+Use GNOME's screenshot UI. O-Tiling's
other default shortcuts remain active. Sway modes and recovery keys do not
apply to this role.
Super+L remains the GNOME lock shortcut. Super+D opens the application launcher.
diff --git a/docs/canonical-laptop.md b/docs/canonical-laptop.md
index 8b60195..a03db70 100644
--- a/docs/canonical-laptop.md
+++ b/docs/canonical-laptop.md
@@ -125,8 +125,14 @@ just canonical-check
The extension schemas can be unavailable until the first new login. Repeat
`canonical-desktop` after that login if it reported missing schemas. Keep Ubuntu
-AppIndicator enabled for tray icons. Disable Ubuntu Tiling Assistant in the
-Extensions app if it conflicts with PaperWM. Do not override a policy lock.
+AppIndicator enabled for tray icons. The desktop recipe disables PaperWM,
+Ubuntu Tiling Assistant, Ubuntu Dock, and the custom corporate status extension.
+Company-locked settings remain unchanged. Super+D opens the app grid; Alt+Tab
+switches windows. GNOME's overview remains available without the dock extension.
+
+O-Tiling splits the focused area along its longer dimension. To replace an
+existing PaperWM installation, run `just canonical-extensions`, log out and back
+in, then run `just canonical-desktop`. No `just apply` is needed for these settings.
Ghostty starts Nix zsh as a login shell. It does not change the authd account's
shell. GNOME keeps its own desktop environment and GNOME Keyring. `pass` remains
@@ -286,7 +292,7 @@ Restore skips keys changed since deployment. It does not reset all of dconf.
Check these operations both docked and undocked:
-- PaperWM focus, window movement, terminal and browser launch.
+- O-Tiling focus, window movement, terminal and browser launch.
- Lock, unlock, suspend, resume, lid state, and external monitors.
- HP webcam selection with `rqr`; the integrated camera when undocked.
- A Google Meet camera, microphone, speaker, and screen-share session.
@@ -309,24 +315,10 @@ Public-IP lookup is disabled. Sensor names and network totals come from Vitals;
select a specific temperature sensor or network device in its preferences if
the defaults are not useful on the laptop.
-The repo-owned `corporate-panel@dotfiles` extension adds compact status text:
-
-- `EXT`: connected external display connectors, not a dock identity.
-- `APT`: upgrades listed in the local apt cache, excluding Snap and Nix.
-- `FAIL`: failed system and user units. A failed query displays `?`, not zero.
-- `REBOOT`: `/run/reboot-required` exists. The panel does not reboot the laptop.
-
-The menu opens display settings, `htop`, `pulsemixer`, Thunderbird, failed-unit
-details, available apt/Snap updates, and reboot details. Its update action runs
-`just update` in the active chezmoi source directory in a terminal. Status checks
-run each minute without sudo, package installation, or apt metadata refresh.
-The custom labels use the personal panel's green, yellow, and red colours.
-
GNOME retains the clock, notifications, privacy indicators, and network/audio
-controls. Ubuntu AppIndicators supplies the tray. PaperWM retains workspace
-navigation. The custom panel does not copy Sway IPC modules, personal VPN
-controls, Arch checks, or the webcam process scanner. Module placement and
-actions are not identical to Waybar; custom actions are in a menu.
+controls. Ubuntu AppIndicators supplies the tray. O-Tiling provides window
+tiling and movement. Emoji Copy uses Super+Period without a persistent panel
+icon. The custom `EXT`, `APT`, `FAIL`, and `REBOOT` status labels are disabled.
On an existing corporate installation, run outside the sandbox:
diff --git a/dot_local/lib/dotfiles/canonical_desktop.py b/dot_local/lib/dotfiles/canonical_desktop.py
index cbda77f..7269a3f 100644
--- a/dot_local/lib/dotfiles/canonical_desktop.py
+++ b/dot_local/lib/dotfiles/canonical_desktop.py
@@ -10,13 +10,18 @@ from pathlib import Path
HOME = Path.home()
STATE = HOME / ".local/state/dotfiles/gnome-settings.json"
EXTENSIONS = [
- "paperwm@paperwm.github.com",
+ "o-tiling@oliwebd.github.com",
"copyous@boerdereinar.dev",
"emoji-copy@felipeftn",
"Vitals@CoreCoding.com",
- "corporate-panel@dotfiles",
"ubuntu-appindicators@ubuntu.com",
]
+DISABLED_EXTENSIONS = [
+ "paperwm@paperwm.github.com",
+ "ubuntu-dock@ubuntu.com",
+ "tiling-assistant@ubuntu.com",
+ "corporate-panel@dotfiles",
+]
def save_state(saved: dict) -> None:
@@ -119,8 +124,20 @@ def shortcuts(saved: dict) -> None:
merge_key(schema, "custom-keybindings", paths, saved)
+def extensions(saved: dict) -> None:
+ schema = "org.gnome.shell"
+ settings = settings_object(schema)
+ if settings is None:
+ return
+ for key, added, removed in [
+ ("enabled-extensions", EXTENSIONS, DISABLED_EXTENSIONS),
+ ("disabled-extensions", DISABLED_EXTENSIONS, EXTENSIONS),
+ ]:
+ values = [value for value in settings.get_strv(key) if value not in removed]
+ write_key(schema, key, list(dict.fromkeys([*values, *added])), saved)
+
+
def apply_settings(saved: dict) -> None:
- merge_key("org.gnome.shell", "enabled-extensions", EXTENSIONS, saved)
merge_key(
"org.gnome.desktop.input-sources",
"xkb-options",
@@ -138,26 +155,47 @@ def apply_settings(saved: dict) -> None:
write_key(
"org.gnome.desktop.wm.keybindings", "toggle-fullscreen", ["<Super>f"], saved
)
- paper = "org.gnome.shell.extensions.paperwm.keybindings"
+ tiling(saved)
+ shortcuts(saved)
+ workspaces(saved)
+ panel(saved)
+ extensions(saved)
+
+
+def tiling(saved: dict) -> None:
+ schema = "org.gnome.shell.extensions.o-tiling"
+ for key, value in {
+ "tile-by-default": True,
+ "new-window-placement": "focused",
+ "active-hint-overlay-enabled": False,
+ "workspace-switcher-style": False,
+ "workspace-number-indicator": False,
+ "panel-transparency": False,
+ "mouse-cursor-follows-active-window": False,
+ "toggle-floating": ["<Super><Shift>space"],
+ }.items():
+ write_key(schema, key, value, saved)
for key in [
- "new-window",
- "take-window",
- "toggle-maximize-width",
- "slurp-in",
- "barf-out-active",
- "cycle-height",
+ "tile-enter",
+ "toggle-tiling",
+ "tile-orientation",
+ "pop-workspace-up",
+ "pop-workspace-down",
]:
- write_key(paper, key, [], saved)
+ write_key(schema, key, [], saved)
for direction, letter in zip(["left", "down", "up", "right"], "hjkl"):
binding = "<Super>Right" if direction == "right" else f"<Super>{letter}"
- write_key(paper, f"switch-{direction}", [binding], saved)
- write_key(paper, f"move-{direction}", [f"<Super><Shift>{letter}"], saved)
- shortcuts(saved)
- workspaces(saved)
- panel(saved)
+ write_key(schema, f"focus-{direction}", [binding], saved)
+ write_key(
+ schema, f"tile-move-{direction}-global", [f"<Super><Shift>{letter}"], saved
+ )
def panel(saved: dict) -> None:
+ emoji = "org.gnome.shell.extensions.emoji-copy"
+ write_key(emoji, "always-show", False, saved)
+ write_key(emoji, "active-keybind", True, saved)
+ write_key(emoji, "emoji-keybind", ["<Super>period"], saved)
schema = "org.gnome.shell.extensions.vitals"
monitor = shlex.join(
["/snap/bin/ghostty", "-e", str(HOME / ".nix-profile/bin/htop")]
@@ -183,7 +221,6 @@ def panel(saved: dict) -> None:
def workspaces(saved: dict) -> None:
write_key("org.gnome.mutter", "dynamic-workspaces", False, saved)
write_key("org.gnome.desktop.wm.preferences", "num-workspaces", 10, saved)
- write_key("org.gnome.shell.extensions.dash-to-dock", "hot-keys", False, saved)
for number in range(1, 11):
key = str(number % 10)
for action, modifier in [("switch", ""), ("move", "<Shift>")]:
diff --git a/meta/canonical/extensions.txt b/meta/canonical/extensions.txt
index 7844496..dab1321 100644
--- a/meta/canonical/extensions.txt
+++ b/meta/canonical/extensions.txt
@@ -1,4 +1,4 @@
-paperwm@paperwm.github.com
+o-tiling@oliwebd.github.com
copyous@boerdereinar.dev
emoji-copy@felipeftn
Vitals@CoreCoding.com
diff --git a/scripts/canonical-vm-guest.sh b/scripts/canonical-vm-guest.sh
index 29caa7d..647fd0a 100644
--- a/scripts/canonical-vm-guest.sh
+++ b/scripts/canonical-vm-guest.sh
@@ -12,11 +12,11 @@ cd "$HOME/dotfiles"
check_extensions() {
test "$(/usr/bin/gsettings get org.gnome.shell disable-user-extensions)" = false
- for extension in corporate-panel@dotfiles $(sed '/^#/d; /^$/d' meta/canonical/extensions.txt); do
+ while IFS= read -r extension; do
gnome-extensions info "$extension"
gnome-extensions list --enabled | grep -Fx "$extension"
gnome-extensions info "$extension" | grep -Eq 'State: (ACTIVE|ENABLED)$'
- done
+ done < <(sed '/^#/d; /^$/d' meta/canonical/extensions.txt)
}
check_mattermost_keyring() {
diff --git a/tests/test_canonical_desktop.py b/tests/test_canonical_desktop.py
index 9bdace1..fac6b8e 100644
--- a/tests/test_canonical_desktop.py
+++ b/tests/test_canonical_desktop.py
@@ -14,6 +14,46 @@ SPEC.loader.exec_module(desktop)
class DesktopTests(unittest.TestCase):
+ def test_extensions_replace_tiler_and_hide_dock_and_status(self):
+ settings = MagicMock()
+ settings.get_strv.side_effect = [
+ ["company", "paperwm@paperwm.github.com", "corporate-panel@dotfiles"],
+ ["unrelated", "o-tiling@oliwebd.github.com"],
+ ]
+ with (
+ patch.object(desktop, "settings_object", return_value=settings),
+ patch.object(desktop, "write_key") as write,
+ ):
+ desktop.extensions({})
+ write.assert_any_call(
+ "org.gnome.shell",
+ "enabled-extensions",
+ ["company", *desktop.EXTENSIONS],
+ {},
+ )
+ write.assert_any_call(
+ "org.gnome.shell",
+ "disabled-extensions",
+ ["unrelated", *desktop.DISABLED_EXTENSIONS],
+ {},
+ )
+
+ def test_tiling_shortcuts_do_not_claim_application_keys(self):
+ with patch.object(desktop, "write_key") as write:
+ desktop.tiling({})
+ schema = "org.gnome.shell.extensions.o-tiling"
+ for key in [
+ "tile-enter",
+ "toggle-tiling",
+ "tile-orientation",
+ "pop-workspace-up",
+ "pop-workspace-down",
+ ]:
+ write.assert_any_call(schema, key, [], {})
+ write.assert_any_call(schema, "new-window-placement", "focused", {})
+ write.assert_any_call(schema, "focus-right", ["<Super>Right"], {})
+ write.assert_any_call(schema, "tile-move-down-global", ["<Super><Shift>j"], {})
+
def test_clipboard_shortcut_preserves_other_display_bindings(self):
settings = MagicMock()
settings.get_strv.return_value = ["<Super>p", "XF86Display", "<Super>x"]
@@ -35,8 +75,11 @@ class DesktopTests(unittest.TestCase):
write.assert_any_call(
"org.gnome.shell.extensions.vitals", "include-public-ip", False, {}
)
- self.assertIn("corporate-panel@dotfiles", desktop.EXTENSIONS)
+ self.assertNotIn("corporate-panel@dotfiles", desktop.EXTENSIONS)
self.assertIn("ubuntu-appindicators@ubuntu.com", desktop.EXTENSIONS)
+ write.assert_any_call(
+ "org.gnome.shell.extensions.emoji-copy", "always-show", False, {}
+ )
def test_unknown_keys_fail_without_writing(self):
settings = MagicMock()
@@ -50,6 +93,7 @@ class DesktopTests(unittest.TestCase):
def test_launcher_uses_gnome_application_view_key(self):
with (
+ patch.object(desktop, "extensions"),
patch.object(desktop, "merge_key"),
patch.object(desktop, "shortcuts"),
patch.object(desktop, "workspaces"),