- JavaScript 96.4%
- Makefile 2.4%
- Shell 0.9%
- CSS 0.3%
|
All checks were successful
CI / check (push) Successful in 19s
- displays built during startup animation or while the overview is up kept the stock view until the next close/open |
||
|---|---|---|
| .github/workflows | ||
| docs | ||
| src | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| CONTRACT.md | ||
| eslint.config.js | ||
| install.sh | ||
| Makefile | ||
| README.md | ||
Monitor Workspaces
Per-monitor workspaces for GNOME Shell 50 and 51. The primary monitor keeps GNOME's own workspaces exactly as they are; every other monitor gets its own private set, switched without the rest of your desktop flinching.
Requirements
-
GNOME Shell 50 or 51 on Wayland
-
Two or more monitors — the extension only acts on non-primary ones, so a single display leaves it with nothing to do
-
org.gnome.mutter workspaces-only-on-primaryset totrue. This is the default and the setting the entire design rests on: it makes Mutter treat windows on secondary monitors as sticky, so native switches can't move them. If something else (PaperWM is the known offender) turned it off, the extension's preferences show it live and fix it with one click:gsettings set org.gnome.mutter workspaces-only-on-primary true -
If PaperWM is enabled, disable it — the two need opposite values for the same mutter setting and cannot coexist.
Install
Easy install
One command — it downloads, packs, installs and enables the extension for the current user:
curl -fsSL https://git.salix.host/salix/gnome-advanced-workspaces/raw/branch/master/install.sh | bash
Then log out and back in.
Installing a different branch
By default the installer builds from master. To install another branch (for
example to try a feature that is not merged yet), pass the branch name after
bash -s --:
curl -fsSL https://git.salix.host/salix/gnome-advanced-workspaces/raw/branch/master/install.sh | bash -s -- some-branch
or set the BRANCH environment variable:
curl -fsSL https://git.salix.host/salix/gnome-advanced-workspaces/raw/branch/master/install.sh | BRANCH=some-branch bash
Both do the same thing, the installer just downloads the tarball of that
branch instead of master. To go back, run the command again without a
branch.
Installing from source
make install # compiles the schema and symlinks src/ into ~/.local/share/gnome-shell/extensions/
Then log out and back in. Wayland cannot reload the shell in place: until
the session restarts, the shell has not scanned the extension directory and
does not know this extension exists. Enabling before the restart fails with
Extension ... does not exist — not because the install failed, but because
you asked a shell that hasn't looked yet.
After the restart:
gnome-extensions enable monitor-workspaces@salix
gnome-extensions info monitor-workspaces@salix # want: State: ACTIVE
The Extensions app does the same enabling with a switch.
Building a bundle
make pack # monitor-workspaces@salix.shell-extension.zip via gnome-extensions pack
The bundle carries the compiled gsettings schema and every module. Install it as a copied bundle with:
gnome-extensions install --force monitor-workspaces@salix.shell-extension.zip
Note this is a copy, not a link: edits to src/ will not apply until you
re-pack. make doctor tells you which kind you have installed.
Using it
Every shortcut drives the monitor holding the focused window. On the primary monitor they do nothing on purpose — GNOME's own workspaces already cover it.
| Shortcut | Action | Default binding |
|---|---|---|
| Previous workspace | switch the focused secondary | Super+Alt+← |
| Next workspace | switch the focused secondary | Super+Alt+→ |
| Go to workspace 1–4 | direct switch | Super+Alt+1 … Super+Alt+4 |
| Go to workspace 5–8 | direct switch | unbound by default |
| Move window to previous | carries the focused window | Super+Alt+Shift+← |
| Move window to next | carries the focused window | Super+Alt+Shift+→ |
All twelve live in the schema as switch-prev, switch-next,
switch-to-1 … switch-to-8, move-window-to-prev, move-window-to-next
and are rebindable from the preferences' Shortcuts page (click a row, press a
chord; Esc cancels, Backspace clears). 5–8 ship unbound on purpose so the
extension never silently claims keys you already use.
Gestures and the wheel
Every input drives the monitor it lands on — a swipe where the fingers are, a wheel where the pointer is. The primary monitor is the shell's in every row below: its gestures, its overview, its wheel, untouched.
| Input | Where | Action |
|---|---|---|
| Three-finger swipe ← / → | On a secondary monitor | That monitor's workspaces slide under your fingers; past the threshold it commits, short of it springs back. The movement is the feedback — no pill |
| Three-finger swipe ← / → | In the overview | Scroll through the paged view of the secondary under the pointer |
| Two-finger scroll | In the overview | Same pages, following the fingers; a discrete wheel notch steps one page at a time |
| Mouse wheel | In the overview, over a secondary's page | Step one page per notch, clamped at the ends — the wheel never wraps, the keyboard does |
Super + mouse wheel |
On a secondary monitor | Switch that monitor's workspace, one notch at a time, at the shell's own wheel cadence; clamped at the ends |
Super + two-finger |
On a secondary, with the Three-finger swipe preference off | The touchpad falls back to the wheel row above instead of going idle |
A plain wheel outside the overview belongs to whatever app is under it;
outside the overview only Super+wheel is a workspace input.
With Blur My Shell's overview blur enabled, the gaps between sliding workspaces use its selected blur pipeline. Without it, the gaps use the normal shell background. This applies to both gesture and keyboard slides.
In the overview
Each secondary monitor gets a row of full-size pages plus a thumbnail strip of its own; the primary keeps GNOME's native row.
| Action | Result |
|---|---|
| Click a page thumbnail, another page, or a window on another page of the same monitor | That page slides in and the overview stays open, as on the primary. The switch commits silently, no pill. Clicking the active page or one of its windows leaves the overview |
| Drag a window onto another page of its monitor | It moves to that virtual workspace; off the shown page, it parks there — invisible until that page comes around |
| Drag a window from the primary onto a secondary's page | The window is adopted by that monitor and moved to it physically — it now lives in that monitor's workspaces |
| Click a window parked on an inactive page (dash, search, any picker) | Un-minimize is intent: the monitor switches to the page holding the window you picked — parked windows are hidden from Alt+Tab precisely so this pick is deliberate |
The panel dots
The panel's workspace dots follow the focus:
| Focus is on | The dots show | A dot click |
|---|---|---|
| The primary monitor | GNOME's own dots, native and functional as before | Opens the overview, as before |
| A secondary monitor | One dot per virtual workspace of that monitor, current one stretched to a pill | Switches that monitor to that workspace — no pill, the click is the feedback |
| …mid-slide (swipe or animated shortcut) | The dots stretch continuously toward the target page | Deferred until the slide lands |
The row is rebuilt the moment the count changes (a dynamic-mode grow or collapse repaints it without waiting for a focus change), and hands the button back to the shell entirely while focus rests on the primary.
Preferences
gnome-extensions prefs monitor-workspaces@salix
| Option | Default | Notes |
|---|---|---|
| Dynamic workspaces | on | Each secondary grows its own workspace count as pages fill, keeping one empty in reserve |
| Workspaces per monitor | 4 | Fixed count, 2–8; insensitive while dynamic mode is on |
| Three-finger swipe | on | Switches the secondary under the pointer; primary keeps GNOME's gesture |
| Slide animation | on | First thing to turn off if a switch ever renders badly |
| On-screen dots | on | The switcher pill appears on the monitor that changed |
| Debug logging | off | Journal trace under the monitor-workspaces prefix |
| Diagnostics | — | Live workspaces-only-on-primary with a one-click fix |
Development
| Target | What it does |
|---|---|
make doctor |
Every precondition, with the fix command on each failure |
make schemas |
Re-compile the gsettings schema (the blob is committed; regenerate after editing the XML) |
make install / make uninstall |
Link src/ in / unlink it |
make pack |
Bundle zip |
make lint |
Parse-check every module with gjs -m — no node, no eslint, load failures outside the shell are fine |
make test |
Model and behavior regression suites; prints ALL PASS, warning noise on a green run is expected |
make check |
lint + test, the way CI runs them |
make logs |
Follow journalctl filtered to this extension |
make nested |
Nested-session guidance (launches devkit if installed) |
Three facts that save hours:
- A fresh shell is the only reload. Wayland has no
Alt+F2 → r, and GJS caches ES modules for the life of the process — toggling the extension off/on does not re-read edited files. Iterate in a nested session. --nestedis gone. Removed in GNOME 49; Mutter Devkit (separate package,sudo dnf install mutter-devkiton Fedora) replaced it. Plaingnome-shell --waylandis not nested — it tries to take over your running session and dies with EBUSY.- Add a second virtual display in the devkit UI before testing, or there is nothing for the extension to act on.
After make check, verify these behaviors in a GNOME Shell 50/51 session with
multiple monitors, with slide animation both on and off:
-
In dynamic mode, leave an empty workspace for an occupied one. The incoming windows must appear even when removing the empty page renumbers the destination.
-
Keep a window focused on one monitor and scroll workspaces on another. Keyboard focus must stay on the original monitor, including when the destination is empty. Return to an occupied workspace and check its last focused window.
-
Move an app to an inactive page, then drag another window of that app from a different monitor onto the visible page. The dragged window must stay visible.
-
In the overview, drag a window between a secondary monitor's workspaces, using both a page and a thumbnail as the target. Repeat in fixed and dynamic mode. Pages must remain visible, show the moved window on its destination, and still work after closing and reopening the overview. Move a window with a keyboard shortcut while the overview stays open and check both pages update. Close another window during a drag or page animation; previews must stay usable during the interaction and refresh afterward.
-
In the overview, click a secondary's peeking neighbour page, then a window on another page. Each click must slide that page in and keep the overview open. Clicking the active page or its window must leave the overview.
-
In dynamic mode, start dragging a window, then close the last window on an earlier inactive workspace. Drop onto a later page or thumbnail. The window must join the windows shown in that target, even if its workspace number changed. A target whose workspace disappeared must reject the drop.
-
Press next several times during a slide, reverse direction, and select a numbered workspace. Each command must resolve without an older animation switching back afterward. Also interrupt a slide with the overview or lock screen.
-
Disconnect and reconnect a secondary monitor. Windows must be released on disconnect and reclaimed when it returns, including after repeated layout events.
-
With Blur My Shell's overview blur enabled, slowly swipe a secondary monitor. The gap must show blurred wallpaper while the pages and windows stay sharp. Check a monitor positioned left of the primary too. Disable overview blur during a swipe and confirm the blur disappears without breaking the slide.
-
In the overview, drag a window onto another secondary workspace thumbnail. Release once and move the pointer: the preview must stop following it without another click. Test with four fixed workspaces and GNOME animations enabled; repeat using the visible part of the next large page as the target, and from the primary monitor. Only the dropped window may animate in on its target; the other windows must not flash or jump, and the source page must ease its remaining windows into the gap. Repeat rapidly and cancel a drag with Escape. Also close another window while dragging; the remaining preview must stay draggable.
Troubleshooting
gnome-extensions enablesays the extension does not exist. Log out and back in first — the shell only scans at session start.- A shortcut does nothing. You are probably on the primary monitor, where
it is a no-op by design. With debug logging on,
make logssays so. - Workspaces seem to leak into each other. Something flipped
workspaces-only-on-primaryoff; the Diagnostics row turns it back on. - Windows stay minimized in the dash. That is how inactive workspaces are parked; clicking a window un-minimizes it and brings you its workspace. Disabling the extension restores every window it hid.
- Total escape hatch (turns off all user extensions, no logout needed):
gsettings set org.gnome.shell disable-user-extensions true— set it back tofalsewhen done. - Anything else: run
make doctorfirst; every failure it prints names the command that resolves it.