i3 - improved tiling WM

User-contributed article: Move a given workspace to active output


Assume you have multiple monitors, and various workspaces on each of them.

You have some workspace 1 active on monitor A, and you want to jump to workspace 2. The default behavior, using the built-in command workspace 2 is to display the workspace 2 on the screen it belongs to.

Another legitimate use-case would be to display the workspace 2 on the currently active screen.

Unfortunately, there is no built-in command in i3 to achieve that, yet. However, thanks to the IPC interface, it is possible to write an external script achieving that.


First, we need to create an executable script doing the job thanks to the IPC interface. In this article, we will assume the script is stored in ~/.config/i3/switch-workspace.py

Here is a possible implementation of the script:

#!/usr/bin/env python

from json import loads
from os import popen
from sys import argv

def ipc_query(req="command", msg=""):
    ans = popen("i3-msg -t " + req + " " +  msg).readlines()[0]
    return loads(ans)

if __name__ == "__main__":
    # Usage & checking args
    if len(argv) != 2:
        print "Usage: switch-workspace.py name-of-workspace"

    newworkspace = argv[1]

    # Retrieving active display
    active_display = None
    for w in ipc_query(req="get_workspaces"):
        if w['focused']:
            active_display = w['output']

    # Moving workspace to active display
    print ipc_query(msg="'workspace " + newworkspace + "; move workspace to output " + active_display + "; workspace " + newworkspace + "'")

This script uses i3-msg directly, but if you have several IPC scripts, or more complex ones, or if you use quotes in your workspaces' names you may want to use the python i3-ipc bindings as done in this article (however, in this case, you might have to add some bindings to the library to implement chained command since sequentiality is critical in this script).

Do not forget to make the script executable, usually, the following command, assuming you adopted the naming of our article, should work:

chmod u+x ~/.config/i3/switch-workspace.py


Once the script is created and made executable, the last step is to add the corresponding bindings in your i3 conf file.

Basically, one way to do that is to replace the workspace X bindings with exec --no-startup-id ~/.config/i3/switch-workspace.py X.

For a standard fr bépo keyboard layout, this will result in:

# switch to workspace
bindsym $mod+quotedbl exec --no-startup-id ~/.config/i3/switch-workspace.py 1
bindsym $mod+guillemotleft exec --no-startup-id ~/.config/i3/switch-workspace.py 2
bindsym $mod+guillemotright exec --no-startup-id ~/.config/i3/switch-workspace.py 3
bindsym $mod+parenleft exec --no-startup-id ~/.config/i3/switch-workspace.py 4
bindsym $mod+parenright exec --no-startup-id ~/.config/i3/switch-workspace.py 5
bindsym $mod+at exec --no-startup-id ~/.config/i3/switch-workspace.py 6
bindsym $mod+plus exec --no-startup-id ~/.config/i3/switch-workspace.py 7
bindsym $mod+minus exec --no-startup-id ~/.config/i3/switch-workspace.py 8
bindsym $mod+slash exec --no-startup-id ~/.config/i3/switch-workspace.py 9
bindsym $mod+asterisk exec --no-startup-id ~/.config/i3/switch-workspace.py 10

But of course, you will have to adapt this to your own keyboard layout.


Author: captnfab, 2014-08-02