Go to file
Tor Hedin Brønner f8119ae0bf Record overrides in the actionIdMap
This means we can get rid of more cases in the ugly switch in navigator.

Guard against non mutter action names, but apply the override even when we can't
get the id.

For some reason restore-shortcuts (`<Super>Escape`) returns
KeybindingsAction.NONE.

Also remove setKeybinding
2018-07-18 22:37:34 +02:00
examples Unify regular keybinding api an schemaless keybinding api 2018-07-06 12:16:37 +02:00
resources About section in prefs GUI 2018-07-11 22:49:00 +02:00
schemas Simplify binding summaries 2018-07-11 18:47:56 +02:00
.dir-locals.el Add gnome-shell-mode to dir-locals 2017-09-14 09:27:10 +02:00
app.js app: Look up custom window handlers in a dict 2018-06-15 10:19:29 +02:00
convenience.js Add the canonical convenience.js file for accessing settings 2017-09-21 16:38:02 +02:00
debug log-viewer: silly bugfix group stacktraces 2018-07-06 13:22:19 +02:00
extension.js Remove utils.as_key_handler 2018-07-18 22:37:34 +02:00
install.sh Minor bugfix: Use absolute path to local extension dir in install script 2017-09-21 10:29:55 +02:00
keybindings.js Record overrides in the actionIdMap 2018-07-18 22:37:34 +02:00
kludges.js Use var for all top level declarations to avoid warnings 2018-04-30 00:03:08 +02:00
LICENSE Add license 2017-09-17 14:19:37 +02:00
liveAltTab.js Prepare for navigator refactor + refactor switch-left/right/up/down 2018-07-18 22:37:34 +02:00
metadata.json About section in prefs GUI 2018-07-11 22:49:00 +02:00
minimap.js minimap: Respect window-gap properly 2018-07-15 20:39:44 +02:00
navigator.js Record overrides in the actionIdMap 2018-07-18 22:37:34 +02:00
notes.org Notes 2018-07-06 12:46:07 +02:00
prefs.js prefs: Fix tooltip 2018-07-16 14:03:02 +02:00
README.md readme: We've support shared monitors a while now 2018-07-17 11:19:46 +02:00
scratch.js Main.layoutManager.focusMonitor is very new so use a "polyfill" for now 2018-06-25 16:50:44 +02:00
settings.js Add tooltip describing conflicts 2018-07-15 20:35:04 +02:00
Settings.ui Filtered keybinding search (quick and dirty) 2018-07-12 12:17:35 +02:00
shell.nix Custom schema (let us create new keybindings/actions) 2017-09-11 18:02:55 +02:00
stackoverlay.js clickoverlays: don't show while the overview is active 2018-07-18 13:49:02 +02:00
stylesheet.css stylesheet.css 2017-09-28 13:29:11 +02:00
tiling.js Refactor switch-next/previous 2018-07-18 22:37:34 +02:00
topbar.js Consistently declare and use screen and display 2018-07-12 16:14:26 +02:00
utils.js Remove utils.as_key_handler 2018-07-18 22:37:34 +02:00

PaperWM

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.

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

Installation

Clone the repo and run the install.sh script from the directory:

./install.sh

It will link the repo to ~/.local/share/gnome-shell-extensions/ where gnome-shell can find it. You can then enable the extension in Gnome Tweaks. Running the extension will automatic install of a user config file as described in Development & user configuration.

Usage

Most functionality is available using a mouse, eg. by clicking on a window at the edge of a monitor. 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. SuperN 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.

AltTab is of course also available.

Keybindings
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
SuperTab or AltTab Cycle through the most recently used windows
SuperShiftTab or AltShiftTab Cycle backwards through the most recently used windows
SuperR Resize the window (cycles through useful widths)
SuperF Maximize the width of a window
SuperShiftF Toggle fullscreen
SuperN or SuperReturn Create a new window from the active application
SuperC or 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 downe. Above_Tab is the key above Tab (` in a US qwerty layout). Like alt-tab Shift is added to move in reverse order.

A workspace has a name and background color. Right-clicking the workspace name lets you change them easily:

The workspace menu

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.

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

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.

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

Keybindings
SuperEscape 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.

Winprops

It's possible to create simple rules for placing new windows. Currently mostly 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;
    Tiling.defwinprop({
        wm_class: "Spotify",
        scratch_layer: true,
        oneshot: 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 = Extension.imports.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(
          "win.new-terminal",
          new imports.gi.GLib.Variant("(ss)", ["window", "current"]));

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

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

Available application actions can be listed like this:

app.action_group.list_actions();

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
opensNavigator 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.

Prior work

A similar idea was apparently tried out a while back: http://10gui.com/