22

Recently, I started to use i3wm and fell in love with it. However, one thing bothers me: controlling more than 10 workspaces.

In my config $mod+1 to $mod+9 switches between the workspaces 1 to 9 (and $mod+0 for 10), but sometimes 10 workspaces just aren't enough.

At the moment I reach out to workspace 11 to 20 with $mod+mod1+1 to $mod+mod1+0, i.e. hitting mod+alt+number. Of course this works without any problems, but it is quite a hassle to switch workspaces like that, since the keys aren't hit easily. Additionally, moving applications between workspaces 11 to 20 requires to mod+shift+alt+number -> ugly.

In my Vim bindings (I have lots of plugins) I started to use double modifier shortcuts, like modkey + r for Plugin 1 and modkey + modkey + r for Plugin 2. This way I can bind every key twice and hitting the mod key twice is easy and fast.

Can I do something similar in i3wm?

How do you make use of more than 10 workspaces in i3wm? Any other solutions?

2
  • I don't know what kind of keyboard layout you have, but could you use some/all of the keys below and to the right of the numbers across the top? i.e. $mod+q is workspace 11, etc. Of course you would have to reassign any of those keys that are in use.
    – airhuff
    Commented Jan 18, 2017 at 6:38
  • Yes, but this effectively reduces the number of shortcuts available for i3 actions. Preferably, I would like to have something like $mod + $mod + 1 for workspace 11, so that a fast double key press of the mod key directly enables me to go for workspace 11-20 with number key 1, 2, ...,9, 0. In Vim I have this behavior: leader + r is mapped to another action than leader + leader + r, thus I can trigger different actions with the same hotkey by just pressing the leader key once or twice.
    – daniel451
    Commented Jan 18, 2017 at 11:35

5 Answers 5

23

i3 does not really support key sequences like vim. Any key binding consists of a single key preceded by an optional list of distinct (so no Shift+Shift) modifiers. And all of the modifiers need to be pressed down at the time the main key is pressed.

That being said, there are two main ways to have a lot of workspaces without having to bind them to long lists of modifiers:

1. Dynamically create and access workspaces with external programs

You can do not have to define a shortcut for every single workspace, you can just create them on the fly by sending a workspace NEW_WS to i3, for example with the i3-msg program:

i3-msg workspace NEW_WS
i3-msg move container to workspace NEW_WS

i3 also comes with the i3-input command, which opens a small input field then runs a command with the given input as parameter

i3-input -F 'workspace %s' -P 'go to workspace: '
i3-input -F 'move container to workspace %s' -P 'move to workspace: '

Bind these these two commands to shortcuts and you can access an arbitrary number of workspaces by just pressing the shortcut and then entering the name (or number) of the workspace you want. (If you only work with numbered workspaces, you might want to use workspace number %s instead of just workspace %s)

2. Statically bind workspaces to simple Shortcuts within key binding modes

Alternatively, for a more static approach, you could use modes in your i3 configuration. You could have separate modes for focusing and moving to workspaces:

set $mode_workspace "goto_ws"
mode $mode_workspace {
    bindsym 1 workspace 1; mode "default"
    bindsym 2 workspace 2; mode "default"
    # […]
    bindsym a workspace a; mode "default"
    bindsym b workspace b; mode "default"
    # […]
    bindsym Escape mode "default"
}
bindsym $mod+w mode $mode_workspace

set $mode_move_to_workspace "moveto_ws"
mode $mode_move_to_workspace {
    bindsym 1 move container to workspace 1; mode "default"
    bindsym 2 move container to workspace 2; mode "default"
    # […]
    bindsym a move container to workspace a; mode "default"
    bindsym b move container to workspace b; mode "default"
    # […]
    bindsym Escape mode "default"
}
bindsym $mod+shift+w mode $mode_move_to_workspace

Or you could have separate bindings for focusing and moving within a single mode:

set $mode_ws "workspaces"
mode $mode_ws {
    bindsym 1 workspace 1; mode "default"
    bindsym Shift+1 move container to workspace 1; mode "default"
    bindsym 2 workspace 2; mode "default"
    bindsym Shift+2 move container to workspace 2; mode "default"
    # […]
    bindsym a workspace a; mode "default"
    bindsym Shift+a move container to workspace a; mode "default"
    bindsym b workspace b; mode "default"
    bindsym Shift+b move container to workspace b; mode "default"
    # […]
    bindsym Escape mode "default"
}
bindsym $mod+shift+w mode $mode_move_to_workspace

In both examples the workspace or move commands are chained with mode "default", so that i3 automatically returns back to the default key binding map after each command.

11

My solution to this is just using more keys:

set $ws0 "0:`:www"
set $ws1 "1:1"
set $ws2 "2:2"
set $ws3 "3:3:fm"
set $ws4 "4:4"
set $ws5 "5:5"
set $ws6 "6:6:dev"
set $ws7 "7:7"
set $ws8 "8:8"
set $ws9 "9:9"
set $ws10 "10:0:music"
set $ws11 "11:-:jd"
set $ws12 "12:=:comm"
set $ws13 "13:B"
set $ws14 "14:H"
set $ws15 "15:E"
set $ws16 "16:I"
set $ws17 "17:D:upwork"


