i3wsr
is a small program that uses I3's IPC Interface
to change the name of a workspace based on its contents.
The chosen name for a workspace is a composite of the WM_CLASS
X11 window
property for each window in a workspace. In action it would look something like this:
i3wsr requires i3wm and numbered workspaces, see i3-configuration
Rust, and Cargo is
required, and i3wsr
can be installed using cargo like so:
cargo install i3wsr
Or alternatively, you can build a release binary,
cargo build --release
Then place the built binary, located at target/release/i3wsr
, somewhere on your $path
.
If you're running Arch you can install either stable, or latest from AUR thanks to reddit user u/OniTux.
Just launch the program and it'll listen for events if you are running I3. Another option is to put something like this in your i3 config
# cargo
exec_always --no-startup-id $HOME/.cargo/bin/i3wsr
# AUR
exec_always --no-startup-id /usr/bin/i3wsr
This program depends on numbered workspaces, since we're constantly changing the workspace name. So your I3 configuration need to reflect this:
bindsym $mod+1 workspace number 1
assign [class="(?i)firefox"] number 1
If you're like me and don't necessarily bind your workspaces to only numbers, or you want to keep a part of the name constant you can do like this:
set $myws "1:[Q]" # my sticky part
bindsym $mod+q workspace number $myws
assign [class="(?i)firefox"] number $myws
This way the workspace would look something like this when it gets changed:
1:[Q] Emacs|Firefox
You can take this a bit further by using a bar that trims the workspace number and be left with only
[Q] Emacs|Firefox
Configuration for i3wsr can be done using cmd flags, or a config file. A config
file allows for more nuanced settings, and is required to configure icons and
aliases. By default i3wsr looks for the config file at
$XDG_HOME/.config/i3wsr/config.toml
or $XDG_CONFIG_HOME/i3wsr/config.toml
.
To specify another path, pass it to the --config
option on invocation:
i3wsr --config ~/my_config.toml
Example config can be found in assets/example_config.toml.
Sometimes a class, instance or name can be overly verbose, use aliases that match to window properties to create simpler names instead of showing the full property
[aliases.class]
# Exact match
"^Google-chrome-unstable$" = "Chrome-dev"
# Substring match
firefox = "Firefox"
# Escape if you want to match literal periods
"Org\\.gnome\\.Nautilus" = "Nautilus"
Alias keys uses regex for matching, so it's possible to get creative:
# This will match gimp regardless of version number reported in class
"Gimp-\\d\\.\\d\\d" = "Gimp"
Remember to quote anything but [a-zA-Z]
, and to escape your slashes. Due to
rust string escapes if you want a literal backslash use two slashes \\d
.
i3wsr supports 3 window properties currently:
[aliases.name] # 1
[aliases.instance] # 2
[aliases.class] # 3
These are checked in descending order, so if i3wsr finds a name alias, it'll use that and if not, then check instance, then finally use class
Deprecation note: previously
wm_property
defined which prop to check for aliases, but this newer approach will allow for multiple types of aliases
This is the default, and the most succinct.
Use WM_INSTANCE
instead of WM_CLASS
when assigning workspace names,
instance is usually more specific. i3wsr will try to get the instance but if it
isn't defined will fall back to class.
A use case for this option could be launching chromium --app="https://web.whatsapp.com"
, and then assign a different icon to whatsapp
in your config file, while chrome retains its own alias:
[icons]
"WhatsApp" = "🗩"
[aliases.class]
Google-chrome = "Chrome"
[aliases.instance]
"web\\.whatsapp\\.com" = "Whatsapp"
Uses WM_NAME
instead of WM_INSTANCE
and WM_CLASS
, this option is very
verbose and relies on regex matching of aliases to be of any use.
A use-case is running some terminal application, and as default i3wsr will only display class regardless of whats running in the terminal.
So you could do something like this:
[aliases.name]
".*mutt$" = "Mutt"
You could display whatever the terminal is running, but this comes with one caveat: i3 has no way of knowing what happens in a terminal and starting say mutt will not trigger any IPC events. The alias will take effect whenever i3 receives a window or workspace event.
It should be possible to write a launcher script, that wraps whatever command your running with a custom i3 ipc trigger event. If anyone figures out a nice way of doing it let me know.
Which property to display if no aliases is found:
[general]
display_property = "instance"
Possible options are class
, instance
, and name
, and will default to class
if not present.
You can alternatively supply cmd argument:
i3wsr --display-property instance
You can configure icons for your WM property, a very basic preset for
font-awesome is configured, to enable it use the option --icons awesome
(requires font-awesome to be installed).
A more in depth icon configuration can be setup by using a configuration file. In there you can define icons for whatever title you'd like.
[icons]
Firefox = "🌍"
# Use quote when matching anything other than [a-zA-Z]
"Org.gnome.Nautilus" = "📘"
i3wsr tries to match an icon with an alias first, if none are found it then
checks your display_property
, and tries to match an icon with a non aliased
display_property
, lastly it will try to match on class.
[aliases.class]
"Gimp-\\d\\.\\d\\d" = "Gimp"
[icons]
Gimp = "📄"
A font that provides icons is of course recommended, like font-awesome. Make sure your bar has that font configured.
Normally i3wsr uses the pipe character |
between class names in a workspace,
but a custom separator can be configured in the config file:
[general]
separator = " "
To use a default icon when no other is defined use:
[general]
default_icon = "💀"
Set a label for empty workspaces.
[general]
empty_label = "🌕"
To display names only if icon is not available, you can use the
--no-icon-names
flag, or enable it in your config file like so:
[options]
no_icon_names = true
If you don't want i3wsr to display names at all, you can use the
--no-names
flag, or enable it in your config file like so:
[options]
no_names = true
If you want duplicates removed from workspaces use either the flag
--remove-duplicates
, or configure it in the options
section of the config
file:
[options]
remove_duplicates = true
By default i3wsr will keep everything until the first space
character is found,
then replace the remainder with titles.
If you want to define a different character that is used to split the
numbered/constant part of the workspace and the dynamic content, you can use
the option --split-at [CHAR]
[general]
split_at = ":"
Here we define colon as the split character, which results in i3wsr only keeping the numbered part of a workspace name when renaming.
This can give a cleaner config, but I've kept the old behavior as default.
Check [Pedro Scaff](https://github.com/pedroscaff)'s port [swaywsr](https://github.com/pedroscaff/swaywsr).
To run tests locally Vagrant is required. Run
script/run_tests.sh
to run tests on ubuntu xenial.
This program would not be possible without i3ipc-rs, a rust library for controlling i3wm through its IPC interface and rust-xcb, a set of rust bindings and wrappers for XCB.