Skip to content
Tiled scrollable window management for Gnome Shell
JavaScript Shell Other
Branch: master
Clone or download
hedning Merge pull request #179 from paperwm/workspace-menu
Modernize the workspace menu
Latest commit 482d291 Oct 21, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
examples tiling: Move cycle to Tiling.cycleWorkspaceSettings Oct 21, 2019
resources About section in prefs GUI Jul 11, 2018
schemas settings: add per workspace directory key Oct 18, 2019
.dir-locals.el Add gnome-shell-mode to dir-locals Sep 14, 2017
.gitignore Add tags to gitignore Dec 8, 2018
LICENSE Add license Sep 17, 2017 readme: Note workspaces-only-on-primary limitations Oct 18, 2019
Settings.ui prefs workspaces: Add `gnome-control-center background` button Oct 12, 2019
app.js app: mkCommandLineSpawner util expanding %d to workspace directory Oct 18, 2019
convenience.js Misc cleanup Jan 5, 2019
debug debug: support native systemd services Sep 19, 2019
extension.js startup: expose failures on startup Oct 1, 2019
gestures.js vertical swipe: fix velocity bug Oct 10, 2019 installer: make sure the gnome shell extensions dir exists Feb 6, 2019
keybindings.js app: Launch new windows from the workspace directory if set Oct 18, 2019
kludges.js kludges: Add overrideWithFallback Oct 18, 2019
liveAltTab.js liveAltTab: kill unminimize animations manually Oct 2, 2019
metadata.json metadata: indicate 3.34 support Sep 19, 2019
minimap.js minimap: Limit highlight height Oct 17, 2019
navigator.js navigator: Don't finish navigation if super is held down Oct 10, 2019 Notes about getting the clutter FPS Sep 15, 2018
prefs.js workspace-directory: prefs GUI Oct 18, 2019
scratch.js Remove `transition` from tween calls Sep 28, 2019 set-recommended-gnome-shell-settings: do not prefer static workspaces Jul 16, 2019
settings.js settings: dev/debugging utils to delete workspace settings Oct 17, 2019
shell.nix Custom schema (let us create new keybindings/actions) Sep 11, 2017 don't die on input from terminal Dec 10, 2018
stackoverlay.js edge overlays: start out unactivated Oct 19, 2019
stylesheet.css stylesheet.css Sep 28, 2017
tiling.js tiling: Move cycle to Tiling.cycleWorkspaceSettings Oct 21, 2019
topbar.js workspace label: Set min width to avoid movement while typing Oct 21, 2019
utils.js registerClass: Support passing extra spec as first arg Oct 20, 2019


project chat

PaperWM is an experimental Gnome Shell extension providing scrollable tiling of windows and per monitor workspaces. It's inspired by paper notebooks and tiling window managers.

Supports Gnome Shell from 3.28 to 3.34 on X11 and wayland.

While technically an extension it's to a large extent built on top of the Gnome desktop rather than merely extending it.

We hang out on zulip.


Clone the repo and run the script from the directory. The installer will link the repo to $XDG_DATA_HOME/gnome-shell/ where gnome-shell can find it.


Cloning the repo directly into $XDG_DATA_HOME also works:

git clone '' \

You can then enable the extension in Gnome Tweaks, or enable if from the command line:

gnome-shell-extension-tool -e

There's a few Gnome Shell settings which works poorly with PaperWM. To use the recommended settings run A "restore previous settings" script is generated so the original settings is not lost. (The script will turn auto-maximize, edge-tiling, attach-modal-dialogs and workspaces-only-on-primary off).

Running the extension will automatic install a user config file as described in Development & user configuration.

Note for Ubuntu users