bindsym $mod+grave workspace $ws0
bindsym $mod+1 workspace $ws1
bindsym $mod+2 workspace $ws2
bindsym $mod+3 workspace $ws3
bindsym $mod+4 workspace $ws4
bindsym $mod+5 workspace $ws5
bindsym $mod+6 workspace $ws6
bindsym $mod+7 workspace $ws7
bindsym $mod+8 workspace $ws8
bindsym $mod+9 workspace $ws9
bindsym $mod+0 workspace $ws10
bindsym $mod+minus workspace $ws11
bindsym $mod+equal workspace $ws12
bindsym $mod+BackSpace workspace $ws13
bindsym $mod+Home workspace $ws14
bindsym $mod+End workspace $ws15
bindsym $mod+Insert workspace $ws16
bindsym $mod+Delete workspace $ws17

for_window [class="Upwork"] move container to workspace $ws17
for_window [class="Spotify"] move container to workspace $ws10
for_window [class="Brave-browser"] move container to workspace $ws0
for_window [class="TelegramDesktop"] move container to workspace $ws12
for_window [class="jetbrains-pycharm"] move container to workspace $ws6
for_window [class="Caja"] move container to workspace $ws3
for_window [class="JDownloader"] move container to workspace $ws11
1

My solution, based on Lukas answer:

# win principal, alt secondary
# set $mod Mod4
# set $mod2 Mod1
#
# # alt principal, win secondary
set $mod Mod1
set $mod2 Mod4

# switch to workspace
bindsym $mod+1 workspace 1
bindsym $mod+2 workspace 2
bindsym $mod+3 workspace 3
bindsym $mod+4 workspace 4
bindsym $mod+5 workspace 5
bindsym $mod+6 workspace 6
bindsym $mod+7 workspace 7
bindsym $mod+8 workspace 8
bindsym $mod+9 workspace 9
bindsym $mod+0 workspace 10
# Workspaces 11-20, with mod2
bindsym $mod2+1 workspace 11
bindsym $mod2+2 workspace 12
bindsym $mod2+3 workspace 13
bindsym $mod2+4 workspace 14
bindsym $mod2+5 workspace 15
bindsym $mod2+6 workspace 16
bindsym $mod2+7 workspace 17
bindsym $mod2+8 workspace 18
bindsym $mod2+9 workspace 19
bindsym $mod2+0 workspace 20

# move focused container to workspace, keeping focus
bindsym $mod+Shift+1 move workspace 1; workspace 1
bindsym $mod+Shift+2 move workspace 2; workspace 2
bindsym $mod+Shift+3 move workspace 3; workspace 3
bindsym $mod+Shift+4 move workspace 4; workspace 4
bindsym $mod+Shift+5 move workspace 5; workspace 5
bindsym $mod+Shift+6 move workspace 6; workspace 6
bindsym $mod+Shift+7 move workspace 7; workspace 7
bindsym $mod+Shift+8 move workspace 8; workspace 8
bindsym $mod+Shift+9 move workspace 9; workspace 9
bindsym $mod+Shift+0 move workspace 10; workspace 10

bindsym $mod2+Shift+1 move workspace 11; workspace 11
bindsym $mod2+Shift+2 move workspace 12; workspace 12
bindsym $mod2+Shift+3 move workspace 13; workspace 13
bindsym $mod2+Shift+4 move workspace 14; workspace 14
bindsym $mod2+Shift+5 move workspace 15; workspace 15
bindsym $mod2+Shift+6 move workspace 16; workspace 16
bindsym $mod2+Shift+7 move workspace 17; workspace 17
bindsym $mod2+Shift+8 move workspace 18; workspace 18
bindsym $mod2+Shift+9 move workspace 19; workspace 19
bindsym $mod2+Shift+0 move workspace 20; workspace 20
1

Al elegant way of doing this could be re-mapping Caps lock to Hyper key using xmodmap

so create an arbitary file ( ~/.Xmodmap here as an example ) with following contents

remove Lock = Caps_Lock
keycode 66 shift  = Hyper_L Caps_Lock 
remove mod4 = Hyper_L
add Mod3 = Hyper_L

The above configurations allows me to use caps lock as a hyper key, and I can also use it as a caps lock key with combination Shift+ caps lock

Accordingly in the i3 config file, i have added the following

# modifier in i3config 

set $super Mod4

set $alt Mod1

set $hyper Mod3

exec --no-startup-id xmodmap ~/.Xmodmap

Now, in i3 config I can use keybindings like

bindsym $hyper+1 workspace 11 
bindsym $hyper+2 workspace 12 
bindsym $hyper+3 workspace 13

in case you end up creating a mess of keyboard keys remapping, running setxkbmap in terminal without arguments will reset keyboard to the original default state

P.S. : hyper key I am referring to is a modifier key, not ctrl+shift+alt combination in macOS some articles point to.

