mirror of
https://github.com/stumpwm/stumpwm.git
synced 2026-09-10 07:26:20 -04:00
3706 lines
114 KiB
Plaintext
3706 lines
114 KiB
Plaintext
\input texinfo @c -*-texinfo-*-
|
|
@c %**start of header
|
|
@setfilename stumpwm.info
|
|
@settitle StumpWM Manual
|
|
@setchapternewpage odd
|
|
@c %**end of header
|
|
|
|
@dircategory X11
|
|
@direntry
|
|
* StumpWM: (stumpwm). A Common Lisp window manager
|
|
@end direntry
|
|
|
|
@ifinfo
|
|
This is the Stump Window Manager user manual.
|
|
|
|
Copyright @copyright{} 2000-2008 Shawn Betts
|
|
Copyright @copyright{} 2014 David Bjergaard
|
|
|
|
Permission is granted to make and distribute verbatim
|
|
copies of this manual provided the copyright notice and
|
|
this permission notice are preserved on all copies.
|
|
|
|
@ignore
|
|
Permission is granted to process this file through TeX
|
|
and print the results, provided the printed document
|
|
carries a copying permission notice identical to this
|
|
one except for the removal of this paragraph (this
|
|
paragraph not being relevant to the printed manual).
|
|
|
|
@end ignore
|
|
Permission is granted to copy and distribute modified
|
|
versions of this manual under the conditions for
|
|
verbatim copying, provided also that the sections
|
|
entitled ``Copying'' and ``GNU General Public License''
|
|
are included exactly as in the original, and provided
|
|
that the entire resulting derived work is distributed
|
|
under the terms of a permission notice identical to this
|
|
one.
|
|
|
|
Permission is granted to copy and distribute
|
|
translations of this manual into another language,
|
|
under the above conditions for modified versions,
|
|
except that this permission notice may be stated in a
|
|
translation approved by the Free Software Foundation.
|
|
@end ifinfo
|
|
|
|
@iftex
|
|
@kbdinputstyle code
|
|
@end iftex
|
|
|
|
@titlepage
|
|
@sp 10
|
|
@titlefont{The Stump Window Manager}
|
|
@author Shawn Betts, David Bjergaard
|
|
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
Copyright @copyright{} 2000-2008 Shawn Betts
|
|
Copyright @copyright{} 2014 David Bjergaard
|
|
|
|
Permission is granted to make and distribute verbatim
|
|
copies of this manual provided the copyright notice and
|
|
this permission notice are preserved on all copies.
|
|
|
|
Permission is granted to copy and distribute modified
|
|
versions of this manual under the conditions for
|
|
verbatim copying, provided also that the sections
|
|
entitled ``Copying'' and ``GNU General Public License''
|
|
are included exactly as in the original, and provided
|
|
that the entire resulting derived work is distributed
|
|
under the terms of a permission notice identical to this
|
|
one.
|
|
|
|
Permission is granted to copy and distribute
|
|
translations of this manual into another language,
|
|
under the above conditions for modified versions,
|
|
except that this permission notice may be stated in a
|
|
translation approved by the Free Software Foundation.
|
|
@end titlepage
|
|
|
|
@contents
|
|
|
|
@node Top, Introduction, (dir), (dir)
|
|
|
|
@ifinfo
|
|
This document explains how to use The Stump Window Manager.
|
|
@end ifinfo
|
|
|
|
@menu
|
|
* Introduction::
|
|
* Key Bindings::
|
|
* Commands::
|
|
* Message and Input Bar::
|
|
* Windows::
|
|
* Frames::
|
|
* Mode-line::
|
|
* Groups::
|
|
* Screens::
|
|
* Minor Modes::
|
|
* Internals::
|
|
* Interacting With Unix::
|
|
* Interacting With X11::
|
|
* Miscellaneous Commands::
|
|
* Colors::
|
|
* Hooks::
|
|
* Modules::
|
|
* Hacking::
|
|
* Advanced Configuration::
|
|
* Command and Function Index::
|
|
* Variable Index::
|
|
|
|
@detailmenu
|
|
--- The Detailed Node Listing ---
|
|
|
|
Introduction
|
|
|
|
* Starting StumpWM::
|
|
* Basic Usage::
|
|
* Basic Concepts::
|
|
* Manipulating Frames and Windows::
|
|
* Interacting with the Lisp process::
|
|
* Init File::
|
|
* Contact the StumpWM developers::
|
|
|
|
Basic Concepts
|
|
|
|
* Screens and Heads::
|
|
* Group Basics::
|
|
* Floating Group Basics::
|
|
* Dynamic Group Basics::
|
|
* Frame Basics::
|
|
* Window Basics::
|
|
* System Trays and the Mode Line::
|
|
|
|
Manipulating Frames and Windows
|
|
|
|
* Moving Between Frames::
|
|
* Manipulating Windows::
|
|
|
|
Key Bindings
|
|
|
|
* List of Default Keybindings::
|
|
* Binding Keys::
|
|
* Modifiers::
|
|
* Remapped Keys::
|
|
|
|
Commands
|
|
|
|
* Writing Commands::
|
|
* StumpWM Types::
|
|
|
|
Message and Input Bar
|
|
|
|
* Customizing The Bar::
|
|
* Using The Input Bar::
|
|
* Programming The Message Bar::
|
|
* Programming the Input Bar::
|
|
|
|
Windows
|
|
|
|
* Window Marks::
|
|
* Customizing Window Appearance::
|
|
* Controlling Raise And Map Requests::
|
|
* Programming With Windows::
|
|
* Rule Based Window Placement::
|
|
* Window Selection Expressions::
|
|
|
|
Frames
|
|
|
|
* Interactively Resizing Frames::
|
|
* Frame Dumping::
|
|
|
|
Groups
|
|
|
|
* Customizing Groups::
|
|
|
|
Screens
|
|
|
|
* External Monitors::
|
|
* Programming With Screens::
|
|
|
|
Minor Modes
|
|
|
|
* Minor Mode Example::
|
|
* Programming With Minor Modes::
|
|
|
|
Internals
|
|
|
|
* IO Loop::
|
|
|
|
Miscellaneous Commands
|
|
|
|
* Menus::
|
|
* StumpWM's Data Directory::
|
|
* Debugging StumpWM::
|
|
* Sending a Bug Report::
|
|
* Timers::
|
|
* Getting Help::
|
|
|
|
Colors
|
|
|
|
* Behind The Scenes Look At Colors::
|
|
|
|
Modules
|
|
* Writing Modules::
|
|
|
|
Hacking
|
|
|
|
* General Advice::
|
|
* Adding Documentation and Editing This Manual::
|
|
* Using git with StumpWM::
|
|
* Sending Patches::
|
|
|
|
@end detailmenu
|
|
@end menu
|
|
|
|
@node Introduction, Key Bindings, Top, Top
|
|
@chapter Introduction
|
|
StumpWM is a manual, tiling X11 window manager written entirely in
|
|
Common Lisp. Unlike traditional window managers, StumpWM places
|
|
windows in order to maximize the amount of the screen used. The
|
|
window layouts managed by StumpWM are defined by the user in much the
|
|
same way that windows are managed by GNU screen, or emacs.
|
|
|
|
Before StumpWM, there was ratpoison, another tiling window manager
|
|
written entirely in C. StumpWM grew out of the authors' frustration
|
|
with writing ratpoison in C. Very quickly we realized we were building
|
|
into ratpoison lispy-emacs style paradigms. StumpWM's goals are
|
|
similar to ratpoison's but with an emphasis on customizability,
|
|
completeness, and cushiness.
|
|
|
|
@menu
|
|
* Starting StumpWM::
|
|
* Basic Usage::
|
|
* Basic Concepts::
|
|
* Manipulating Frames and Windows::
|
|
* Interacting with the Lisp process::
|
|
* Init File::
|
|
* Contact the StumpWM developers::
|
|
@end menu
|
|
|
|
@node Starting StumpWM, Basic Usage, Introduction, Introduction
|
|
@section Starting StumpWM
|
|
There are a number of ways to start StumpWM but the most straight
|
|
forward method is as follows. This assumes you have a copy of the
|
|
StumpWM source code and are using the @samp{SBCL} Common Lisp
|
|
environment.
|
|
|
|
@enumerate
|
|
@item
|
|
Install the prerequisites and build StumpWM as described in
|
|
@file{README}. This should give you a @file{stumpwm} executable.
|
|
|
|
@item
|
|
In your @file{~/.xinitrc} file include the line
|
|
@command{/path/to/stumpwm}. Remember to replace @samp{/path/to/}
|
|
with the actual path.
|
|
|
|
@item
|
|
Finally, start X windows with @command{startx}. Cross your
|
|
fingers. You should see a @samp{Welcome To the Stump Window Manager}
|
|
message pop up in the upper, right corner. At this point, you have
|
|
successfully started StumpWM.
|
|
@end enumerate
|
|
|
|
@@@ stumpwm
|
|
|
|
@node Basic Usage, Basic Concepts, Starting StumpWM, Introduction
|
|
@section Basic Usage
|
|
Once you have StumpWM up and running, the first thing you might want
|
|
to do is start @command{emacs}. Type @kbd{C-t e}, or in other words
|
|
@kbd{Control + t} followed by @kbd{e}. Now perhaps you want an
|
|
@command{xterm}. Type @kbd{C-t c}. Now you have some programs running.
|
|
|
|
To see a list of windows StumpWM is managing, type @kbd{C-t w}. The
|
|
highlighted window is the one you're looking at right now. It's the
|
|
focused window.
|
|
|
|
All of StumpWM's keys are bound to named commands, which can be
|
|
executed not only by keys but also from the input bar. Type @kbd{C-t
|
|
;} to open a command prompt. Now type @command{time} and press
|
|
return. Note, @command{time} can also be called by typing @kbd{C-t a}.
|
|
Throughout this manual you'll find definitions for commands,
|
|
functions, and variables. Any command you see in this manual can be
|
|
executed from the input bar or bound to a key.
|
|
|
|
At this point you probably want to switch back from your new
|
|
@command{xterm} to @command{emacs}. Type @kbd{C-t C-t}. This runs the
|
|
@command{other} command. Type it again and you're back to xterm.
|
|
|
|
Perhaps you'd like to see @command{emacs} and @command{xterm}
|
|
side-by-side. Type @kbd{C-t s}. You have now split the screen into 2
|
|
@command{frames}. For more information see @ref{Frames}. To switch to the
|
|
empty frame type @kbd{C-t TAB}. Now let's pull the xterm window into
|
|
this empty frame. Type @kbd{C-t w} for a window listing. Find the
|
|
@command{xterm} window. See the number beside it? Type @kbd{C-t} followed
|
|
by @command{xterm}'s window number.
|
|
|
|
Another common activity is browsing the internet. Type @kbd{C-t !}.
|
|
The input bar pops up again. You can now run a shell command. Let's
|
|
start a web browser: type @command{firefox} into the input bar and press
|
|
return.
|
|
|
|
Unfortunately, @command{firefox} probably isn't wide enough because it's
|
|
in one of the frames. Type @kbd{C-t Q} to remove all frames but the
|
|
current one and resize it to fit the screen.
|
|
|
|
For a full list of key bindings, see @ref{List of Default Keybindings}.
|
|
|
|
@node Basic Concepts, Manipulating Frames and Windows, Basic Usage, Introduction
|
|
@section Basic Concepts
|
|
|
|
An introduction to some of the basic concepts used by StumpWM.
|
|
|
|
@menu
|
|
* Screens and Heads::
|
|
* Group Basics::
|
|
* Floating Group Basics::
|
|
* Dynamic Group Basics::
|
|
* Frame Basics::
|
|
* Window Basics::
|
|
* System Trays and the Mode Line::
|
|
@end menu
|
|
|
|
@node Screens and Heads, Group Basics, Basic Concepts, Basic Concepts
|
|
@subsection Screens and Heads
|
|
A screen is an Xlib concept representing a section of video memory
|
|
onto which physical monitors, called ``heads'', are mapped. A screen can
|
|
be thought of as an abstract rectangle containing all the heads
|
|
arranged in a particular layout.
|
|
|
|
With most modern systems, you'll only have a single screen no matter
|
|
how many heads are connected to your computer. Each head will have its
|
|
own frame, and you can move between heads using the normal frame
|
|
movement commands.
|
|
|
|
The layout of the heads within the screen can be specified in one of two
|
|
ways: either at startup using your system's Xorg configuration files, or
|
|
on the fly using tools like XRandR. If the computer is booted with
|
|
multiple monitors attached, but without specifying a layout for them,
|
|
they will all show identical output.
|
|
|
|
StumpWM will attempt to detect the layout of the heads once at
|
|
startup, or any time a RandR command is issued.
|
|
|
|
In rarer setups you may have multiple screens, with one head per
|
|
screen. That means that you'll move between heads using screen
|
|
movement commands (`snext', `sprev', and `sother') rather than frame
|
|
movement commands.
|
|
|
|
@node Group Basics, Floating Group Basics, Screens and Heads, Basic Concepts
|
|
@subsection Group Basics
|
|
A group is usually referred to as a ``desktop'' or ``workspace'' in other
|
|
window managers. StumpWM starts with a single group, called ``Default''.
|
|
Each group has its own configuration of frames and windows that is
|
|
separate from and independent of other groups. You can't have
|
|
different groups display in different monitors: when you switch
|
|
groups, all monitors switch to that group.
|
|
|
|
Each group contains an ordered list of frames.
|
|
|
|
@node Floating Group Basics, Dynamic Group Basics, Group Basics, Basic Concepts
|
|
@subsection Floating Group Basics
|
|
Within a floating group, windows behave more like they do in traditional
|
|
window managers: rather than being arranged into frames, they each have
|
|
their own box, which can be freely resized and repositioned, and allowed
|
|
to overlap. Each window has a thicker border at the top. Left click in
|
|
this border and drag to move the window, or right click and drag to
|
|
resize it.
|
|
|
|
A modifier key can be used to perform the move and resize operations
|
|
by clicking in the window itself instead of on its top border. The
|
|
default modifier is super, and can be configured with
|
|
@var{*float-window-modifier*}.
|
|
|
|
### *float-window-modifier*
|
|
|
|
Most of the window-switching commands listed below do not function in
|
|
a floating group. You're restricted to `other', the `select-window-*'
|
|
commands, and `windowlist'.
|
|
|
|
|
|
@node Dynamic Group Basics, Frame Basics, Floating Group Basics, Basic Concepts
|
|
@subsection Dynamic Group Basics
|
|
Within a dynamic group, windows are organized into a @dfn{master window} and a
|
|
@dfn{window stack}, with one of each per head. When a new window is added to a
|
|
head within a dynamic group, that heads master window is pushed onto that heads
|
|
window stack, and the new window becomes the master window. When a head becomes
|
|
to full (ie more windows cannot be placed upon the stack) a overflow policy is
|
|
used to determine which window to move to a separate head or group.
|
|
|
|
!!! gnew-dynamic
|
|
|
|
!!! gnewbg-dynamic
|
|
|
|
!!! rotate-windows
|
|
|
|
!!! change-layout
|
|
|
|
!!! change-default-layout
|
|
|
|
!!! change-split-ratio
|
|
|
|
!!! change-default-split-ratio
|
|
|
|
!!! retile
|
|
|
|
!!! select-floating-window
|
|
|
|
### *rotation-focus-policy*
|
|
|
|
When defining commands, anything restricted to tiling groups will also be
|
|
active in dynamic groups. To fully restrict it to tiling groups, call the
|
|
function dyn-blacklist-command on the command in question.
|
|
|
|
The head placement policy, overflow policy, master layout, and default
|
|
split ratio of dynamic groups are special in that they can only be
|
|
modified once a dynamic group object has been instantiated. To change
|
|
their initial values the function @code{set-dynamic-group-initial-values}
|
|
can be used to modify these values before instantiating a dynamic group,
|
|
but not after.
|
|
|
|
@menu
|
|
* Dynamic Group Index::
|
|
@end menu
|
|
|
|
@node Dynamic Group Index, Frame Basics, Dynamic Group Basics, Dynamic Group Basics
|
|
@subsection Dynamic Group Index
|
|
Index of exported variables, commands, and functions defined in the
|
|
dynamic group file.
|
|
|
|
### *rotation-focus-policy*
|
|
|
|
@@@ set-dynamic-group-initial-values
|
|
|
|
@@@ dynamic-group-p
|
|
|
|
@@@ dynamic-group-master-layout
|
|
|
|
@@@ dynamic-group-head-layout
|
|
|
|
@@@ dynamic-group-default-split-ratio
|
|
|
|
@@@ dynamic-group-head-split-ratio
|
|
|
|
@@@ dynamic-group-overflow-policy
|
|
|
|
@@@ dynamic-group-head-placement-policy
|
|
|
|
@@@ dyn-blacklist-command
|
|
|
|
@@@ dyn-unblacklist-command
|
|
|
|
!!! gnew-dynamic
|
|
|
|
!!! gnewbg-dynamic
|
|
|
|
!!! rotate-windows
|
|
|
|
!!! rotate-stack
|
|
|
|
!!! swap-windows
|
|
|
|
!!! change-layout
|
|
|
|
!!! change-default-layout
|
|
|
|
!!! change-split-ratio
|
|
|
|
!!! change-default-split-ratio
|
|
|
|
!!! retile
|
|
|
|
!!! select-floating-window
|
|
|
|
!!! exchange-window-with-master
|
|
|
|
!!! hnext
|
|
|
|
!!! hprev
|
|
|
|
!!! fnext-in-head
|
|
|
|
!!! fprev-in-head
|
|
|
|
@node Frame Basics, Window Basics, Dynamic Group Basics, Basic Concepts
|
|
@subsection Frame Basics
|
|
Frames are the boxes within which windows are displayed. StumpWM
|
|
starts with a single frame per head, meaning that each monitor shows a
|
|
single window, full screen. If you want to see windows side-by-side,
|
|
you can ``split'' this frame in two, either vertically or horizontally.
|
|
These frames can be further split, creating nested boxes.
|
|
|
|
Technically speaking, frames live within a ``frame tree''. When you
|
|
split a frame, the command actually creates @emph{two} new frames
|
|
side-by-side within the original parent frame. This has implications for
|
|
the behaviour of many commands that interact with frames.
|
|
|
|
Within this frame tree model, all frames either contain other frames,
|
|
or contain windows, or are empty. The command `fclear' will hide all of a
|
|
frame's windows and show the background.
|
|
|
|
@node Window Basics, System Trays and the Mode Line, Frame Basics, Basic Concepts
|
|
@subsection Window Basics
|
|
Windows are created by programs to display their output. They take the
|
|
shape of the frame in which they are created. The windows within a
|
|
frame are ordered by how recently that window was focused. Only the
|
|
top window in the stack is visible.
|
|
|
|
@node System Trays and the Mode Line, , Window Basics, Basic Concepts
|
|
@subsection System Trays and the Mode Line
|
|
Many users choose to sacrifice a little screen real-estate to display
|
|
some generally useful information: the current time and date, wireless
|
|
network connections, the names of open windows, etc. StumpWM allows
|
|
you to display this information in a bar across either the top or the
|
|
bottom of the screen. There are two ways to do this: using external
|
|
programs called system trays, or using StumpWM's own mode line.
|
|
|
|
System trays are a special kind of X window. They advertise to running
|
|
programs that they are available for embedding icons or notifications
|
|
from those programs. They often also display clickable icons for each
|
|
open window. Common tray programs include the GNOME panel or KDE's
|
|
kicker, or simpler programs such as stalonetray. Simply starting one
|
|
of these programs is usually enough for StumpWM to detect it, place it
|
|
correctly, and allow it to function normally.
|
|
|
|
The mode line, a concept borrowed from Emacs, is a built-in part of
|
|
StumpWM. It is essentially a string of text that can include a variety
|
|
of information about your current session, including the names of
|
|
current groups and windows. Several modules provide for
|
|
different types of information. @xref{Mode-line, Mode Line}, (and the modules
|
|
directory) for more.
|
|
|
|
@node Manipulating Frames and Windows, Interacting with the Lisp process, Basic Concepts, Introduction
|
|
@section Manipulating Frames and Windows
|
|
Frames and windows are concepts borrowed from Emacs and the GNU Screen
|
|
program, and should be familiar to users of those programs. Others may
|
|
find the terms a little confusing. In other window managers, a
|
|
``window'' usually refers to a bounded box on the screen, showing output
|
|
from a single program. StumpWM splits this into two concepts: the
|
|
``frame'' is the bounded box, the ``window'' is the visible output of a
|
|
program.
|
|
|
|
One frame can contain many windows. As new windows are created, they
|
|
appear at the top of the window-stack of the current frame. This is
|
|
also a little different from other tiling window managers, many of
|
|
which automatically create new frames for new windows.
|
|
|
|
Both frames and windows are ordered by when they were last focused. In
|
|
the following commands and documentation, the terms ``next'' and
|
|
``previous'' refer to this order. ``Other'' refers to the most-recently
|
|
focused object. Calling ``other'' commands multiple times will bounce
|
|
back and forth between the two most recent objects.
|
|
|
|
By default, StumpWM starts with a single group, called ``Default'',
|
|
which contains one full-screen frame per head. You can split individual
|
|
frames horizontally or vertically using the `hsplit' and `vsplit'
|
|
commands, bound to ``C-t S'' and ``C-t s'' by default. When a frame is
|
|
split, the next-most-recently-focused window is pulled into the new
|
|
frame. @xref{Frames}, and @ref{Windows}, for a complete listing of
|
|
commands.
|
|
|
|
|
|
@menu
|
|
* Moving Between Frames::
|
|
* Manipulating Windows::
|
|
@end menu
|
|
|
|
@node Moving Between Frames, Manipulating Windows, Manipulating Frames and Windows, Manipulating Frames and Windows
|
|
@subsection Moving Between Frames
|
|
Once you have multiple frames, you can move between them in various
|
|
ways:
|
|
|
|
@itemize
|
|
@item
|
|
@command{fnext} (@kbd{C-t o} or @kbd{C-t TAB}) jumps to the next frame in
|
|
the current group's frame list.
|
|
|
|
@item
|
|
@command{fother} (@kbd{C-t M-TAB}) jumps to the last frame that had
|
|
focus.
|
|
|
|
@item
|
|
@command{fselect} (@kbd{C-t f}) displays numbers on each visible frame: hit a
|
|
number key or click it to move to that frame.
|
|
|
|
@item
|
|
@command{move-focus} (@kbd{C-t <arrow key>}) focus the frame in the direction of
|
|
the arrow key pressed.
|
|
|
|
@item
|
|
@command{sibling} (unbound by default) focus the frame from which the
|
|
current frame was split.
|
|
|
|
@end itemize
|
|
|
|
@node Manipulating Windows, , Moving Between Frames, Manipulating Frames and Windows
|
|
@subsection Manipulating Windows
|
|
|
|
Some commands change which window is currently focused, some move
|
|
windows between frames, and some may do both at once.
|
|
|
|
There are two general ways to move focus between windows: either
|
|
between windows belonging to the current frame, or between all windows
|
|
within the current group. Within a single frame:
|
|
|
|
@itemize
|
|
@item
|
|
@command{next-in-frame} (@kbd{C-t C-M-n}) focus the next window in the current
|
|
frame's list of windows.
|
|
|
|
@item
|
|
@command{prev-in-frame} (@kbd{C-t C-M-p}) focus the previous window in the
|
|
current frame's list of windows.
|
|
|
|
@item
|
|
@command{other-in-frame} (@kbd{C-t M-t}) focus the most recently focused window
|
|
in the current frame's list of windows.
|
|
|
|
@item
|
|
@command{frame-windowlist} (unbound by default) display a menu of windows in
|
|
the currently-focused frame, and allow the user to choose one.
|
|
Alternately, the command @command{frame-windows} will simply display the
|
|
list of window names, with no menu choice available.
|
|
|
|
@end itemize
|
|
|
|
Within the current group, the following commands will go straight to
|
|
the specified window. They will never move a window from its original
|
|
frame, and so may result in focus switching frames.
|
|
|
|
@itemize
|
|
@item
|
|
@command{next} (@kbd{C-t M-n}) focus the next window in the current group.
|
|
|
|
@item
|
|
@command{prev} (@kbd{C-t M-p}) focus the previous window in the current group.
|
|
|
|
@item
|
|
@command{other} or @command{other-window} (unbound by default) focus the
|
|
most recently focused window in the current group.
|
|
|
|
@item
|
|
@command{next-urgent} (@kbd{C-t C-u}) focus the next window that has marked
|
|
itself ``urgent''.
|
|
|
|
@item
|
|
@command{select} or @command{select-window} (@kbd{C-t '}) prompt for the
|
|
title of a window and focus it. Works with partial completion of the
|
|
title.
|
|
|
|
@item
|
|
@command{select-window-by-name} (unbound by default) prompt for the
|
|
title of a window and focus it. Requires the window title to be entered
|
|
exactly.
|
|
|
|
@item
|
|
@command{select-window-by-number} (@kbd{C-t <number>}) choose a window by
|
|
number.
|
|
|
|
@item
|
|
@command{windowlist} (@kbd{C-t "}) display a menu of windows in the
|
|
currently-focused group, and allow the user to choose one.
|
|
|
|
@end itemize
|
|
|
|
The following commands always keep the current frame focused. If the
|
|
selected window is not in the current frame, it will be pulled there
|
|
from wherever it is (hence the ``pull'' naming scheme).
|
|
|
|
@itemize
|
|
@item
|
|
@command{pull} or @command{pull-window-by-number} (@kbd{C-t C-<number>})
|
|
pull the numbered window into the current frame.
|
|
|
|
@item
|
|
@command{pull-hidden-next} (@kbd{C-t n} or @kbd{C-t SPC}) pull the next
|
|
currently undisplayed window in the window list into the current frame.
|
|
|
|
@item
|
|
@command{pull-hidden-previous} (@kbd{C-t p}) pull the previous currently
|
|
undisplayed window in the window list into the current frame.
|
|
|
|
@item
|
|
@command{pull-hidden-other} (@kbd{C-t C-t}) pull the most recently
|
|
focused, currently undisplayed window into the current frame.
|
|
|
|
@end itemize
|
|
|
|
The following commands move the current window from one frame to
|
|
another, bringing focus with them.
|
|
|
|
@itemize
|
|
@item
|
|
@command{move-window} (@kbd{C-t M-<arrow>}) move the currently focused
|
|
window in the direction indicated by the arrow key.
|
|
|
|
@item
|
|
@command{exchange-direction} (unbound by default) prompt for a
|
|
direction, then swap the currently focused window with the top window of
|
|
the frame in that direction.
|
|
|
|
@end itemize
|
|
|
|
@node Interacting with the Lisp process, Init File, Manipulating Frames and Windows, Introduction
|
|
@section Interacting with the Lisp process
|
|
|
|
Since StumpWM is a Lisp program, there is a way for you to evaluate
|
|
Lisp code directly, on the same Lisp process that StumpWM is running on.
|
|
Type @kbd{C-t :} and an input box will appear. Then type some Lisp
|
|
expression.
|
|
|
|
When you call @command{eval} this way, you will be in the STUMPWM-USER
|
|
package, which imports all the exported symbols from the main STUMPWM
|
|
package.
|
|
|
|
@table @code
|
|
@item *mode-line-border-width*
|
|
Reads the value of @var{*mode-line-border-width*}.
|
|
|
|
@item (setf *mode-line-border-width* 3)
|
|
Sets the variable @var{*mode-line-border-width*} to 3.
|
|
|
|
@item (set-prefix-key (kbd "C-M-H-s-z"))
|
|
Calls the @code{set-prefix-key} function (and sets a new keyboard prefix)
|
|
@end table
|
|
|
|
@node Init File, Contact the StumpWM developers, Interacting with the Lisp process, Introduction
|
|
@section Init File
|
|
|
|
Like other window managers, StumpWM's configuration and startup
|
|
state can be controlled by an initialization file. Unlike other
|
|
window managers, StumpWM's init is not limited to changing settings
|
|
and keybindings. The init file is itself a Common Lisp program
|
|
running in a Common Lisp environment, so you can write your own
|
|
hacks and make them a part of your StumpWM experience.
|
|
|
|
On launch, StumpWM searches for an init file of different names and
|
|
locations on your system, and will use the first one found in this
|
|
order:
|
|
|
|
@itemize
|
|
@item `~/.stumpwmrc' is the classic UNIX-style configuration name;
|
|
|
|
@item `~/.stumpwm.d/init.lisp' is an Emacs-style location and name;
|
|
|
|
@item `~/.config/stumpwm/config' is the XDG standard;
|
|
|
|
@item `/etc/stumpwmrc' is a system-wide file giving all users a
|
|
standardized environment.
|
|
@end itemize
|
|
|
|
StumpWM includes a basic `sample-stumpwmrc.lisp' in its source
|
|
directory. You can use this as a template when you're starting out:
|
|
copy it to the above name and location you prefer and edit it to
|
|
suit your preferences.
|
|
|
|
It is possible to split your initialization among multiple files,
|
|
if you call the additional files from within an init file matching
|
|
the names and locations listed above.
|
|
|
|
### *processing-existing-windows*
|
|
|
|
@node Contact the StumpWM developers, , Init File, Introduction
|
|
@section Contact the StumpWM developers
|
|
The StumpWM home page is @url{http://stumpwm.nongnu.org/}.
|
|
|
|
The StumpWM mailing list is @email{stumpwm-devel@@nongnu.org} which
|
|
you can subscribe to at
|
|
@url{https://lists.nongnu.org/mailman/listinfo/stumpwm-devel}. It is
|
|
the preferred way of contacting developers for questions. If you have
|
|
a bug report or patch, please open an issue or pull request at
|
|
@url{https://github.com/stumpwm/stumpwm/issues}.
|
|
|
|
The StumpWM IRC channel can be found on Freenode at
|
|
@uref{irc://irc.libera.chat/#stumpwm, @code{#stumpwm}}.
|
|
|
|
@node Key Bindings, Commands, Introduction, Top
|
|
@chapter Key Bindings
|
|
StumpWM is controlled entirely by keystrokes and Lisp commands. It
|
|
mimics GNU Screen's keyboard handling. StumpWM's default prefix key is
|
|
@kbd{C-t}.
|
|
|
|
@menu
|
|
* List of Default Keybindings::
|
|
* Binding Keys::
|
|
* Modifiers::
|
|
* AltGr Keys::
|
|
* Remapped Keys::
|
|
@end menu
|
|
|
|
@node List of Default Keybindings, Binding Keys, Key Bindings, Key Bindings
|
|
@section List of Default Keybindings
|
|
The following is a list of keybindings.
|
|
|
|
@table @kbd
|
|
@item C-t @var{d}
|
|
Select the window with the corresponding digit@tie{}@var{d}
|
|
|
|
@item C-t C-@var{d}
|
|
Pull the window with the corresponding digit@tie{}@var{d} into the current frame
|
|
|
|
@item C-t n
|
|
@itemx C-t C-n
|
|
@itemx C-t Space
|
|
Go to the next window in the window list
|
|
|
|
@item C-t p
|
|
@itemx C-t C-p
|
|
Go to the previous window in the window list
|
|
|
|
@item C-t '
|
|
Go to a window by name
|
|
|
|
@item C-t "
|
|
Select a window from a list and focus the window.
|
|
|
|
@item C-t C-g
|
|
Abort the current command. This is useful if you accidentally hit @kbd{C-t}
|
|
|
|
@item C-t i
|
|
Display information about the current window.
|
|
|
|
@item C-t f
|
|
Select a frame by number
|
|
|
|
@item C-t s
|
|
Split current frame vertically
|
|
|
|
@item C-t S
|
|
Split current frame horizontally
|
|
|
|
@item C-t k
|
|
@itemx C-t C-k
|
|
Sends a kill message to the current frame and the running program.
|
|
|
|
@item C-t K
|
|
Kills the current frame and running program; like a @command{kill -9}.
|
|
|
|
@item C-t c
|
|
@itemx C-t C-c
|
|
Run an X terminal; by default @command{xterm}
|
|
|
|
@item C-t e
|
|
@itemx C-t C-e
|
|
Run Emacs or raise it if it is already running.
|
|
|
|
@item C-t t
|
|
Sends a @kbd{C-t} to the frame; this is useful for applications like Firefox
|
|
which make heavy use of @kbd{C-t} (in Firefox's case, for opening a new
|
|
tab). This is similar to how GNU screen uses @kbd{C-a a}.
|
|
|
|
@item C-t w
|
|
@itemx C-t C-w
|
|
Prints out a list of all the windows, their number, and their name.
|
|
|
|
@item C-t RET
|
|
@itemx C-t C-RET
|
|
Show all windows and let the user select one, make that window the
|
|
focus.
|
|
|
|
@item C-t b
|
|
@itemx C-t C-b
|
|
Banish the mouse point to the lower right corner of the screen.
|
|
|
|
@item C-t a
|
|
@itemx C-t C-a
|
|
Display the current time and date, much like the Unix command @command{date}.
|
|
|
|
@item C-t C-t
|
|
Switch to the last window to have focus in the current frame.
|
|
|
|
@item C-t !
|
|
Prompt for a shell command to run via @file{/bin/sh}. All output is discarded.
|
|
|
|
@item C-t R
|
|
If the screen is split into multiple frames, one split will be
|
|
undone. If there is only one split, the effect will be the same as @kbd{C-t Q}.
|
|
|
|
@item C-t o
|
|
@itemx C-t TAB
|
|
If the screen is split into multiple frames, focus shifts to the
|
|
@command{next} frame, where it cycles to the right and then down; analogous
|
|
to @kbd{C-x o} in Emacs.
|
|
|
|
@item C-t F
|
|
Display ``Current Frame'' in the frame which has focus.
|
|
|
|
@item C-t ;
|
|
Opens the input box. StumpWM commands can be run from here, and the
|
|
input history moved through.
|
|
|
|
@item C-t :
|
|
Opens the input box, but all things typed in here will be sent to the
|
|
Common Lisp interpreter where they will be run as Lisp programs; thus,
|
|
input should be valid Common Lisp.
|
|
|
|
@item C-t C-h
|
|
@itemx C-t ?
|
|
The help. These can be customized using the @var{*help-keys*} variable.
|
|
|
|
@item C-t -
|
|
Hide all frames and show the root window.
|
|
|
|
@item C-t Q
|
|
Removes all splits and maximizes the frame with focus.
|
|
|
|
@item C-t Up
|
|
@itemx C-t Down
|
|
@itemx C-t Left
|
|
@itemx C-t Right
|
|
Shift focus to an adjacent frame in the specified direction. @kbd{C-t Up} will
|
|
shift focus up, if possible, @kbd{C-t Down} will shift downwards, etc.
|
|
|
|
@item C-t v
|
|
Prints out the version of the running StumpWM.
|
|
|
|
@item C-t #
|
|
Toggle the mark on the current window
|
|
|
|
@item C-t m
|
|
@itemx C-t C-m
|
|
Display the last message. Hitting this keybinding again displays the
|
|
message before that, and so on.
|
|
|
|
@item C-t l
|
|
@itemx C-t C-l
|
|
redisplay the current window and force it to take up the entire frame.
|
|
|
|
@item C-t G
|
|
Display all groups and windows in each group. For more information see @ref{Groups}.
|
|
|
|
@item C-t F@var{n}
|
|
Jump to the corresponding group @var{n}. @kbd{C-t F1} jumps to group 1 and so on.
|
|
|
|
@item C-t g g
|
|
Show the list of groups.
|
|
|
|
@item C-t g c
|
|
Create a new group.
|
|
|
|
@item C-t g n
|
|
@itemx C-t g C-n
|
|
@itemx C-t g SPC
|
|
@itemx C-t g C-SPC
|
|
Go to the next group in the list.
|
|
|
|
@item C-t g N
|
|
Go to the next group in the list and bring the current window along.
|
|
|
|
@item C-t g p
|
|
@itemx C-t g C-p
|
|
Go to the previous group in the list.
|
|
|
|
@item C-t g P
|
|
Go to the previous group in the list and bring the current window along.
|
|
|
|
@item C-t g '
|
|
Select a group by name or by number.
|
|
|
|
@item C-t g "
|
|
Select a group from a list and switch to it.
|
|
|
|
@item C-t g m
|
|
Move the current window to the specified group.
|
|
|
|
@item C-t g k
|
|
Kill the current group. All windows are merged into the next group.
|
|
|
|
@item C-t g A
|
|
@itemx C-t g r
|
|
Change the current group's name.
|
|
|
|
@item C-t g @var{d}
|
|
Go to the group with digit @var{d}. @kbd{C-t g 1} jumps to group 1 and so on.
|
|
|
|
@item C-t +
|
|
Make frames the same height or width in the current frame's subtree.
|
|
|
|
@item C-t h k
|
|
Describe the specified key binding.
|
|
|
|
@item C-t h f
|
|
Describe the specified function.
|
|
|
|
@item C-t h v
|
|
Describe the specified variable.
|
|
|
|
@item C-t h w
|
|
List all key sequences that are bound to the specified command
|
|
|
|
@item C-t h c
|
|
Describe the specified command.
|
|
@end table
|
|
|
|
@node Binding Keys, Modifiers, List of Default Keybindings, Key Bindings
|
|
@section Binding Keys
|
|
|
|
@@@ define-key
|
|
@@@ undefine-key
|
|
@@@ kbd
|
|
!!! set-prefix-key
|
|
|
|
@@@ make-sparse-keymap
|
|
|
|
### *root-map*
|
|
### *top-map*
|
|
### *groups-map*
|
|
### *group-top-maps*
|
|
### *exchange-window-map*
|
|
### *key-seq-color*
|
|
|
|
!!! bind
|
|
!!! unbind
|
|
!!! send-escape
|
|
@@@ grab-pointer
|
|
@@@ ungrab-pointer
|
|
### *banish-pointer-to*
|
|
|
|
@@@ final-key-p
|
|
@@@ help-key-p
|
|
@@@ cancel-key-p
|
|
### *editor-bindings*
|
|
### *numpad-map*
|
|
|
|
@node Modifiers, AltGr Keys, Binding Keys, Key Bindings
|
|
@section Modifiers
|
|
|
|
Many users have had some difficulty with setting up modifiers for
|
|
StumpWM keybindings. This is caused by a combination of how StumpWM
|
|
handles modifiers and the default modifiers list for many users' X
|
|
servers.
|
|
|
|
@itemize
|
|
|
|
@item
|
|
My ``Super'' key doesn't work!
|
|
|
|
This is most likely caused by having the Hyper and Super keys listed
|
|
as the same modifier in the modifier list.
|
|
|
|
@example
|
|
$ xmodmap
|
|
xmodmap: up to 3 keys per modifier, (keycodes in parentheses):
|
|
|
|
shift Shift_L (0x32), Shift_R (0x3e)
|
|
lock Caps_Lock (0x42)
|
|
control Control_L (0x25), Control_R (0x6d)
|
|
mod1 Alt_L (0x40), Alt_R (0x71), Meta_L (0x9c)
|
|
mod2 Num_Lock (0x4d)
|
|
mod3
|
|
mod4 Super_L (0x7f), Hyper_L (0x80)
|
|
mod5 Mode_switch (0x5d), ISO_Level3_Shift (0x7c)
|
|
@end example
|
|
|
|
The problem is in the line beginning with ``mod4''. The way to set up
|
|
the modifier list correctly is to have just the Super key as the mod4
|
|
modifier. The following @command{xmodmap} commands will do just that.
|
|
|
|
@example
|
|
# clear out the mod4 modifier
|
|
$ xmodmap -e 'clear mod4'
|
|
$ xmodmap
|
|
xmodmap: up to 3 keys per modifier, (keycodes in parentheses):
|
|
|
|
shift Shift_L (0x32), Shift_R (0x3e)
|
|
lock Caps_Lock (0x42)
|
|
control Control_L (0x25), Control_R (0x6d)
|
|
mod1 Alt_L (0x40), Alt_R (0x71), Meta_L (0x9c)
|
|
mod2 Num_Lock (0x4d)
|
|
mod3
|
|
mod4
|
|
mod5 Mode_switch (0x5d), ISO_Level3_Shift (0x7c)
|
|
|
|
# add Super as a mod4 modifier
|
|
$ xmodmap -e 'add mod4 = Super_L'
|
|
$ xmodmap
|
|
xmodmap: up to 3 keys per modifier, (keycodes in parentheses):
|
|
|
|
shift Shift_L (0x32), Shift_R (0x3e)
|
|
lock Caps_Lock (0x42)
|
|
control Control_L (0x25), Control_R (0x6d)
|
|
mod1 Alt_L (0x40), Alt_R (0x71), Meta_L (0x9c)
|
|
mod2 Num_Lock (0x4d)
|
|
mod3
|
|
mod4 Super_L (0x73), Super_L (0x7f)
|
|
mod5 Mode_switch (0x5d), ISO_Level3_Shift (0x7c)
|
|
@end example
|
|
|
|
You can automate this by storing the commands in a file and calling
|
|
xmodmap when you start your X session.
|
|
|
|
@example
|
|
$ cat ~/.Xmodmap
|
|
clear mod4
|
|
add mod4 = Super_L
|
|
@end example
|
|
|
|
If you use @command{startx}, modify your @file{~/.xsession} or @file{~/.xinitrc} file.
|
|
|
|
@example
|
|
$ cat ~/.xsession
|
|
#!/bin/sh
|
|
|
|
xmodmap ~/.Xmodmap
|
|
exec /usr/bin/stumpwm
|
|
@end example
|
|
|
|
If you use a settings daemon from one of the major desktop
|
|
environments (Gnome,KDE, or Unity) you may be able to set keyboard
|
|
modifiers from their respective configuration GUIs. If not,
|
|
@command{xmodmap} should always work if invoked at the right place.
|
|
|
|
@item
|
|
Handling Meta and Alt: when do I use @kbd{M-} and @kbd{A-}?
|
|
|
|
If you have no Meta keys defined (see the output of the @command{xmodmap}
|
|
command), then StumpWM will treat the @kbd{M-} prefix in keybindings to
|
|
mean Alt. However, if there are Meta keys defined, then the @kbd{M-}
|
|
prefix refers to them, and the @kbd{A-} prefix refers to Alt.
|
|
|
|
Most users will simply use @kbd{M-} to refer to their Alt keys. However,
|
|
users that define separate Meta and Alt keys will use @kbd{M-} to refer
|
|
to the former, and @kbd{A-} to refer to the latter.
|
|
|
|
@item
|
|
How can I set up a Hyper key and use it with StumpWM?
|
|
|
|
To set up a Hyper key, you need to do two things: bind a physical key
|
|
to be a Hyper key, and add that key to the modifiers list.
|
|
|
|
The following example shows how to bind the control key at the
|
|
bottom-left of most keyboards to be Hyper. This is useful if you've
|
|
made Caps Lock into a control key, and have no use for the bottom-left
|
|
key.
|
|
|
|
@example
|
|
$ xmodmap -e 'keycode 37 = Hyper_L'
|
|
$ xmodmap -e 'clear mod5'
|
|
$ xmodmap -e 'add mod5 = Hyper_L'
|
|
@end example
|
|
|
|
To use a different key for Hyper, replace the keycode ``37'' above.
|
|
Use the @command{xev} program to see the keycode that any physical key has.
|
|
Refer to the section above on setting up the Super key to see how to
|
|
automate setting the Hyper key when you start X.
|
|
|
|
Now you can use @kbd{H-} as a prefix in StumpWM bindings.
|
|
|
|
@example
|
|
(define-key *top-map* (kbd "H-RET") "fullscreen")
|
|
(define-key *top-map* (kbd "H-Left") "gprev")
|
|
(define-key *top-map* (kbd "H-Right") "gnext")
|
|
(define-key *top-map* (kbd "H-TAB") "other")
|
|
@end example
|
|
|
|
Since essentially no programs have Hyper bindings, you can safely bind
|
|
commands to the @var{*top-map*}.
|
|
|
|
@end itemize
|
|
### *all-modifiers*
|
|
### *modifiers*
|
|
|
|
@node AltGr Keys, Remapped Keys, Modifiers, Key Bindings
|
|
@section AltGr Keys
|
|
|
|
StumpWM uses the CLX client library for X11, which doesnt support the
|
|
XKB extension. As such support for Alt Graph must be handled
|
|
specially.
|
|
|
|
Preliminary support for Alt Graph in StumpWM is done by registering
|
|
AltGr as a modifier key and specially handling it when it is a member of
|
|
a key press' state. By default StumpWM treats AltGr key presses as a
|
|
normal key and not a modifier, and this behavior should not be changed
|
|
unless necessary. To enable treating AltGr as a modifier, the user must
|
|
place the following in their stumpwmrc:
|
|
|
|
@example
|
|
(register-altgr-as-modifier)
|
|
@end example
|
|
|
|
Additionally, the variable @var{*altgr-offset*} defaults to 2, which may
|
|
be appropriate for the users keyboard layout, or may not. Some users may
|
|
have an AltGr offset of 4, or potentially 6. If, after calling
|
|
@code{register-altgr-as-modifier}, keys on AltGr aren't being registered
|
|
properly, then the offset may need to be changed. The user can check
|
|
this explicitly by finding a keysym that requires AltGr and passing it
|
|
to @code{keysym-requires-altgr}. As an example, some layouts have @kbd{ł} on
|
|
@kbd{AltGr+l}. In such a case, the following example would return true
|
|
when @var{*altgr-offset*} is correct:
|
|
|
|
@example
|
|
(stumpwm::keysym-requires-altgr
|
|
(stumpwm::stumpwm-name->keysym "lstroke"))
|
|
@end example
|
|
|
|
@@@ register-altgr-as-modifier
|
|
### *altgr-offset*
|
|
|
|
@node Remapped Keys, , AltGr Keys, Key Bindings
|
|
@section Remapped Keys
|
|
|
|
StumpWM may be configured to translate certain familiar top level
|
|
keybindings to alternative key sequences that are understood by
|
|
specific applications. For example, Emacs users are very familiar with
|
|
@kbd{C-n} and @kbd{C-p} as keybindings for scrolling down and up one
|
|
line at a time. However, most applications use these specific
|
|
keybindings for other actions. The @code{stumpwm:define-remapped-keys}
|
|
function may be used to define such application specific remapping of
|
|
keybindings.
|
|
|
|
@@@ define-remapped-keys
|
|
|
|
@example
|
|
(define-remapped-keys
|
|
'(("(Firefox|Chrome)"
|
|
("C-n" . "Down")
|
|
("C-p" . "Up")
|
|
("C-f" . "Right")
|
|
("C-b" . "Left")
|
|
("C-v" . "Next")
|
|
("M-v" . "Prior")
|
|
("M-w" . "C-c")
|
|
("C-w" . "C-x")
|
|
("C-y" . "C-v")
|
|
("M-<" . "Home")
|
|
("M->" . "End")
|
|
("C-M-b" . "M-Left")
|
|
("C-M-f" . "M-Right")
|
|
("M-f" . "C-Right")
|
|
("M-b" . "C-Left")
|
|
("C-k" . ("C-S-End" "C-x")))))
|
|
@end example
|
|
|
|
The above form adds Emacs like keybindings to windows whose @var{window-class} matches ``Firefox'' or ``Chrome''. Additional application specific bindings may be included by using the specific X @var{window-class} values.
|
|
|
|
The window matching pattern can also be specified as a function which returns @code{T} if the focused window matches.
|
|
|
|
@example
|
|
;; Match any window with a window-class matching "Firefox"
|
|
(define-remapped-keys
|
|
`((,(lambda (win)
|
|
(string-equal "Firefox" (window-class win)))
|
|
("C-n" . "Down")
|
|
("C-p" . "Up")
|
|
("C-f" . "Right")
|
|
("C-b" . "Left")
|
|
("C-v" . "Next")
|
|
("M-v" . "Prior")
|
|
("M-w" . "C-c")
|
|
("C-w" . "C-x")
|
|
("C-y" . "C-v")
|
|
("M-<" . "Home")
|
|
("M->" . "End")
|
|
("C-M-b" . "M-Left")
|
|
("C-M-f" . "M-Right")
|
|
("M-f" . "C-Right")
|
|
("M-b" . "C-Left")
|
|
("C-k" . ("C-S-End" "C-x")))))
|
|
@end example
|
|
|
|
@subsection Circumventing Remapped Keys
|
|
|
|
However, if the original key binding needs to be explictly applied the
|
|
@command{send-raw-key} command may be used. It will prompt for a key
|
|
which will be passed to the application as-is. For example, if the
|
|
@command{send-raw-key} command were bound to @kbd{C-t C-q} as follows:
|
|
|
|
@example
|
|
(define-key *root-map* (kbd "C-q") "send-raw-key")
|
|
@end example
|
|
|
|
Then, pressing @kbd{C-t C-q}, while the Firefox window has focus,
|
|
would prompt asking for ``Press a key to send''. Pressing @kbd{C-n} at
|
|
the prompt will send the keystroke as-is to Firefox, causing it to
|
|
open a new window.
|
|
|
|
If more than a single key needs to be passed to the application as-is,
|
|
the variable @var{*remapped-keys-enabled-p*} may be used.
|
|
Set to nil it will disable all remapped keys.
|
|
|
|
!!! send-raw-key
|
|
|
|
### *remapped-keys-enabled-p*
|
|
|
|
@node Commands, Message and Input Bar, Key Bindings, Top
|
|
@chapter Commands
|
|
If you've used Emacs before you'll find the distinction between
|
|
commands and functions familiar. Commands are simply functions that
|
|
can be bound to keys and executed interactively from StumpWM's input
|
|
bar. Whereas, in Emacs, the special "(interactive)" declaration is
|
|
used to turn a function into a command, in StumpWM commands are made
|
|
with a separate @command{defcommand} or
|
|
@command{define-interactive-keymap} macro.
|
|
|
|
Once a command is defined, you can call it by invoking the
|
|
@command{colon} command (@kbd{C-t ;}), and typing the name
|
|
of the command. This may be sufficient for commands that aren't used
|
|
very often. To see all the currently-defined commands, invoke the
|
|
command called @command{commands}: ie press @kbd{C-t ;},
|
|
type ``commands'', and hit return.
|
|
|
|
Commonly-used commands can also be bound to a keystroke, which is much
|
|
more convenient. To do this, use the @command{define-key}
|
|
function (see @ref{Key Bindings}), giving the name of the command as a
|
|
string. For example:
|
|
|
|
@example
|
|
(define-key *root-map* (kbd "d") "exchange-direction")
|
|
@end example
|
|
|
|
You cannot give the command name as a symbol, nor can you bind a key
|
|
to a regular function defined with @command{defun}.
|
|
|
|
If the command takes arguments (see @ref{Writing Commands}), you can fix
|
|
those arguments when defining the key-binding, by including the
|
|
arguments in the same string as the command name, separated by a
|
|
space. For instance, the @command{exchange-direction} command,
|
|
which is unbound by default, requires a direction in which to exchange
|
|
windows. If you call @command{exchange-direction} directly, it
|
|
will prompt you for the direction. If you know that you often exchange
|
|
in left/right directions, and want those actions bound to keys, you
|
|
can use the following in your customization file:
|
|
|
|
@example
|
|
(define-key *root-map* (kbd "[") "exchange-direction left")
|
|
(define-key *root-map* (kbd "]") "exchange-direction right")
|
|
@end example
|
|
|
|
Multiple arguments can be included by adding them to the command
|
|
string, separated by spaces. Not all argument types can be represented
|
|
as strings, but StumpWM will do its best to convert types.
|
|
|
|
StumpWM does not implement the Emacs concept of prefix arguments.
|
|
|
|
@menu
|
|
* Writing Commands::
|
|
* StumpWM Types::
|
|
* Common Built-in Commands::
|
|
@end menu
|
|
|
|
@node Writing Commands, StumpWM Types, Commands, Commands
|
|
@section Writing Commands
|
|
StumpWM commands are written much like any Lisp function. The main
|
|
difference is in the way command arguments are specified. The
|
|
@command{defcommand} macro takes a list of arguments as its first
|
|
form (similar to the @command{defun} macro), and a corresponding
|
|
list of types as its second form. All arguments must belong to a
|
|
``type''. Each type specification has two parts: a keyword specifying
|
|
the argument type, and a string prompt that will be displayed when
|
|
asking the user to enter the argument value. A typical
|
|
@command{defcommand} might look like this:
|
|
|
|
@example
|
|
(defcommand now-we-are-six (name age)
|
|
((:string "Enter your name: ")
|
|
(:number "Enter your age: "))
|
|
(message "~a, in six years you will be ~a" name (+ 6 age)))
|
|
@end example
|
|
|
|
If @command{now-we-are-six} is called interactively via the
|
|
@command{colon} command, the user will be prompted for a string
|
|
and a number, which will then be bound to ``name'' and ``age'',
|
|
respectively, in the body of the command.
|
|
|
|
When invoking the command via a key-binding, it is possible to provide
|
|
some or all of the arguments directly:
|
|
|
|
@example
|
|
(define-key *root-map* (kbd "L") "now-we-are-six John")
|
|
@end example
|
|
|
|
In this case, hitting @kbd{C-t L} will only prompt for an age (the first
|
|
string argument is already bound to ``John''). Argument values provided
|
|
this way always bind to the earliest arguments defined: ie, it is not
|
|
possible to specify an age, but prompt the user for a name.
|
|
|
|
If the type declaration does not include a prompt (ie, it looks like
|
|
``(:type nil)'', or ``(:type)'' or just ``:type''), the argument is
|
|
considered optional. It can be provided via a key-binding invocation, as
|
|
above, but if it isn't, the user will not be prompted, and the argument
|
|
will be bound to nil.
|
|
|
|
It is possible to limit the scope under which the command will
|
|
be usable: a command can be defined to work only a specific group type;
|
|
the three currently implemented are tile groups,f loating groups, and
|
|
dynamic groups. This is done by replacing the name of the command with a
|
|
two-element list: the name of the command as a symbol, and either the symbol
|
|
tile-group or floating-group. For instance, the @command{next} command,
|
|
which only functions in tile groups, is defined this way:
|
|
|
|
@example
|
|
(defcommand (next tile-group) @dots{})
|
|
@end example
|
|
|
|
%%% defcommand
|
|
%%% defcommand-alias
|
|
### *last-command*
|
|
|
|
@section Interactive Keymaps
|
|
|
|
Interactive keymaps are a special type of command that basically
|
|
pushes another keymap on top of the current one. The new keymap will
|
|
only be removed after an exit command is run. An example is
|
|
@command{iresize}.
|
|
|
|
The macro @command{define-interactive-keymap} is used to define an
|
|
interactive keymap. The first argument is the same as
|
|
@command{defcommand}. The second argument is a list of extra
|
|
configurations that can be used for controlling the command and the
|
|
rest are the key bindings for the new command, optionally with a
|
|
@code{t} appended; this tells @code{define-interactive-keymap} to
|
|
exit the keymap upon use of that keybinding.
|
|
|
|
For instance, a simple interactive keymap:
|
|
|
|
@example
|
|
(define-interactive-keymap my-new-command nil
|
|
((kbd "a") "execute-a-command")
|
|
((kbd "b") "execute-b-command" t))
|
|
@end example
|
|
|
|
This creates a command called @code{my-new-command} that, when called,
|
|
will activate the interactive keymap mode. In this mode, the user can
|
|
press ``a'' or ``b'' repeatedly, omitting any prefix. The default exit
|
|
commands are @code{RET}, @code{C-g} and @code{ESC}.
|
|
|
|
This creates a command called @code{my-new-command} that, when called,
|
|
will activate the interactive keymap mode. In this mode, the user can
|
|
press ``a'' or ``b'', omitting any prefix. The user can press ``a''
|
|
repeatedly, however pressing ``b'' exits the keymap. The default exit
|
|
commands are @code{RET}, @code{C-g} and @code{ESC}.
|
|
|
|
The available configuration is @code{on-enter}, @code{on-exit} and
|
|
@code{abort-if}:
|
|
|
|
@example
|
|
(defun before-foo () (message "start foo"))
|
|
(defun after-foo () (message "end foo"))
|
|
(defun foo-p () (and *bar* *baz*))
|
|
(defparameter *custom-exit-keys* '((kbd "RET") (kbd "SPC")
|
|
(kbd "C-g") (kbd "ESC")))
|
|
|
|
(define-interactive-keymap foo (:on-enter #'before-foo
|
|
:on-exit #'after-foo
|
|
:abort-if #'foo-p
|
|
:exit-on *custom-exit-keys*))
|
|
@end example
|
|
|
|
In the above example, the message ``start foo'' will appear before
|
|
starting the interactive keymap, ``end foo'' will appear right after
|
|
the command exits; We've added SPC as an exit key with custom exit
|
|
keys. Also, the command executes only if the variables @code{*bar*}
|
|
and @code{*baz*} are true.
|
|
|
|
%%% define-interactive-keymap
|
|
!!! call-and-exit-kmap
|
|
|
|
@node StumpWM Types, , Writing Commands, Commands
|
|
@section StumpWM Types
|
|
All command arguments must be of a defined ``StumpWM type''. The
|
|
following types are pre-defined:
|
|
|
|
|
|
@table @var
|
|
@item :y-or-n
|
|
A yes or no question returning T or NIL.
|
|
@item :variable
|
|
A lisp variable
|
|
@item :function
|
|
A lisp function
|
|
@item :command
|
|
A StumpWM command as a string.
|
|
@item :key-seq
|
|
A key sequence starting from *TOP-MAP*
|
|
@item :window-number
|
|
An existing window number
|
|
@item :number
|
|
An integer number
|
|
@item :string
|
|
A string
|
|
@item :key
|
|
A single key chord
|
|
@item :window-name
|
|
An existing window's name
|
|
@item :direction
|
|
A direction symbol. One of :UP :DOWN :LEFT :RIGHT
|
|
@item :gravity
|
|
A gravity symbol. One of :center :top :right :bottom :left :top-right :top-left :bottom-right :bottom-left
|
|
@item :group
|
|
An existing group
|
|
@item :frame
|
|
A frame
|
|
@item :shell
|
|
A shell command
|
|
@item :rest
|
|
The rest of the input yet to be parsed.
|
|
@item :module
|
|
An existing StumpWM module
|
|
@end table
|
|
|
|
Additional types can be defined using the macro
|
|
@command{define-stumpwm-type}. Emacs users who are accustomed to writing
|
|
more complicated interactive declarations using "(interactive (list
|
|
@dots{}))" forms will find that similar logic can be put into StumpWM
|
|
type definitions. The macro is called like this:
|
|
|
|
@example
|
|
(define-stumpwm-type :type-name (input prompt) body)
|
|
@end example
|
|
|
|
The keyword :type-name will then be available for use in
|
|
@command{defcommand} macros. When commands are called, the bodies
|
|
of these type definitions are called in turn to produce actual
|
|
argument values.
|
|
|
|
Type definitions produce their value in one of several ways: by
|
|
reading it from the argument line bound to a keystroke, by prompting
|
|
the user to enter a value, or by generating it programmatically.
|
|
|
|
Within the body of the type definition, the argument ``input'' is bound
|
|
to the argument line provided in the command string, and ``prompt'' to
|
|
the string prompt provided in the @command{defcommand} form. The
|
|
usual convention is to first check if an argument has been provided in
|
|
``input'' and, if it hasn't, to prompt for it using ``prompt''.
|
|
|
|
StumpWM provides several convenience functions for handling the value
|
|
of ``input'':
|
|
|
|
@itemize
|
|
@item
|
|
@command{argument-pop} (input) pop the next space-delimited word or a
|
|
double quote delimited string argument from the argument
|
|
line. Backslashes may be used to escape double quotes or backslashes
|
|
inside double quoted strings.
|
|
|
|
@item
|
|
@command{argument-pop-rest} (input) return the remainder of the
|
|
argument line as a single string, leaving input empty
|
|
|
|
@item
|
|
@command{argument-pop-or-read} (input prompt &optional
|
|
completions) either pop an argument from the argument line, or if it
|
|
is empty use ``prompt'' to prompt the user for a value
|
|
|
|
@item
|
|
@command{argument-pop-rest-or-read} (input prompt &optional
|
|
completions) either return the remainder of the argument line as a
|
|
string, leaving input empty, or use ``prompt'' to prompt the user for
|
|
a value
|
|
|
|
@end itemize
|
|
|
|
As an example, here's a new type called :smart-direction. The
|
|
existing :direction type simply asks for one of the four directions
|
|
``left'', ``right'', ``up'' or ``down'', without checking to see if there's a
|
|
frame in that direction. Our new type, :smart-direction, will look
|
|
around the current frame, and only allow the user to choose a
|
|
direction in which another frame lies. If only one direction is
|
|
possible it will return that automatically without troubling the user.
|
|
It signals an error for invalid directions; it could alternately
|
|
return a ``nil'' value in those cases, and let the command handle that.
|
|
|
|
@example
|
|
(define-stumpwm-type :smart-direction (input prompt)
|
|
(let ((valid-dirs
|
|
(loop ; gather all the directions in which there's a neighbouring frame
|
|
with values = '(("up" :up)
|
|
("down" :down)
|
|
("left" :left)
|
|
("right" :right))
|
|
with frame-set = (stumpwm::group-frames
|
|
(window-group (current-window)))
|
|
for dir in values
|
|
for neighbour = (stumpwm::neighbour
|
|
(second dir)
|
|
(stumpwm::window-frame (current-window))
|
|
frame-set)
|
|
if (and neighbour (stumpwm::frame-window neighbour))
|
|
collect dir))
|
|
(arg (argument-pop input))) ; store a possible argument
|
|
(cond ((null valid-dirs) ; no directions, bail out
|
|
(throw 'error "No valid directions"))
|
|
(arg ; an arg was bound, but is it valid?
|
|
(or (second (assoc arg valid-dirs :test #'string=))
|
|
(throw 'error "Not a valid direction")))
|
|
((= 1 (length valid-dirs)) ; only one valid direction
|
|
(second (car valid-dirs)))
|
|
(t ; multiple possibilities, prompt for direction
|
|
(second (assoc (car (select-from-menu (current-screen)
|
|
valid-dirs
|
|
prompt))
|
|
valid-dirs :test #'string=))))))
|
|
|
|
(defcommand smarty (dir) ((:smart-direction "Pick a direction: "))
|
|
;; `dir' is a keyword here
|
|
(if dir
|
|
(message "You're going ~a." (string-downcase dir))
|
|
(message "You're not going anywhere.")))
|
|
|
|
(define-key *root-map* (kbd "R") "smarty right")
|
|
@end example
|
|
|
|
%%% define-stumpwm-type
|
|
|
|
@node Common Built-in Commands, , Writing Commands, Commands
|
|
@section Common Built-in Commands
|
|
|
|
!!! emacs
|
|
!!! version
|
|
!!! banish
|
|
!!! ratwarp
|
|
!!! ratrelwarp
|
|
!!! ratclick
|
|
!!! restart-hard
|
|
!!! restart-soft
|
|
!!! lastmsg
|
|
!!! commands
|
|
!!! keyboard-quit
|
|
!!! quit
|
|
!!! reload
|
|
!!! echo-date
|
|
!!! eval-line
|
|
!!! command-mode
|
|
!!! list-window-properties
|
|
!!! show-window-properties
|
|
!!! time
|
|
|
|
@node Message and Input Bar, Windows, Commands, Top
|
|
@chapter Message and Input Bar
|
|
|
|
### *suppress-echo-timeout*
|
|
!!! echo
|
|
@@@ err
|
|
@@@ wrap
|
|
### *message-max-width*
|
|
### *help-max-height*
|
|
### *which-key-format*
|
|
!!! colon
|
|
|
|
%%% with-restarts-menu
|
|
@@@ restarts-menu
|
|
|
|
@menu
|
|
* Customizing The Bar::
|
|
* Using The Input Bar::
|
|
* Programming The Message Bar::
|
|
* Programming the Input Bar::
|
|
@end menu
|
|
|
|
@node Customizing The Bar, Using The Input Bar, Message and Input Bar, Message and Input Bar
|
|
@section Customizing The Bar
|
|
The bar's appearance and behavior can be modified with the following
|
|
functions and variables. See @ref{Colors} for an explanation of how to
|
|
set these color variables.
|
|
|
|
@@@ set-fg-color
|
|
@@@ set-bg-color
|
|
@@@ set-border-color
|
|
@@@ set-msg-border-width
|
|
@@@ set-font
|
|
|
|
### *message-window-class*
|
|
### *message-window-padding*
|
|
### *message-window-y-padding*
|
|
### *message-window-margin*
|
|
### *message-window-y-margin*
|
|
### *message-window-gravity*
|
|
### *message-window-input-gravity*
|
|
### *message-window-timer*
|
|
### *timeout-wait*
|
|
### *timeout-wait-multiline*
|
|
### *input-window-class*
|
|
### *input-window-gravity*
|
|
|
|
@node Using The Input Bar, Programming The Message Bar, Customizing The Bar, Message and Input Bar
|
|
@section Using The Input Bar
|
|
|
|
The following is a list of keybindings for the Input Bar. Users of Emacs
|
|
will recognize them.
|
|
|
|
@table @kbd
|
|
@item DEL
|
|
Delete the character before point (@code{delete-backward-char}).
|
|
|
|
@item M-DEL
|
|
Kill back to the beginning of the previous word (@code{backward-kill-word}).
|
|
|
|
@item C-d
|
|
@itemx Delete
|
|
Delete the character after point (@code{delete-forward-char}).
|
|
|
|
@item M-d
|
|
Kill forward to the end of the next word (@code{forward-kill-word}).
|
|
|
|
@item C-f
|
|
@itemx Right
|
|
Move forward one character (@code{forward-char}).
|
|
|
|
@item M-f
|
|
Move forward one word (@code{forward-word}).
|
|
|
|
@item C-b
|
|
@itemx Left
|
|
Move backward one character (@code{backward-char}).
|
|
|
|
@item M-b
|
|
Move backward one word (@code{backward-word}).
|
|
|
|
@item C-a
|
|
@itemx Home
|
|
Move to the beginning of the current line (@code{move-beginning-of-line}).
|
|
|
|
@item C-e
|
|
@itemx End
|
|
Move to the end of the current line (@code{move-end-of-line}).
|
|
|
|
@item C-k
|
|
Kill to the end of the line (@code{kill-line}).
|
|
|
|
@item C-u
|
|
Kill to the beginning of the line (@code{kill-to-beginning}),
|
|
the same as @kbd{C-a C-k}.
|
|
|
|
@item C-p
|
|
@itemx Up
|
|
Move to the next earlier entry saved in the command history (@command{history-back}).
|
|
|
|
@item C-n
|
|
@itemx Down
|
|
Move to the next later entry saved in the command history (@command{history-forward}).
|
|
|
|
@item RET
|
|
Submit the entered command (@command{submit}).
|
|
|
|
@item C-g
|
|
Abort the current action by closing the Input Bar (@command{abort}).
|
|
|
|
@item C-y
|
|
Paste text from clipboard into the Input Bar (@command{yank-selection}).
|
|
|
|
@item TAB
|
|
Clockwise tab complete the current string, if possible. Press @kbd{TAB} again to
|
|
cycle through completions.
|
|
|
|
@item S-TAB
|
|
Counter-clockwise tab complete the current string, if possible. Press @kbd{S-TAB} again to
|
|
cycle through completions.
|
|
|
|
@end table
|
|
|
|
@node Programming The Message Bar, Programming the Input Bar, Using The Input Bar, Message and Input Bar
|
|
@section Programming The Message Bar
|
|
|
|
@@@ echo-string
|
|
@@@ message
|
|
%%% with-message-queuing
|
|
### *queue-messages-p*
|
|
### *input-history-ignore-duplicates*
|
|
### *input-completion-style*
|
|
@@@ make-input-completion-style-cyclic
|
|
@@@ make-input-completion-style-unambiguous
|
|
!!! copy-last-message
|
|
|
|
@node Programming the Input Bar, , Programming The Message Bar, Message and Input Bar
|
|
@section Programming the Input Bar
|
|
New input behavior can be added to the input bar by creating editing
|
|
functions and binding them to keys in the @var{*input-map*} using
|
|
@command{define-key}, just like other key bindings.
|
|
|
|
An input function takes 2 arguments: the input structure and the key pressed.
|
|
|
|
@@@ read-one-line
|
|
@@@ read-one-char
|
|
@@@ completing-read
|
|
@@@ input-insert-string
|
|
@@@ input-insert-char
|
|
|
|
### *input-map*
|
|
|
|
@node Windows, Frames, Message and Input Bar, Top
|
|
@chapter Windows
|
|
|
|
!!! next
|
|
!!! prev
|
|
!!! delete-window
|
|
!!! kill-window
|
|
!!! kill-windows-current-group
|
|
!!! kill-windows-other
|
|
!!! echo-windows
|
|
!!! other-window
|
|
!!! pull-hidden-next
|
|
!!! pull-hidden-previous
|
|
!!! pull-hidden-other
|
|
!!! pull-from-windowlist
|
|
!!! renumber
|
|
!!! meta
|
|
!!! select-window
|
|
!!! select-window-by-number
|
|
!!! select-window-by-name
|
|
!!! repack-window-numbers
|
|
!!! title
|
|
!!! windowlist
|
|
!!! windowlist-by-class
|
|
!!! fullscreen
|
|
!!! info
|
|
!!! refresh
|
|
!!! redisplay
|
|
!!! float-this
|
|
!!! unfloat-this
|
|
!!! flatten-floats
|
|
!!! unmaximize
|
|
!!! toggle-always-on-top
|
|
!!! toggle-always-show
|
|
!!! window-send-string
|
|
|
|
@@@ window-head
|
|
@@@ window-sync
|
|
@@@ window-visible-p
|
|
@@@ raise-window
|
|
@@@ focus-window
|
|
|
|
|
|
### *xwin-to-window*
|
|
### *window-format*
|
|
### *window-info-format*
|
|
### *window-name-source*
|
|
### *new-window-preferred-frame*
|
|
### *hidden-window-color*
|
|
|
|
### *honor-window-moves*
|
|
|
|
|
|
%%% define-fullscreen-in-frame-rule
|
|
@@@ add-fullscreen-in-frame-rule
|
|
@@@ remove-fullscreen-in-frame-rule
|
|
### *fullscreen-in-frame-p-window-functions*
|
|
|
|
|
|
@menu
|
|
* Window Marks::
|
|
* Customizing Window Appearance::
|
|
* Controlling Raise And Map Requests::
|
|
* Programming With Windows::
|
|
* Rule Based Window Placement::
|
|
* Window Selection Expressions::
|
|
@end menu
|
|
|
|
@node Window Marks, Customizing Window Appearance, Windows, Windows
|
|
@section Window Marks
|
|
Windows can be marked. A marked window has a # beside it in the window
|
|
list. Some commands operate only on marked windows.
|
|
|
|
!!! mark
|
|
!!! clear-window-marks
|
|
!!! pull-marked
|
|
|
|
@node Customizing Window Appearance, Controlling Raise And Map Requests, Window Marks, Windows
|
|
@section Customizing Window Appearance
|
|
|
|
### *maxsize-border-width*
|
|
### *transient-border-width*
|
|
### *normal-border-width*
|
|
### *window-border-style*
|
|
|
|
See @ref{Colors} for an explanation of how to set these color
|
|
variables.
|
|
|
|
@@@ set-win-bg-color
|
|
@@@ set-focus-color
|
|
@@@ set-unfocus-color
|
|
@@@ set-float-focus-color
|
|
@@@ set-float-unfocus-color
|
|
@@@ set-normal-gravity
|
|
@@@ set-maxsize-gravity
|
|
@@@ set-transient-gravity
|
|
|
|
!!! gravity
|
|
@@@ gravity-coords
|
|
|
|
@node Controlling Raise And Map Requests, Programming With Windows, Customizing Window Appearance, Windows
|
|
@section Controlling Raise And Map Requests
|
|
It is sometimes handy to deny a window's request to be focused. The
|
|
following variables determine such behavior.
|
|
|
|
A map request occurs when a new or withdrawn window requests to be
|
|
mapped for the first time.
|
|
|
|
A raise request occurs when a client asks the window manager to give
|
|
an existing window focus.
|
|
|
|
### *deny-map-request*
|
|
### *deny-raise-request*
|
|
### *suppress-deny-messages*
|
|
|
|
Some examples follow.
|
|
|
|
@example
|
|
;; Deny the firefox window from taking focus when clicked upon.
|
|
(push '(:class "gecko") stumpwm:*deny-raise-request*)
|
|
|
|
;; Deny all map requests
|
|
(setf stumpwm:*deny-map-request* t)
|
|
|
|
;; Deny transient raise requests
|
|
(push '(:transient) stumpwm:*deny-map-request*)
|
|
|
|
;; Deny the all windows in the xterm class from taking focus.
|
|
(push '(:class "Xterm") stumpwm:*deny-raise-request*)
|
|
@end example
|
|
|
|
@node Programming With Windows, Rule Based Window Placement, Controlling Raise And Map Requests, Windows
|
|
@section Programming With Windows
|
|
|
|
%%% define-window-slot
|
|
|
|
@@@ window-send-string
|
|
### *default-window-name*
|
|
### *window-events*
|
|
### *window-parent-events*
|
|
|
|
@node Rule Based Window Placement, Window Selection Expressions, Programming With Windows, Windows
|
|
@section Rule Based Window Placement
|
|
|
|
%%% define-frame-preference
|
|
@@@ clear-window-placement-rules
|
|
|
|
!!! remember
|
|
!!! forget
|
|
!!! dump-window-placement-rules
|
|
!!! restore-window-placement-rules
|
|
### *window-placement-rules*
|
|
@node Window Selection Expressions, , Rule Based Window Placement, Windows
|
|
@section Window Selection Expressions
|
|
Window Selection Expressions (WSE) were inspired by SQL. The intent is
|
|
to allow writing consise code to select the windows you need and to
|
|
act upon them (or just to get the list of selected windows). The
|
|
implementation includes a set of (hopefully) consistent
|
|
concisely-named wrappers for the StumpWM functionality useful for
|
|
window set description and the act-on-matching-windows macro that
|
|
encapsulates the logic of iterating over a window set.
|
|
|
|
If we had SQL in StumpWM, we would write
|
|
@code{select window_id from windows as w where w.title = 'XTerm'}. WSE chooses to be
|
|
more Lisp-style and instead uses
|
|
@code{(act-on-matching-windows (w) (titled-p w "XTerm") w)}
|
|
|
|
The @code{act-on-matching-windows} function also allows performing some
|
|
actions, for example getting all the windows titled XTerm into the
|
|
current group:
|
|
@code{(act-on-matching-windows (w) (titled-p w "XTerm") (pull-w w))}
|
|
|
|
@@@ move-windows-to-group
|
|
%%% act-on-matching-windows
|
|
@@@ pull-w
|
|
@@@ titled-p
|
|
@@@ title-re-p
|
|
@@@ classed-p
|
|
@@@ class-re-p
|
|
@@@ typed-p
|
|
@@@ type-re-p
|
|
@@@ roled-p
|
|
@@@ role-re-p
|
|
@@@ resed-p
|
|
@@@ res-re-p
|
|
@@@ grouped-p
|
|
@@@ in-frame-p
|
|
|
|
@node Frames, Mode-line, Windows, Top
|
|
@chapter Frames
|
|
Frames contain windows. All windows exist within a frame.
|
|
|
|
Those used to ratpoison will notice that this differs from ratpoison's
|
|
window pool, where windows and frames are not so tightly connected.
|
|
|
|
!!! pull-window-by-number
|
|
!!! hsplit
|
|
!!! vsplit
|
|
!!! hsplit-equally
|
|
!!! vsplit-uniformly
|
|
!!! vsplit-equally
|
|
!!! hsplit-uniformly
|
|
!!! remove-split
|
|
!!! only
|
|
!!! curframe
|
|
!!! fnext
|
|
!!! fprev
|
|
!!! sibling
|
|
!!! fother
|
|
!!! fselect
|
|
!!! resize
|
|
!!! resize-direction
|
|
!!! balance-frames
|
|
!!! fclear
|
|
!!! move-focus
|
|
!!! move-window
|
|
!!! next-in-frame
|
|
!!! prev-in-frame
|
|
!!! other-in-frame
|
|
!!! next-urgent
|
|
!!! frame-windowlist
|
|
!!! echo-frame-windows
|
|
!!! exchange-direction
|
|
!!! expose
|
|
|
|
%%% save-frame-excursion
|
|
|
|
@@@ run-or-pull
|
|
@@@ only-one-frame-p
|
|
|
|
### *min-frame-width*
|
|
### *min-frame-height*
|
|
### *new-frame-action*
|
|
### *expose-auto-tile-fn*
|
|
### *expose-n-max*
|
|
### *frame-indicator-text*
|
|
### *frame-indicator-timer*
|
|
### *frame-number-map*
|
|
|
|
@menu
|
|
* Interactively Resizing Frames::
|
|
* Frame Dumping::
|
|
@end menu
|
|
|
|
@node Interactively Resizing Frames, Frame Dumping, Frames, Frames
|
|
@section Interactively Resizing Frames
|
|
There is a mode called @code{iresize} that lets you interactively
|
|
resize the current frame. To enter the mode use the @code{iresize}
|
|
command or type @key{C-t r}.
|
|
|
|
The following keybindings apply to the mode:
|
|
@table @kbd
|
|
@item C-p
|
|
@itemx Up
|
|
@itemx k
|
|
Shrink the frame vertically.
|
|
|
|
@item C-n
|
|
@itemx Down
|
|
@itemx j
|
|
Expand the frame vertically.
|
|
|
|
@item C-f
|
|
@itemx Right
|
|
@itemx l
|
|
Expand the frame horizontally.
|
|
|
|
@item C-b
|
|
@itemx Left
|
|
@itemx h
|
|
Shrink the frame horizontally.
|
|
|
|
@item C-g
|
|
@itemx ESC
|
|
Abort the interactive resize.
|
|
|
|
@item RET
|
|
Select the highlighted option.
|
|
|
|
@end table
|
|
|
|
!!! iresize
|
|
@@@ setup-iresize
|
|
### *resize-map*
|
|
|
|
### *resize-increment*
|
|
|
|
@node Frame Dumping, , Interactively Resizing Frames, Frames
|
|
@section Frame Dumping
|
|
The configuration of frames and groups can be saved and restored using
|
|
the following commands.
|
|
|
|
!!! dump-desktop-to-file
|
|
!!! dump-group-to-file
|
|
!!! dump-screen-to-file
|
|
!!! restore-from-file
|
|
!!! place-existing-windows
|
|
!!! place-current-window
|
|
|
|
The configuration files are stored in the
|
|
@var{$XDG_CONFIG_HOME/stumpwm}. The file name specified is saved as a
|
|
@code{.dump} file type. For example, @code{: dump-desktop-to-file
|
|
example} may save a file in
|
|
@code{~/.local/share/stumpwm/example.dump}. @code{restore-from-file}
|
|
also adds the @code{.dump} extension by default.
|
|
|
|
@node Mode-line, Groups, Frames, Top
|
|
@chapter The Mode Line
|
|
The mode line is a bar that runs across either the top or bottom of
|
|
a head and is used to display information. By default the mode line
|
|
displays the list of windows, similar to the output @kbd{C-t w} produces.
|
|
|
|
Alternatively, external panel applications such as the GNOME panel and
|
|
KDE's kicker may be used. Simply starting one of these programs is enough
|
|
to set it as the mode line of the head it would like to be on (if the
|
|
panel is XRandR aware) or whichever head is available. In order to
|
|
avoid problems displaying menus, configure your panel application for
|
|
positioning at the top or bottom of the head rather than relying on
|
|
@var{*mode-line-position*}
|
|
|
|
The mode line can be turned on and off with the @command{mode-line}
|
|
command or the lisp function @code{stumpwm:toggle-mode-line}. Each
|
|
head has its own mode line. For example:
|
|
|
|
@example
|
|
;; turn on/off the mode line for the current head only.
|
|
(stumpwm:toggle-mode-line (stumpwm:current-screen)
|
|
(stumpwm:current-head))
|
|
@end example
|
|
|
|
The mode line is updated after every StumpWM command.
|
|
|
|
To display the window list and the current date on the modeline, one
|
|
might do the following:
|
|
|
|
@example
|
|
(setf stumpwm:*screen-mode-line-format*
|
|
(list "%w | "
|
|
'(:eval (stumpwm:run-shell-command "date" t))))
|
|
@end example
|
|
|
|
@code{(stumpwm:run-shell-command "date" t)} runs the command
|
|
@command{date} and returns its output as a string.
|
|
|
|
!!! mode-line
|
|
|
|
@@@ toggle-mode-line
|
|
|
|
### *screen-mode-line-format*
|
|
### *time-format-string-default*
|
|
### *mode-line-fixed-title-width*
|
|
### *time-modeline-string*
|
|
### *mode-line-window-class*
|
|
$$$ *new-mode-line-hook*
|
|
### *screen-mode-line-formatters*
|
|
### *window-formatters*
|
|
@@@ bar
|
|
@@@ bar-zone-color
|
|
@@@ add-screen-mode-line-formatter
|
|
@@@ enable-mode-line
|
|
|
|
The following variables control the color, position, and size of the
|
|
mode line. See @ref{Colors} for an explanation of how to set these
|
|
color variables.
|
|
|
|
### *mode-line-position*
|
|
### *mode-line-border-width*
|
|
### *mode-line-highlight-template*
|
|
### *mode-line-pad-x*
|
|
### *mode-line-pad-y*
|
|
### *mode-line-background-color*
|
|
### *mode-line-foreground-color*
|
|
### *mode-line-border-color*
|
|
### *mode-line-timeout*
|
|
|
|
@menu
|
|
* Mode-line Interaction::
|
|
@end menu
|
|
|
|
@node Mode-line Interaction, , Mode-line, Mode-line
|
|
@section Mode-line Interaction
|
|
Mode line formatters can register sections of text to be clickable by
|
|
use of the color formatters @code{:on-click} and
|
|
@code{:on-click-end}. Any text enclosed by these formatters has its
|
|
bounds saved, and when the mode line recieves a button press event these
|
|
bounds are checked against to find a clickable area, whose registered
|
|
function is then called. These formatters can be thought of as similar
|
|
to XML tags.
|
|
|
|
To disable the on-click behavior, remove the function
|
|
@code{check-for-ml-press} from the hook @var{*mode-line-click-hook*}.
|
|
|
|
To call a function by click the function must first be registered. The
|
|
function must take at least one argument, the button code. Here is an
|
|
example of a click-to-focus function and its registration:
|
|
|
|
@example
|
|
(defun ml-on-click-focus-window (code id &rest rest)
|
|
(declare (ignore code rest))
|
|
(when-let ((window (window-by-id id)))
|
|
(focus-all window)))
|
|
|
|
(register-ml-on-click-id :ml-on-click-focus-window #'ml-on-click-focus-window)
|
|
@end example
|
|
|
|
This defines a function that focuses a window based upon its X11 window
|
|
ID, and registers it under the ID @code{:ml-on-click-focus-window}. Here
|
|
is an example of a mode line formatter that makes use of this function:
|
|
|
|
@example
|
|
(add-screen-mode-line-formatter #\i 'fmt-head-window-list-clickable)
|
|
(defun fmt-head-window-list-clickable (ml)
|
|
"Using *window-format*, return a 1 line list of the windows,
|
|
space seperated and clickable."
|
|
(flet ((fmt-w (w)
|
|
(let ((str (format-expand *window-formatters*
|
|
*window-format*
|
|
w)))
|
|
(format-with-on-click-id (if (eq w (current-window))
|
|
(fmt-highlight str)
|
|
str)
|
|
:ml-on-click-focus-window
|
|
(window-id w)))))
|
|
@verbatim
|
|
(format nil "~{~a~^ ~}"
|
|
@end verbatim
|
|
(mapcar #'fmt-w
|
|
(sort1 (head-windows (mode-line-current-group ml)
|
|
(mode-line-head ml))
|
|
#'< :key #'window-number)))))
|
|
@end example
|
|
|
|
In the above formatter, every windows expansion is wrapped in a
|
|
:on-click/end pair, which takes the ID we registered as the function to
|
|
call and the window ID as an argument to be passed to its function. The
|
|
arguments provided to @code{:on-click} will be read but not
|
|
evaluated. The string generated will look like so:
|
|
|
|
@example
|
|
"^(:on-click :ml-on-click-focus-window 308242)window text^(:on-click-end)"
|
|
@end example
|
|
|
|
Clickable text can be nested, in which case the innermost clickable text
|
|
will take precendent. In the following example @code{:id2} will be
|
|
dispatched when clicking @code{2}, but @code{:id1} will be dispatched
|
|
when clicking @code{1} and @code{3}:
|
|
|
|
@example
|
|
"^(:on-click :id1)1^(:on-click :id2)2^(:on-click-end)3^(:on-click-end)"
|
|
@end example
|
|
|
|
If one wished for right click to delete windows, then the following
|
|
example could be placed in the .stumpwmrc:
|
|
|
|
@example
|
|
(labels ((ml-on-click-focus-or-delete-window (code id &rest rest)
|
|
(declare (ignore rest))
|
|
(when-let ((window (window-by-id id)))
|
|
(let ((button (decode-button-code code)))
|
|
(case button
|
|
((:left-button)
|
|
(focus-all window))
|
|
((:right-button)
|
|
(delete-window window)))))))
|
|
(register-ml-on-click-id :ml-on-click-focus-window
|
|
#'ml-on-click-focus-or-delete-window))
|
|
@end example
|
|
|
|
This will replace the @code{:ml-on-click-focus-window} function, and all
|
|
uses of @code{:on-click} formatters referring to
|
|
@code{:ml-on-click-focus-window} will use the new function.
|
|
|
|
@@@ register-ml-on-click-id
|
|
@@@ format-with-on-click-id
|
|
|
|
@node Groups, Screens, Mode-line, Top
|
|
@chapter Groups
|
|
Groups in StumpWM are more commonly known as @dfn{virtual desktops} or
|
|
@dfn{workspaces}. Why not create a new term for it?
|
|
|
|
!!! gnew
|
|
!!! gnew-float
|
|
!!! gnew-dynamic
|
|
!!! gnewbg
|
|
!!! gnewbg-float
|
|
!!! gnewbg-dynamic
|
|
!!! gnext
|
|
!!! gprev
|
|
!!! gnext-with-window
|
|
!!! gprev-with-window
|
|
!!! gother
|
|
!!! gmerge
|
|
!!! groups
|
|
!!! vgroups
|
|
!!! gselect
|
|
!!! gmove
|
|
!!! gmove-and-follow
|
|
!!! gmove-marked
|
|
!!! gkill
|
|
!!! gkill-other
|
|
!!! grename
|
|
!!! grouplist
|
|
|
|
### *list-hidden-groups*
|
|
### *group-top-maps*
|
|
### *default-group-name*
|
|
|
|
@@@ add-group
|
|
@@@ group-add-head
|
|
@@@ group-add-window
|
|
@@@ group-button-press
|
|
@@@ group-current-head
|
|
@@@ group-current-window
|
|
@@@ group-delete-window
|
|
@@@ group-focus-window
|
|
@@@ group-indicate-focus
|
|
@@@ group-lost-focus
|
|
@@@ group-move-request
|
|
@@@ group-raise-request
|
|
@@@ group-remove-head
|
|
@@@ group-before-resize-head
|
|
@@@ group-after-resize-head
|
|
@@@ group-resize-request
|
|
@@@ group-root-exposure
|
|
@@@ group-startup
|
|
@@@ group-suspend
|
|
@@@ group-sync-all-heads
|
|
@@@ group-sync-head
|
|
@@@ group-wake-up
|
|
|
|
@@@ really-raise-window
|
|
### *run-or-raise-all-groups*
|
|
|
|
@menu
|
|
* Customizing Groups::
|
|
@end menu
|
|
|
|
@node Customizing Groups, , Groups, Groups
|
|
@section Customizing Groups
|
|
|
|
### *group-formatters*
|
|
### *group-format*
|
|
|
|
@@@ current-group
|
|
|
|
@node Screens, Minor Modes, Groups, Top
|
|
@chapter Screens
|
|
StumpWM handles multiple screens.
|
|
|
|
!!! snext
|
|
!!! sprev
|
|
!!! sother
|
|
|
|
|
|
### *run-or-raise-all-screens*
|
|
|
|
@menu
|
|
* External Monitors::
|
|
* Programming With Screens::
|
|
@end menu
|
|
|
|
@node External Monitors, Programming With Screens, Screens, Screens
|
|
@section External Monitors
|
|
StumpWM refers to each monitor as a head. Heads are logically
|
|
contained by screens. In a dual-monitor configuration, there will be
|
|
one screen with two heads. Non-rectangular layouts are supported
|
|
(frames will not be created in the 'dead zone'.) And message windows
|
|
will be displayed on the current head--that is, the head to which the
|
|
currently focused frame belongs.
|
|
|
|
In addition, StumpWM listens for XRandR events and re-configures the
|
|
heads to match the new monitor configuration. Occasionally StumpWM
|
|
will miss an XRandR event, use @code{refresh-heads} to synchronize
|
|
the head configuration.
|
|
|
|
!!! refresh-heads
|
|
|
|
@node Programming With Screens, , External Monitors, Screens
|
|
@section Programming With Screens
|
|
|
|
@@@ current-screen
|
|
|
|
@@@ screen-current-window
|
|
|
|
@@@ current-window
|
|
|
|
### *screen-list*
|
|
|
|
@node Minor Modes, Internals, Screens, Top
|
|
@chapter Minor Modes
|
|
|
|
Like Emacs, StumpWM has the concept of minor modes. These are defined by
|
|
the macro @code{DEFINE-MINOR-MODE}. Defining a minor mode creates a
|
|
class and a set of methods specializing upon it. Minor modes are scoped
|
|
to a window, head, group, or screen, or they may be unscoped. In
|
|
addition to this minor modes may be local or global. When a minor mode
|
|
is global all new instances of the scope object will be created with the
|
|
minor mode already active in them. Minor modes define their own top
|
|
level and root level keymaps, as well as hooks that are run upon
|
|
enabling or disabling the minor mode, and a lighter to display in the
|
|
mode line.
|
|
|
|
Minor modes are mixins that get added to the appropriate scope object
|
|
when enabled. As such minor modes allow the augmenting, modifying, and
|
|
overriding of default StumpWM behavior by defining methods for the
|
|
generic functions of the scope object. For example, a minor mode may be
|
|
scoped to a window and define a method for the generic function
|
|
@code{UPDATE-DECORATION} to change how window decoration is handled for
|
|
the windows it is enabled in.
|
|
|
|
%%% define-minor-mode
|
|
|
|
@menu
|
|
* Programming With Minor Modes::
|
|
* Minor Mode Scopes::
|
|
* Minor Mode Example::
|
|
@end menu
|
|
|
|
@node Programming With Minor Modes, Minor Mode Scopes, Minor Modes, Minor Modes
|
|
@section Programming With Minor Modes
|
|
|
|
Minor modes get their power from their ability to override and augment
|
|
generic functions which are called with the minor mode's scope object as
|
|
an argument. If you find a function whose behavior you wish to augment
|
|
or override in the process of writing a minor mode, open an issue or
|
|
submit a PR to generify the function. Generification is easily done like
|
|
so:
|
|
|
|
@example
|
|
(defun somefun (a b)
|
|
"docstring"
|
|
(otherfun (+ a b)))
|
|
;; the above becomes
|
|
(defgeneric somefun (a b)
|
|
(:documentation "docstring")
|
|
(:method (a b)
|
|
(otherfun (+ a b))))
|
|
@end example
|
|
|
|
When defining a minor mode, the programmer may desire to perform setup
|
|
for the minor mode. This is can be done in three ways. The first is to
|
|
hang a function upon the minor modes enable hook. However this runs the
|
|
risk of users potentially clobbering the initialization function, or
|
|
modifying the hook such that the initialization function is not the
|
|
first function run. The second way is to define a method for the generic
|
|
function @code{update-instance-for-different-class}. This function
|
|
should specialize upon the minor mode as the second argument. As a final
|
|
option, one can define before, after, and around methods for the generic
|
|
function @code{autoenable-minor-mode} if and only if the method does not
|
|
access any slots within the object.
|
|
|
|
One of the pitfalls of minor modes is that they are ultimately enabled
|
|
by calling @code{change-class}, which places some restrictions upon
|
|
where they can be enabled. Specifically, it is implied to be undefined
|
|
behavior if a minor mode is enabled in an object from within a method
|
|
which accesses slots of that object. While in practice this has not
|
|
proven to be an issue at the time of writing, this is undefined behavior
|
|
and future versions of SBCL may break if this is done.
|
|
|
|
When writing a minor mode, it is often useful to separate out the
|
|
desired functionality into its own mixin classes and use those in the
|
|
superclass list of the minor mode. For example:
|
|
|
|
@example
|
|
(define-minor-mode my-mode (my-mixin minor-mode) ())
|
|
@end example
|
|
|
|
This prevents issues with inheritance and dynamic mixins from cropping
|
|
up. Since minor modes are just classes, a minor mode can descend from
|
|
another minor mode. However after enabling the subclass minor mode, the
|
|
superclass minor mode cannot be enabled. However if the superclass minor
|
|
mode is enabled first, then the subclass minor mode can be enabled. The
|
|
easiest way around this is the aforementioned approach of mixins.
|
|
As an example of the inheritance issue, take the following minor mode
|
|
definitions:
|
|
|
|
@example
|
|
(define-minor-mode x () ())
|
|
(define-minor-mode y (x) ())
|
|
|
|
(enable-minor-mode 'x)
|
|
(enable-minor-mode 'y) ; both modes are enabled
|
|
;; As opposed to
|
|
(enable-minor-mode 'y)
|
|
(enable-minor-mode 'x) ; signals an error
|
|
@end example
|
|
|
|
|
|
When enabling and disabling minor modes theres a set of generic
|
|
functions in charge of determining what object to mix the minor mode in
|
|
to and whether or not to mix it.
|
|
|
|
@@@ autoenable-minor-mode
|
|
|
|
Defining a minor mode defines a main method for this generic function
|
|
which will mix the minor mode into the scope object when called and
|
|
returns T. This method specializes upon the minor mode symbol and the
|
|
scope type. The minor mode will only be enabled and the hooks run when
|
|
the function @code{ENABLE-WHEN} returns T. Any before after or around
|
|
methods for this function must not access any slots.
|
|
|
|
@@@ autodisable-minor-mode
|
|
|
|
Defining a minor mode defines a main method for this generic function
|
|
which specializes upon the mode symbol and the mode, and removes the
|
|
minor mode from the object. Any methods for this function must not
|
|
access any slots.
|
|
|
|
@@@ enable-when
|
|
|
|
Outside of autoenabling and autodisabling minor modes, there are several
|
|
generic functions which dispatch upon minor modes and their names.
|
|
|
|
@@@ minor-mode-global-p
|
|
@@@ minor-mode-scope
|
|
@@@ minor-mode-enable-hook
|
|
@@@ minor-mode-disable-hook
|
|
@@@ minor-mode-hook
|
|
|
|
@@@ minor-mode-keymap
|
|
|
|
This function has a set of main methods defined which all call the next
|
|
method to obtain a list of top maps for every minor mode. Any extra
|
|
keymaps one wishes to add to the minor mode may be added by defining a
|
|
main method which calls @code{call-next-method} and returns a flat
|
|
list. Similarly, an around method may be used which abides by the same
|
|
rules.
|
|
|
|
@@@ minor-mode-lighter
|
|
|
|
This function operates similarly to @code{minor-mode-keymap}, with a
|
|
main method defined for every minor mode which calls
|
|
@code{call-next-method} and returns a flat list. In addition there is a
|
|
single around method defined which concatenates all these strings
|
|
together.
|
|
|
|
There are also a set of regular functions and special variables which
|
|
which may be of use when working with minor modes.
|
|
|
|
@@@ enable-minor-mode
|
|
@@@ disable-minor-mode
|
|
@@@ list-modes
|
|
@@@ list-minor-modes
|
|
@@@ current-minor-modes
|
|
@@@ minor-mode-enabled-p
|
|
@@@ find-minor-mode
|
|
|
|
### *minor-mode*
|
|
### *minor-mode-enable-hook*
|
|
### *minor-mode-disable-hook*
|
|
### *unscoped-minor-modes*
|
|
|
|
€€€ minor-mode
|
|
|
|
@node Minor Mode Scopes, Minor Mode Example, Programming With Minor Modes, Minor Modes
|
|
@section Minor Mode Scopes
|
|
|
|
Minor modes can be scoped to different objects in a rather arbitrary
|
|
manner. These scopes are defined by the macro
|
|
@code{DEFINE-MINOR-MODE-SCOPE}. Because minor modes are implemented as
|
|
mixins, the object returned by a scopes current object function must be
|
|
a class instance.
|
|
|
|
%%% define-minor-mode-scope
|
|
|
|
%%% define-descended-minor-mode-scope
|
|
|
|
@@@ add-minor-mode-scope
|
|
|
|
When a minor mode is defined its scope is looked up and validated by the
|
|
function @code{VALIDATE-SCOPE}. This function takes a scope and a list
|
|
of superclasses, and ensures that the scope can descend from the
|
|
superclasses scopes. This restricts the valid scopes to ensure that a
|
|
minor mode scoped to @code{:GROUP} cant be a subclass of a minor mode
|
|
scoped to @code{:WINDOW}, for example. However there is a way to
|
|
override this by explicitly stating that two otherwise incompatible
|
|
scopes are compatible. This is done by defining methods for the generic
|
|
function @code{VALIDATE-SUPERSCOPE} which specialize upon the scope
|
|
designators. Such methods should return at least one value, indicating
|
|
if the superscope is a valid parent of the scope. If multiple values are
|
|
returned, the second value must indicate whether the superscope is an
|
|
invalid parent of the scope. For example:
|
|
|
|
@verbatim
|
|
(defmethod stumpwm:validate-superscope ((c (eql :id1)) (p (eql :id2)))
|
|
"Explicitly allow id1 to descend from id2"
|
|
(values t nil))
|
|
|
|
(defmethod stumpwm:validate-superscope ((c (eql :id3)) (p (eql :id4)))
|
|
"Explicitly prevent id3 from descending from id4"
|
|
(values nil t))
|
|
@end verbatim
|
|
|
|
When defining and using scopes the type specifier is important; it is
|
|
used to determine what minor modes should be mixed into an object when
|
|
it is created. For this reason it is important when defining a minor
|
|
mode or minor mode scope to understand the type hierarchy. It may also
|
|
be in the programmers best interests to define an accompanying type.
|
|
|
|
Below is an example of a minor mode scope definition that descends from
|
|
the @code{:WINDOW} scope, and is restricted to only firefox
|
|
windows. This would be used to implement a minor mode that only gets
|
|
mixed in to firefox windows, for example to implement key rebinding.
|
|
|
|
@verbatim
|
|
(defun %firefox-window-p (w)
|
|
(and (typep w 'window)
|
|
(string-equal (window-class window) "Firefox")))
|
|
|
|
(define-descended-minor-mode-scope :firefox-window :window
|
|
:filter-type (satisfies %firefox-window-p))
|
|
@end verbatim
|
|
|
|
The following scopes are predefined:
|
|
@itemize
|
|
@item
|
|
Designator: @code{:UNSCOPED}, type: @code{T}
|
|
Current object: return the global unscoped object.@*
|
|
|
|
@item
|
|
Designator: @code{:SCREEN}, type: @code{SCREEN}
|
|
Current object: return the current screen.@*
|
|
|
|
@item
|
|
Designator: @code{:GROUP}, type: @code{GROUP}
|
|
Current object: return the current group.@*
|
|
|
|
@item
|
|
Designator: @code{:TILE-GROUP}, type: @code{TILE-GROUP}
|
|
Current object: return the current group.@*
|
|
|
|
@item
|
|
Designator: @code{:DYNAMIC-GROUP}, type: @code{DYNAMIC-GROUP}
|
|
Current object: return the current group.@*
|
|
|
|
@item
|
|
Designator: @code{:FLOAT-GROUP}, type: @code{FLOAT-GROUP}
|
|
Current object: return the current group.@*
|
|
|
|
@item
|
|
Designator: @code{:TILING-NON-DYNAMIC-GROUP}, type: @code{TILE-GROUP}
|
|
Current object: return the current group when it is a non-dynamic tiling
|
|
group.@*
|
|
|
|
@item
|
|
Designator: @code{:HEAD}, type: @code{HEAD}
|
|
Current object: return the current head.@*
|
|
|
|
@item
|
|
Designator: @code{:FRAME}, type: @code{FRAME}
|
|
Current object: return the current frame when in a tiling group.@*
|
|
|
|
@item
|
|
Designator: @code{:FRAME-EXCLUDING-HEAD}, type: @code{ONLY-FRAME-NO-HEADS}
|
|
Descends from minor mode scope @code{:FRAME}.
|
|
|
|
@item
|
|
Designator: @code{:WINDOW}, type: @code{WINDOW}
|
|
|
|
Current object: return the current window.@*
|
|
All objects: collect every window from every group in the current screen.
|
|
|
|
@item
|
|
Designator: @code{:TILE-WINDOW}, type: @code{TILE-WINDOW}
|
|
|
|
Current object: return the current window.@*
|
|
All objects: collect every window from every tiling group, filtering all
|
|
floating windows.
|
|
|
|
@item
|
|
Designator: @code{:FLOAT-WINDOW}, type: @code{FLOAT-WINDOW}
|
|
|
|
Current object: return the current window.@*
|
|
All objects: colelct every window from every group, filtering all non
|
|
floating windows.
|
|
|
|
@end itemize
|
|
|
|
@node Minor Mode Example, , Minor Mode Scopes, Minor Modes
|
|
@section Minor Mode Example
|
|
|
|
A simple example of a minor mode is a version of the Emacs modes viper
|
|
or evil for StumpWM. Such a minor mode might look like this:
|
|
|
|
@verbatim
|
|
(define-minor-mode swm-evil-mode () ()
|
|
(:scope :screen)
|
|
(:interactive t)
|
|
(:top-map '(("i" . "swm-evil-mode")
|
|
("j" . "move-focus down")
|
|
("k" . "move-focus up")
|
|
("h" . "move-focus left")
|
|
("l" . "move-focus right")
|
|
("p" . "pull-hidden-previous")
|
|
("n" . "pull-hidden-next")
|
|
("S" . "hsplit")
|
|
("s" . "vsplit")
|
|
("r" . "remove-split")
|
|
("g" . *groups-map*)
|
|
("x" . *exchange-window-map*)))
|
|
(:lighter-make-clickable nil)
|
|
(:lighter "EVIL"))
|
|
@end verbatim
|
|
|
|
In the above example, the minor mode @code{swm-evil-mode} is defined,
|
|
alongside a command of the same name which toggles it on and off. The
|
|
minor mode is scoped to a screen, meaning that upon activation it will
|
|
be dynamically mixed in to the screen object. The lighter is the string
|
|
@code{"EVIL"} and the lighter is not made clickable.
|
|
|
|
When defining a minor mode top map it is important to avoid multi-key
|
|
bindings that clobber the prefix key. For example, if the prefix key is
|
|
@kbd{C-t} then defining the keybinding @kbd{C-t n} in the top map of a
|
|
minor mode is an error. Instead bind the key @kbd{n} in the minor mode's
|
|
root map.
|
|
|
|
As another example we can define a frame topbar mode. This should adjust
|
|
every frame to leave extra space at the top of the frame to display a
|
|
bar of some sort. The following assumes that the functions
|
|
@code{frame-display-height} and @code{frame-display-y} are generic.
|
|
|
|
@example
|
|
(defclass frame-topbar ()
|
|
((frame-topbar-height :initform 10 :accessor frame-topbar-height)))
|
|
|
|
(defmethod frame-display-height :around (group (frame frame-topbar))
|
|
(let ((height (call-next-method)))
|
|
(- height (frame-topbar-height frame))))
|
|
|
|
(defmethod frame-display-y :around (group (frame frame-topbar))
|
|
(let ((y (call-next-method)))
|
|
(+ y (frame-topbar-height frame))))
|
|
|
|
(define-minor-mode frame-bar (frame-topbar minor-mode) ()
|
|
(:global t)
|
|
(:scope :frame)
|
|
(:lighter "T-BAR")
|
|
(:interactive frame-topbar-mode))
|
|
|
|
(defmethod update-instance-for-different-class :after
|
|
(prev (obj frame-bar) &rest rest)
|
|
(declare (ignore prev rest))
|
|
(when (frame-window obj)
|
|
(let* ((group (window-group (frame-window obj)))
|
|
(windows (frame-windows group obj)))
|
|
(mapc #'maximize-window windows))))
|
|
@end example
|
|
|
|
In the above example, a class is defined which holds the height of the
|
|
frame topbar. Then two around methods are defined such that windows
|
|
querying the frame for their y position and height get an updated value
|
|
reflecting the topbars presence. Then a minor mode is defined which
|
|
inherits from the class we defined. It is scoped to frames and is a
|
|
global minor mode, so it will be enabled in all existing frames and any
|
|
other frames as they are created. Finally the initialization is handled
|
|
in the after method for update-instance-for-different-class, which
|
|
updates every window to have a new size which respects the topbar.
|
|
|
|
The implementation of the actual topbar is left as an exercise for the
|
|
reader.
|
|
|
|
@node Internals, Interacting With Unix, Minor Modes, Top
|
|
@chapter Internals
|
|
@menu
|
|
* IO Loop::
|
|
* Internal Functions Documentation::
|
|
@end menu
|
|
|
|
@node IO Loop, Internal Functions Documentation, , Internals
|
|
@section IO Loop
|
|
|
|
StumpWM's internal loop is implemented by a generic multiplexing I/O
|
|
loop for listening to I/O events from multiple sources. The model is
|
|
as follows:
|
|
|
|
An I/O multiplexer is represented as an object, with which I/O
|
|
channels can be registered to be monitored for events when the I/O
|
|
loop runs. An I/O channel is any object for which the generic
|
|
functions IO-CHANNEL-IOPORT, IO-CHANNEL-EVENTS and
|
|
IO-CHANNEL-HANDLE are implemented.
|
|
|
|
IO-CHANNEL-IOPORT, given an I/O multiplexer and an I/O channel,
|
|
should return the underlying system I/O facility that the channel
|
|
operates on. The actual objects used to represent an I/O facility
|
|
depends on the Lisp implementation, operating system and the
|
|
specific I/O loop implementation, but, for example, on Unix
|
|
implementations they will likely be numeric file descriptors. The
|
|
I/O loop implementation implements IO-CHANNEL-IOPORT methods for
|
|
the facilities it understands (such as FD-STREAMs on SBCL), so
|
|
user-implemented channels should simply call IO-CHANNEL-IOPORT
|
|
recursively on whatever it operates on.
|
|
|
|
IO-CHANNEL-EVENTS, given an I/O channel, should return a list of
|
|
the events that the channel is interested in. See the
|
|
documentation for IO-CHANNEL-EVENTS for further details.
|
|
|
|
The I/O loop guarantees that it will check what events a channel
|
|
is interested in when it is first registered, and also at any time
|
|
the channel has been notified of an event. If the channel changes
|
|
its mind at any other point in time, it should use the
|
|
IO-LOOP-UPDATE function to notify the I/O loop of such
|
|
changes. The I/O loop may very well also update spuriously at
|
|
other times, but such updates are not guaranteed.
|
|
|
|
IO-CHANNEL-HANDLE is called by the I/O loop to notify a channel of
|
|
an event.
|
|
|
|
An I/O multiplexer is created with a MAKE-INSTANCE call on the
|
|
class of the desired multiplexer implementation. If the code using
|
|
the multiplexer has no certain preferences on an implementation
|
|
(which should be the usual case), the variable *DEFAULT-IO-LOOP*
|
|
points to a class that should be generally optimal given the
|
|
current Lisp implementation and operating system.
|
|
|
|
Given a multiplexer, channels can be registered with it using
|
|
IO-LOOP-ADD, unregistered with IO-LOOP-REMOVE, and updated with
|
|
IO-LOOP-UPDATE (as described above). Call IO-LOOP on the
|
|
multiplexer to actually run it.
|
|
### *default-io-loop*
|
|
### *current-io-loop*
|
|
@@@ io-channel-ioport
|
|
@@@ io-channel-events
|
|
@@@ io-channel-handle
|
|
@@@ io-loop-add
|
|
@@@ io-loop-remove
|
|
@@@ io-loop-update
|
|
@@@ io-loop
|
|
|
|
@node Internal Functions Documentation, , IO Loop, Internals
|
|
@section Internal Functions Documentation
|
|
|
|
### *executing-stumpwm-command*
|
|
### *suppress-abort-messages*
|
|
!!! refresh-time-zone
|
|
!!! getsel
|
|
!!! putsel
|
|
!!! copy-unhandled-error
|
|
@@@ define-stumpwm-command
|
|
!!! set-contrib-dir
|
|
|
|
@node Interacting With Unix, Interacting With X11, Screens, Top
|
|
@chapter Interacting With Unix
|
|
|
|
!!! run-shell-command
|
|
|
|
@@@ programs-in-path
|
|
@@@ pathname-is-executable-p
|
|
@@@ pathname-as-directory
|
|
|
|
|
|
@@@ run-or-raise
|
|
### *shell-program*
|
|
|
|
@@@ getenv
|
|
@@@ (setf getenv)
|
|
|
|
@node Interacting With X11, Miscellaneous Commands, Interacting With Unix, Top
|
|
@chapter Interacting With X11
|
|
|
|
@@@ set-x-selection
|
|
@@@ get-x-selection
|
|
### *default-selections*
|
|
### *x-selection*
|
|
|
|
@node Miscellaneous Commands, Colors, Interacting With X11, Top
|
|
@chapter Miscellaneous Commands
|
|
The following is a list of commands that don't really fit in any other
|
|
@@@ split-string
|
|
|
|
@@@ argument-line-end-p
|
|
@@@ argument-pop
|
|
@@@ argument-pop-rest
|
|
### *display*
|
|
@@@ input-delete-region
|
|
@@@ input-goto-char
|
|
@@@ input-point
|
|
@@@ input-substring
|
|
@@@ input-validate-region
|
|
@@@ list-directory
|
|
%%% move-to-head
|
|
@@@ no-focus
|
|
### *record-last-msg-override*
|
|
### *toplevel-io*
|
|
|
|
@menu
|
|
* Menus::
|
|
* StumpWM's Data Directory::
|
|
* Debugging StumpWM::
|
|
* Sending a Bug Report::
|
|
* Timers::
|
|
* Getting Help::
|
|
@end menu
|
|
|
|
@node Menus, StumpWM's Data Directory, , Miscellaneous Commands
|
|
@section Menus
|
|
@section Menus
|
|
There are three different types of menus in StumpWM; single selection
|
|
menus; interactive menus; and batch menus. Single-selection menus, as
|
|
the name suggests, are used to pick a single item from a list.
|
|
Interactive menus are used for marking multiple selections. Batch
|
|
menus are used for performing actions on multiple menu items. Both
|
|
batch and interactive menus share the same navigational keybindings,
|
|
which are found in the table below. These can be customized by
|
|
modifying the @var{*menu-map*} variable. Commands specific to each
|
|
menu type can be modified by @var{*single-menu-map*} and
|
|
@var{*batch-menu-map*}.
|
|
|
|
@table @kbd
|
|
@item C-p
|
|
@itemx Up
|
|
@itemx k
|
|
Highlight the previous menu option.
|
|
|
|
@item C-n
|
|
@itemx Down
|
|
@itemx j
|
|
Highlight the next menu option.
|
|
|
|
@item S-Down
|
|
Scroll the entire page down one entry.
|
|
|
|
@item S-Up
|
|
Scroll the entire page up one entry.
|
|
|
|
@item PageUp
|
|
Scroll up one page.
|
|
|
|
@item PageDown
|
|
Scroll down one page.
|
|
|
|
@item C-g
|
|
@itemx ESC
|
|
Abort the menu.
|
|
|
|
@end table
|
|
|
|
In addition, you can customize the number of items shown at a time (a
|
|
page) with the @var{*menu-maximum-height*} variable. The default
|
|
value, @code{50}, limits the menu size to 50 items. Setting it to
|
|
@code{nil} will remove the limit on how many menu entries are shown
|
|
(be careful, this can crash X11 when attempting to display a large
|
|
amount of items).
|
|
|
|
### *menu-map*
|
|
@@@ menu-page-up
|
|
@@@ menu-page-down
|
|
@@@ menu-up
|
|
@@@ menu-down
|
|
@@@ menu-scroll-up
|
|
@@@ menu-scroll-down
|
|
@@@ menu-abort
|
|
@@@ menu-backspace
|
|
@@@ menu-entry-apply
|
|
@@@ menu-entry-display
|
|
@@@ menu-finish
|
|
@@@ command-menu
|
|
|
|
@subsection Single Selection Menus
|
|
Single selection menus can be searched; start typing when the menu is
|
|
active, and the results are immediately filtered. Use @key{RET} to
|
|
selected the highlighted option.
|
|
|
|
@table @kbd
|
|
|
|
@item RET
|
|
Select the highlighted option.
|
|
|
|
@end table
|
|
|
|
### *single-menu-map*
|
|
@@@ select-from-menu
|
|
|
|
@subsection Batch Menus
|
|
Batch menus provide a menu that allows the user to mark items. Items
|
|
are marked by highlighting an item, then pressing a corresponding
|
|
key. The key pressed depends on the menu being shown, and the desired
|
|
action. For example, in a menu allowing users to manage windows,
|
|
windows to be closed/removed could be marked by @key{d}, and windows
|
|
to be raised could be marked by @key{r}. All available actions and
|
|
their keybindings are shown below. These can be customized with @var{*batch-menu-map*}.
|
|
|
|
@table @kbd
|
|
@item n
|
|
@item Space
|
|
Highlight the next item.
|
|
|
|
@item p
|
|
Highlight the previous item.
|
|
|
|
@item u
|
|
Unmark the selected item, then move the cursor down.
|
|
|
|
@item DEL
|
|
Unmark the selected item, then move the cursor up if it is not at the
|
|
top of the menu.
|
|
|
|
@item x
|
|
@item RET
|
|
Exit the menu and perform the actions associated with each mark.
|
|
|
|
@end table
|
|
### *batch-menu-map*
|
|
@@@ select-from-batch-menu
|
|
|
|
|
|
@node StumpWM's Data Directory, Debugging StumpWM, Menus, Miscellaneous Commands
|
|
@section StumpWM's Data Directory
|
|
If you want to store StumpWM data between sessions, the recommended
|
|
method is to store them in @file{~/.stumpwm.d/}. StumpWM supplies
|
|
some functions to make doing this easier.
|
|
|
|
### *data-dir*
|
|
@@@ data-dir-file
|
|
%%% with-data-file
|
|
|
|
@node Debugging StumpWM, Sending a Bug Report, StumpWM's Data Directory, Miscellaneous Commands
|
|
@section Debugging StumpWM
|
|
|
|
### *debug-level*
|
|
### *debug-stream*
|
|
### *debug-expose-events*
|
|
@@@ redirect-all-output
|
|
|
|
@node Sending a Bug Report, Timers, Debugging StumpWM, Miscellaneous Commands
|
|
@section Sending a Bug Report
|
|
While StumpWM's code-base is quite mature, it still contains some
|
|
bugs. If you encounter one here are some guidelines for making sure
|
|
the developers can fix it:
|
|
@itemize @bullet
|
|
@item
|
|
Include a procedure for reproducing the bug/bad behavior. Ideally this
|
|
will include numbered steps starting with instructions on how you
|
|
start StumpWM. Also include what the expected behavior was.
|
|
@item
|
|
Be as detailed as possible. Then add more detail!
|
|
@item
|
|
Make sure its not something you introduced by using an empty @file{.xinitrc}
|
|
containing only @samp{exec /path/to/stumpwm}.
|
|
@item
|
|
Make sure the bug is present even when @file{.stumpwmrc} is empty.
|
|
@item
|
|
If you are using the git version, include the hash of the master
|
|
branch, or better include the commit when you started to notice the
|
|
bug.
|
|
@item
|
|
If you have code that fixes the bug, then open a pull request at
|
|
@url{https://github.com/stumpwm/stumpwm/compare/}.
|
|
@item
|
|
If you don't have code to fix the bug, then open an issue at
|
|
@url{https://github.com/stumpwm/stumpwm/issues/new}.
|
|
@end itemize
|
|
|
|
@node Timers, Getting Help, Sending a Bug Report, Miscellaneous Commands
|
|
@section Timers
|
|
StumpWM has a timer system similar to that of @dfn{Emacs}.
|
|
|
|
@@@ idle-time
|
|
@@@ run-with-timer
|
|
@@@ cancel-timer
|
|
|
|
@defun timer-p @var{timer}
|
|
Return T if TIMER is a timer structure.
|
|
@end defun
|
|
|
|
@node Getting Help, , Timers, Miscellaneous Commands
|
|
@section Getting Help
|
|
|
|
!!! describe-key
|
|
!!! describe-variable
|
|
!!! describe-function
|
|
!!! describe-command
|
|
!!! where-is
|
|
!!! modifiers
|
|
!!! which-key-mode
|
|
|
|
@@@ lookup-command
|
|
|
|
### *help-map*
|
|
### *help-keys*
|
|
|
|
@node Colors, Hooks, Miscellaneous Commands, Top
|
|
@chapter Colors
|
|
When specifying a color, it is possible to use its X11 Color Name
|
|
(usually in the file @file{/etc/X11/rgb.txt}). You can also use a
|
|
six digit hex string prefixed by a '#' character in the same way that
|
|
you can specify colors in HTML.
|
|
|
|
All text printed by StumpWM is run through a coloring engine before
|
|
being displayed. All color commands start with a @samp{^} (caret)
|
|
character and apply to all text after it.
|
|
|
|
@table @code
|
|
@item ^0-9
|
|
A caret followed by a single digit number changes the foreground color
|
|
to the specified color. A @samp{*} can be used to specify the normal
|
|
color. See the color listing below.
|
|
|
|
@item ^0-90-9
|
|
A caret followed by two digits sets the foreground and background
|
|
color. The first digit refers to the foreground color and the second
|
|
digit to the background color. A @samp{*} can be used in place of
|
|
either digit to specify the normal color. See the color listing below.
|
|
|
|
@item ^B
|
|
Turn on bright colors.
|
|
|
|
@item ^b
|
|
Turn off bright colors.
|
|
|
|
@item ^n
|
|
Use the normal background and foreground color.
|
|
|
|
@item ^R
|
|
Reverse the foreground and background colors.
|
|
|
|
@item ^r
|
|
Turn off reverse colors.
|
|
|
|
@item ^[
|
|
Push the current colors onto the color stack. The current colors remain unchanged.
|
|
|
|
@item ^]
|
|
Pop the colors off the color stack.
|
|
|
|
@item ^>
|
|
Align the rest of the line to the right of the window.
|
|
|
|
@item ^f<n>
|
|
Sets the current font to the font at index n in the screen's font list.
|
|
|
|
@item ^(<modifier> &rest arguments)
|
|
Allows for more complicated color settings:
|
|
<modifier> can be one of :fg, :bg, :reverse, :bright, :push, :pop, :font and :>.
|
|
The arguments for each modifier differ:
|
|
|
|
@itemize
|
|
@item
|
|
:fg and :bg take a color as an argument, which can either be a numeric
|
|
index into the color map or a hexadecimal color in the form of "#fff"
|
|
or "#ffffff".
|
|
@item
|
|
:reverse and :bright take either t or nil as an argument. T enables
|
|
the setting and nil disables it.
|
|
@item
|
|
:push and :pop take no arguments. :push pushes the current settings onto
|
|
the color stack, leaving the current settings intact. :pop pops color
|
|
settings off the stack, updating the current settings.
|
|
@item
|
|
:font takes an integer that represents an index into the screen's
|
|
list of fonts, or, possibly, a literal font object that can
|
|
immediately be used. In a string you'll probably only want to specify
|
|
an integer.
|
|
@item
|
|
:> takes no arguments. It triggers right-alignment for the rest of the line.
|
|
@item
|
|
:on-click takes one or more arguments and registers the following text
|
|
area as clickable. The initial argument must be an ID registered using
|
|
the function REGISTER-ML-ON-CLICK-ID.
|
|
@item
|
|
:on-click-end takes no arguments. It marks the end of clickable text
|
|
begun by :on-click.
|
|
|
|
@end itemize
|
|
|
|
@item ^^
|
|
Print a regular caret.
|
|
@end table
|
|
|
|
The default colors are made to resemble the 16 VGA colors and are:
|
|
@table @asis
|
|
@item 0 black
|
|
@item 1 red
|
|
@item 2 green
|
|
@item 3 yellow
|
|
@item 4 blue
|
|
@item 5 magenta
|
|
@item 6 cyan
|
|
@item 7 white
|
|
@end table
|
|
|
|
There are only 8 colors by default but 10 available digits. The last
|
|
two digits are left up to the user. @ref{Behind The Scenes Look At
|
|
Colors} for information on customizing colors.
|
|
|
|
@menu
|
|
* Behind The Scenes Look At Colors::
|
|
@end menu
|
|
|
|
@node Behind The Scenes Look At Colors, , Colors, Colors
|
|
@section Behind The Scenes Look At Colors
|
|
|
|
Color indexes are stored in @var{*colors*} as a list. The default list
|
|
of colors leave 2 slots for the user to choose. If you'd like to use
|
|
@samp{Papaya Whip} and @samp{Dark Golden Rod 3} you might eval the
|
|
following:
|
|
|
|
@example
|
|
(setf *colors* (append *colors*
|
|
(list "PapayaWhip"
|
|
"DarkGoldenRod3")))
|
|
(update-color-map (current-screen))
|
|
@end example
|
|
|
|
Of course, you can change all the colors if you like.
|
|
|
|
Additionally, both the normal and bright versions of a color can be
|
|
specified by using a list of the form @code{(normal-color bright-color)},
|
|
for instance:
|
|
|
|
@example
|
|
(setf *colors* (append *colors*
|
|
(list (list "PeachPuff" "PapayaWhip")
|
|
(list "DarkGoldenRod3" "PaleGoldenrod"))))
|
|
(update-color-map (current-screen))
|
|
@end example
|
|
|
|
@@@ parse-color-string
|
|
@@@ uncolorify
|
|
### *colors*
|
|
@@@ update-color-map
|
|
|
|
@node Hooks, Modules, Colors, Top
|
|
@chapter Hooks
|
|
StumpWM exports a number of hooks you can use to add customizations;
|
|
like hooks in Emacs, you add to a hook with the @code{add-hook}
|
|
function. For example:
|
|
|
|
@example
|
|
(stumpwm:add-hook 'stumpwm:*new-window-hook* 'my-new-window-custos)
|
|
@end example
|
|
|
|
adds your @code{my-new-window-custos} function to the list of
|
|
functions called when a new window appears.
|
|
|
|
%%% add-hook
|
|
%%% remove-hook
|
|
%%% remove-all-hooks
|
|
@@@ run-hook
|
|
@@@ run-hook-with-args
|
|
|
|
The following hooks are available:
|
|
|
|
$$$ *new-window-hook*
|
|
$$$ *destroy-window-hook*
|
|
$$$ *focus-window-hook*
|
|
$$$ *place-window-hook*
|
|
$$$ *start-hook*
|
|
$$$ *internal-loop-hook*
|
|
$$$ *focus-frame-hook*
|
|
$$$ *new-frame-hook*
|
|
$$$ *message-hook*
|
|
$$$ *top-level-error-hook*
|
|
$$$ *focus-group-hook*
|
|
$$$ *hooks-enabled-p*
|
|
$$$ *remove-split-hook*
|
|
$$$ *key-press-hook*
|
|
$$$ *root-click-hook*
|
|
$$$ *click-hook*
|
|
$$$ *mode-line-click-hook*
|
|
$$$ *urgent-window-hook*
|
|
$$$ *event-processing-hook*
|
|
$$$ *pre-command-hook*
|
|
$$$ *post-command-hook*
|
|
$$$ *menu-selection-hook*
|
|
$$$ *new-head-hook*
|
|
$$$ *command-mode-end-hook*
|
|
$$$ *command-mode-start-hook*
|
|
$$$ *destroy-mode-line-hook*
|
|
$$$ *quit-hook*
|
|
$$$ *restart-hook*
|
|
$$$ *selection-notify-hook*
|
|
$$$ *split-frame-hook*
|
|
|
|
@node Modules, Hacking, Hooks, Top
|
|
@chapter Modules
|
|
A module is an ASDF system that adds additional functionality to
|
|
StumpWM. StumpWM searches for modules in the
|
|
@var{*data-dir*}@file{/modules} directory. By default this is
|
|
@file{~/.stumpwm.d/modules}.
|
|
|
|
Officially supported modules exist in a separate repository within the
|
|
StumpWM organization on github. You can install the latest copy by
|
|
issuing @command{make install-modules} from StumpWM's root source
|
|
directory. This will run:
|
|
@example
|
|
git clone git@@github.com:stumpwm/stumpwm-contrib.git ~/.stumpwm.d/modules
|
|
@end example
|
|
|
|
|
|
!!! load-module
|
|
@@@ list-modules
|
|
### *load-path*
|
|
!!! add-to-load-path
|
|
@@@ init-load-path
|
|
@@@ find-module
|
|
|
|
@menu
|
|
* Writing Modules::
|
|
@end menu
|
|
|
|
@node Writing Modules, , Modules, Modules
|
|
@section Writing Modules
|
|
Make sure to read @ref{Hacking}. If you are familiar with writing lisp
|
|
packages for ASDF then you can jump in and get started. In either
|
|
case, quicklisp ships a @code{quickproject} package that makes setting
|
|
up a new module very easy. After installing quicklisp (see the
|
|
README.md for a link):
|
|
|
|
We're going to put our new module in the @file{modules/} directory of
|
|
@var{*data-dir*} so that it will be immediately loadable by StumpWM.
|
|
|
|
First make the directory @file{new-module}, then from a REPL issue:
|
|
@example
|
|
(ql:quickload "quickproject")
|
|
(quickproject:make-project #p"~/.stumpwm.d/modules/new-module" :depends-on '(stumpwm) :name "new-module")
|
|
@end example
|
|
This will create:
|
|
@example
|
|
-rw-rw-r-- 1 dave dave 68 Apr 6 19:38 package.lisp
|
|
-rw-rw-r-- 1 dave dave 53 Mar 16 2014 README.txt
|
|
-rw-rw-r-- 1 dave dave 271 Mar 16 2014 new-module.asd
|
|
-rw-rw-r-- 1 dave dave 1.8K Apr 6 17:51 new-module.lisp
|
|
@end example
|
|
|
|
The file @file{new-module.lisp} will contain the actual implementation
|
|
of your module. ASDF requires two other files in order to understand
|
|
how to load and compile your module. They are @file{new-module.asd}
|
|
and @file{package.lisp}. In our example, @file{new-module.asd} should
|
|
contain:
|
|
@example
|
|
(asdf:defsystem #:new-module
|
|
:serial t
|
|
:description "Describe new-module here"
|
|
:author "Anne N. O'Nymous"
|
|
:license "GPLv3"
|
|
:depends-on (#:stumpwm)
|
|
:components ((:file "package")
|
|
(:file "new-module"))) ; any other files you make go here
|
|
@end example
|
|
The @file{package.lisp} will contain:
|
|
@example
|
|
(defpackage #:new-module
|
|
(:use #:cl :stumpwm))
|
|
@end example
|
|
With these two files defined, and the implementation written in
|
|
@file{new-module.lisp}, you should be able to load your module.
|
|
|
|
Before we load it, we have to add the path to our @var{*load-path*}.
|
|
This can be accomplished by running the following from a REPL:
|
|
@example
|
|
(stumpwm:add-to-load-path "~/.stumpwm.d/modules/new-module")
|
|
@end example
|
|
You can also run this interactively with @kbd{C-t ;}, which is bound
|
|
to the @command{colon} command.
|
|
|
|
Because we've put our module in a sub-directory of the default
|
|
@var{*module-dir*}, it will automatically get added to the
|
|
@var{*load-path*} the next time StumpWM starts. If you choose to
|
|
develop your module somewhere else (e.g.
|
|
@file{~/quicklisp/local-projects}), then you'll have add
|
|
@example
|
|
(add-to-load-path "~/quicklisp/local-projects/new-module")
|
|
@end example
|
|
to your @file{.stumpwmrc}.
|
|
|
|
When you've finished writing your module, you can distribute it
|
|
however you see fit. If it becomes very popular, or you would like
|
|
the StumpWM devs to maintain it (and they agree), you can have your
|
|
module merged with the stumpwm-contrib repository on github, just open
|
|
a pull request to start the discussion.
|
|
|
|
@node Hacking, Advanced Configuration, Modules, Top
|
|
@chapter Hacking
|
|
|
|
@menu
|
|
* General Advice::
|
|
* Adding Documentation and Editing This Manual::
|
|
* Using git with StumpWM::
|
|
* Sending Patches::
|
|
@end menu
|
|
|
|
@node General Advice, Adding Documentation and Editing This Manual, Hacking, Hacking
|
|
@section Hacking: General Advice
|
|
|
|
@enumerate
|
|
|
|
@item
|
|
Pay attention to file names and contents. If you're making changes to
|
|
mode-line related code, don't put it in @file{core.lisp}. If you're
|
|
introducing some completely new featureset, consider putting all of
|
|
the new code in a new file.
|
|
|
|
@item
|
|
Does a command need to be user-visible (``interactive'') or is it just
|
|
called by other commands?
|
|
|
|
@itemize
|
|
@item
|
|
If it's not going to be user-visible, you can just use the familiar
|
|
@code{(defun foo () ...)} syntax.
|
|
|
|
@item
|
|
If you want the command to be used interactively, you use StumpWM's
|
|
@code{defcommand} syntax, as in the examples below.
|
|
|
|
@example
|
|
(defcommand test (foo bar)
|
|
((:string "How you're going to prompt for variable foo: ")
|
|
(:number "How you want to prompt for variable bar: "))
|
|
"This command is a test"
|
|
(body...))
|
|
|
|
(defcommand test2 () ()
|
|
"This is also a test"
|
|
(body...))
|
|
|
|
(defcommand title (args) (interactive-args)
|
|
"Doc string"
|
|
(body...))
|
|
@end example
|
|
|
|
So basically, inside the first set of parentheses after the
|
|
function name, you specify what (if any) arguments will be passed to
|
|
the command. The second set of parentheses tells StumpWM how to get
|
|
those arguments if they're not explicitly passed to the command. For
|
|
example,
|
|
|
|
@example
|
|
((:string "What do you want to do: "))
|
|
@end example
|
|
|
|
will read a string from the input the user provides. The quoted
|
|
text is the prompt the user will see. Of course, if you were to, say,
|
|
call the command test, as defined above, from another piece of code,
|
|
it wouldn't give the prompt as long as you fed it arguments.
|
|
@end itemize
|
|
|
|
@item
|
|
Note that all commands defined using the @code{defcommand} syntax are
|
|
available both to be called with @kbd{C-t ;} and from within other lisp
|
|
programs, as though they had been defun-ned (which, in fact, they
|
|
have).
|
|
|
|
@item
|
|
Any code that depends on external libraries or programs that some
|
|
users might not have installed should be packaged as a module and
|
|
placed in the @file{*data-dir*/modules/} directory.
|
|
|
|
@item
|
|
Don't be afraid to submit your patches to the StumpWM mailing list!
|
|
It may not immediately make it into the official git repository, but
|
|
individual users might find it useful and apply it to their own setup,
|
|
or might be willing to offer suggestions on how to improve the code.
|
|
|
|
@end enumerate
|
|
|
|
@node Adding Documentation and Editing This Manual, Using git with StumpWM, General Advice, Hacking
|
|
@section Hacking: Adding Documentation and Editing This Manual
|
|
|
|
The manual is written in @command{texinfo}, so you may want to read
|
|
that manual. The @file{stumpwm.texi.in} is processed by StumpWM with
|
|
some additional markup in the form of three letter character entries
|
|
@c need to double up the at-signs in the @code{@@@ function} to escape
|
|
@c them.
|
|
at the beginning of a line. @code{@@@@@@ function} defines functions,
|
|
@code{%%% some-macro} expands to that macro and its docstring, etc.
|
|
Contributors are strongly encouraged to add these items to this manual
|
|
whenever something new is defined in a patch. You can test if your
|
|
texinfo edits are valid by generating them with
|
|
@command{make stumpwm.info}, and viewing the new @file{stumpwm.info} with
|
|
@command{info -f /path/to/stumpwm.info}, or @command{make
|
|
stumpwm.texi} for the raw stuff.
|
|
|
|
@table @asis
|
|
@item %%% macro
|
|
@item @@@@@@ function
|
|
@item ### variable
|
|
@item $$$ hook
|
|
@item !!! StumpWM command
|
|
@end table
|
|
|
|
@node Using git with StumpWM, Sending Patches, Adding Documentation and Editing This Manual, Hacking
|
|
@section Hacking: Using git with StumpWM
|
|
|
|
For quite a while now, StumpWM has been using the git version control
|
|
system for development. If you're using one of the official
|
|
releases, you can get the bleeding-edge source code from the official
|
|
git repository with a single command:
|
|
|
|
@example
|
|
$ git clone git@@github.com:stumpwm/stumpwm.git
|
|
@end example
|
|
|
|
After this, you'll have a complete git repository, along with the
|
|
complete revision history since the switch. Feel free to play around;
|
|
git has some important features that actually make this safe!
|
|
|
|
Before we get to that stuff, though, you're going to want to tell git
|
|
about yourself so that your information is included in your commits
|
|
and patches. The very minimum you're going to want to do is:
|
|
|
|
@example
|
|
$ git config --global user.name "Anne N. O'Nymous"
|
|
$ git config --global user.email "anonymous@@foo.org"
|
|
@end example
|
|
|
|
Be sure to check out the manual for @command{git-config}--there are several
|
|
options you might want to set, such as enabling colorized output or
|
|
changing the editor and pager you use when making commits and viewing
|
|
logs.
|
|
|
|
For the sake of argument, let's say you want to make some major
|
|
changes to both @file{user.lisp} and @file{core.lisp}, add a file
|
|
called @file{DANGEROUS_EXPERIMENT_DO_NOT_USE_OR_@-ELSE.lisp}, and
|
|
remove the manual because you're too 1337 for such things. However,
|
|
you don't want to break your entire StumpWM setup and start over.
|
|
Thankfully, you don't have to. Before you get started, issue this
|
|
command from the StumpWM source directory:
|
|
|
|
@example
|
|
$ git checkout -b experimental
|
|
@end example
|
|
|
|
You should now find yourself in a new branch, called experimental. To
|
|
confirm this, type @command{git branch}; there should be
|
|
an asterisk next to the branch you're currently viewing. At any time,
|
|
you can type @command{git checkout master} to return to your master branch,
|
|
and at any time you can have as many branches of the project as you
|
|
like. If you want to create a new branch based not on the master
|
|
branch but on your experimental branch, for example, you'd type:
|
|
|
|
@example
|
|
$ git checkout -b new-experiment experimental
|
|
@end example
|
|
|
|
This will place you in a newly-created branch called ``new-experiment''
|
|
which should be identical to your experimental branch as of the last
|
|
commit (more on that soon). If you're actually typing out the
|
|
directions, switch back to your old experimental branch like so:
|
|
|
|
@example
|
|
$ git checkout experimental
|
|
@end example
|
|
|
|
Anyway, now that you have a new branch, create that new file with the
|
|
long name, which we'll just call @file{danger.lisp} for brevity. Make whatever
|
|
changes you want to it, and when you're done, tell git about your new
|
|
file.
|
|
|
|
@example
|
|
$ git add dangerous.lisp
|
|
@end example
|
|
|
|
Now, let's pretend you're done making changes. Tell git you're done
|
|
for now:
|
|
|
|
@example
|
|
$ git commit
|
|
@end example
|
|
|
|
This will open up a prompt in your editor of choice for you to
|
|
describe your changes. Try to keep the first line short, and then add
|
|
more explanation underneath (for an example, run the command @command{git log}
|
|
and take a look at some of the longer commit explanations). Save that
|
|
file and then do this:
|
|
|
|
@example
|
|
$ git checkout master
|
|
$ ls
|
|
@end example
|
|
|
|
Then look for your new file. It's not there! That's because you've
|
|
done all of your work in another branch, which git is currently hiding
|
|
from you so that you can ``check out'' the branch called ``master.'' All
|
|
is as it should be---your master repository is still safe.
|
|
|
|
@example
|
|
$ git checkout experimental
|
|
@end example
|
|
|
|
Now, delete @file{manual.lisp} and @file{stumpwm.texi}. That's right. Wipe them off
|
|
the face of the Earth, or at least off the hard drive of your
|
|
computer. When you're done, you don't have to tell git you've deleted
|
|
them; it'll figure it out on its own (though things may not compile
|
|
properly unless you edit @file{Makefile.in} and @file{stumpwm.asd}. Anyway, go ahead
|
|
and edit @file{core.lisp} and @file{user.lisp}. Really break 'em. Run free! When
|
|
you're done, do another commit, as above, and give it a stupid title
|
|
like ``lolz i b0rked stUmpwm guys wTF!?!?!!111!'' Now try to compile.
|
|
Just try. It won't work. If it does, you're some kind of savant or
|
|
something. Keep up the good work. If you've actually managed to break
|
|
StumpWM like you were supposed to, never fear! You have two options at
|
|
this point.
|
|
|
|
One is to go back to the master branch (with another git checkout) and
|
|
just delete your experimental branch, like so:
|
|
|
|
@example
|
|
$ git branch -D
|
|
@end example
|
|
|
|
The ``@code{-D}'' means to force a delete, even if the changes you've made
|
|
aren't available elsewhere. A ``@code{-d}'' means to delete the branch if and
|
|
only if you've merged the changes in elsewhere.
|
|
|
|
The other option is to create patches for each of your commits so far,
|
|
delete the branch, and then apply any working/wanted patches in a new
|
|
branch. Create your patches (after committing) like so:
|
|
|
|
@example
|
|
$ git format-patch -o patches origin
|
|
@end example
|
|
|
|
(Before doing that you can review your changes with @command{git log origin..})
|
|
|
|
You can also use the @command{format-patch} command to create a patch of working
|
|
code to send in to the mailing list.
|
|
|
|
A developer might ask you to try out something they're working on. To
|
|
fetch their master branch, you'd do this:
|
|
|
|
@example
|
|
$ git remote add -f -m master -t master foo git://bar.org/~foo/stumpwm
|
|
@end example
|
|
|
|
Here, ``foo'' is the shorthand name you'll use to refer to that
|
|
repository in the future. To checkout a local copy of that repository,
|
|
you'd then do
|
|
|
|
@example
|
|
$ git checkout --track -b foo-master foo/master
|
|
@end example
|
|
|
|
Later you could use @command{git pull foo} to update while looking at that
|
|
branch (and note that @command{git pull} with no arguments, in the master
|
|
branch, will update your StumpWM from the official repository).
|
|
|
|
Finally, if you want to move your experimental changes into your
|
|
master branch, you'd checkout your master branch and run:
|
|
|
|
@example
|
|
$ git merge experimental
|
|
@end example
|
|
|
|
If there are file conflicts, @command{git diff} will show you where they are;
|
|
you have to fix them by hand. When you're done, do another
|
|
|
|
@example
|
|
$ git commit -a
|
|
@end example
|
|
|
|
to finalize the changes to your master branch. You can then delete
|
|
your experimental branch. Alternately, you can wait until your changes
|
|
(assuming you sent them in) make it into the official repository
|
|
before deleting your experimental branch.
|
|
|
|
@node Sending Patches, , Using git with StumpWM, Hacking
|
|
@section Sending Patches
|
|
While patches are still welcome on the mailing list, StumpWM's
|
|
development has mostly migrated to github's issue tracker. This means
|
|
you can open a pull request to submit a patch to StumpWM. The
|
|
following guidelines apply to pull requests and patches sent to the
|
|
mailing list.
|
|
|
|
@itemize
|
|
@item
|
|
Make sure it applies clean to the main git repository
|
|
|
|
@item
|
|
Ensure that you aren't introducing tabs, extra blank lines, or whitespace at the end of lines.
|
|
|
|
@item
|
|
Ensure your patch doesn't contain irrelevant indenting or reformatting changes.
|
|
|
|
@item
|
|
Try to make your patch address a single issue. If your patch changes
|
|
two unrelated issues, break them into two seperate patches that can
|
|
stand on their own.
|
|
|
|
@item
|
|
Don't send intermediate patches. When you're working on a feature you
|
|
might make several commits to your local repository as you refine it
|
|
and work out the bugs. When it's polished and ready to ship, send it
|
|
as one patch! Sometimes it makes sense to send it as multiple patches
|
|
if each patch contains a discrete feature or bug fix that can stand on
|
|
its own. If one of your patches changes code that was added or
|
|
modified in an earlier patch, consider merging them together and
|
|
sending them as one.
|
|
|
|
@end itemize
|
|
|
|
@node Advanced Configuration, Command and Function Index, Hacking, Top
|
|
@chapter Advanced Configuration
|
|
|
|
### *default-package*
|
|
### *default-bg-color*
|
|
@@@ run-commands
|
|
### *startup-message*
|
|
### *list-hidden-groups*
|
|
%%% defprogram-shortcut
|
|
### *initializing*
|
|
!!! loadrc
|
|
### *ignore-wm-inc-hints*
|
|
### *max-last-message-size*
|
|
### *module-dir*
|
|
@@@ set-module-dir
|
|
### *mouse-focus-policy*
|
|
### *resize-hides-windows*
|
|
### *root-click-focuses-frame*
|
|
### *suppress-frame-indicator*
|
|
### *suppress-window-placement-indicator*
|
|
### *text-color*
|
|
### *draw-in-color*
|
|
### *timeout-frame-indicator-wait*
|
|
### *top-level-error-action*
|
|
|
|
|
|
@node Command and Function Index, Variable Index, Advanced Configuration, Top
|
|
@unnumbered Command and Function Index
|
|
@printindex fn
|
|
|
|
@node Variable Index, , Command and Function Index, Top
|
|
@unnumbered Variable Index
|
|
@printindex vr
|
|
|
|
@bye
|