The desktop-icon extension (which is on by default) and PaperWM is not compatible (eg. #145).

Ubuntu makes it difficult to disable desktop-icon so it is suggested to use vanilla gnome session instead sudo apt install gnome-session and select gnome or gnome-wayland using the gear icon on login.

desktop-icon can (sometimes) be disabled via the web interface if the GNOME Shell integration is installed on the browser: or via gnome tweaks sudo apt install gnome-tweaks and be disabled under the extensions tab.


Most functionality is available using a mouse, eg. activating a window at the edge of the monitor by clicking on it. In wayland its possible to navigate with 3-finger swipes on the trackpad. But the primary focus is making an environment which works well with a keyboard.

All keybindings start with the Super modifier. On most keyboards it's the Windows key, on mac keyboards it's the Command key. It's possible and recommended to modify the keyboard layout so that Super is switched with Alt making all the keybindings easier to reach. This can be done through Gnome Tweaks under Keybard & MouseAdditional Layout OptionsAlt/Win key behaviorLeft Alt is swapped with Left Win.

Most keybindings will grab the keyboard while Super is held down, only switching focus when Super is released. Escape will abort the navigation taking you back to the previously active window.

Adding Ctrl to a keybinding will take the current window with you when navigating.

Window management and navigation is based around the three following concepts.

Scrollable window tiling

The window tiling with the minimap shown

New windows are automatically tiled to the right of the active window, taking up as much height as possible. SuperReturn will open a new window of the same type as the active window.

Activating a window will ensure it's fully visible, scrolling the tiling if necessary. Pressing Super. activates the window to the right. Super, activates the window to the left. On a US keyboard these keys are intuitively marked by < and >, they are also ordered the same way on almost all keyboard layouts. A minimap will be shown when Super is continually being pressed, as can be seen in the above screenshot.

Pressing SuperI will move the window to the right below the active window, tiling them vertically in a column. SuperO will do the opposite, pushing the bottom window out of the current column.

Swiping the trackpad horizontally with three fingers will scroll the tiling (only available in Wayland).

AltTab is of course also available.

PaperWM doesn't handle attached modal dialogs very well, so it's best to turn it off in Gnome Tweaks (under Windows).

Super, or Super. Activate the next or previous window
SuperLeft or SuperRight Activate the window to the left or right
SuperUp or SuperDown Activate the window above or below
SuperHome or SuperEnd Activate the first or last window
SuperCtrl, or SuperCtrl. Move the current window to the left or right
SuperCtrlLeft or SuperCtrlRight Move the current window to the left or right
SuperCtrlUp or SuperCtrlDown Move the current window up or down
Supert Take the window, placing it when finished navigating
SuperTab or AltTab Cycle through the most recently used windows
SuperShiftTab or AltShiftTab Cycle backwards through the most recently used windows
SuperC Center the active window horizontally
SuperR Resize the window (cycles through useful widths)
SuperShiftR Resize the window (cycles through useful heights)
SuperF Maximize the width of a window
SuperShiftF Toggle fullscreen
SuperReturn or SuperN Create a new window from the active application
SuperBackspace Close the active window
SuperI Absorb the window to the right into the active column
SuperO Expel the bottom window out to the right

The workspace stack & monitors

The most recently used workspace stack

Pressing SuperAbove_Tab will slide the active workspace down revealing the stack as shown in the above screenshot. You can then flip through the most recently used workspaces with repeated Above_Tab presses while holding Super down. Above_Tab is the key above Tab (` in a US qwerty layout). Like alt-tab Shift is added to move in reverse order.

The workspace name is shown in the top left corner replacing the Activities button adding a few enhancements. Scrolling on the name will let you browse the workspace stack just like SuperAbove_Tab. Right clicking the name lets you access and change the workspace name and the background color:

The workspace menu

Swiping the trackpad vertically with three fingers lets you navigate the workspace stack (only available in Wayland).

There's a single scrollable tiling per workspace. Adding another monitor simply makes it possible to have another workspace visible. The workspace stack is shared among all the monitors, windows being resized vertically as necessary when workspace is displayed on another monitor.

PaperWM currently works best using the workspaces span monitors preference, this can be turned on with Gnome Tweaks under Workspaces. If you want to use workspaces only on primary you need to place the secondary monitor either below or above the primary (with the best result having it below).

Workspace Keybindings
SuperAbove_Tab or SuperPage_Down Cycle through the most recently used workspaces
SuperShiftAbove_Tab or SuperPage_Up Cycle backwards through the most recently used workspaces
SuperCtrlAbove_Tab or SuperCtrlPage_Down Cycle through the most recently used, taking the active window with you
SuperCtrlShiftAbove_Tab or SuperCtrlPage_Up Cycle backwards through the most recently used, taking the active window with you
Monitor Keybindings
SuperShiftArrow_key Select neighbouring monitor
SuperShiftCtrlArrow_key Move active window to neighbouring monitor

Scratch layer

The floating scratch layer, with the alt tab menu open

The scratch layer is an escape hatch to a familiar floating layout. This layer is intended to store windows that are globally useful like chat applications and in general serve as the kitchen sink. When the scratch layer is active it will float above the tiled windows, when hidden the windows will be minimized.

Opening a window when the scratch layer is active will make it float automatically.

Pressing SuperEscape toggles between showing and hiding the windows in the scratch layer. Activating windows in the scratch layer is done using SuperTab, the floating windows having priority in the list while active. <

Pressing SuperEscape toggles between showing and hiding the windows in the scratch layer. When the scratch layer is active SuperTab gives priority to floating windows. When the tiling is active SuperShiftTab selects the most recently used scratch window.

SuperCtrlEscape will move a tiled window into the scratch layer or alternatively tile an already floating window. This functionality can also be accessed through the window context menu (AltSpace).

SuperEscape Toggle between showing and hiding the most recent scratch window
SuperShiftEscape Toggle between showing and hiding the scratch windows
SuperCtrlEscape Toggle between floating and tiling the current window
SuperTab Cycle through the most recently used scratch windows
SuperH Minimize the current window

Development & user configuration

A default user configuration, user.js, is created in ~/.config/paperwm/ with three functions init, enable and disable. init will run only once on startup, enable and disable will be run whenever extensions are being told to disable and enable themselves. Eg. when locking the screen with SuperL.

We also made an emacs package, gnome-shell-mode, to make hacking on the config and writing extensions a more pleasant experience. To support this out of the box we also install a metadata.json so gnome-shell-mode will pick up the correct file context, giving you completion and interactive evaluation ala. looking glass straight in emacs.

Pressing SuperInsert will assign the active window to a global variable metaWindow, its window actor to actor, its workspace to workspace and its PaperWM style workspace to space. This makes it easy to inspect state and test things out.

Using dconf-editor to modify settings

GSETTINGS_SCHEMA_DIR=$HOME/.local/share/gnome-shell/extensions/ dconf-editor /org/gnome/shell/extensions/paperwm/


It's possible to create simple rules for placing new windows. Currently most useful when a window should be placed in the scratch layer automatically. An example, best placed in the init part of user.js:

    let Tiling = Extension.imports.Tiling;
        wm_class: "Spotify",
        scratch_layer: true,

The wm_class of a window can be looked up by clicking SuperInsert and then checking the value of metaWindow.wm_class in emacs or looking glass.

New Window Handlers

If opening a new application window with SuperReturn isn't doing exactly what you want you can create custom functions to fit your needs. Say you want new emacs windows to open the current buffer by default, or have new terminals inherit the current directory:

    let App =;
    App.customHandlers['emacs.desktop'] =
        () => imports.misc.util.spawn(['emacsclient', '--eval', '(make-frame)']);
    App.customHandlers['org.gnome.Terminal.desktop'] =
        (metaWindow, app) => app.action_group.activate_action(
          new"(ss)", ["window", "current"]));

The app id of a window can be looked up like this:

var Shell =;
var Tracker = Shell.WindowTracker.get_default();
var app = Tracker.get_window_app(metaWindow);

Available application actions can be listed like this:



Due to limitations in the mutter keybinding API we need to steal some built in Gnome Shell actions by default. Eg. the builtin action switch-group with the default SuperAbove_Tab keybinding is overridden to cycle through recently used workspaces. If an overridden action has several keybindings they will unfortunately all activate the override, so for instance because AltAbove_Tab is also bound to switch-group it will be overridden by default. If you want to avoid this, eg. you want AltTab and AltAbove_Tab to use the builtin behavior simply remove the conflicts (ie. SuperTab and SuperAbove_Tab and their Shift variants) from /org/gnome/desktop/wm/keybindings/switch-group (no restarts required).

User defined keybindings

Extension.imports.keybindings.bindkey(keystr, name, handler, options)

Option Values Meaning
activeInNavigator true, false The keybinding is active when the minimap/navigator is open
opensMinimap true, false The minimap will open when the keybinding is invoked
let Keybindings = Extension.imports.keybindings;
Keybindings.bindkey("<Super>j", "my-favorite-width",
                    (metaWindow) => {
                        let f = metaWindow.get_frame_rect();
                        metaWindow.move_resize_frame(true, f.x, f.y, 500, f.h);
                    { activeInNavigator: true });

See examples/keybindings.js for more examples.

Recommended extensions

These extensions are good complements to PaperWM:

Prior work

A similar idea was apparently tried out a while back:

You can’t perform that action at this time.