UI
Currently, penrose offers a single piece of built in UI via the penrose_ui crate:
a status bar. The bar is inspired by the dwm
status bar and provides a simple API
for writing your own text based widgets for rendering to the screen.
In addition to the widgets described below there are a couple of debugging based widgets which are useful when trying to diagnose issues with the window manager state but probably not something you want on your screen all the time. If you are interested in taking a look at them they can be found here
The Text widget
For building up simple widgets there is the Text widget which can be used to provide most of the layout and re-render logic with an easy to use API. Any time the contents of the widget are modified it will be re-rendered to the bar. On its own this isn't particularly useful but you can add hooks to set the content in response to changes in the window manager state (which we'll take a look at in the next section).
Text widgets are left justified by default but this can be switched to right justified if
desired. There is also the ability to specify that the widget is greedy
which will cause
it to take up any available left over space once all other widgets have finished laying
out their contents. Personally I use this with the ActiveWindowName
widget to take up
the middle of the status bar and act as a sort of active screen indicator .
The RefreshText widget
If you want to render something that doesn't depend on the internal state of the window
manager (such as the current time, volume, connected wifi network etc) then you can set up
a very minimal widget quickly using RefreshText
. All you need is a function that returns
the string to be rendered when it is called and the styling you'd like to use when rendering.
From that you get a widget that will check if it needs to re-render every time the internal
window manager state is refreshed and re-render any time the output of your function changes.
The sys
module has a number of simple widgets of this nature that you can use as a reference
to get you started. For example, this is all you need to display the current date and time:
#![allow(unused)] fn main() { use penrose::util::spawn_for_output_with_args; use penrose_ui::bar::widgets::{RefreshText, TextStyle}; pub fn current_date_and_time(style: &TextStyle) -> RefreshText { RefreshText::new(style, || { spawn_for_output_with_args("date", &["+%F %R"]) .unwrap_or_default() .trim() .to_string() }) } }
Built in widgets
Workspaces
The Workspaces widget is the most complicated built in widget on offer. It checks the currently available workspaces and several properties about each one:
- The tag assigned to the workspace
- Whether or not the workspace is focused (and on what screen)
- If there are any windows visible on the workspace
From that it will generate a workspace listing with highlighting to indicate the current state of your window manager. Workspaces with windows present are assigned a different foreground color and focused workspaces are assigned a different background color. The active workspace is indicated with its own highlight for visibility as well.
RootWindowName
The RootWindowName widget is an idea lifted directly from dwm: any time the root window name is updated it will re-render with its content set to the new name. The xsetroot tool can be used to set the root window name to whatever string you like and typically this is used by spawning a shell script that updates the root window name with system stats on an interval:
# Set the root window name to the current date and time
$ xsetroot -name "$(date '+%F %R')"
ActiveWindowName
In a similar way, ActiveWindowName will display the title of the currently focused
window. Given that there is less control over what the contents of this string will be,
this widget allows you to set a maximum character count after which the title is
truncated to ...
.
This widget will also only render on the active screen so it works well as a visual indicator of which screen currently has focus.
CurrentLayout
The CurrentLayout widget simply calls the layout_name
method on the active workspace
each time the internal state is refreshed. Each Layout
is free to specify whatever name it
choses so if you want to customise the text displayed by this widget you will need to write a
LayoutTransformer
that intercepts the inner name and maps it to your preferred string
instead (or write a new widget that bakes that behaviour into the widget itself).