Skip to content

Bar Modules

Bakkeby edited this page Feb 27, 2024 · 10 revisions

The content of the bar is controlled by individual modules that handles drawing of content and button clicks in isolation.

What this means is that the modules do not need to be concerned about other modules present on the bar.

This page outlines how bar modules work in general.

Modules

Here is a list of the modules that are available by default:

Module Description
workspaces Shows workspace icons on the bar
systray Positions the systray on the bar
ltsymbol Indicates the current layout used using symbols
flexwintitle Draws window titles on the bar
status Shows user defined content on the bar
wintitle_hidden Shows window titles for clients that are hidden
wintitle_floating Shows window titles for clients that are floating
powerline Adds powerline separators between bar modules

Refer to the individual pages above for more information about configuration options and what features they provide.

The engine

Prior to the bar being drawn the scheme for the bar is derived from the layout used by the active workspace.

This scheme is then used for the bar border (if enabled) as well as window title separators.

The bar rules are checked in the order they are defined in the barrules array in config.h.

static const BarRule barrules[] = {
	/* monitor bar scheme lpad rpad value alignment        sizefunc         drawfunc         clickfunc         hoverfunc         name */
	{ -1,      0,  0,     0,   5,   0,    BAR_ALIGN_LEFT,  size_workspaces, draw_workspaces, click_workspaces, hover_workspaces, "workspaces" },
	{ 'A',     0,  0,     5,   5,   0,    BAR_ALIGN_RIGHT, size_systray,    draw_systray,    click_systray,    NULL,             "systray" },
	...
};

If the bar index as well as the monitor matches that of the current bar then the rule applies.

Refer to the Bar Rules page for further setup details on this.

A bar argument will be passed to the functions (sizefunc, drawfunc, clickfunc, hoverfunc) that belong to the bar module and this argument will hold several values indicating where the module is to be drawn and how much space is available.

Here is the struct for said argument:

typedef struct {
	int x;
	int y;
	int h;
	int w;
	int lpad;
	int rpad;
	int value;
	int scheme;
} BarArg;

The x, y, h and w values determine the size and position of the bar module.

The left and right padding (lpad and rpad) are taken as-is from the bar rule. These determine the amount of space to between modules on either side.

The arbitrary value is taken as-is from the bar rule and provides module specific hints to the bar module. This is primarily used for the status module for status updates and status click handling.

If the rule specifies a colour scheme then that scheme is passed to the bar module as part of the argument. This scheme will be used for the bar module unless it manages colours on its own.

The bar modules engine keeps track of the space available on the bar to draw modules.

It makes a call to the size function which should return the space required to draw the module.


Most bar modules will return the minimum space required to draw the module, but functions that draw window titles tend to claim all the available space hence such modules are defined last in the rules array.


The engine will then check the alignment part of the bar rule which determines where on the bar the module is placed.

Refer to the alignment section of the bar rules page for a description of the various options.

If a module is to be centered within the available space then the bar is split into two:

  • the remaining space on the left of the center module and
  • the remaining space on the right of the center module

Note that this will occur only once. If a bar module is centered again on the remaining space on the right hand side of the center module then the space on the right of the module will be lost indefinitely.

If you find yourself in a situation like this then consider splitting the bar into multiple bars instead.


When the final position of the bar module has been determined the bar argument is passed in a call to the draw function of the module. This should return a positive value if something was drawn and 0 otherwise.

If nothing was drawn on the bar after going through all the rules then the bar will be hidden automatically.

Likewise if something was drawn and the bar was hidden then it will be shown.

The exact position and size of each bar module is recorded for the bar as these are later used when handling mouse clicks on the bar which are handled separately in the barpress function.

This will loop through the bar rules that apply to the bar and use the stored positions of each bar module to determine which of the modules the clicked.

If the module has a click function then this will be called and the function can perform its own calculations as and if needed, e.g. to work out which of the window titles were clicked on.

The click function is expected to return a value from the click enum (e.g. ClkLtSymbol) allowing for button bindings to evaluate bespoke user defined actions.

Below there is more information about the different module functions should you want to implement your own. You may also want to refer to existing implementations if anything is unclear.

sizefunc

Signature:

static int size_<module>(Bar *bar, BarArg *a);

The function is expected to return an integer value representing the amount of pixels needed to draw the module.

The bar argument a->w will represent the maximum space available for the module. This value is the available space less the left and right padding for the bar rule which means that the bar module does not need to take padding into account when giving its size requirements.

drawfunc

Signature:

static int draw_<module>(Bar *bar, BarArg *a);

The function is expected to draw the module and to return an integer value representing the amount of pixels that were drawn (or at a minimum a positive value to indicate that something was drawn).

The bar arguments of a->x, a->y, a->w and a->h determine the position where the module is to be drawn and the size. If the module draws content beyond this size then it will bleed into other modules.

The module does not have to take a->lpad and a->rpad into account because these are have already been accounted for in the size and position values above. The padding values are still there for reference should the module need this information.

Unless the module manages colours on its own then it is expected that it uses the colour scheme as indicated by a->scheme by default.

The module has no obligation to take the a->value parameter into account, but it can use this to elicit varying behaviour across module instances. The value is arbitrary and its interpretation is entirely module specific.

clickfunc

Signature:

static int click_<module>(Bar *bar, Arg *arg, BarArg *a);

This function is optional and can be NULL in the bar rules configuration.

The click function does not know which button was clicked and as such can not differentiate between a left click and a right click for example. This is intentional and by design.

The reason for this is that the intention of the click function is merely to indicate what was clicked and leave the actionable bit to button bindings.

As such the function is expected to return one of the click enum values in dusk.c (search for ClkLtSymbol). A new click enum value can be added if needed, e.g. ClkNameOfModule.

The arg reference will be passed to the function called if there is a button binding that matches both the mouse click and the click type returned by the click function. This is true as long as the button binding itself does not explicitly pass in an argument.

This means that the click function can set the arg value to something that the function for the button binding will take into account.

For example the wintitle modules will set arg->v to be a reference to the client of which the window title was clicked. Another example would be the workspace module setting arg->v to be a reference to the workspace that was clicked.

Also refer to the Button Bindings page.

hoverfunc

Signature:

static int hover_<module>(Bar *bar, BarArg *a, XMotionEvent *ev);

This function is optional and can be NULL in the bar rules configuration.

The a->x and a->y coordinates refer to the mouse position relative to the bar module.

The XMotionEvent ev->x and ev->y coordinates are relative to the bar window. To get absolute mouse pointer coordinates take bar->bx and bar->by into account as well.

This function will be triggered if a user hovers the mouse over the given module.

For an example implementation refer to the WorkspacePreview functionality.


Back to Bar.

Clone this wiki locally