1

I've done this by storing the "toggle" variable to a file in /tmp. We can't use environment variables for the toggle, because each bindsym exec spawns a new shell and there's no way to set the environment variable in a parent process. In most distros, /tmp is tmpfs and stored in RAM, so it's still pretty fast to use.

Mod+= increases the "workspace modifier", adding 10 to every workspace number.

Mod+- decreases the "workspace modifier", subtracting 10 from every workspace number.

Normally, pressing Mod+1 will bring you to workspace 1. After pressing Mod+=, it will bring you to workspace 11.

Here's the config:

#Increase workspace modifier
bindsym $mod+equal exec echo $(( `cat /tmp/workspace_modifier` + 1 )) > /tmp/workspace_modifier

#Decrease workspace modifier
bindsym $mod+minus exec n=$(( `cat /tmp/workspace_modifier` - 1 )) && echo `[ $n -le 0 ] && echo '' || echo $n` > /tmp/workspace_modifier

#Switch to workspace
bindsym $mod+0 exec i3-msg workspace number `cat /tmp/workspace_modifier`0
bindsym $mod+1 exec i3-msg workspace number `cat /tmp/workspace_modifier`1
bindsym $mod+2 exec i3-msg workspace number `cat /tmp/workspace_modifier`2
bindsym $mod+3 exec i3-msg workspace number `cat /tmp/workspace_modifier`3
bindsym $mod+4 exec i3-msg workspace number `cat /tmp/workspace_modifier`4
bindsym $mod+5 exec i3-msg workspace number `cat /tmp/workspace_modifier`5
bindsym $mod+6 exec i3-msg workspace number `cat /tmp/workspace_modifier`6
bindsym $mod+7 exec i3-msg workspace number `cat /tmp/workspace_modifier`7
bindsym $mod+8 exec i3-msg workspace number `cat /tmp/workspace_modifier`8
bindsym $mod+9 exec i3-msg workspace number `cat /tmp/workspace_modifier`9

#Move focused container to workspace
bindsym $mod+Shift+0 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`0
bindsym $mod+Shift+1 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`1
bindsym $mod+Shift+2 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`2
bindsym $mod+Shift+3 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`3
bindsym $mod+Shift+4 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`4
bindsym $mod+Shift+5 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`5
bindsym $mod+Shift+6 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`6
bindsym $mod+Shift+7 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`7
bindsym $mod+Shift+8 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`8
bindsym $mod+Shift+9 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`9

Note that in this config, Mod+0 moves to workspace 0 instead of workspace 10. If this is important to you, you may wish to use these bindings:

bindsym $mod+0 exec n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` && i3-msg workspace number `echo "$w*10 + 10" | bc`
bindsym $mod+Shift+0 exec n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` && i3-msg move container to workspace number `echo "$w*10 + 10" | bc`

Keeping workspace names becomes very complicated because of the way i3 config handles variables: it does direct replacement instead of injecting them in the environment of exec commands, so it's not possible to retrieve the values dynamically without redeclaring them in the exec command. This quickly gets messy:

set $ws1 "1: one"
set $ws2 "2: two"
set $ws1 "11: eleven"
set $ws2 "12: twelve"

bindsym $mod+Shift+1 exec key=1 ws1=$ws1 ws2=$ws2 ws11=$ws11 ws12=$ws12 && i=`cat /tmp/workspace_modifier` && dynamic=ws${i}${key} && text=${!dynamic} && workspace=$(echo `[ "$text" ] && echo "$text" || echo ${i}${key}` ) && i3-msg move container to workspace number $workspace

This should works as long as in the exec command you only declare the workspaces that have been named using the set command. If, for example, you define set $ws1 "1: text" but do not set $ws11, then include ws11=$ws11 in the exec command, i3 config will expand ws11=$ws11 to ws11="1: one"1 because it matches $ws1 in $ws11. It works fine otherwise.

If you wish to use workspace names plus keep Mod+0 set to workspace 10, use these bindsyms:

bindsym $mod+0 exec key=0 ws1=$ws1 ws2=$ws2 ws3=$ws3 ws4=$ws4 ws5=$ws5 ws6=$ws6 ws7=$ws7 ws8=$ws8 ws9=$ws9 ws10=$ws10 && n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` i=`echo "$w*10 + 10" | bc` && dynamic=ws${i} && text=${!dynamic} && workspace=$(echo `[ "$text" ] && echo "$text" || echo ${i}` ) && i3-msg workspace number $workspace
bindsym $mod+Shift+0 exec key=0 ws0=$ws0 ws1=$ws1 ws2=$ws2 ws3=$ws3 ws4=$ws4 ws5=$ws5 ws6=$ws6 ws7=$ws7 ws8=$ws8 ws9=$ws9 ws10=$ws10 && n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` i=`echo "$w*10 + 10" | bc` && dynamic=ws${i} && text=${!dynamic} && workspace=$(echo `[ "$text" ] && echo "$text" || echo ${i}` ) && i3-msg move container to workspace number "$workspace"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .