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

Setup

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.

Rule matching

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).

Rule attributes

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.

Resume

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.

⚠️ **GitHub.com Fallback** ⚠️