Client_Rules - bakkeby/dusk GitHub Wiki
Client rules are specific instructions for the window manager as to how certain windows should be handled.
As an example this can allow for:
- the gimp appliation to start as floating on workspace 4
- the chat client to start on workspace 2 and
- the presentation program is to start in fullscreen
The client rule is defined as a struct
in the window manager:
typedef struct {
const char *class;
const char *role;
const char *instance;
const char *title;
const char *wintype;
const int transient;
const double opacity;
const uint64_t flags;
const char *floatpos;
const char scratchkey;
const char *workspace;
const char *label;
const char swallowedby;
const char swallowkey;
const char *iconpath;
const char *alttitle;
int resume;
} Rule;
A structure in C can be thought of as a user defined data type - it allows data items of different types to be combined in a single record.
There is more than one way to initialise a struct
type, but we will focus on two options here and
which one to use is up to you.
The first option is to include all the fields when creating the rules, e.g.
static const Rule clientrules[] = {
// class role instance title wintype transient opacity flags floatpos scratchkey ws label swallowedby swallowkey iconpath resume
{ "Gimp", NULL, NULL, NULL, NULL, 0, 0, 0, NULL, NULL, "4" NULL, 0, 0, NULL, 0 },
{ "Firefox", NULL, NULL, NULL, NULL, 0, 0, 0, NULL, NULL, "9" NULL, 0, 0, NULL, 0 },
...
The benefit of this is that the user can see the values of all the fields and can easily make changes if need be.
On the other hand a setup like this often result in a lot maintenance with regards to spacing to make sure that the columns are aligned.
Also for the rule that places the gimp application on workspace 4 there is a lot of irrelevant information which can affect readability, more so if the columns are misaligned.
The other option is to only specify the fields that should be set by using the field names, e.g.
static const Rule clientrules[] = {
{ .class = "Gimp", .workspace = "4" },
{ .class = "Firefox", .workspace = "9" },
...
The benefit of this is that you only see what is relevant. That said this way you do need to know
the names of the struct
fields and to include these names when setting the fields.
The rules are configured in the clientrules
list in config.h.
The client rule has six filters:
class
role
instance
title
wintype
transient
The values for these can be found using the xprop
tool which lists X property atoms for a window.
Here are the properties that are relevant for client rules:
WM_CLASS(STRING) = instance, class
WM_NAME(STRING) = title
WM_WINDOW_ROLE(STRING) = role
_NET_WM_WINDOW_TYPE(ATOM) = wintype
WM_TRANSIENT_FOR(WINDOW): window id # 0x4c00024
Here is a practical example:
WM_CLASS(STRING) = "Navigator", "firefox"
WM_NAME(COMPOUND_TEXT) = "Home · bakkeby/dusk Wiki — Mozilla Firefox"
WM_WINDOW_ROLE(STRING) = "Toplevel"
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
Here the class is "firefox", the instance is "Navigator", the window role is "Toplevel" and the window type is normal. The window title is "Home · bakkeby/dusk Wiki — Mozilla Firefox".
These would then translate to something like this for the rules.
.class = "firefox", ...
.instance = "Navigator", ...
.title = "Mozilla Firefox", ...
.role = "Toplevel", ...
.wintype = WTYPE "NORMAL", ...
You do not need to specify all of these, only include the ones that is relevant for identifying the window (or windows) of interest.
The class of the Firefox browser is appears to be distribution (or packaging) specific and tends to come through as either "Firefox" or "firefox" which can cause some confusion with regards to rules as they are case sensitive.
In the title above we only included "Mozilla Firefox" and not the full text. This works because
the comparison is done using the strstr
function which looks for the presence of a substring in a
string. This is true for the class, instance and role filters as well.
When it comes to the window type we used WTYPE "NORMAL"
rather than
"_NET_WM_WINDOW_TYPE_NORMAL". The WTYPE
is just a short hand macro that adds
"_NET_WM_WINDOW_TYPE_" so either of the two can be used. Most windows are normal hence the
window type filter is primarily for special window types like "DESKTOP", "SPLASH", "DIALOG", etc.
If a filter is NULL
(or not set) then it does not apply.
You can generally ignore the transient
filter as it will default to 0 and thus the rule will only
apply to normal windows. By default client rules do not apply to transient windows,
but if you add a rule that has .transient = 1
then that rule will apply to transient windows and
transient windows only. If .transient = -1
is used then the rule applies to both normal and
transient windows. It is recommended to avoid specifying the workspace in client rules that
apply to transient windows because such windows are expected to show up on the same workspace as the
parent window.
Rules are checked in the order they are set in the clientrules
array.
If all filters of a rule matches that of the client window then the rule applies and values / attributes are set.
Only a single rule will match a client window (unless the client has the resume
flag set).
If a rule matches a client window then attributes of that rule will be set for the client.
The client rule can have the following attributes:
opacity
flags
floatpos
scratchkey
workspace
label
swallowedby
swallowkey
iconpath
alttitle
The first sets the opacity / transparency level of the client. For example .opacity = 0.80
would
make the window 80% opaque. This depends on a compositor that takes the _NET_WM_WINDOW_OPACITY
property of a window into account. Refer to the changeopacity function for more
details on this.
The flags
attribute allows a combination of flags to be set for the client.
E.g. .flags = Floating|Centered
would both make the window floating and placed in the center of
the screen. Refer to the Flags page for a list of flags that can be set for a client.
The floatpos
attribute defines the floating position for a floating window.
Refer to the floatpos function for options.
The scratchkey
attribute is only used in relation to associating a window with a specific
scratchpad. Refer to the Scratchpads topic for more information on that.
The workspace
attribute specifies which workspace the window is to start on and is matched based
on the workspace name. Refer to the wsrules configuration and the
Workspaces topic for more details.
The label
attribute specifies the label of the client which is used to decorate the workspace
icon in the bar if the WorkspaceLabels functionality is enabled.
The swallowedby
attribute is an experimental feature that aims to enable window swallowing for
special cases where the new process is not a descendant of the window launching the process (e.g.
like with a file manager like nautilus). Let's say that the file manager is used to open PDF files
which opens as new windows. Now if we want those windows to be swallowed by the file manager the
idea is that we would set a designated scratch key for the file manager client using client rules
(just setting a scratch key, this does not have to be a full scratchpad). Then we would have other
client rules to match on the PDF reader windows and we would set swallowedby
to be the same key
as set for the file manager. In principle when the PDF reader window opens it would match the
client rule and the window manager would find the file manager to be the window that should swallow
the PDF reader window.
The swallowkey
is in relation to the above and sets the a corresponding unique key / character
for the terminal client.
For both of the above refer to the workaround for file managers for an example use case.
The iconpath
attribute is an experimental feature that allows the user to specify the path to a
.png file that is to be used as the window icon instead of the icon that is provided by the window
itself (if any). The path needs to be 255 or less characters long in order for the icon not to be
lost when performing a restart of the window manager.
The alttitle
attributes allows for an alternate window title to be set for the client which will
be displayed instead of the normal window title if the AltWindowTitles functionality is enabled.
By default the first rule to match a window is the rule that applies for the client.
Optionally .resume = 1
can be added to a rule to allow for other rules that matches the window to
be applied as well.
Note that in the case that two rules matches the window then the outcome will be a combination of those two rules.
Attribute fields of the last rule will take precedence if they are set except for the flags
attribute which will result in a union of the two rules. What this means is that if the first rule
say that the client is floating then the second rule can't override that.
The practical use cases for this feature is very limited.
Back to Configuration.