-
Notifications
You must be signed in to change notification settings - Fork 24
How to set up scratchpads
This quick guide goes through the basics of setting up scratchpads.
The general idea of scratchpads is to have a window that you can quickly open to make some quick notes and then hide again, much like a physical scratchpad or notebook.
When it comes to window managers the term scratchpads have become synonymous with windows that pop in and out of existence on demand using keybindings.
In practice any window can be used as a scratchpad, for example a web browser or even a combination of multiple windows.
There are some basic principles with regards to how it works that may help you understand why scratchpads are configured the way they are.
Let's say that we want a keybinding MOD+w
to open the program kwrite
as a scratchpad.
Having configured the scratchpad correctly we have the expected scenario of:
- the user hits the
MOD+w
keybinding (1) - the window manager will search for a client (window) that is associated with the given scratchpad
- if such a client is found then it will be revealed (or toggled away if already visible)
- but if such a client does not exist then it will spawn the program instead (2)
- the spawned process should open a window and
- that window will ask to be shown (i.e. to be mapped) and
- the window will be managed by the window manager and
- we need a client rule (3) to associate the window with the given scratchpad so that the window manager may find it the next time the user hits that same keybinding
In terms of configuration we need three separate things for this to work:
- (1) - a keybinding
- (2) - a command to spawn if we do not have a client associated with the scratchpad
- (3) - a client rule to associate the new window with the given scratchpad
Let's continue with the example of using kwrite
as a scratchpad toggled using MOD+w
.
static const char *spcmd_w[] = {"w", "kwrite", "--title", "scratchpad_w", NULL};
^ (2) the command to execute if the scratchpad window does not exist.
Let's break this down.
static const char *spcmd_w[] = ...
^^^^^^^
This is just the variable name and this can be whatever you want. We will refer to this later when setting up the keybindings.
Here we name it spcmd
, short for scratchpad command, followed by _w
just to signify that the
command is intended to be used for the MOD+w
keyboard shortcut.
... = {"w", "kwrite", ...
^^^
A scratchpad is defined through a scratch "key" that is set for one or more clients.
This leading single character ("w" in this case) is the scratch key that we are going to associate the scratchpad command with.
You can use any character you want, but it is good practice to use the same character as the keyboard shortcut that you will use to toggle this scratchpad.
The reason for this is that it will be easier later on to tell which scratchpad commands, keyboard shortcuts and client rules belong together.
... = {"w", "kwrite", "--title", "scratchpad_w", NULL};
^^^^^^ ^^^^^^^ ^^^^^^^^^^^^ ^^^^
Then follows the actual command to be executed, which in this case is
kwrite --title scratchpad_w
. The title argument is application specific and allows us to set a
unique window title for the program. We need a unique window title later on when setting up the
client rule.
The double quotes and commas between words, followed by a NULL
value, is required by execvp
which will handle the execution of the command. Adding "kwrite --title scratchpad_w" will not work
because there are no commands in the system named like that (with spaces and all).
The keyboard shortcuts are set up using a macro named SCRATCHKEYS
.
SCRATCHKEYS(MODKEY, XK_w, spcmd_w)
^ (1) the keybinding to toggle/spawn the scratchpad.
Fairly straightforward. We pass the MODKEY
, the keysym we want to associate the scratchpad with
and the name of the command we created earlier.
The macro looks like this and will set up three keybindings to toggle, set and remove scratchpads.
#define SCRATCHKEYS(MOD,KEY,CMD) \
{ KeyPress, MOD, KEY, togglescratch, {.v = CMD } }, \
{ KeyPress, MOD|Ctrl, KEY, setscratch, {.v = CMD } }, \
{ KeyPress, MOD|Ctrl|Shift, KEY, removescratch, {.v = CMD } }, \
{ .title = "scratchpad_w", .scratchkey = 'w', .flags = Floating },
^ (3) client rule(s) to associate the window with the given scratch key.
Here we filter on the title of "scratchpad_w" - because we explicitly change the window title of the program through the command.
If the new window matches the given rule then the scratch key of w
will be set for the client so
that the window manager will be able to find the client the next time the keybinding is pressed.
Additionally the window will be made floating through the flags (optional, you can have tiled scratchpads).
Tip: If the program allows for the WM class to be changed via command line arguments then it is generally better to use that than changing the title - this because there are often other things that may influence the window title of a program.
It is possible to skip the creation of the command variable and bundle it straight with the keybinding.
To do that we will replace the existing SCRATCHPADS
macro with the following:
#define SCRATCHKEYS(MOD,KEY,SKEY,...) \
{ KeyPress, MOD, KEY, togglescratch, {.v = (const char*[]){ SKEY, __VA_ARGS__, NULL } } }, \
{ KeyPress, MOD|Ctrl, KEY, setscratch, {.v = (const char*[]){ SKEY, NULL } } }, \
{ KeyPress, MOD|Ctrl|Shift, KEY, removescratch, {.v = (const char*[]){ SKEY, NULL } } }, \
and add keybindings with inline commands like this:
SCRATCHKEYS(Super, XK_w, "w", "kwrite", "--title", "Scratchpad (w)")
SCRATCHKEYS(Super, XK_e, "e", "kwrite", "--title", "Scratchpad (e)")
SCRATCHKEYS(Super, XK_r, "r", "kwrite", "--title", "Scratchpad (r)")
As demonstrated in the examples above adding a prefix or suffix indicating which scratchpad a given command is associated with makes the configuration a bit more manageable.
For example seeing the command of spcmd_x
in the config file lets you draw the conclusion that it
is in relation to the scratchpad with the MOD+x
keybinding.
The same goes with finding a client rule that refers to "scratchpad_x" or "scratchpad (x)".
Doing this consistently makes it easier to spot what commands, keybindings and client rules are associated with each other should you need to make changes.
Here are a few issues that are fairly regular.
Problem: I have set up scratchpads but when I hit the keybinding nothing happens.
1) Check that you have set up a keybinding to spawn the command
2) Check that the command and arguments are correctly spaced with commas and separate strings for each argument.
E.g. this will not work:
static const char *spcmd_w[] = {"w", "st -n 'spterm (w)' -g 120x34", NULL };
but this should:
static const char *spcmd_w[] = {"w", "st", "-n", "spterm (w)", "-g", "120x34", NULL };
Double check that the command works on the command line.
Note that if you are executing a shell script then that shell script may not be in the PATH
environment variable that is visible to your window manager. This may be different from what you may
have set in bash
or some other shell.
If that is the case then try checking if using an absolute path to the script works. If that solves
the issue then you may want to consider updating the path in your ~/.profile
file.
Problem: I have set up scratchpads, but every time I hit the keybinding a new window spawns instead of hiding the existing window.
1) Most likely your client rule does not match the window and thus the client is not associated with the given scratchpad.
Double check the client rules and note that:
- other rules may be interfering and
- some windows come through with no title, no class and no instance (e.g. spotify) and
- some windows may change title, class and instance after having been mapped (e.g. LibreOffice applications)
Problem: I use a particular application as a normal client, but I also want a second instance to work as a scratchpad. When I launch the normal client it becomes the scratchpad which I do not want.
1) Double check the client rules that identify the window as a scratchpad
Generally you will want to be able to uniquely identify the scratchpad window using the class, instance and/or window title (or other filters, if available). Some, but not all, windows will allow for some of these properties to be overridden using command line arguments.
If such command line arguments are available then you should definitely use them.
In cases where the application does not allow new instances to be spawned with a unique class, instance or window title then it may be that the only real solution is to assign scratchpads on demand during runtime.
Also see the scratchpads page for more details.
Back to Guides.
Concepts | Configuration | Features | Flags | Functionality | Functions