This module depends on CLIM and SLIM, so please ensure they are somewhere that
they are somewhere that ASDF can find them. If you dont have a copy of CLIM
and SLIM, please evaluate (ql:quickload :clim)
and (ql:quickload :slim)
at
a repl before using this module.
It is highly recommended to run this module from a repl connected to the StumpWM image, but if you want to play it risky, add the following to your stumpwmrc.
(load-module "clim-mode-line")
(clim-mode-line:app-main)
This must occur before any mode lines are created.
If loading through a repl, eval the following forms.
(ql:quickload :clim)
(ql:quickload :slim)
(ql:quickload :clim-mode-line)
(clim-mode-line:app-main)
This mode line is very much a work in progress. Currently it displays groups and the windows of the current group, and allows you to move/focus windows and groups through click and dragging them.
While it would be a welcome addition, this mode line doesnt interpret the stumpwm mode line format list.
The equivalent of the mode line screen format from StumpWM is the mode line
format slot of the frame. This is interacted with via the functions
mode-line-format
and set-mode-line-format
. It should be a list of lists of
functions. Every function should be a formatter function, as described
below. By default this is bound to '((format-groups format-align-right
format-windows))
. All symbols reside in the clim-mode-line
package.
When writing a formatter for this mode line, you can use the whole gamut of CLIM formatting and drawing functionality. In addition to this, a set of macros are provided to ease the process of writing a formatter.
For defining a simple string formatter, the macro define-formatter
is
provided.
(define-formatter bar "|")
The above defines a function called format-bar
which formats |
to the
mode line.
A formatter function is function which takes a frame, pane, and list of
formatters following it. The formatter should format some stuff to the pane,
and then call the function call-next-formatter
with the list of following
formatters, the frame, and the pane. A simple example is the formatter
function format-align-right
. All of the logic of this formatter is wrapped
up in the macro with-right-alignment
, so the actual definition of this
function is:
(defun format-align-right (frame pane other-formatters)
(with-right-alignment (frame pane)
(call-next-formatter other-formatters frame pane)))
Lets take a look at a slightly more complicated formatter, one which makes
use of the function present
.
(defun format-groups (frame pane other-formatters)
(declare (ignorable frame))
(let ((current-group (stumpwm:current-group)))
(do-list-with-interspersed-element
(group (stumpwm::sort-groups (stumpwm:current-screen))
(format pane " "))
(with-stumpwm-highlighting (pane (eq current-group group))
(present group 'stumpwm::group :stream pane :single-box t))))
(call-next-formatter other-formatters frame pane))
The format-groups
function obtains the current group, and then uses the
macro do-list-with-interspersed-element
to loop over the sorted groups,
binding each group to group
. This macro intersperses (format pane " ")
with the body of the macro. This is important to avoid formatting " "
before the first element. So, for each group we use
with-stumpwm-highlighting
to, when the group is the current group, reverse
the background and foreground colors. The actual writing of the group to the
pane is handled by the present
presentation method for the stumpwm::group
type. Finally, we call call-next-formatter
to advance to the next formatter
in the list.
All formatters which format something to the pane must do so within the macro
with-cell
. This macro handles formatting within a table when relevant. All
with-stumpwm-*
macros eventually place all display within the with-cell
macro.
The logic of how to display something is handled by defining a present
method. These are needed in order to allow gestures to be active for the
presented object painlessly. For example, dragging a window onto a group with
the right pointer button moves the window to the group. In CLIM this is
called a translation, and it translates from a presentation to a command by
way of a gesture. The presentation method present
is generally simple, just
formatting some text to a stream. For example, the present
method for a
window is:
(define-presentation-method present
(window (type stumpwm::window) stream view &key)
(let ((str (string-trim '(#\space)
(stumpwm::format-expand stumpwm::*window-formatters*
stumpwm::*window-format*
window))))
(format stream "~A" str)))
This defines a presentation method, specifically the present
method, for a
window. The symbol window
is the object being presented, and stream
is
where it should be presented to.
Commands are written using the macro define-mode-line-command
. Much like
defun, this takes a name, an argument list, and a body. The name should begin
with com-
, followed by the name of the command. Each argument in the
argument list must be of the form (argument type)
, much like in
defmethod
.
Where it gets interesting is defining translators. A translator translates
from a presentation to a command. There are two types of translators used in
this application: presentation to command drag and drop translators. Each of
these take a gesture which is used to “activate” the translator. For example,
the command translator mode-line-switch-to-group
translates from a
stumpwm::group
presentation to the command com-switch-to-group
with the
gesture :left-click
. This is why the use of present
is so important, as
unless something is presented these translators wont be active.
The macro define-presentation-to-command-translator
takes a name, a list of
options, an argument list, and a body. The options must begin with the
from-type, followed by the command to translate to, followed by the command
table it is present in. For the clim mode line this command table is
mode-line
. Following that is a set of keyword arguments. The most relevant
to this document are :gesture
, :priority
, :documentation
, and
:menu
. :gesture
determines which gesture will trigger this translator,
:priority
determines what order translations should be sorted in,
:documentation
determines what is displayed when the operation menu is
brought up, and :menu
determines if an entry will show up in the operation
menu. The argument list is a list of symbols (typically one), and the body
must generate a list which the command can be applied to.
The macro define-drag-and-drop-translator
functions similarly, but also
takes a destination type, and must call the command in question explicitly.
Of note, if a gesture is used for both a presentation-to-command-translator and a drag-and-drop-translator then whichever has the highest priority will be active. It is unclear to me whether this is a limitation of clim or of my own understanding.
See the file commands-and-translators.lisp
for examples and more
information.
Herin lies a walkthrough and explanation of the various files present in this module.
This file contains general macros that dont make sense to define elsewhere. These include the clim-mode-line table formatting macros, ink inversion macros, alignment macros, and looping macros.
This file contains a simple patch to a mcclim function in the clim-clx package. This is needed to register the window created as a panel. Without it, the mode line would be created as a regular window.
This file contains the application frame definition and all glue functions. The display function lies here, alongside an update function, and the function to run the frame.
This file contains all presentation methods. Currently only group and window
presentation methods are present. The present
presentation methods are only
in charge of writing the appropriate text to the stream given. These methods
should not call any of the slim
table macros.
This file contains all formatter functions. These functions correspond, at least conceptually, to the mode line formatter functions of stumpwm, but take different arguments and operate in a different manner.
The format of the mode line is represented by a list, where each element is itself a list representing a row. Each of these row representing lists is a list of formatter functions. These functions draw text to cells.
When writing a formatter function, text is written to the mode line by
writing to the pane argument. All formats must occur within a slim:cell
.
Formatter functions may format plain text, or present an object. When
presenting an object the presentation method will format all text to the
pane, and the call to present
must be within a slim:cell
.
This file defines a set of gestures used to interact with the mode line. They are all pointer gestures, and all combinations of control, meta, and super are defined for both left and right pointer buttons. These gestures are used for translators. Translators translate a gesture to a command. For example, clicking on an object, or dragging an object onto another object.
Currently, this module is developed on a machine with one screen and one head, and as such multi head or multi screen setups are not explicitly supported. While supporting multi head setups is a goal, the main goal is getting the clim mode line to be on rough feature parity with the existing mode line.
Background colors are currently not supported very well.