wmii/doc/customizing.tex
2011-09-23 20:35:20 -07:00

943 lines
32 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\chapter{Customizing \wmii}
There are several configuration schemes available for \wmii. If
you're only looking to add basic key bindings, status monitors,
\emph{et cetera}, you should have no trouble modifying the stock
configuration for your language of choice. If you're looking for
deeper knowledge of \wmii's control interface though, this
section is for you. We'll proceed by building a configuration
script in \POSIX\ |sh| syntax and then move on to a discussion
of the higher level constructs in the stock configuration
scripts.
For the purposes of pedagogy, we'll construct the script in the
literate programming style of Knuth, whereby we construct the
code in fragments and explain each one in detail. For your
convenience, each fragment name is linked to its definition.
\section{Events}
The \wmii\ control interface is largely event driven. Each event
is represented by a single, plain-text line written to the
|/event| file. You can think of this file as a named pipe. When
reading it, you won't receive an EOF\footnote{End of File} until
\wmii\ exits. Moreover, any lines written to the file will be
transmitted to everyone currently reading from it. Notable
events include key presses, the creation and destruction of
windows, and changes of focus and views.
We'll start building our configuration with an event processing
framework:
\begin{Fragment}{Event Loop}
# Broadcast a custom event
wmiir xwrite /event Start wmiirc
# Turn off globbing
set -f
# Open /event for reading
wmiir read /event |
# Read the events line by line
while read line; do
# Split the line into words, store in $@
set -- $line
event=$1; shift
line = "$(echo $line | sed s/^[^ ]* // | tr -d \n)"
# Process the event
case $event in
Start) # Quit when a new instance starts
[ $1 = wmiirc ] && exit;;
«Event Handlers»
esac
done
\end{Fragment}
Now, we need to consider which types of events we'll need to
handle:
\begin{Fragment}{Event Handlers}
«View Button Events»
«Urgency Events»
«Unresponsive Clients»
«Notice Events»
«Key Events»
«Client Menu Events»
«Tag Menu Events»
\end{Fragment}
\section{Bar Items}
The bar is described by the files in the two directories |/lbar/| and
|/rbar/| for buttons on the left and right side of the bar,
respectively. The files act as control files (section
\ref{sec:controlfiles}) with the contents:
\begin{code}
color Color Tuple
label Label
\end{code}
A Color Tuple is defined as:
\begin{code}
Color Tupleforeground color background color border color
* ColorRGB color | RGBA color
RGB color6 character RGB hex color code
RGBA color ≔ rgba:red/green/blue/alpha
\end{code}
\noindent
where all of the colors are represented as lowercase,
hexidecimal values. In the case of RGBA colors, they may be 1--4
characters long, though they will be standardized internally to
2 characters.
\medskip
Let's define our basic theme information now:
\begin{Fragment}{Theme Definitions}
normcolors=000000 c1c48b 81654f
focuscolors=000000 81654f 000000
background=333333
font=drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*
\end{Fragment}
\subsection{View Buttons}
With a basic understanding of bar items in mind, we can write
our view event handlers:
\index{events!CreateTag}
\index{events!DestroyTag}
\index{events!FocusTag}
\index{events!UnfocusTag}
\begin{Fragment}{View Button Events}
CreateTag) # CreateTag Tag Name
echo $normcolors $1 | wmiir create /lbar/$1;;
DestroyTag) # DestroyTag Tag Name
wmiir rm /lbar/$1;;
FocusTag) # FocusTag Tag Name
wmiir xwrite /lbar/$1 $focuscolors $1;;
UnfocusTag) # UnfocusTag Tag Name
wmiir xwrite /lbar/$1 $normcolors $1;;
\end{Fragment}
\subsection{Urgency}
\index{events!UrgentTag|(}
\index{events!NotUrgentTag|(}
Windows can specify that they require attention, and in X11
parlance, this is called urgency\footnote{\ICCCM{4.1.2.4}}. When
a window requests attention as such, or declares that it's been
satisfied, \wmii\ broadcasts an event for the client and an
event for each view that it belongs to. It also fills in the
layout box of any client deemed urgent. It's the job of a script
to decide how to handle urgency events above and beyond that
basic measure. The standard scripts simply mark urgent views
with an asterisk:
\begin{Fragment}{Urgency Events}
# The urgency events are Client events when the program
# owning the window sets its urgency state. They're Manager
# events when wmii or the wmii user sets the state.
UrgentTag) # UrgentTag Client or Manager Tag Name
wmiir xwrite /lbar/$2 $2;;
NotUrgentTag) # NotUrgentTag Client or Manager Tag Name
wmiir xwrite /lbar/$2 $2;;
\end{Fragment}
\index{events!UrgentTag|)}
\index{events!NotUrgentTag|)}
\subsection{Notices}
The standard scripts provide a custom Notice event for
displaying status information. The events appear in the long bar
between the left and right sides for five seconds.
\begin{Fragment}{Notice Events}
Notice)
wmiir xwrite /rbar/!notice $line
kill $xpid 2>/dev/null # Let's hope this isn't reused...
{ sleep 5; wmiir xwrite /rbar/!notice ; } &
xpid = $!;;
\end{Fragment}
\section{Keys}
\label{sec:keybindings}
\index{key bindings}
\index{filesystem!/!keys}
\index{filesystem!/!event}
Now to the part you've no doubt been waiting for: binding keys.
When binding keys, you need to be aware of two files, |/keys|
and |/event|. The former defines which keys \wmii\ needs to
grab, and the latter broadcasts the events when they're pressed.
Key names are specified as a series of modifiers followed by a
key name, all separated by hyphens. Valid modifier names are
|Control|, |Shift|, |Mod1| (usually Alt), |Mod2|, |Mod3|, |Mod4|
(usually the Windows® key), and |Mod5|. Modifier keys can be
changed via |xmodmap(1)|, the details of which are beyond the
scope of this document.
Key names can be detected by running |xev| from a
terminal, pressing the desired key, and looking at the output
(it's in the parentheses, after the keysym). Or, more simply,
you can run the \man 1 {wikeyname} utility bundled with \wmii\
and press the key you wish to bind.
Examples of key bindings:
\begin{description}
\item[Windows® key + Capital A] |Mod4-Shift-A|
\item[Control + Alt + Space] |Mod1-Control-Space|
\end{description}
Now, let's bind the keys we plan on using:
\begin{Fragment}{Bind Keys}
{
cat <<!
Mod4-space
Mod4-d
Mod4-s
Mod4-m
Mod4-a
Mod4-p
Mod4-t
Mod4-Return
Mod4-Shift-space
Mod4-f
Mod4-Shift-c
Mod4-Shift-t
Mod4-h
Mod4-j
Mod4-k
Mod4-l
Mod4-Shift-h
Mod4-Shift-j
Mod4-Shift-k
Mod4-Shift-l
!
for i in 1 2 3 4 5 6 7 8 9 0; do
echo Mod4-$i
echo Mod4-Shift-$i
done
} | wmiir write /keys
\end{Fragment}
and lay a framework for processing their events:
\begin{Fragment}{Key Events}
Key) # Key Key Name
case $1 in
«Motion Keys»
«Client Movement Keys»
«Column Mode Keys»
«Client Command Keys»
«Command Execution Keys»
«Tag Selection Keys»
«Tagging Keys»
esac;;
\end{Fragment}
\section{Click Menus}
Sometimes, you have your hand on the mouse and don't want to
reach for the keyboard. To help cope, \wmii\ provides a
mouse-driven, single-click menu. The default configuration uses
it for client and tag menus.
\begin{Fragment}{Click Menu Initialization}
clickmenu() {
if res=$(wmii9menu -- “$@”); then eval “$res”; fi
}
\end{Fragment}
\section{Control Files}
\label{sec:controlfiles}
Several directories including the root, have control files,
named |ctl|. These files are used to control the object (e.g., a
client or tag) represented by the directory. Each line of the
file, with the possible section of the first, represents a
control variable and its value. In the case of all but the root
|/ctl| file, the first line represents the id of the directory.
In the case of |/tag/foo/ctl|, for instance, the first line
should read |foo|. This is useful when dealing with the special
|sel/| directories. For instance, when |foo| is the selected
tag, the special |/tag/sel| directory is a link to |/tag/foo|,
and the first line of |/tag/sel/ctl| will read |foo|, just as
if you'd accessed |/tag/foo/ctl| directly.
The rest of the lines, the control variables, can be modified by
writing new values to the control file. For instance, if a
client is fullscreen, its control file will contain the line:
\begin{code}
fullscreen on
\end{code}
\noindent To restore the client from fullscreen, either of the
following lines may be written to its control file:
\begin{code}
fullscreen off
fullscreen toggle
\end{code}
When next read, the |fullscreen on| line will have been replaced
with |fullscreen off|. No care need be taken to preserve the
other contents of the file. They're generated anew each time
it's read.
\section{Clients}
\def\clientlabel{/client/$\langle\mathit{client}\rangle$/}
\index{filesystem!/client/*/@\clientlabel|(}
Clients are represented by directories under the |/client/|
tree. Subdirectory names represent the client's X11 window ID.
The special |sel/| directory represents the currently selected
client. The files in these directories are:
\begin{description}
\item[ctl] The client's control file, containing the following
properties:
\index{filesystem!/client/*/@\clientlabel!ctl}
\begin{description}
\item[allow] The set of unusual actions the client is
allowed to perform, in the same format as the tag set.
\begin{description}
\item[activate] The client is allowed to activate
itself—that is, focus its window and, as the case may
require, uncollapse it and select a tag it resides on.
This flag must be set on a client if you wish it able to
activate itself from the system tray.
\end{description}
\item[floating] Defines whether this client is likely to
float when attached to a new view. May be |on|, |off|,
|always|, or |never|. Ordinarilly, the value changes
automatically whenever the window is moved between the
floating and managed layers. However, setting a value of
|always| or |never| overrides this behavior.
\item[fullscreen] The client's fullscreen state. When
|on|, the client is displayed fullscreen on all of its
views. Possible values are |on|, |off|, and |toggle|.
\item[group] The client's group ID, or |0| if not part of
a group. Clients tend to open with the same tags and in
the same columns as the last active member of their
group. Setting this property is only useful when done
via the rules file.
\item[kill] When written, the window is closed politely,
if possible.
\item[pid] Read-only value of the PID of the program that
owns the window, if the value is available and the
process is on the same machine as wmii.
\item[slay] When written, the client is disconnected
peremptorily. If the client's PID is available and the
process is the same machine as wmii, its parent process
is killed
\item[tags] The client's tags. The same as the tags file.
\item[urgent] The client's urgency state. When |on|, the
client's layout box will be highlighted. Possible values
are |on|, |off|, and |toggle|.
\end{description}
\item[props] The client's window class (the X11
|WM_CLASS|\footnote{\ICCCM{4.1.2.5}}
property) and title string, separated by colons. This file
is not writable.
\index{filesystem!/client/*/@\clientlabel!props}
\item[label] The client's window title. May be written to
change the client's title.
\index{filesystem!/client/*/@\clientlabel!label}
\item[tags]
\index{filesystem!/client/*/@\clientlabel!tags}
The client's tags. Tag names are separated by |+|, |-|, or
|^| signs. Tag names which directly follow a |+| sign are
added, while whose following a |-| sign are removed and
those following a |^| are toggled. If the value written
begins with one of these characters, the value is appended
to the clients tags rather than replacing them.
Tags formatted as |/regex/| are treated as regular
expressions, which place the client on any extant matching
tag\footnote{While a client with a regex tag will always
appear in all matching views, it will not keep those views
in existence. When the last client explicitly tagged with a
view is removed, the view is deleted as soon as it becomes
inactive.}. Regular expression tags which directly follow a
minus sign are treated as exclusion expressions. For
example, the tag string |+/foo/-/food/| will match the tag
|foobar|, but not the tag |foodstand|.
\end{description}
\index{filesystem!/client/*/@\clientlabel|)}
\subsection{Key Bindings}
To control clients, we'll add the following key bindings:
\begin{Fragment}{Client Command Keys}
Mod4-Shift-c) wmiir xwrite /client/sel/ctl kill;;
Mod4-f) wmiir xwrite /client/sel/ctl Fullscreen toggle;;
\end{Fragment}
And to manage their tags, we'll need:
\begin{Fragment}{Tagging Keys}
Mod4-Shift-t)
# Get the selected client's id
c=$(wmiir read /client/sel/ctl | sed 1q)
# Prompt the user for new tags
tags=$(wmiir ls /tag | sed s,/,,; /^sel$/d | wimenu)
# Write them to the client
wmiir xwrite /client/$c/tags $tag;;
Mod4-Shift-[0-9])
wmiir xwrite /client/sel/tags ${1*-};;
\end{Fragment}
\subsection{Click Menus}
\index{events!ClientMouseDown}
\begin{Fragment}{Client Menu Events}
ClientMouseDown) # ClientMouseDown Client ID Button
[ $2 = 3 ] && clickmenu \
“Delete:wmiir xwrite /client/$1/ctl kill” \
“Kill: wmiirxwrite /client/$1/ctl slay” \
“Fullscreen:wmiir xwrite /client/$1/ctl fullscreen on”
\end{Fragment}
\subsection{Unresponsive Clients}
\index{events!UnresponsiveClient|(}
When \wmii\ tries to close a window, it waits 8 seconds for the
client to respond, and then lets its scripts decide what to do
with it. The stock scripts prompt the user for input:
\begin{Fragment}{Unresponsive Clients}
UnresponsiveClient) # UnresponsiveClient Client ID
{
# Use wihack to make the xmessage a transient window of
# the problem client. This will force it to open in the
# floaing layer of whatever views the client is attached to
resp=$(wihack -transient $1 \
xmessage -nearmouse -buttons Kill,Wait -print \
“The following client is not responding.” \
“What would you like to do?$(echo)\
$(wmiir read /client/$1/label))
[ $resp = Kill ] && wmiir xwrite /client/$1/ctl slay
} &;;
\end{Fragment}
\index{events!UnresponsiveClient|)}
\section{Views}
\def\taglabel{/tag/$\langle\mathit{tag}\rangle$/}
\index{filesystem!/tag/*/@\taglabel|(}
Views are represented by directories under the |/tag/| tree. The
special |sel/| directory represents the currently selected
client. The |sel| tag is treated similarly elsewhere. The files
in these directories are:
\begin{description}
\item[ctl]
The view's control file. The properties are:
\index{filesystem!/tag/*/@\taglabel!ctl|(}
\begin{description}
\item[select Area] Select the column Area, where
Area is a 1-based column index, or |~| for the floating
area. It may be optionally preceded by Screen|:|, where
Screen is a 0-based Xinerama screen index, or “sel”. When
omitted, Screen defaults to 0, the primary screen.
\item[select Area Client Index] Select the column Area, and
the Client Indexth client.
\item[select client Client ID] Select the client with the
X11 window ID Client ID.
\item[select Direction]
Select the client in Direction where Direction may be
one of up $\wedge$ down $\wedge$ left $\wedge$ right.
\item[send client Client ID Area] Send Client ID to
Area. Area may be |sel| for the selected area, and
|client Client ID| may be |sel| for the currently selected
client.
\item[send client Client ID Direction]
Send Client ID to a column or position in its column in
the given direction.
\item[send client Client ID toggle] If Client ID is
floating, send it to the managed layer. If it's managed,
send it to the floating layer.
\item[swap client Client ID \ldots] The same as the |send|
commands, but swap Client ID with the client at the given
location.
\item[colmode Area Mode] Set Area's mode to Mode,
where Mode is a string of values similar to tag
specifications. Values which may be added and removed are as
follows for managed areas:
\begin{description}
\item[stack] One and only one client in the area is
uncollapsed at any given time. When a new client is
selected, it is uncollapsed and the previously selected
client is collapsed.
\item[max] Collapsed clients are hidden from view
entirely. Uncollapsed clients display an indicator
{\itn/m}, where m is the number of collapsed
clients directly above and below the client, plus one,
and n is the client's index in the stack.
\item[default] Like subtracting the stack mode, but all
clients in the column are given equal height.
\end{description}
For the floating area, the values are the same, except that
in |max| mode, floating clients are hidden when the managed
layer is selected.
\item[grow Frame Direction {[Amount]}] Grow Frame in
the given direction, by Amount. Amount may be any
integer, positive or negative. If suffixed with |px|,
it specifies an exact pixel amount, otherwise it specifies a
“reasonable increment”. Defaults to 1.
Frame may be one of:
\begin{itemize}
\item client Client ID
\item Area Client Index
\end{itemize}
\item[nudge Frame Direction {[Amount]}] Like
|grow|, but move the client in Direction instead of
resizing it.
\end{description}
\index{filesystem!/tag/*/@\taglabel!ctl|)}
\end{description}
\index{filesystem!/tag/*/@\taglabel|)}
\subsection{Key Bindings}
We'll use the following key bindings to interact with views:
\begin{Fragment}{Motion Keys}
Mod4-h) wmiir xwrite /tag/sel/ctl select left;;
Mod4-l) wmiir xwrite /tag/sel/ctl select right;;
Mod4-k) wmiir xwrite /tag/sel/ctl select up;;
Mod4-j) wmiir xwrite /tag/sel/ctl select down;;
Mod4-space) wmiir xwrite /tag/sel/ctl select toggle;;
\end{Fragment}
\begin{Fragment}{Client Movement Keys}
Mod4-Shift-h) wmiir xwrite /tag/sel/ctl send sel left;;
Mod4-Shift-l) wmiir xwrite /tag/sel/ctl send sel right;;
Mod4-Shift-k) wmiir xwrite /tag/sel/ctl send sel up;;
Mod4-Shift-j) wmiir xwrite /tag/sel/ctl send sel down;;
Mod4-Shift-space) wmiir xwrite /tag/sel/ctl send sel toggle;;
\end{Fragment}
\begin{Fragment}{Column Mode Keys}
Mod4-d) wmiir xwrite /tag/sel/ctl colmode sel -stack-max;;
Mod4-s) wmiir xwrite /tag/sel/ctl colmode sel stack-max;;
Mod4-m) wmiir xwrite /tag/sel/ctl colmode sel stack+max;;
\end{Fragment}
\subsection{Click Menus}
\index{events!LeftBarMouseDown}
\begin{Fragment}{Tag Menu Events}
LeftBarMouseDown) # LeftBarMouseDown Button Bar Name
[ $1 = 3 ] && clickmenu \
“Delete:delete_view $2
\end{Fragment}
\section{Command and Program Execution}
Perhaps the most important function we need to provide for is
the execution of programs. Since \wmii\ users tend to use
terminals often, we'll add a direct shortcut to launch one.
Aside from that, we'll add a menu to launch arbitrary programs
(with completions) and a separate menu to launch wmii specific
commands.
We use |wmiir setsid| to launch programs with their own session
IDs to prevent untoward effects when this script dies.
\begin{Fragment}{Command Execution Initialization}
terminal() { wmiir setsid xterm “$@” }
proglist() {
IFS=:
wmiir proglist $1 | sort | uniq
unset IFS
}
\end{Fragment}
\subsection{Key Bindings}
\begin{Fragment}{Command Execution Keys}
Mod4-Return) terminal & ;;
Mod4-p) eval exec wmiir setsid “$(proglist $PATH | wimenu)&;;
Mod4-a) {
set -- $(proglist $WMII_CONFPATH | wimenu)
which=$(which which)
prog=$(PATH=$WMII_CONFPATH $which $1); shift
eval exec $prog “$@”
} &;;
\end{Fragment}
\section{The Root}
The root filesystem contains the following:
\index{!filesystem!/|(}
\begin{description}
\item[ctl] The control file. The properties are:
\index{filesystem!/!ctl}
\begin{description}
\item[bar on top $\wedge$ bottom] Controls where the bar
is shown.
\item[border] The border width, in pixels, of floating
clients.
\item[colmode Mode] The default column mode for newly
created columns.
\item[focuscolors Color Tuple] The colors of focused
clients.
\item[normcolors Color Tuple] The colors of unfocused
clients and the default color of bar buttons.
\item[font Font] The font used throughout \wmii. If
prefixed with |xft:|, the Xft font renderer is used, and
fonts may be antialiased. Xft font names follow the
fontconfig formula. For instance, 10pt, italic Lucida
Sans would be specified as
\begin{code}
xft:Lucida Sans-10:italic
\end{code}
See \man 1 {fc-match}.
\item[grabmod Modifier Keys] The key which must be
pressed to move and resize windows with the mouse
without clicking hot spots.
\item[incmode Mode] Controls how X11 increment hints are
handled in managed mode. Possible values are:
\begin{description}
\item[ignore] Increment hints are ignored entirely.
Clients are stretched to fill their full allocated
space.
\item[show] Gaps are shown around managed client
windows when their increment hints prevent them from
filling their entire allocated space.
\item[squeeze] When increment hints cause gaps to show
around clients, \wmii\ will try to adjust the sizes
of the clients in the column to minimize lost space.
\end{description}
\item[view Tag] Change the currently visible view.
\item[exec Command] Replaces this \wmii\ instance with
Command. Command is split according to rc quoting
rules, and no expansion occurs. If the command fails to
execute, \wmii\ will respawn.
\item[spawn Command] Spawns Command as it would spawn
|wmiirc| at startup. If Command is a single argument
and doesn't begin with |/| or |./|,%
\hskip 1ex|$WMII_CONF|\-|PATH| is
searched for the executable. Otherwise, the whole
argument is passed to the shell for evaluation.
\end{description}
\item[keys] The global keybindings. See section \ref{sec:keybindings}.
\index{filesystem!/!keys|primary}
\item[event] The global event feed. See section \ref{sec:keybindings}.
\index{filesystem!/!event|primary}
\item[colrules]
\index{filesystem!/!colrules}
The |/colrules| file contains a list of
rules which affect the width of newly created columns.
Rules have the form:
\begin{quote}\texttt{
/regex/ -> width{\color{gray}[}+width{\color{gray}]*}}
\end{quote}
Where,
\begin{code}
widthpercent of screen | pixelspx
\end{code}
When a new column, n, is created on a view whose name
matches regex, it is given the nth supplied width.
If there is no nth width, it is given
$1/\mbox{ncolth}$ of the screen.
\item[rules]
\index{filesystem!/!rules}
The |/rules| file contains a list of
rules similar to the colrules. These rules set
properties for a client when it is created.
Rules are specified:
\begin{quote}\texttt{
/regex/ -> key{\color{gray}=}value {\color{gray}\ldots}}
\end{quote}
When a client's name:class:title matches
regex, the matching rules are applied. For each
key=value pair, the |ctl| file property matching
key is set to value. Additionally, the following
keys are accepted and have special meaning:
\begin{description}
\item[continue]
Normally, when a matching rule is encountered,
rule matching stops. When the continue key is
provided (with any value), matching continues at
the next rule.
\item[force-tags]
Like tags, but overrides any settings obtained
obtained from the client's group or from the
|_WMII_TAGS| window property.
\end{description}
\end{description}
\index{!filesystem!/|)}
\subsection{Configuration}
We'll need to let \wmii\ know about our previously defined theme
information:
\begin{Fragment}{Configuration}
«Theme Definitions»
xsetroot -solid $background
wmiir write /ctl <<!
border 2
focuscolors $focuscolors
normcolors $normcolors
font $font
grabmod Mod4
!
\end{Fragment}
\subsection{Key Bindings}
And we need a few more key bindings to select our views:
\begin{Fragment}{Tag Selection Keys}
Mod4-t)
# Prompt the user for a tag
tags=$(wmiir ls /tag | sed s,/,,; /^sel$/d | wimenu)
# Write it to the filesystem.
wmiir xwrite /ctl view $tags;;
Mod4-[0-9])
wmiir xwrite /ctl view ${1*-};;
\end{Fragment}
\section{Tieing it All Together}
\begin{code}
#!/bin/sh
«Click Menu Initialization»
«Command Execution Initialization»
«Configuration»
«Bind Keys»
«Event Loop»
\end{code}
\section{The End Result}
For clarity, here is the end result:
\begin{code}
#!/bin/sh
# «Click Menu Initialization»
clickmenu() {
if res=$(wmii9menu -- “$@”); then eval “$res”; fi
}
# «Command Execution Initialization»
terminal() { wmiir setsid xterm “$@” }
proglist() {
IFS=:
wmiir proglist $1 | sort | uniq
unset IFS
}
# «Configuration»
# «Theme Definitions»
normcolors=000000 c1c48b 81654f
focuscolors=000000 81654f 000000
background=333333
font=drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*
xsetroot -solid $background
wmiir write /ctl <<!
border 2
focuscolors $focuscolors
normcolors $normcolors
font $font
grabmod Mod4
!
# «Bind Keys»
{
cat <<!
Mod4-space
Mod4-d
Mod4-s
Mod4-m
Mod4-a
Mod4-p
Mod4-t
Mod4-Return
Mod4-Shift-space
Mod4-f
Mod4-Shift-c
Mod4-Shift-t
Mod4-h
Mod4-j
Mod4-k
Mod4-l
Mod4-Shift-h
Mod4-Shift-j
Mod4-Shift-k
Mod4-Shift-l
!
for i in 1 2 3 4 5 6 7 8 9 0; do
echo Mod4-$i
echo Mod4-Shift-$i
done
} | wmiir write /keys
# «Event Loop»
# Broadcast a custom event
wmiir xwrite /event Start wmiirc
# Turn off globbing
set -f
# Open /event for reading
wmiir read /event |
# Read the events line by line
while read line; do
# Split the line into words, store in $@
set -- $line
event=$1; shift
line = "$(echo $line | sed s/^[^ ]* // | tr -d \n)"
# Process the event
case $event in
Start) # Quit when a new instance starts
[ $1 = wmiirc ] && exit;;
# «Event Handlers»
# «View Button Events»
CreateTag) # CreateTag Tag Name
echo $normcolors $1 | wmiir create /lbar/$1;;
DestroyTag) # DestroyTag Tag Name
wmiir rm /lbar/$1;;
FocusTag) # FocusTag Tag Name
wmiir xwrite /lbar/$1 $focuscolors $1;;
UnfocusTag) # UnfocusTag Tag Name
wmiir xwrite /lbar/$1 $normcolors $1;;
# «Urgency Events»
# The urgency events are Client events when the program
# owning the window sets its urgency state. They're Manager
# events when wmii or the wmii user sets the state.
UrgentTag) # UrgentTag Client or Manager Tag Name
wmiir xwrite /lbar/$2 $2;;
NotUrgentTag) # NotUrgentTag Client or Manager Tag Name
wmiir xwrite /lbar/$2 $2;;
# «Unresponsive Clients»
UnresponsiveClient) # UnresponsiveClient Client ID
{
# Use wihack to make the xmessage a transient window of
# the problem client. This will force it to open in the
# floaing layer of whatever views the client is attached to
resp=$(wihack -transient $1 \
xmessage -nearmouse -buttons Kill,Wait -print \
“The following client is not responding.” \
“What would you like to do?$(echo)” \
$(wmiir read /client/$1/label))
[ $resp = Kill ] && wmiir xwrite /client/$1/ctl slay
} &;;
# «Notice Events»
Notice)
wmiir xwrite /rbar/!notice $line
kill $xpid 2>/dev/null # Let's hope this isn't reused...
{ sleep 5; wmiir xwrite /rbar/!notice ; } &
xpid = $!;;
# «Key Events»
Key) # Key Key Name
case $1 in
# «Motion Keys»
Mod4-h) wmiir xwrite /tag/sel/ctl select left;;
Mod4-l) wmiir xwrite /tag/sel/ctl select right;;
Mod4-k) wmiir xwrite /tag/sel/ctl select up;;
Mod4-j) wmiir xwrite /tag/sel/ctl select down;;
Mod4-space) wmiir xwrite /tag/sel/ctl select toggle;;
# «Client Movement Keys»
Mod4-Shift-h) wmiir xwrite /tag/sel/ctl send sel left;;
Mod4-Shift-l) wmiir xwrite /tag/sel/ctl send sel right;;
Mod4-Shift-k) wmiir xwrite /tag/sel/ctl send sel up;;
Mod4-Shift-j) wmiir xwrite /tag/sel/ctl send sel down;;
Mod4-Shift-space) wmiir xwrite /tag/sel/ctl send sel toggle;;
# «Column Mode Keys»
Mod4-d) wmiir xwrite /tag/sel/ctl colmode sel -stack-max;;
Mod4-s) wmiir xwrite /tag/sel/ctl colmode sel stack-max;;
Mod4-m) wmiir xwrite /tag/sel/ctl colmode sel stack+max;;
# «Client Command Keys»
Mod4-Shift-c) wmiir xwrite /client/sel/ctl kill;;
Mod4-f) wmiir xwrite /client/sel/ctl fullscreen toggle;;
# «Command Execution Keys»
Mod4-Return) terminal & ;;
Mod4-p) eval exec wmiir setsid “$(proglist $PATH | wimenu)” &;;
Mod4-a) {
set -- $(proglist $WMII_CONFPATH | wimenu)
prog=$(PATH=$WMII_CONFPATH which $1); shift
eval exec $prog “$@”
} &;;
# «Tag Selection Keys»
Mod4-t)
# Prompt the user for a tag
tags=$(wmiir ls /tag | sed s,/,,; /^sel$/d | wimenu)
# Write it to the filesystem.
wmiir xwrite /ctl view $tag;;
Mod4-[0-9])
wmiir xwrite /ctl view ${1*-};;
# «Tagging Keys»
Mod4-Shift-t)
# Get the selected client's id
c=$(wmiir read /client/sel/ctl | sed 1q)
# Prompt the user for new tags
tags=$(wmiir ls /tag | sed s,/,,; /^sel$/d | wimenu)
# Write them to the client
wmiir xwrite /client/$c/tags $tag;;
Mod4-Shift-[0-9])
wmiir xwrite /client/sel/tags ${1*-};;
esac;;
# «Client Menu Events»
ClientMouseDown) # ClientMouseDown Client ID Button
[ $2 = 3 ] && clickmenu \
“Delete:wmiir xwrite /client/$1/ctl kill” \
“Kill:wmiir xwrite /client/$1/ctl slay” \
“Fullscreen:wmiir xwrite /client/$1/ctl fullscreen on”
# «Tag Menu Events»
LeftBarMouseDown) # LeftBarMouseDown Button Bar Name
[ $1 = 3 ] && clickmenu \
“Delete:delete_view $2
esac
done
\end{code}