StumpWM for personalized computing
[ Modified: long ago (before 2024 Apr 09) ]

[ ...new document for info from a longer document...lots of links need correcting, likely to info yet to be transferred into new documents... ]


Eval:            

Interactive extensible computer interface.
Typing instructions for the computer.
Personalize interactions with the computer.
This way, that way, or any way.
Convenient reference.

Additions and modifications.

# beyond the computer as it is popularly known

[ ...relate prior section about
 familiar ways of the computer
 with the means of StumpWM...
...probably need to complete
 that section first...

...this is introductory
 rather than promotion...
...how to relate and realize
 there is really
 nothing new to learn... ]

...merely view management (StumpWM)...
...plus a means for instructing the computer instead of programming it (Lisp)...
...sort of like jotting down a quick
grocery list (a couple of instructions)
for the computer to do,
instead of writing a book (a program)...

# example setup of StumpWM

StumpWM version 1.0.1 (20.11):
stumpwm.github.io ; StumpWM manual ; StumpWM wiki (tips and tricks)
Steel Bank Common Lisp (SBCL) 2.1.0
sbcl.org
Common Lisp X Interface (CLX) 0.7.5
github.com/sharplispers/clx
alexandria 1.0.1
common-lisp.net/project/alexandria
cl-ppcre 2.1.1
edicl.github.io/cl-ppcre
an Xserver, f.e. x.org (The X.Org Foundation R12008000)
any Xserver compatible system
For example, TinyCore ( tinycorelinux.net/ports.html), such as its piCore 12.0 (includes 64-bit version).

# interactive curiosity:  typing for actions and help

StumpWM provides various prompts for typing computer instructions, or the name of a StumpWM command, or for help.

Call forth a specific prompt by invisibly typing the abbreviated button sequence for it, f.e. "Control-t :" for the "Eval: " prompt. Use the Control button in the same manner as the Shift button, t.i. hold the Control button before typing a letter (skip the hyphen), then afterwards let go of it.

Or, visibly type the command name for a prompt at the ": " prompt (Invoke a StumpWM command by its name).

Move the text cursor anywhere within the single line of text as needed (Typing within a line of text). Type the Return button or Enter button to complete the invocation, regardless of where the text cursor is located. Or, type the ESC button to escape from the prompt without invoking.

Consider assigning a single button for any commonly invoked prompt (Make a StumpWM keymap and pair a button).

# invoke a StumpWM command by its name

Invoke a command by visibly typing its name and then typing either the Enter button or the Return button. While typing, a list of command names beginning with those letters are immediately shown below the prompt.

Type the TAB button to choose the name at the top of the list and the list is hidden. Type the TAB button to cycle through the other hidden choices, or hold the Shift button and type the TAB button to cycle in reverse.

List all commands with the commands command.



A couple of related prompts help with learning about commands, or discovering a button name and its assigned command. Consider a more convenient button for the set of Help commands (StumpWM keymap: *help-map*).


# use a program

Type the name of a program to start it. While typing, a list of program names beginning with those letters are shown below the prompt.

Type the TAB button to choose the name at the top of the list and the list is hidden. Type the TAB button to cycle through the other hidden choices, or hold the Shift button and type the TAB button to cycle in reverse.



Starting a program displaces the current document or program from the current frame (or full screen). The prior program or document is only hidden. Consider commands for switching to a hidden program, or splitting the screen (Essential split-view commands).

Note this is an alias for run-shell-command which actually accepts a "shell command", a computer instruction for the operating system rather than StumpWM. Thereby, the results for a shell command (instead of a program name) will appear in the console whence StumpWM was started, rather than with the StumpWM messages.

# compose a Lisp instruction

Change the appearance of the prompts and messages (Customize prompts and messages). Pair a button on the buttonboard with a StumpWM command or a custom Lisp instruction (Customize the buttonboard). Place the pointer anywhere on the screen and select with it, and without using the pointer-box (Pointer placement and activation).

Numbers and "double-quoted text" are the most basic forms of Lisp, and parentheses embrace items for a Lisp list. There are about a half-dozen Lisp instructions for naming memory, referencing an item in a list, and constructing or re-listing a list (An intro for Lisp).



A couple of related prompts help with learning about or verifying named memory, or names for Lisp instructions. Consider a more convenient button for the set of Help commands (StumpWM keymap: *help-map*).


# typing within a line of text

The stumpwm:*input-map* keymap displaces the *top-map* while typing in a prompt (StumpWM 4.2 Using the Input Bar).


After typing text within a prompt, the left/right arrow buttons move the text cursor within the line of text.

The up/down arrow buttons bring forth prior/later typed text for editing and re-using, thereby less re-typing.

Type the Return button or Enter button to complete the invocation, regardless of where the text cursor is located within the line of text. Or, type the ESC button to escape from the prompt without invoking.


Other button sequences for moving the text cursor are described with "C-" for the Control button and "M-" for the Meta button (StumpWM 4.2 Using the Input Bar), and are similar to the text editing commands in the prompts of Emacs (GNU). The Alt button is usually the substitute for the Meta button.

Either the Home button or "Control-a" moves the text cursor to the beginning of the line. Either the End button or "Control-e" moves the text cursor to the end of the line.

Either "Meta-f" or "Alt-f" moves the text cursor forward one word, and "Meta-b" or "Alt-b" moves the text cursor backward one word.


The stumpwm:*input-map* keymap has no button for listing the command abbreviations for editing text in a prompt. Either consult the manual for the full listing (StumpWM 4.2 Using the Input Bar), or consider enabling the listing (The button list for text editing).

# the button list for text editing

Prefix: F12
DEL   INPUT-DELETE-BACKWARD-CHAR
M-DEL INPUT-BACKWARD-KILL-WORD
C-d   INPUT-DELETE-FORWARD-CHAR
M-d   INPUT-FORWARD-KILL-WORD
Delete INPUT-DELETE-FORWARD-CHAR
C-f   INPUT-FORWARD-CHAR
Right INPUT-FORWARD-CHAR
M-f   INPUT-FORWARD-WORD
C-b   INPUT-BACKWARD-CHAR
Left  INPUT-BACKWARD-CHAR
M-b   INPUT-BACKWARD-WORD
C-a   INPUT-MOVE-BEGINNING-OF-LINE
Home  INPUT-MOVE-BEGINNING-OF-LINE
C-e   INPUT-MOVE-END-OF-LINE
End   INPUT-MOVE-END-OF-LINE
C-k   INPUT-KILL-LINE
C-u   INPUT-KILL-TO-BEGINNING
C-p   INPUT-HISTORY-BACK
Up    INPUT-HISTORY-BACK
C-n   INPUT-HISTORY-FORWARD
Down  INPUT-HISTORY-FORWARD
RET   INPUT-SUBMIT
C-g   INPUT-ABORT
ESC   INPUT-ABORT
C-y   INPUT-YANK-SELECTION
C-Y   INPUT-YANK-CLIPBOARD
TAB   INPUT-COMPLETE-FORWARD
ISO_LEFT_TAB INPUT-COMPLETE-BACKWARD
All else INPUT-SELF-INSERT

The full listing reveals many duplicates, but they can be unassigned by re-defining a button to nil (Make a StumpWM keymap and pair a button). There is a sort of mysterious command stumpwm:input-yank-clipboard (Insert text into a prompt) invoked with "Control-Y" (a capital y, t.i. Shift-y), as it seems to be undocumented in the manual.

Peculiarly, pairing a button with an existing input command for the stumpwm:*input-map* keymap requires using the quote for the command name instead of double-quoting it. That is because the input "commands" are actually just functions, defined with defun rather than stumpwm:defcommand (StumpWM version 1.0.1, "input.lisp").

Any new function for the stumpwm:*input-map* must be defined with defun to accept two Lisp forms: a reference to the current prompt, and the button that invoked the command (StumpWM 4.4 Programming the Input Bar). Most input functions never use the button itself, but they must still be able to receive it.


As a StumpWM keymap, the stumpwm:*input-map* itself can be assigned to a button (StumpWM keymap: *help-map*).

: describe-key
F12 is not bound.
Eval: (define-key *top-map* (kbd "F12") '*input-map*)

While the commands are obviously useless outside of a prompt, typing its newly assigned button followed by a question mark "?" could reveal the button list with no need for the manual (Make a StumpWM keymap and pair a button). Instead, a boring error excitingly appears (Named, memory, Lisp instructions, and errors).

StumpWM Crashed With An Unhandled Error!
Copy the error to the clipboard with the 'copy-unhandled-error' command.
The value
    T
  is not of type
    STUMPWM::KEY
Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {0123456789}>
0: (STUMPWM::PRINT-MODS T)
1: (STUMPWM::PRINT-KEY T)
2: (STUMPWM::DISPLAY-BINDINGS-FOR-KEYMAPS ...)
...

Consider replacing stumpwm::print-key with a minor modification (Replacement for stumpwm::print-key).

# insert text into a prompt

The default abbreviations "Control-y" and "Control-Y" are for inserting text at a prompt, from the :primary and :clipboard of the stumpwm:*x-selection* (The button list for text editing). As "double-quoted text", each can be partial Lisp forms.

The term "yank" (copy from storage and insert into the text) is complementary to "kill" (extract from the text and put into storage), an ancient capitulation [ Long, long ago in another century, the first letter of other terms were already being used for other Emacs commands. ] familiarized in Emacs (Emacs 12. Killing and moving text).

Initially, the stumpwm:*x-selection* starts as only nil. Eventually, it might have :primary or :clipboard.

Eval: *x-selection*
NIL

The stumpwm:input-yank-selection inserts into the prompt a copy of whatever is listed immediately after :primary within *x-selection*. The stumpwm:input-yank-clipboard inserts a copy of whatever is listed immediately after :clipboard.


# Extract part of the line in a prompt

Invoking either stumpwm:input-kill-line with "Control-k" or stumpwm:input-kill-to-beginning with "Control-u" will add what is removed from the prompt into stumpwm:*x-selection* immediately after :primary as "double-quoted text".

Eval: *x-selection*
(:PRIMARY "(cons 'something 'from-prompt)")

The stumpwm:input-kill-line extracts rightwardly, starting at the text cursor until the end of the line. The stumpwm:input-kill-to-beginning extracts leftwardly, starting at the text cursor until the beginning of the line.

As such, the description for stumpwm:input-kill-to-beginning as "Control-u" is incorrect (StumpWM 4.2 Using the Input Bar).

C-u
Kill to the beginning of the line (kill-to-beginning), the same as C-a C-k.

The "C-a" invokes input-move-beginning-of-line, which moves the text cursor to the beginning of the line. Invoking stumpwm:input-kill-line with "C-k" afterwards extracts to the end of line, therefore the whole line rather than only from the text cursor to the beginning of line.


The commands input-backward-kill-word as "M-DEL" [ Hold the Meta modifier button (often the same as the Alt button), then type the delete button. ] and input-backward-kill-word as "M-d" are misnomered (The button list for text editing). They delete rather than extract from the prompt. The *x-selection* remains unchanged, and the deleted text is lost.


# Copy the last message

...the copy-last-message command...then yank into the prompt...


# Set stumpwm:*x-selection* directly

Consider using setf (An intro for Lisp) to replace the "double-quoted text" in stumpwm:*x-selection*.

Eval: (setf (cadr *x-selection*)  "'(the-first-part of-something")
Eval: *x-selection*
(:PRIMARY "'(the-first-part of-something")

Similarly, the stumpwm:input-yank-clipboard accesses the info after :clipboard within the stumpwm:*x-selection*. When :clipboard is missing, just add it along with the new "double-quoted text".

Eval: (setf (cddr *x-selection*)  '(:clipboard " the-last-part)"))
Eval: *x-selection*
(:PRIMARY "'(the-first-part of-something" :CLIPBOARD " the-last-part)")
Eval: (setf (cadddr *x-selection*)  " the-sequel)"))

# the Lisp instruction prompt:  an outlet for ingenuity

Eval:            

StumpWM provides the Lisp instruction prompt "Eval: " by means of "Control-t :" for evaluating a single line of Lisp instruction after the Return button or Enter button is typed (Compose a line of instruction).

Numbers and "double-quoted text" essentially remain the same. Named memory is referenced for its content. A Lisp list is evaluated as an instruction.

Using quote for named memory prevents referencing the memory at that moment. Using quote for a Lisp list prevents evaluation of it as an instruction at that moment. There are about a half dozen essential Lisp instructions (An intro for Lisp).

# named memory, Lisp instructions, and errors

The setf (An intro for Lisp) associates a name with a memory location in the computer, and anything can be stored in that memory. A Lisp instruction is a pair of parentheses with the instruction name as the leftmost list item.


Type a name to find out whether there is information associated with it yet, or type a Lisp instruction for the computer. A message with successful results appears on the screen for a few seconds, and then conveniently disappears.

Eval: stumpwm:*input-window-gravity*
:TOP-LEFT
Eval: (setf stumpwm:*input-window-gravity* :center)
:CENTER

The delay is the number of seconds set in stumpwm:*timeout-wait* (StumpWM 4.1). However, it can also be paused by typing the button for a keymap prefix, such as the stumpwm::*escape-key* button, because StumpWM is waiting for the remainder of the sequence (Make a StumpWM keymap and pair a button). Finish typing the sequence and the message will likely be removed as the next command is invoked.


Otherwise, when the name has yet to be set or the Lisp instruction is mistyped, a boring description of an error will excitingly appear and stay visible.

Forever.

Almost. The error message will disappear when the next StumpWM command is invoked (Remove the message from the screen), f.e. when invoking the prompt again.

Eval: something
The variable SOMETHING is unbound.Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING> {1234567890}>
0: (STUMPWM::BACKTRACE-STRING)
1: (ERR "~A" #<UNBOUND-VARIABLE SOMETHING {2345678901}>)
2: (EVAL-LINE "something")
3: (STUMPWM::CALL-INTERACTIVELY "eval" #S(STUMPWM::ARGUMENT-LINE :STRING "eval" :START 5))
4: (STUMPWM::EVAL-COMMAND "eval" T)
5: ((LAMBDA (&REST #:GO &KEY :CODE :STATE &ALLOW-OTHER-KEYS) :IN "/tmp/stumpwm-20.11/events.lisp") :CODE 66 :STATE 0)
6: (STUMPWM::HANDLE-EVENT :DISPLAY #<XLIB:DISPLAY :0 (The X.Org Foundation R12008000)> ...)

 [ ...Pretty much the same hereafter
   for every error message,
   except maybe different line counting.
   Usually only terribly important,
   hence perfectly ignorable... ]

17: (STUMPWM ":0")
18: ((LAMBDA NIL :IN "/tmp/stumpwm-20.11/make-image.lisp"))
19: ((FLET SB-UNIX::BODY :IN SB-IMPL::START-LISP))
20: ((FLET "WITHOUT-INTERRUPTS-BODY-1" :IN SB-IMPL::START-LISP))
21: (SB-IMPL::START-LISP)

The very top line above line count zero is probably the most revealing, and probably enough to realize why the error happened.

The "Backtrace" is abruptly tacked onto the end of the first line, but can be made to start on a newline if desired (Replacement for stumpwm:err).

That "Backtrace" bores into the processing depths of the Lisp interpreter. Likely only about the first half-dozen lines of the error, line count zero through maybe five or so, will be relevant.

Afterwards is essentially the same for every error message. The middle reveals the constant looping that waits for typed buttons, the core of StumpWM. The very end is actually how the StumpWM program itself began, as a "Lisp image".


Consider trying again with the Lisp instruction prompt "Control-t :", then using the up arrow button to show the previous typed line, and then editing it to get a different result (Typing within a line of text).

# assigning to named memory from collections

With Common Lisp, both a function from defun (CLHS) and any other Lisp form from setf (CLHS) can be associated with the same symbol, t.i. named memory, at the same time. Consider this as a convenience when replacing functions (An introspective approach for defun).


The pecularity of packages in Common Lisp means extra care is needed when querying named memory for ascertaining prior use of a name, especially with the misleading feedback from symbol-package and the package locks of SBCL.

Eval: (symbol-package 'print-key)
#<PACKAGE "STUMPWM-USER">
Eval: print-key
The variable PRINT-KEY is unbound.Backtrace...
Eval: (setf print-key '(something))
(SOMETHING)
Eval: print-key
(SOMETHING)

Query the named memory with its known package name and two colons "::" just to be sure. Consider "Control-t h f" for stumpwm:describe-function (StumpWM keymap: *help-map*).

Eval: stumpwm:print-key
The symbol "PRINT-KEY" is not external in the STUMPWM package.
       Stream: #<dynamic-extent STRING-INPUT-STREAM (unavailable) from "stumpwm:...">Backtrace...
Eval: stumpwm::print-key
The variable STUMPWM::PRINT-KEY is unbound.Backtrace...
Describe Function: print-key
The symbol STUMPWM-USER::PRINT-KEY is not bound to any function.
Describe Function: stumpwm::print-key
function: print-key
(print-key key)

# optional or required collection names

An error message claiming a (known) name is undefined is a clue that the collection name is needed.

Eval: (global-pointer-position stumpwm:*display*)
The function STUMPWM-USER::GLOBAL-POINTER-POSITION is undefined.Backtrace...

Friendlier feedback is given by "Control-t h f" for stumpwm:describe-function for querying about a instruction name, or "Control-t h v" for stumpwm:describe-variable for querying about a placeholder name (StumpWM keymap: *help-map*). Though their responses never reveal the package name, they do confirm or deny the existence of a name in a package.

Describe Function: stumpwm:global-pointer-position
No such symbol: STUMPWM::GLOBAL-POINTER-POSITION.
Describe Function: xlib:global-pointer-position
function: global-pointer-position
(global-pointer-position DISPLAY)
Eval: (xlib:global-pointer-position stumpwm:*display*)
1050
787
#<XLIB:WINDOW :0 389>
Describe Variable: stumpwm:*display*
variable: *DISPLAY*
The display for the X server
Its value is:
#<DISPLAY :0 (The X.Org Foundation R12008000)>.
Eval: (xlib:global-pointer-position *display*)
1050
787
#<XLIB:WINDOW :0 389>

The feedback from the function or variable queries is a little misleading. It might print two colons when declaring the name as undefined, even when only one colon was used during a query.

Otherwise, consider trying another query with two colons whenever it says it did try only one colon and failed to find anything. Also, a successful message leaves off the collection name even when it is required.


Many StumpWM names for placeholders or Lisp instructions have no need for the "stumpwm:" collection name, f.e. *top-map* or define-key. Try it and find out. However, the collection name does make obvious where to personally seek documentation.

When the collection name is required, sometimes an extra colon is also needed, f.e. stumpwm::read-key. That is usually because the placeholder or Lisp instruction is probably unintended for common use. The documentation for it is likely in the source file, if at all.


The StumpWM names for placeholders usually include an asterisk "*" before and after the name, f.e. stumpwm:*top-map*. That is only a convention when creating a placeholder with the defvar (CLHS). (The intended effect of defvar is essentially useless from the Lisp instruction prompt, its intended use is for within files.) Consider a different approach for new names, distinctive for certainty.

# there can be only one instruction

Only one Lisp form is evaluated by stumpwm:eval-line, either at its prompt or given to it as a command for a button. Later forms on the line are simply ignored by it.

The cons pairs the results of two Lisp forms. The format (CLHS) constructs "double-quoted text", typically from the evaluation results of any number of Lisp forms.


# Two instructions at once.

Consider using cons for pairing two instructions for evaluation by eval-line.

For example, define a button on the buttonboard to press and release the primary button for the pointer (Alternative for pointer activation and drag'n drop).

Eval: (setf press.1 '(xlib/xtest:fake-button-event *display* 1 t))
Eval: (setf release.1 '(xlib/xtest:fake-button-event *display* 1 nil))
: describe-key
F10 is not bound.
Eval: (define-key *top-map* (kbd "F10") "eval-line (cons (eval press.1) (eval release.1))")

# Multiple instructions at once.

The format (CLHS) is a way of having the computer write the results of any number of Lisp instructions, and formatted with additional text described within double-quotes. No additional text is required, and in fact an empty set of double-quotes is fine.


Consider using format for combining multiple instructions for evaluation by eval-line. Consider storing the format instruction to avoid the conflict of its double-quotes within the double-quotes for define-key.

For example, place the pointer at a specific location on the screen with xlib:warp-pointer (Alternative for pointer placement), then press and release the primary button for it.

Eval: do-point.a
The variable DO-POINT.A is unbound.Backtrace...
Eval: (setf do-point.a '(format nil "" (eval point.a) (eval press.1) (eval release.1)))
: describe-key
F11 is not bound.
Eval: (define-key *top-map* (kbd "F11") "eval-line (eval do-point.a)")
Eval: point.a
The variable POINT.A is unbound.Backtrace...
Eval: (setf point.a '(xlib:warp-pointer (screen-root(current-screen)) 600 450))

Essentially, the format begins with three parts:

format nil ""

Consider using cons to add each part to the left end of any list of instructions.

Eval: press-release.1
The variable PRESS-RELEASE.1 is unbound.Backtrace...
Eval: (setf press-release.1 '((eval press.1) (eval release.1)))
Eval: do-point.b
The variable DO-POINT.B is unbound.Backtrace...
Eval: (setf do-point.b (cons '(eval point.b) press-release.1))
Eval: do-point.b
((EVAL POINT.B) (EVAL PRESS.1) (EVAL RELEASE.1))
Eval: (setf do-point.b (cons "" do-point.b))
Eval: (setf do-point.b (cons nil do-point.b))
Eval: (setf do-point.b (cons 'format do-point.b))
Eval: do-point.b
(FORMAT NIL "" (EVAL POINT.B) (EVAL PRESS.1) (EVAL RELEASE.1))
Eval: (eval do-point.b)

Optionally, use "~s" for the result of each instruction. The "~%" provides a blank line, but StumpWM consolidates a series of blank lines into only one for its messages.

Eval: (setf d.1 '(format nil "~s~%~s~%~s" (eval a.1) (eval b.1) (eval c.1)))

# flow of the moment


[ ...at the very least,
 connect the dots by outlining this,
 then fill it in with whatever time remains...

...ideally, connect with the core impetus
 of everyday life activities
 as a bridge to
 the computer medium as an occasional tool,
 much like a notepad of paper is occasional...
... ]

An extensible computing environment, like the Lisp image with StumpWM, can be adjusted as needed for the moment. Modify with basic instructions for the moment rather than making permanent changes.

Consider making notes on what and how to modify, perhaps on paper. Note successes, possibilities, interests, and contradictions. Group a collection of changes that have been typed in for a session, and consider saving it to an external storage device for less re-typing later.

Only the changes that have been added for the moment need consideration. Rebooting is a fresh restart, a new beginning. Instructions are restorable from external storage as needed, and retain adaptability.

As a list, any part of such a collection can be modified, or re-stored into named memory, or simply referenced in place. Any part can be evaluated, or the parts can be coordinated for applying all at once.


[ ...outline briefly various basic approaches, and link to relevant sections... ]

Construct an instruction for evaluation

  1. Type text in the prompt.
  2. Insert as text any abdexter or dexter from any introspected list.
    [ ...see "insert text from introspected list into prompt" in notepad
    (also the page in notepad named "Beyond the Lisp evaluation prompt",
    section beginning with stumpwm:read-one-line,
    specifically "For example, (defun insert.cadr (input key)..."),
    as it is the final dot to connect
    (as it obviates copy/paste, and maybe text editors),
    so must prioritize and complete this before reaching final meal... ]
    
    [ ...partial description for introspection already (Abbi-abbi introspection),
    but reference the description for buttons when its description is added
    (but new from notes, for assigning to stumpwm:*input-map*)... ]
    
  3. Evaluate the instruction.

Re-use an instruction

Consider naming an instruction and then assigning a button to evaluate the name. In that way, the instruction can be modified later by means of its name. There also is no need to re-assign the button.

  1. Assign a button to evaluate an instruction. (Any instruction at the press of a button)

Modify an instruction

Any part of named instruction is readily modified with setf by referencing an abdexter or a dexter within it. No need to re-assign a button to a modified instruction.

  1. Introspect the instruction (as a list).
    [ ...part of #2 in "Construct an instruction" above... ]
  2. In the Lisp instruction prompt, type the replacement for any abdexter or dexter, likely with setf.
    Optionally insert as text the abdexter or dexter from introspecting the instruction and edit it as the replacement.
    [ ...same as #2 in "Construct an instruction" above... ]
  3. Complete the evaluation for the replacement.

Store an instruction for later use

  1. Pair a description (t.i. "double-quoted text") with an instruction.
  2. Write to an external storage device.
    [ ...remember that section is from long ago,
    needs to be revised... ]

Re-store prior instructions

  1. Read a list from a storage device.
    [ ...remember that section is from long ago,
    needs to be revised... ]
  2. Introspection of the list.
  3. Assign a button to evaluate any abdexter or dexter that is a Lisp instruction, or to the whole list. (Any instruction at the press of a button)
    [ ...add another example over there that evaluates a list half... ]

# an intro for Lisp with StumpWM

At the core of Lisp is a paragon of lists, either empty or efficiently multi-dimensional, because Lisp is "LISt Processing".

Lists are notated parenthetically: ( ). There are also computer actions for constructing a list from a pair of items, for referencing an item in a list, and for associating a name to a list.


There are about a half-dozen important Lisp functions, t.i. named instructions.


An instruction for the computer is written as a parenthetical list beginning with a name for a computer action. That name is followed by any additional info needed for functioning in that manner.

Technically, a "Lisp form" is text formatted in a way that is readable by the Lisp interpreter. It can be as plain as a number, or "double-quoted text" such as for messages, or merely a name for a Lisp symbol associated with another Lisp form. It can also be a quoted symbol or list (with quote).


Decimal system numbers can begin with a - or +. A hexadecimal number begins with #x, then can have a - or +, then is followed by a group of 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f; capitalized is okay. A binary number begins with #b, then can have - or +, then is followed by a group of 0 or 1.

The Lisp interpreter prints a number as a decimal number, and without a +. For example, either 12 or #xC or #b+1100 is shown as 12.

A calculation with a number as a fraction, f.e. 4/3 or #b100/11 or #x4/3, produces a fraction when appropriate. For example, 4/3 subtracted from 2 results in 2/3, and #b100/11 subtracted from 2 also results in 2/3.

Basic calculations are with the +, -, *, and / Lisp functions (CLHS 12.2 The Numbers Dictionary). For example, (- 2 #b100/11) is 2/3. Notably (/ 4 3) is 4/3, but (/ 4.0 3) is 1.3333334 instead. The expt is for exponentials, f.e. 2^3 is (expt 2 3) is 8, though 2.0 results from the reverse (expt 8 1/3).


The "Eval: " prompt for Lisp instructions is from the stumpwm:eval-line command with "Control-t :" (The Lisp instruction prompt: an outlet for ingenuity). Type the name of a Lisp symbol to reveal whether it is associated with anything, or type a Lisp instruction for the computer.

Eval: something
The variable SOMETHING is unbound.Backtrace...
Eval: (quote something)
SOMETHING

quote (CLHS): Suppress immediate evaluation of a legitimate Lisp form. Commonly abbreviated to one single quote mark ' instead, especially in messages with results or feedback from the Lisp interpreter.

Though evaluation is suppresed, the quoted item is expected to be a legit Lisp form, otherwise the Lisp interpreter (SBCL) complains. A quoted legit placeholder name is acceptable even when yet to be used.

However, a colon in the middle of a placeholder name (Optional or required collection names) indicates it is from a collection and it must already exist, otherwise an error is shown.

Eval: something
The variable SOMETHING is unbound.Backtrace...
Eval: (quote something)
SOMETHING
Eval: 'something
SOMETHING
Eval: (quote (quote something))
'SOMETHING
Eval: (quote cl:something)
Symbol "SOMETHING" not found in the COMMON-LISP package.
       Stream: #<dynamic-extent STRING-INPUT-STREAM (unavailable) from "'cl:some...">Backtrace...

cons (CLHS): Construct a new list by pairing two Lisp forms (Lisp lists are pairs).

Keep in mind the Lisp interpreter messages abbreviate the dextral half of a list (Abbreviated notation for the dextral half), and nil when it is the dexter because nil is treated as an empty list (Lisp and NIL: No Items in List).

Eval: (cons "Two words." (quote a-name))
("Two words." . A-NAME)
Eval: (cons 3 '("Two words." . a-name))
(3 "Two words." . A-NAME)
Eval: (cons 'something nil)
(SOMETHING)
Eval: (cons ( ) 'something)
(NIL . SOMETHING)
Eval: (quote (cons 'something 'more))
(CONS 'SOMETHING 'MORE)
Eval: (quote (something . more))
(SOMETHING . MORE)

car (CLHS): Call up the abdexter reference of a list, t.i. its left half.

The left half of a list is often referred to as "the car", or "the abdexter", or "the abbi". Especially for a series of list halves, t.i. sublevels of a data matrix, it is more simply spoken as "ab" or "a", or just "a" when written.

For example, in the list "((1 . 2) . (3 . 4))" the number 3 is the abdexter of the dexter, or the "ab-dex". Written briefly as the "ad" but spoken individually as "a d".

Eval: (car (quote ((1 . 2) . (3 . 4))))
(1 . 2)
Eval: (car (cdr '((1 . 2) . (3 . 4))))
3

cdr (CLHS): [just say "c-d-r", or "dexter"] Call up the dexter reference of a list, t.i. its right half.

The left half of a list is often referred to as "the c-d-r", or "the dexter", or "the dexi". Especially for a series of list halves, t.i. sublevels of a data matrix, it is more simply spoken as "dex" or "d", or just "d" when written.

For example, in the list "((1 . 2) . (3 . 4))" the number 2 is the dexter of the abdexter, or the "dex-ab". Written briefly as the "da" but spoken individually as "d a".

Eval: (cdr '((1 . 2) . (3 . 4)))
(3 . 4)
Eval: (cdr (car '((1 . 2) . (3 . 4))))
2

eval (CLHS): Evaluating the contents of named memory will return the results. Evaluating a list quoted with quote (or preceded with an apostrophe) requires the list is an instruction, t.i. the leftmost item is the name of a function.

Eval: '(cons 1 2)
(CONS 1 2)
Eval: (eval '(cons 1 2))
(1 . 2)
Eval: (setf later.test '(cons 1 2))
(CONS 1 2)
Eval: later.test
(CONS 1 2)
Eval: (eval later.test)
(1 . 2)

setf (CLHS): Assign the temporary memory of the Lisp interpreter.

Associate a name with "double-quoted text", a number, the evaluated results of a Lisp instruction, or a quoted Lisp instruction for later evaluation. Or, associate one of the references within a list with anything, such as setting the car of the list.

Eval: prose
The variable PROSE is unbound.Backtrace...
Eval: (setf prose "A list of characters." a-list '(10 . 9))
(10 . 9)
Eval: prose
"A list of characters."
Eval: a-list
(10 . 9)
Eval: (setf (cdr a-list) 4)
4
Eval: a-list
(10 . 4)
Eval: (setf do-it (quote (setf (car a-list) 15)))
(SETF (CAR A-LIST) 15)
Eval: do-it
(SETF (CAR A-LIST) 15)
Eval: a-list
(10 . 4)
Eval: (eval do-it)
15
Eval: a-list
(15 . 4)
Eval: do-it
(SETF (CAR A-LIST) 15)

# reading and writing within the Lisp interpreter


[ ...need to revise, essentially as "Naming and writing memos"... ]

The means for associating a nickname with information on a computer has generally been obscure with the software pre-installed on it. However, a Lisp interpreter such as SBCL used by StumpWM makes it straightforward with the Common Lisp setf macro (CLHS). Any information can be noted within the Lisp interpreter by associating a label with it.

(setf
remember "Something to remember."
a-name   "And one more thing.")

Nonetheless, that, too, is obscured as Common Lisp has 978 symbols of its own, including variables, functions, and macros. For whatever reasons, many implementations of Common Lisp (such as SBCL) have implemented everything as if the Common Lisp specification was an assignment.

As aforementioned, the evaluation prompt provided by "Control-t :" in StumpWM waits for only a single line, suitable for a quick short note (The Lisp instruction prompt: an outlet for ingenuity).

Eval: (setf a-symbol "A name is a Lisp symbol.")
"A name is a Lisp symbol."

To see the information again, simply type the name in the evaluation prompt again and type the Return button or Enter button. The name, a Lisp symbol, will be evaluated and once again a message with the result will be displayed for a few seconds, then disappear again.

Eval: a-symbol
"A name is a Lisp symbol."

As noted about Lisp and NIL, the final item in every parenthetical list is denoted by a space-separated dot, t.i. a period. The final list item is typically nil, so for brevity such lists are typed or printed without it, as mentioned in Lisp lists are pairs. Therefore, a list without a dotted final item actually does have one, and in that case it is nil.

Therefore, a straightforward way of converting a named symbol with a single item into a list for itself is pairing it with nil, and re-using its name. Notice from the message that the Lisp interpreter favors printing the abbreviated form, without the dotted nil.

Eval: remember
"Something to remember."
Eval: (setf remember (cons remember nil))
("Something to remember.")
Eval: remember
("Something to remember.")

Replace with a new list from the cons function by pairing the new information with the list itself.

Eval: (setf remember (cons "Curiosity more than expectations." remember))
("Curiosity more than expectations."
 "Something to remember.")
Eval: (setf remember (cons a-name remember))
("And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")
Eval: (setf remember (cons a-symbol remember))
("A name is a Lisp symbol."
 "And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")
Eval: (setf remember (cons "A quick note: write questions on paper." remember))
("A quick note: write questions on paper."
 "A name is a Lisp symbol."
 "And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")
Eval: remember
("A quick note: write questions on paper."
 "A name is a Lisp symbol."
 "And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")

Multiple car and cdr references can be abbreviated up to four places, as mentioned in Lisp lists are pairs. For example, a reference to the car of the cdr of a list can be from the abbreviated cadr function, t.i. the "a-d" of the list. As noted about Lisp and NIL, a list without a dotted final item actually does have one, and in that case it is nil.

Eval: (car remember)
"A quick note: write questions on paper."
Eval: (cdr remember)
("A name is a Lisp symbol."
 "And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")
Eval: (car (cdr remember))
"A name is a Lisp symbol."
Eval: (cadr remember)
"A name is a Lisp symbol."
Eval: remember
("A quick note: write questions on paper."
 "A name is a Lisp symbol."
 "And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")
Eval: (cddddr remember)
("Something to remember.")
Eval: (car (cddddr remember))
"Something to remember."
Eval: (cdr (cddddr remember))
NIL

The information is accessible only while the Lisp interpreter exists, so it will be gone after quitting StumpWM or turning off the computer. On the other hand, there are ways of removing parts of a list, and without turning off the computer.

Recall the setf instruction can set the value for a position in a list (An intro for Lisp), t.i. either the car or the cdr of the list. That makes leaving out an item simple, which is the same as removing it.

Eval: remember
("A quick note: write questions on paper."
 "A name is a Lisp symbol."
 "And one more thing."
 "Curiosity more than expectations."
 "Something to remember.")
Eval: (car (cdr (cdr remember)))
"And one more thing."
Eval: (cdr (cdr (cdr remember)))
("Curiosity more than expectations."
 "Something to remember.")
Eval: (setf (caddr remember) (cdddr remember))
("Curiosity more than expectations."
 "Something to remember.")
Eval: remember
("A quick note: write questions on paper."
 "A name is a Lisp symbol."
 "Curiosity more than expectations."
 "Something to remember.")

# reading and writing with the computer medium


[ ...need to revise, probably "...Long-term storage of memos"... ]

Write information to a document in computer memory so it will be available the next time the computer is turned on (if it successfully restarts) by using with-open-file (CLHS) along with pprint (CLHS) for "pretty printing".

The with-open-file instruction has a plethora of options because it uses open (CLHS), so focus on what is desired. For example: write to a document; create the document when non-existent; append to the document when it does exist.

(with-open-file
(to-the-doc-from-WOF "/actual/name/for/document"
:direction :output
:if-does-not-exist :create
:if-exists :append)
(pprint "What you can do, while weeping."
to-the-doc-from-WOF))

It turns out this makes the eyes water, as it is a bit much to be typing into the Lisp interpreter every single time, and the StumpWM evaluation prompt handles only one line at a time. However, a Lisp instruction is an abdextrally half-paired list (Lisp lists are pairs).

Consider writing on paper a list of instructions for writing to a document, then noting the parts.

(with-open-file
(WOFdoc "/actual/name/of/doc"
:direction :output
:if-does-not-exist :create
:if-exists :append)
(pprint "Less weeping." WOFdoc) )

That list of Lisp instructions is essentially a list of three items.

  1. The name of the function for the instruction list: with-open-file.

  2. A list of options for with-open-file. First, a placeholder for when the document is opened successfully, followed by the location and document name, which is required. After those two, an option name is associated with an option, as many as needed. (Therefore, there will be an even number of list items.)

  3. The pprint instruction list. It prints any quoted Lisp form, such as "double-quoted text" or the results of Lisp instructions. After that is the reference to the opened file provided by the aforementioned placeholder declared in the list of options for with-open-file.

One approach is by constructing each sublist separately using quote (An intro for Lisp), or its abbreviated form as one single quote mark ', to write as much as comfortably possible at the evaluation prompt. Associate a placeholder name for each with setf.

Eval: (setf wof-options '(WOFdoc "/actual/name/of/doc" :direction :output :if-does-not-exist :create :if-exists :append))
(WOFDOC "/actual/name/of/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
Eval: (setf the-printer '(pprint "Divide and concoct." WOFdoc))
(PPRINT "Divide and concoct." WOFDOC)

A confirmation message from the Lisp interpreter prints the names of Lisp symbols with all uppercase letters. That is partially because the Lisp interpreter acknowledges only one case for letters in symbol names, and the convention of the Lisp interpreter is to reveal that by printing Lisp symbols as having uppercase letters.

Of course, that means symbol names varying only by case all reference the same symbol assigned to the same information. For example, the Common Lisp instruction names can be typed with whatever case desired and the Lisp interpreter will be fine with that, such as Format or FORMAT or fOrMat, and so on.

A Lisp instruction is an abdextrally half-paired list (Contrary formation and Lisp instructions) that begins with nil as its dexter. As it is leftwardly constructed, each additional part is the left half of the pair and the gradually forming list is always the right half.

Remember, using the up/down arrow buttons within the evaluation prompt brings forth prior/later typed text for editing and re-using, thereby less re-typing (The Lisp instruction prompt: an outlet for ingenuity).

Eval: (setf write-to-doc-recipe (cons the-printer nil))
((PPRINT "Divide and concoct." WOFDOC))
Eval: (setf write-to-doc-recipe (cons wof-options write-to-doc-recipe))
((WOFDOC "/actual/name/of/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT "Divide and concoct." WOFDOC))
Eval: (setf write-to-doc-recipe (cons (quote with-open-file) write-to-doc-recipe))
(WITH-OPEN-FILE
(WOFDOC "/actual/name/of/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT "Divide and concoct." WOFDOC))

The name is just a placeholder for the list of Lisp instructions, so the name by itself just reveals what it references.

Eval: write-to-doc-recipe
(WITH-OPEN-FILE
(WOFDOC "/actual/name/of/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT "Divide and concoct." WOFDOC))

Evaluate what the placeholder references by placing it in an instruction list using eval (An intro for Lisp). The "double-quoted text" listed with the pprint instruction will be written to the document named with the overall with-open-file instruction.

Eval: (eval write-to-doc-recipe)

[ ...describe the Lisp instructions for reading from a document, perhaps with read (CLHS), though it is a little bit tricky to view a whole document... ]


[ ...describe the delete-file (CLHS) instruction for deleting the files... ]

   (delete-file "/name/of/file")

Whenever desired, either change what to write to the document or change the document name with setf (An intro for Lisp). Query the parts of the recipe for confirmation of the correct place to change before changing it.

Eval: write-to-doc-recipe
(WITH-OPEN-FILE
(WOFDOC "/actual/name/of/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT "Divide and concoct." WOFDOC))
Eval: (car (cdr write-to-doc-recipe))
(WOFDOC "/actual/name/of/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
Eval: (cadr (cadr write-to-doc-recipe))
"/actual/name/of/doc"
Eval: (setf (cadr (cadr write-to-doc-recipe)) "/another/doc")
"/another/doc"
Eval: (caddr write-to-doc-recipe)
(PPRINT "Divide and concoct." WOFDOC)
Eval: (cadr(caddr write-to-doc-recipe)))
"Divide and concoct."
Eval: (setf (cadr (caddr write-to-doc-recipe)) "This is something else.")
"This is something else."
Eval: write-to-doc-recipe
(WITH-OPEN-FILE
(WOFDOC "/another/doc" :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT "This is something else." WOFDOC))

Optionally, use setf to replace the text in the instructions with a placeholder. Thereon, use setf to change the placeholder instead of the Lisp instructions. Optionally, insert a placeholder in the instructions for the document name, too.

Eval: (setf (cadr (cadr write-to-doc-recipe)) (quote doc-for-writing))
DOC-FOR-WRITING
Eval: (setf (cadr (caddr write-to-doc-recipe)) (quote text-to-write))
TEXT-TO-WRITE
Eval: write-to-doc-recipe
(WITH-OPEN-FILE
(WOFDOC DOC-FOR-WRITING :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT TEXT-TO-WRITE WOFDOC))
Eval: (setf doc-for-writing "/and/another/doc")
"/and/another/doc"
Eval: (setf text-to-write "Something for another document.")
"Something for another document."
Eval: (eval write-to-doc-recipe)
Eval: (setf text-to-write "And some more.")
"And some more."
Eval: (eval write-to-doc-recipe)

[ ...describe a setf instruction that will set the contents of the recipe to a placeholder write-to-doc... ]

   (setf recipe-for-later (cons write-to-doc-recipe nil))
   (setf recipe-for-later (cons 'write-to-doc recipe-for-later))
   (setf recipe-for-later (cons 'setf recipe-for-later))

[ ...Therefore that instruction sets a placeholder named write-to-doc to the contents of the recipe. Write that setf instruction to a document, then it can be read by the Lisp interpreter later with the load instruction. No need to type the recipe again and it is readily used with eval. ... ]

[ ...Typing the name in the evaluation prompt reveals the recipe. That shows the document name and text to write both have placeholders in the recipe for easily changing without needing to modify the recipe. ... ]

Ultimately, choose a new document name for writing these Lisp instructions. [ ...refer to the previously described new symbol with new instructions... ] Evaluate the instructions again and this recipe is written to that chosen document.

Eval: (setf doc-for-writing "/doc/for/this/recipe")
"/doc/for/this/recipe"
Eval: (setf text-to-write recipe-for-later)
(SETF WRITE-TO-DOC
(WITH-OPEN-FILE
(WOFDOC DOC-FOR-WRITING :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE :IF-EXISTS :APPEND)
(PPRINT TEXT-TO-WRITE WOFDOC)))
Eval: (eval write-to-doc-recipe)

[ ...describe using load for reading it from the document. Or, maybe with read then eval... ]

# introspection of a list at the press of a button

dexi-abbi list introspection

[ ...eventually assign buttons to the instructions,
 and demonstrate on a common Lisp instruction
 or arbitrary abdextrally half-paired list... ]

(Dexi-abbi introspection)

dexi-abbi swap of cDAr and cADr

[ ...eventually assign buttons to the instructions,
 and demonstrate on a common Lisp instruction
 or arbitrary abdextrally half-paired list... ]

Ensure nil at both ends. A lisp instruction already has nil at its rightmost end.

(setf
 abbi.inspect (cons nil a.lisp.instruction))

Shift the cDAr rightward by shifting the cADr leftward. Work on a copy by setting the results to the name, instead of setting each half of car and cdr by reference.

(setf abbi.inspect
 (cons
  (cons
   (cons
    (caar abbi.inspect)
    (cADr abbi.inspect))
   (cDAr abbi.inspect))
  (cddr abbi.inspect)))

Shift the cADr leftward by shifting the cDAr rightward. Work on a copy by setting the results to the name, instead of setting each half of car and cdr by reference.

(setf abbi.inspect
 (cons
  (caar abbi.inspect)
  (cons
   (cADr abbi.inspect)
   (cons
    (cDAr abbi.inspect)
    (cddr abbi.inspect)))))

An actual swap is its own inverse, hence can reverse itself. Work on a copy by setting the results to the name, instead of setting each half of car and cdr by reference.

(setf abbi.inspect
 (cons
  (cons
   (caar abbi.inspect)
   (cADr abbi.inspect))
  (cons
   (cDAr abbi.inspect)
   (cddr abbi.inspect))))

extract and insert

[ ...eventually assign buttons to the instructions,
 and demonstrate on a common Lisp instruction
 or arbitrary abdextrally half-paired list... ]

([ ...extract and insert... ])

# customize prompts and messages

The messages and prompts from StumpWM appear when needed, each at pre-specified locations on the screen. The characteristics of text color, background color, and the border are generally shared by both messages and prompts (StumpWM 4.1).

As expected, those characteristics are adjustable with the Lisp instruction prompt (...an outlet for ingenuity).

Location of prompts and messages
Border and padding
Color for prompts:
Three message types, and their color

# location of prompts and messages

Use setf (An intro for Lisp) to set the location of prompts and the location of messages.

Eval: (setf stumpwm:*input-window-gravity* :center)
Eval: (setf stumpwm:*message-window-gravity* :bottom)

Possible gravity names for the messages or prompts begin with a colon ":".

 _______________________________________________
| :top-left |      |  :top   |     | :top-right |
|___________|      |_________|     |____________|
|                                               |
|                                               |
|--------          -----------         ---------|
| :left |          | :center |         | :right |
|--------          -----------         ---------|
|                                               |
|______________     _________    _______________|
| :bottom-left |   | :bottom |  | :bottom-right |
|______________|___|_________|__|_______________|

# border and padding

The border width from stumpwm:set-msg-border-width and its color (X Window System color) from stumpwm:set-border-color are absolutely consistent for prompts and all types of messages. Use setf for the padding around messages and prompts.

Eval: (stumpwm:set-msg-border-width 3)
Eval: (stumpwm:set-border-color "CornflowerBlue")
Eval: (setf stumpwm:*message-window-padding* 7)
Eval: (setf stumpwm:*message-window-y-padding* 5)

# color for prompts

The prompts use the background color from stumpwm:set-bg-color and the text color (foreground) from stumpwm:set-fg-color. Any standard X Window System color.

Eval: (stumpwm:set-bg-color "DarkOrchid4")
Eval: (stumpwm:set-fg-color "Thistle1")

# three message types, and their color

The colors get messy in StumpWM when it comes to its messages. There are at least three types: documentation messages, error messages, and messages with Lisp results. They use some of the eight colors listed in stumpwm:*colors*.

Documentation messages come from the help commands describe-command, describe-key, where-is, describe-variable, and describe-function. The default buttons that invoke them are listed by "Control-t h ?" (StumpWM keymap: *help-map*).

Documentation messages use the same background and text colors as the prompt, t.i. stumpwm:set-bg-color and stumpwm:set-fg-color. They also emphasize some text with the sixth color (darker and brighter) from stumpwm:*colors*. Technically, that means four colors must be coordinated legibly.

Eval: (setf (cADr (cDDDDr stumpwm:*colors*)) "LightSkyBlue1")
Eval: (stumpwm:update-color-map (stumpwm:current-screen))

Error messages use the background color from stumpwm:set-bg-color, but for the text they use the second color (its lighter version) in stumpwm:*colors*, t.i. its cadr.

Eval: (setf (cADr stumpwm:*colors*) "DeepSkyBlue3")
Eval: (stumpwm:update-color-map (stumpwm:current-screen))

Messages from Lisp results are temporarily displayed after using the Lisp instruction prompt (...an outlet for ingenuity). Those messages use the background color from stumpwm:set-bg-color only for the padding around the message. The background and text colors are the darker versions of the car and caddr colors from stumpwm:*colors*.

Eval: (setf (cAr stumpwm:*colors*) "DarkOrchid4")
Eval: (setf (cADDr stumpwm:*colors*) "Thistle1")
Eval: (stumpwm:update-color-map (stumpwm:current-screen))

Consider using a substitute for update-color-map (github.com) that respects the colors of stumpwm:*colors*. Just copy into a new file and modify it, then load the file with load and use the new instruction. Note some names within it will need "stumpwm::" (two colons).

For example, simply changing the -0.25 to 0 ensures the first fabricated list is the exact colors specified rather than darker. Maybe drop the brightener to 0.2 for the second fabricated list, or perhaps accept more colors in an &optional additional list.

# customize the buttonboard [...revision...]

A computer does what a person desires at the mere press of a button, but for most people that is only science fiction (Any instruction at the press of a button).

The default response of a computer for a button pressed on a buttonboard is either invoking a command, or simply ignored. Typical computer commands store info into computer memory, or maybe draw a symbol on the screen.

A list of buttons paired with command names or specific instructions is a "keymap". The Xserver provides the default keymaps for any buttonboard attached to the computer, pairing the location of each button to the symbol name presumed to be written on it.

The Xserver observes all button presses from all buttonboards or other devices attached to the computer (Discover keycodes for buttons), then informs the relevant computer program. StumpWM is a computer program that insists on managing specific or sometimes all button presses from the Xserver.

StumpWM uses its own keymaps for matching a button pressed on the buttonboard to one of its own commands. When there is no match, the Xserver passes it on to the next relevant computer program, if any.

   buttonboard
       \/
     Xserver
       \/
       \/         matched
 StumpWM keymap     >>>   StumpWM command

    no match
       \/
     Xserver
       \/
       \/         matched
computer program    >>>   command
     keymap

    no match
       \/
 typed or ignored

That computer program matches the button to one of its own commands. Otherwise, the program might request the relevant Xserver keymap (based on pressed modifier buttons like Shift) and match the button with it. Typically, that results in typing a symbol, if it is that kind of computer program.

# understanding buttonboard keymaps

All of the buttons on a buttonboard are essentially the same, and their symbols are only suggestions. Swapping the button caps does nothing to change what the computer does when a button is pressed, because the buttonboard itself remains unchanged.

The computer is usually given a list of buttonboard locations associated with an instruction for each, a mapping of buttons known as a "keymap". An instruction might draw something on the screen, or maybe it changes the keymap for the buttonboard thereby enabling a different list of instructions from the buttons.

There are usually at least two keymaps with instructions for entering letters, numbers, and punctuation, and a few other keymaps for invoking commands. For example, perhaps lowercase letters are from one keymap, and uppercase from another.

..:___:___:___:..             ..:___:___:___:..
  |   |   |   |      hold       |   |   |   |
  | q | w | e |      Shift      | Q | W | E |
..|___|___|___|..    button   ..|___|___|___|..
  |   |   |   |         -->     |   |   |   |
  | a | s | d |                 | A | S | D |
..|___|___|___|..             ..|___|___|___|..
  :   :   :   :                 :   :   :   :

The Shift button is a "modifier" button, a button whose instruction swaps out the default keymap for an alternate keymap. The traditional modifier buttons have been Shift, Control, Alt, Hyper, Meta, Super, Command, Option, and many others.

For example, hold the Shift button and the computer references a different list of button instructions, t.i. a different keymap, while that modifier button is held. Release the Shift button and the default keymap is active again.

The Shift Lock or Caps Lock modifier buttons provide a similar effect, but without needing to hold either one. Instead, press and release one of them to make that alternate keymap active, then press and release again to make the default keymap active.

# find commands and buttons

StumpWM makes use of invisible typing, partly because it lacks its own manufactured buttonboard with dedicated buttons for itself. StumpWM re-assigns buttons despite what is already written on them, initially for invoking specific prompts and other commands (Interactive curiosity: typing for actions and help).


Many commands are bound to a sequence of buttons, with the first button as "Control-t". Each button in the sequence is bound to a keymap (), except the final button which invokes its command.

Typing a button for a keymap and then a question mark "?" reveals its list of commands and sub-keymaps (). That also makes the question mark "?" an innocuous means for canceling a button sequence.

Invoke the which-key-mode command and then from that moment on each keymap is automatically revealed while typing any button sequence (Invoke a StumpWM command by its name). Invoking the which-key-mode command a second time cancels the effect.


The stumpwm:describe-key command reveals the command associated with a button or a sequence of buttons (Invoke a StumpWM command by its name).

: describe-key
Describe Key:
C-t h k is bound to "describe-key".
DESCRIBE-KEY KEYS
Either interactively type the key sequence or supply it as text. This command prints the command bound to the specified key sequence.
Describe Key:
ESC is not bound.

That also reveals the actual name of a button, which might be different than what is written on it. Capital letters matter. For example, the "delete" button is actually named "DEL" and the "forward delete" button is actually named "Delete".

The Control button is abbreviated "C-". The Meta button is "M-", but might also imply the Alt button or Option button instead when it is unavailable. The Shift button is merely implied by punctuation or a capital letter needing it.


The stumpwm:where-is command provides a comma-separated list of all the buttons paired to a command (Invoke a StumpWM command by its name). Space-separated buttons means it is a sequence with its initial buttons paired to keymaps before its final button.

: where-is
Where is command: where-is
"where-is" is on C-t h w.
Where is command: time
"time" is on C-t a, C-t C-a.


[ ...describe revealing the button list for a keymap...

...likely include the stumpwm::*escape-key* button...
... ]

Press and release the button paired with a keymap, t.i. its "Prefix", then type a question mark "?" to reveal the buttons defined in it.

# make a StumpWM keymap and pair a button

The stumpwm:define-key is for pairing a button with either a StumpWM command or with a StumpWM keymap.

Press and release a button that has been paired with a command, then that command is invoked. Press and release a button that has been paired with a keymap, then that keymap temporarily replaces the *top-map* keymap (StumpWM keymap: *top-map*) until the next button is pressed.

A command or keymap can be paired multiple times, even within the same keymap. However, a button can be defined only once within a keymap. Defining the same button again within the same keymap simply replaces its previous definition.


# Make a blank StumpWM keymap.

The stumpwm::make-kmap instruction makes a new empty keymap. Use the setf (An intro for Lisp) to assign a name to the new keymap.

Eval: a-new.keymap
The variable A-NEW.KEYMAP is unbound.Backtrace...
Eval: (setf a-new.keymap  (stumpwm::make-kmap))
#S(STUMPWM::KMAP :BINDINGS NIL)

# Pair a button with a command or keymap.

The stumpwm:define-key instruction adds to a specified keymap a button name paired with either a double-quoted StumpWM command or the quote (An intro for Lisp) of a StumpWM keymap. The stumpwm:kbd instruction converts a button name to a StumpWM key description.

: describe-command
Describe Command: colon
COLON &OPTIONAL INITIAL-INPUT
Read a command...
Eval: (define-key a-new.keymap  (kbd "F1") "colon")
: describe-key
Describe Key:
ESC is not bound.
Eval: (define-key *top-map*  (kbd "ESC") 'a-new.keymap)
: describe-key
F1 is not bound.
: describe-key
ESC F1 is bound to "colon".
COLON &OPTIONAL INITIAL-INPUT
Read a command...

Prefix: ESC
F1    colon

Pairing a button with a keymap might also automatically assign to that keymap the question mark "?" button for conveniently revealing its list of buttons (Find commands and buttons). The question mark for that is never listed.

When the question mark "?" button is already assigned in the keymap, then there is no default way of revealing the whole listing until its question mark is unpaired. Instead, consider the describe-key or the where-is commands (Find commands and buttons).


# Unpair a button.

Prefix: ESC
(EMPTY MAP)

Pair a button with nil to return it to normal for a specific keymap.

Eval: (define-key a-new.keymap  (kbd "F1") nil)
: describe-key
ESC F1 is not bound.

# [...fill a keymap...]


[ ...repurpose a former section into a new example
 for stumpwm::fill-keymap...

...note stumpwm::fill-keymap requires
 the name is set to nil
 rather than to a keymap...

...simply reset a named keymap
 to NIL before filling it,
 or fill for a newly assigned name
 and then setf the stored results
 to the name of a prior keymap...
... ]

Think of an unused name for a new keymap, then assign nil to it with setf. That name is for referencing the memory that has the keymap, such as setting it to nil before filling it, or setting it to a prior keymap.

Eval: buttons.my
The variable BUTTONS.MY is unbound.Backtrace...
Eval: (setf buttons.my nil)

Choose buttons that personally make sense for each command, and fit comfortably with the workflow of the day or hour.

Eval: (stumpwm::fill-keymap  buttons.my  (kbd "c")"pull-hidden-other"  (kbd "f")"pull-hidden-previous"  (kbd "j")"pull-hidden-next"  (kbd "m")"run-shell-command"  (kbd"x")"gother"  (kbd"d")"gprev"  (kbd"k")"gnext"  (kbd",")"gnew")

Assign the keymap to a button either before or after filling it for the first time. No need to do it again after changing the keymap. Use the quote for the keymap name rather than double-quotes with stumpwm:define-key (Pair a button with a command or keymap).

: describe-key
F20 is not bound.
Eval: (define-key *top-map* (kbd "F20") 'buttons.my)
Prefix: F20
c     pull-hidden-other
f     pull-hidden-previous
j     pull-hidden-next
m     run-shell-command
x     gother
d     gprev
k     gnext
,     gnew

Type the button for the keymap and then a question mark "?" to get a listing of the abbreviations. They are listed in the order they were added.

Modify the new keymap at any time as usual. Add another button and command (Pair a button with a command or keymap), or remove a button (Unpair a button).


Consider storing the original instruction for filling that named keymap with the setf and the quote, by using the up/down arrows for bringing forth the prior/next lines for less re-typing (Typing within a line of text).

Eval: fill.buttons.my
The variable FILL.BUTTONS.MY is unbound.Backtrace...
Eval: (setf fill.buttons.my   '(stumpwm::fill-keymap  buttons.my  (kbd "c")"pull-hidden-other"  (kbd "f")"pull-hidden-previous"  (kbd "j")"pull-hidden-next"  (kbd "m")"run-shell-command"  (kbd"x")"gother"  (kbd"d")"gprev"  (kbd"k")"gnext"  (kbd",")"gnew")

Modify it at any time, perhaps with introspection (Abbi-abbi introspection). Add another button and command to the list, or just change the order for a different ordered listing from the question mark "?".


Reset the keymap to nil before evaluating the instruction to refill the keymap again, because stumpwm::fill-keymap refuses to replace a keymap. Consider storing the current keymap to another name before resetting it, for restoring that version of the keymap later.

Eval: prior.buttons.my
The variable PRIOR.BUTTONS.MY is unbound.Backtrace...
Eval: (setf prior.buttons.my  buttons.my)
Eval: (setf buttons.my  nil)
Eval: (eval fill.buttons.my)
...some time later...
Eval: (setf buttons.my  prior.buttons.my)

# examples of custom commands

Assigning a button to Lisp instructions for StumpWM requires the instructions are a StumpWM command.

Conveniently, eval-line is a StumpWM command that evaluates a Lisp instruction given to it. It optionally accepts info immediately without need for the prompt.

The stumpwm:define-key allows for giving such info to a command within the double-quotes, but there must be a space after the command.

No need to create a new command for every set of Lisp instructions. Just pick a button on the button board and associate with any keymap (Make a StumpWM keymap and pair a button).


# Any instruction at the press of a button.

Consider storing an instruction in named memory, then use the eval Lisp instruction to evaluate the named memory. Coincidentally, the "double-quoted text" prevents the need for named memory to already exist.

: describe-key
F14 is not bound.
Eval: (define-key *top-map* (kbd "F14") "eval-line (eval do.it)")

Change the instruction in the named memory whenever desired. No need to redefine the button, it will evaluate whatever is currently in the named memory.


# Introspect a duplicated half-paired list.

Consider defining buttons for introspection of a half-paired list, f.e. perhaps a Lisp instruction (Contrary formation and Lisp instructions). Specifically, consider abbi-abbi introspection (Abbi-abbi introspection), and ensure working on a copy.


Introspect its cADr rightwardly by continuously associating the cADr with the cAr. Note the name is assigned to the memory that has the new result, thereby no longer referencing the original list.


(setf abbi-abbi.inspect
 (cons
  (cons
   (cADr abbi-abbi.inspect)
   (cAr abbi-abbi.inspect))
  (cDDr abbi-abbi.inspect)))
: describe-key
F17 is not bound.
Eval: (define-key *top-map* (kbd "F17") "eval-line (setf abbi-abbi.inspect (cons (cons (cADr abbi-abbi.inspect) (cAr abbi-abbi.inspect)) (cDDr abbi-abbi.inspect)))")

Introspect its cADr leftwardly by continuously associating the cAAr with the cDr. Note the name is assigned to the memory that has the new result, thereby no longer referencing the original list.


(setf abbi-abbi.inspect
 (cons
  (cDAr abbi-abbi.inspect)
  (cons
   (cAAr abbi-abbi.inspect)
   (cDr abbi-abbi.inspect))))
: describe-key
F16 is not bound.
Eval: (define-key *top-map* (kbd "F16") "eval-line (setf abbi-abbi.inspect (cons (cDAr abbi-abbi.inspect) (cons (cAAr abbi-abbi.inspect) (cDr abbi-abbi.inspect))))")

Use the setf to associate a list with the introspection name, t.i. the name used with setf in the instructions assigned to the buttons. Initially, that will be a reference to the memory (Re-listing rather than re-arranging).

Use the buttons until the StumpWM message reveals the desired sublist as the cADr. The instructions assigned to the buttons associate the name to the memory that has the new results, thereby no longer referencing the memory of the original list.


Easily assign a new cADr with the setf in the Lisp instruction prompt.

Eval: (setf (cadr abbi-abbi.inspect) 'something.new)

Prepend a new item to the cDr by pairing it with cDr. Nothing is eliminated.

Eval: (setf (cdr abbi-abbi.inspect) (cons 'something.new (cdr abbi-abbi.inspect)))

Displace the cADr is by setting it to a reference of the cDDr, thereby eliminating the cADr.

Eval: (setf (cadr abbi-abbi.inspect) (cddr abbi-abbi.inspect))

Use the buttons to rewind to the beginning to restore the new list. Use setf to associate the new list with a new name, or with the name of the original list to replace it.


# Introspect a referenced half-paired list.

Consider defining buttons for introspection of a half-paired list by reference, f.e. perhaps a Lisp instruction (Contrary formation and Lisp instructions). Specifically, consider abbi-abbi introspection (Abbi-abbi introspection), and maintain the reference to the orginal list.


Introspect its cADr rightwardly by continuously associating the cADr with the cAr. Note references to the car and cdr of the named memory are assigned individually rather than assigning the name itself to new memory.

(setf (cAr abbi-abbi.inspect)
 (cons
  (cADr abbi-abbi.inspect)
  (cAr abbi-abbi.inspect)))

(setf (cDr abbi-abbi.inspect)
 (cDDr abbi-abbi.inspect))

Consider using cons with the eval-line command in order to evaluate a pair of instructions (Two instructions at once).

: describe-key
F17 is not bound.
Eval: (define-key *top-map* (kbd "F17") "eval-line (cons (setf(cAr abbi-abbi.inspect) (cons(cADr abbi-abbi.inspect)(cAr abbi-abbi.inspect))) (setf(cDr abbi-abbi.inspect) (cDDr abbi-abbi.inspect)))")

Introspect its cADr leftwardly by continuously associating the cAAr with the cDr. Note references to the car and cdr of the named memory are assigned individually rather than assigning the name itself to new memory.


(setf (cDr abbi-abbi.inspect)
 (cons
  (cAAr abbi-abbi.inspect)
  (cDr abbi-abbi.inspect)))

(setf (cAr abbi-abbi.inspect)
 (cDAr abbi-abbi.inspect))
: describe-key
F16 is not bound.
Eval: (define-key *top-map* (kbd "F16") "eval-line (cons (setf(cDr abbi-abbi.inspect) (cons(cAAr abbi-abbi.inspect)(cDr abbi-abbi.inspect))) (setf(cAr abbi-abbi.inspect)(cDAr abbi-abbi.inspect)))")

Use the setf to associate a list from named memory with the introspection name, t.i. the name used with setf in the instructions assigned to the buttons. Initially, that will be a reference to the memory (Re-listing rather than re-arranging).

Use the buttons until the StumpWM message reveals the desired sublist as the cADr. Remember, these instructions assigned to the buttons associate results with individual references to the car and cdr of the list, t.i within the named memory, rather than reassigning the name itself to new memory.


Easily substitute the cADr using the setf, t.i. eliminate the current cADr and provide a new one.

Eval: (setf (cadr abbi-abbi.inspect) 'something.new)

Prepend a new item to the cDr by pairing it with cDr. Nothing is eliminated.

Eval: (setf (cdr abbi-abbi.inspect) (cons 'something.new (cdr abbi-abbi.inspect)))

Displace the cADr is by setting it to a reference of the cDDr, thereby eliminating the cADr.

Eval: (setf (cadr abbi-abbi.inspect) (cddr abbi-abbi.inspect))

Use the buttons to rewind to the beginning to restore the list, thereby also for the named memory it referenced.

Optionally use setf to assign nil to the introspection name in order to disassociate it from the list of the named memory it referenced, or to another list for another introspection.

# Customize the buttonboard

A computer does what a person desires at the mere press of a button, but for most people that is only science fiction.

Neural-scan interfaces, such as buttonboards and motionboxes, transcend operating systems by means of virtual network computing (VNC). Personalizing their operation on the client computer overcomes the inadequate options of a host computer.

A personalizable computer (...no need to change the world) shares its neural-scan interfaces by connecting to the VNC host on another computer on the same desk, then the latter has no need of its own. The common desire of "rebinding keys" for any software becomes consistent and steadfast, regardless of software upgrades on other computers.

Marking relevant starting points for the pointer (Make a point...) and consistently maneuvering it (Efficient pointer jumping) effectively supplants the arbitrary approach of the motionbox with a never-miss selection-based interface. This helps open the door to repeatability by the computer of a sequence of actions.

# Interactive keymaps: custom buttonboard layouts


[ ...an interactive keymap is less flexible
 than a "sparse keymap"
 because it is impossible to change the buttons afterwards
 for an interactive keymap (kinda contradictory),
 and the *root-map* is unavailable unless specifically assigned
 which means no buttons for Help or for prompts like eval-line
 unless specifically assigned...

...consider using stumpwm:push-top-map with a new keymap,
 then stumpwm:pop-top-map to restore prior keymap...

...But...those simply assign another keymap to *top-map*
 then they use the stumpwm:sync-keys function.
 Though those push/pop functions also save and restore
 the prior buttons assigned in *top-map*,
 that is nothing special because
 the assigned buttons could simply be already in another keymap.
 Just switch between various keymaps for *top-map* instead...

 In other words, consider from the Lisp instruction prompt:
  (cons (setf *top-map* another-keymap) (stumpwm:sync-keys))

... ]

[ ...
 ...the stumpwm:*root-map* is separate.

 so consider assigning the StumpWM prefix
 or any other preferred button
 to the *root-map* for its command buttons
 (such as for the various prompts like eval-line)...
... ]

[ ...

The StumpWM prefix button is always available, by default as "C-t". The StumpWM prefix is reliably referenced as stumpwm:*escape-key*. It is reliably re-assignable with set-prefix-key. Use the stumpwm:*escape-key* reference when wanting to assign the StumpWM prefix button to a button, such as for a command or to a keymap.


... ]


[ ...all info about "interactive keymaps"
 will likely be removed soon... ]

Evoking an interactive keymap temporarily enables its assigned buttons without need of a prefix button for each. That is very similar to using Shift Lock or Caps Lock in order to get capital letters, but in this case each assigned button instantly invokes a command instead.

The stumpwm:define-interactive-keymap (StumpWM 3.2) accepts a list of options after the chosen name for the interactive keymap, but an empty list or nil means apply the defaults. Next, each button and its desired command is grouped within parentheses, distinct from the others.

;;Consider rebinding the pointer-halving commands.
(stumpwm:define-interactive-keymap
 halving.map
 ()
 ((stumpwm:kbd "i") "pointer-halving-up.nu")
 ((kbd"j")"pointer-halving-left.nu")
 ((kbd"k")"pointer-halving-down.nu")
 ((kbd"l")"pointer-halving-right.nu")
 ((kbd";")"pointer-halving-toggle.nu")
 ((kbd"m")"pointer-halving-back.nu")
 ((kbd",")"pointer-halving-begin.nu")
 ((kbd".")"pointer-halving-recenter.nu")
 ((kbd"h")"pointer-button-activate.nu 1")
 ((kbd"u")"pointer-button-toggle.nu 1")
 ((kbd"n")"pointer-button-activate.nu 3"))

Use define-key to assign the button for activating the interactive keymap. Double-quote the chosen name because an interactive keymap is actually a command, unlike a sparse keymap (Make a list of command buttons).

   (stumpwm:define-key stumpwm:*top-map*
    (stumpwm:kbd "F7") "halving.map"))

By default, the ESC button, or the Return button, or "Control-g" disables the interactive keymap. As a command, the interactive keymap can be invoked by its chosen name with the commands prompt (Invoke a StumpWM command by its name) of "Control-t ;" (a semicolon), too.


[ ...describe at least the :exit-on option for changing the default buttons for exiting the interactive keymap. For example, set it to be the same as the button defined to start, so then it feels like an on/off toggle button for the interactive keymap. Probably something like:
(:exit-on ((kbd "F7")))
Or, also include "Control-g":
(:exit-on ((kbd "F7") (kbd "C-g")))
for the same familiarity of other StumpWM commands
... ]

[ ...describe defining an interactive keymap with the evaluation prompt (The Lisp instruction prompt) using list introspection (Exploring a half-paired list)...
Though, already described that for pointer jumping (Efficient pointer jumping for any grid of options)... ]

# pointer placement and activation


The most immediate change to StumpWM is applied with the eval-line command, available with Control-t then colon, usually notated as "C-t :" (The Lisp instruction prompt: an outlet for ingenuity).

# alternative for pointer activation and drag'n drop

The basic pointer activation in StumpWM (the Xwindow manager formerly known as "ratpoison") depends on a legacy function named ratclick. That might fail when the CLX library is without support for the XTEST extension for the Xserver, especially when the XTEST extension is undetected.

The StumpWM functions expect xlib:fake-button-event from a CLX library, but it has been known to be named xlib/xtest:fake-button-event (CLX "extensions/xtest.lisp": 13 and 117–128). Therefore, confirm the name and requirements in the sources when needed.

The xlib/xtest:fake-button-event requires a display like stumpwm:*display*, the number of the pointer-box button, and either t or nil for either pressing or releasing the button.

The primary button is usually 1 and the secondary button is traditionally 3, because the middle button is usually presumed even when nonexistent. Pressing a button on the pointer-box is one event, and releasing the same button is another event.

Eval: (setf press.1 '(xlib/xtest:fake-button-event stumpwm:*display* 1 t))
Eval: (setf release.1 '(xlib/xtest:fake-button-event stumpwm:*display* 1 nil))

Consider defining a separate buttonboard button (Any instruction at the press of a button) for each event, then drag'n'drop can be done without disaster.

: describe-key
F7 is not bound.
Eval: (stumpwm:define-key stumpwm:*top-map* (stumpwm:kbd "F7") "eval-line (eval press.1)")
: describe-key
F8 is not bound.
Eval: (stumpwm:define-key stumpwm:*top-map* (stumpwm:kbd "F8") "eval-line (eval release.1)")

Consider combining both events for a single buttonboard button, for when the pointer is already in the perfect location. The eval-line evaluates only one Lisp form (The Lisp instruction prompt: an outlet for ingenuity), but cons is a single instruction that accepts two Lisp forms (There can be only one instruction).

Eval: (cons (eval press.1) (eval release.1))

Drag'n'drop involves moving the pointer. A press of the button at the drop location is probably innocuous. Consider repurposing the buttonboard button assigned to releasing the pointer-box button, as the press/release combo event likely suffices. Otherwise, choose another buttonboard button.

Eval: (define-key *top-map* (kbd "F8") "eval-line (cons (eval press.1) (eval release.1))")

Consider adding the actions to an interactive keymap (...custom buttonboard layouts), such as with pointer jumping (Efficient pointer jumping) or pointer halving (Mathemagical pointer and cursor placement).

# toggle for drag'n drop

A dragon would probably drop what a bird typically drops, as they both have a cloaca, but likely a bit more biohazardous for anyone underneath it. Similarly, accidentally letting go of the button on a pointer-box while trying to reposition the cursor might be disasterous, or at least lead to extra work to undo the accident.

The Xserver keeps track of whether a "pointer button" has been pressed, as well as any pressed modifier buttons on the buttonboard intended for that pointer button. As such, it is possible to toggle a button press and a button release individually with the same command bound to a single button on the buttonboard instead.

The Common Lisp X Interface function xlib:query-pointer (CLX 13.5 Pointer Position) reveals what pointer buttons are pressed, by means of the fifth element it returns.

(car
(cddddr
(multiple-value-call 'list
(xlib:query-pointer
(stumpwm:screen-root(stumpwm:current-screen))))))

For example, when button 1 is pressed, the result from it is 256, because it is actually the binary mask: 00000001 00000000. The first part (from right to left, just like decimal numbers) indicates the modifier buttons pressed on the buttonboard, with zero meaning nothing pressed. While 2^8 is 256 (t.i. 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2), the eight bits include zero, therefore the first byte is 0–255. A ninth bit is required to begin the next range for 256–511 (instead of 512 for 2^9), which is why the ninth bit is 1 and represents 256.

A decimal number can be used as a mask, which is why the results of xlib:query-pointer returns "256". The binary "1 00000000" is merely a different way of writing the number, rather than a different number. Specifically, in Common Lisp #b100000000 means that is a binary number, which is 1 with eight zeros, the aforementioned "256".

The Xserver seems to track only five pointer buttons, so only the first five bits are used of the second 8-bit byte. That means when there are five buttons on a pointer-box and all are pressed (and held), and with no modifier buttons pressed, then the Xserver would return the number known in binary as: 00011111 00000000.

One way to programmatically determine from the bits of such a number which button is pressed is with Common Lisp logic functions (CLHS 12.2 The Numbers Dictionary). For example, logand can compare each bit from two numbers and return a new number. Only the bits for the positions that are 1 in both numbers will be 1 in the new number, otherwise a bit will be zero. Order of the numbers for logand is of no matter because it is only a comparison.

 (logand
 #b00011111
 #b00000100)
means:
   00011111  -  all five buttons are pressed
   00000100  -  mask representing button 3
   --------
   00000100  -  this figured out button 3 is pressed


 (logand
 #b00000001
 #b00000100)
means:
   00000001  -  only button 1 is pressed
   00000100  -  mask representing button 3
   --------
   00000000  -  this figured out button 3 is released

A number can be manipulated like a mask by using "arithmetic shift" to shift the bits to the left or right, by means of the function ash. That means "00000001" (binary for 2) shifted by 3 becomes "00001000" (binary for 8), because a positive shift is leftwards. In other words: 1 * 2^3.

(ash 1 3)
  => 8

Since buttons 1–5 are positions 1–5 in the 8-bit byte, then the mask for a button can be made by shifting a "1" until it is in the same position. For example, "00000001" to "00000100" for button 3 would be a shift of 2, which is one less than the button number.

(setf button 3)
(ash 1 (- button 1))
  => 4

Therefore, a command can be written to inform the Xserver a pointer button has been pressed, and the same command can be used for releasing the pointer button by confirming the button with the mask the Xserver returns when the pointer is queried.

Toggle primary button for "press" or "release", f.e. text selection, drag'n drop without accidental drop, or anything else distinguishing a button press from a button release event.

# alternative for pointer placement

The Common Lisp X Interface function xlib:warp-pointer (CLX 13.5 Pointer Position) when given an Xwindow and coordinates will place the pointer at those coordinates within the area of that Xwindow.

The function xlib:pointer-position (CLX 13.5) when given a specified Xwindow returns the coordinates of the pointer (and some more data).

Alternatively, the function xlib:global-pointer-position (CLX 13.5) when given a display (like stumpwm:*display*) returns the individual coordinates of the pointer and the root Xwindow.

Eval: (xlib:global-pointer-position stumpwm:*display*)
600
450
#<XLIB:WINDOW :0 123>

These functions make use of the Common Lisp peculiarity (contrary to other Lisps) of "returning multiple values", t.i. returning a series instead of a list.

Eval: (cadr (xlib:global-pointer-position stumpwm:*display*))
The value
       600
     is not of type
       LIST
     when binding LISTBacktrace for: #<SB-THREAD:THREAD "main thread" RUNNING {0123456789}>
0: (STUMPWM::BACKTRACE-STRING)
1: (ERR "~A" #<TYPE-ERROR expected-type: LIST datum: 1050>)
...

Only the "primary value" gets noticed by other Lisp functions. All other values after the first are lost, by default.

Eval: point.test
The variable POINT.TEST is unbound.Backtrace...
Eval: (setf point.test (xlib:global-pointer-position stumpwm:*display*))
600
Eval: point.test
600

The Common Lisp special operator multiple-value-call (CLHS 5.3 The data and control flow dictionary) or a similar "multiple-value-" macro must be used for accessing all the values, f.e. as an actual list.

Eval: (multiple-value-call 'list (xlib:global-pointer-position stumpwm:*display*))
(600 450 #<XLIB:WINDOW :0 123>)
Eval: (multiple-value-list (xlib:global-pointer-position stumpwm:*display*))
(600 450 #<XLIB:WINDOW :0 123>)
Eval: (reverse (cdr (reverse (multiple-value-list (xlib:global-pointer-position stumpwm:*display*)))))
(600 450)
Eval: (multiple-value-call 'cons (xlib:global-pointer-position stumpwm:*display*))
invalid number of arguments: 3Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {0123456789}>
0: (STUMPWM::BACKTRACE-STRING)
1: (ERR "~A" #<SB-INT:SIMPLE-PROGRAM-ERROR "invalid number of arguments: ~S" {9012345678}>)
...
Eval: (multiple-value-bind (x y) (xlib:global-pointer-position stumpwm:*display*) (cons x y))
(600 . 450)

# efficient pointer jumping for any grid of options

Experience with the pointer a selection-based interface from a consistent grid layout of commands or options, often presented as icons.

 ____  ____  ____  ____
|    ||    ||    ||    |
|    || *  ||    ||    |
|____||____||____||____|
 ____  ____  ____  ____
|    ||    ||    ||    |
|    ||    ||    ||    |
|____||____||____||____|

Start with the pointer placed within the region of one of the options. Displace the pointer either leftward or rightward approximately the same distance as the width of the columns, or either upward or downward approximately the same distance as the height of the rows.

The xlib:warp-pointer-relative (CLX 13.5) displaces the pointer from its current coordinates. It requires a display like stumpwm:*display*, then the offset for the x-axis (horizontal) and the offset for the y-axis (vertical).

The origin (0, 0) is left-top corner, so downward and rightward are positive offsets, and upward and leftward are negative offsets. The pointer is automatically kept within the bounds of the screen by xlib:warp-pointer-relative, despite any requests beyond.

Eval: (xlib:global-pointer-position stumpwm:*display*)
600
450
#<XLIB:WINDOW :0 123>
Eval: (xlib:warp-pointer-relative stumpwm:*display* -64 0)
Eval: (xlib:global-pointer-position stumpwm:*display*)
536
450
#<XLIB:WINDOW :0 123>
Eval: jump.offset
The variable JUMP.OFFSET is unbound.Backtrace...
Eval: (setf jump.offset 64)
64
Eval: (xlib:warp-pointer-relative *display* jump.offset 0)
Eval: (xlib:global-pointer-position *display*)
600
450
#<XLIB:WINDOW :0 123>

Consider stumpwm:define-interactive-keymap for defining an interactive keymap (...custom buttonboard layouts) with buttons for displacing the pointer each direction, perhaps r-d-s-f for up-down-left-right (for an ASDF buttonboard layout).

Gradually construct the Lisp instruction (Contrary formation and Lisp instructions) as a quoted Lisp form for later evaluation. One way is by beginning with a dextrally half-paired list for everything before all of the button/command pairs: function name, chosen name, and list of options (or nil when none).

Eval: jump.map
The variable JUMP.MAP is unbound.Backtrace...
Eval: make.jump.map
The variable MAKE.JUMP.MAP is unbound.Backtrace...
Eval: (setf make.jump.map '((define-interactive-keymap . jump.map) . (:exit-on ((kbd "F7")))))
((DEFINE-INTERACTIVE-KEYMAP . JUMP.MAP). (:EXIT-ON ((KBD "F7"))))

Then, cons each button/command list item abdextrally to a second half-paired list beginning with nil (required by a Lisp instruction). Recall, the up/down arrow buttons in the evaluation prompt reveal the prior/later typed instructions for editing and re-using (The Lisp instruction prompt: an outlet for ingenuity).

Eval: (setf make.jump.map (cons make.jump.map nil))
(((DEFINE-INTERACTIVE-KEYMAP . JUMP.MAP) . (:EXIT-ON ((KBD "F7")))))
Eval: (setf (cdr make.jump.map) (cons '((kbd "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))") (cdr make.jump.map)))
Eval: (setf (cdr make.jump.map) (cons '((kbd "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)") (cdr make.jump.map)))
Eval: (setf (cdr make.jump.map) (cons '((kbd "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)") (cdr make.jump.map)))
Eval: (setf (cdr make.jump.map) (cons '((kbd "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)") (cdr make.jump.map)))

Penultimately, unwind the dextrally half-paired list and cons each of its items with the abdextrally half-paired list (Exploring a half-paired list). There are three items in it, so only two need be addressed.

Eval: make.jump.map
(((DEFINE-INTERACTIVE-KEYMAP . JUMP.MAP) . (:EXIT-ON ((KBD "F7"))))
 ((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))
Eval: (setf make.jump.map (cons (caar make.jump.map) (cons (cdar make.jump.map) (cdr make.jump.map))))
((DEFINE-INTERACTIVE-KEYMAP . JUMP.MAP)
 (:EXIT-ON ((KBD "F7")))
 ((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))
Eval: (setf make.jump.map (cons (caar make.jump.map) (cons (cdar make.jump.map) (cdr make.jump.map))))
(DEFINE-INTERACTIVE-KEYMAP JUMP.MAP
 (:EXIT-ON ((KBD "F7")))
 ((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))

Finally, evaluate the instruction and a new command is made (t.i. the chosen name) for evoking the interactive keymap. Assign a button to that command name.

Eval: (eval make.jump.map)
#S(STUMPWM::COMMAND :NAME EXIT-JUMP.MAP :CLASS T :ARGS NIL)
: describe-key
F7 is not bound.
Eval: (define-key *top-map* (kbd "F7") "jump.map")
NIL

By default, the ESC button, or the Return button, or "Control-g" disables the interactive keymap, unless :exit-on was assigned in its options.

Consider a couple of instructions for larger or smaller jumps with + and - (CLHS 12.1.1 Numeric Operations).

Eval: make.jump.bigger
The variable MAKE.JUMP.BIGGER is unbound.Backtrace...
Eval: make.jump.littler
The variable MAKE.JUMP.LITTLER is unbound.Backtrace...
Eval: (setf make.jump.bigger '(setf jump.offset (+ jump.offset 16)))
Eval: (setf make.jump.littler '(setf jump.offset (- jump.offset 16)))
Eval: jump.offset
64
Eval: (eval make.jump.bigger)
80
Eval: jump.offset
80
Eval: (eval make.jump.littler)
64
Eval: jump.offset
64

Consider assigning a couple more buttons for those instructions. Either unwind the Lisp instruction for that interactive keymap until the button/command pairs are exposed, or simply reference the cDDDr. Abdextrally cons the additional button/command pairs.

Eval: (cdddr make.jump.map)
(((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))
Eval: (setf (cdddr make.jump.map) (cons '((kbd "g") "eval-line (eval make.jump.bigger)") (cdddr make.jump.map)))
Eval: (setf (cdddr make.jump.map) (cons '((kbd "a") "eval-line (setf jump.offset (- jump.offset 16))") (cdddr make.jump.map)))
Eval: make.jump.map
(DEFINE-INTERACTIVE-KEYMAP JUMP.MAP
 (:EXIT-ON ((KBD "F7")))
 ((KBD "a") "eval-line (setf jump.offset (- jump.offset 16))")
 ((KBD "g") "eval-line (eval make.jump.bigger)")
 ((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))

Rewind if necessary, then use eval again. No need to re-assign the same button, because it is the same command name.

Eval: (eval make.jump.map)
#S(STUMPWM::COMMAND :NAME EXIT-JUMP.MAP :CLASS T :ARGS NIL)

Consider including buttons for pointer activation and drag'n drop (Alternative for pointer activation and drag'n drop). Perhaps "h" for the primary button, with "u" for press and "m" for release.

Eval: press.1
The variable PRESS.1 is unbound.Backtrace...
Eval: release.1
The variable RELEASE.1 is unbound.Backtrace...
Eval: (setf press.1 '(xlib/xtest:fake-button-event *display* 1 t))
Eval: (setf release.1 '(xlib/xtest:fake-button-event *display* 1 nil))
Eval: (cdddr make.jump.map)
(((KBD "a") "eval-line (setf jump.offset (- jump.offset 16))")
 ((KBD "g") "eval-line (eval make.jump.bigger)")
 ((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))
Eval: (setf (cdddr make.jump.map) (cons '((kbd "u") "eval-line (eval press.1)") (cdddr make.jump.map)))
Eval: (setf (cdddr make.jump.map) (cons '((kbd "m") "eval-line (eval release.1)") (cdddr make.jump.map)))
Eval: (setf (cdddr make.jump.map) (cons '((kbd "h") "eval-line (cons(eval press.1)(eval release.1))") (cdddr make.jump.map)))

Maybe ";" for the secondary button.

Eval: press.3
The variable PRESS.3 is unbound.Backtrace...
Eval: release.3
The variable RELEASE.3 is unbound.Backtrace...
Eval: (setf press.3 '(xlib/xtest:fake-button-event *display* 3 t))
Eval: (setf release.3 '(xlib/xtest:fake-button-event *display* 3 nil))
Eval: (setf (cdddr make.jump.map) (cons '((kbd ";") "eval-line (cons(eval press.3)(eval release.3))") (cdddr make.jump.map)))

Confirm and re-evalutate.

Eval: make.jump.map
(DEFINE-INTERACTIVE-KEYMAP JUMP.MAP
 (:EXIT-ON ((KBD "F7")))
 ((KBD ";") "eval-line (cons(eval press.3)(eval release.3))")
 ((KBD "h") "eval-line (cons(eval press.1)(eval release.1))")
 ((KBD "m") "eval-line (eval release.1)")
 ((KBD "u") "eval-line (eval press.1)")
 ((KBD "a") "eval-line (setf jump.offset (- jump.offset 16))")
 ((KBD "g") "eval-line (eval make.jump.bigger)")
 ((KBD "f") "eval-line (xlib:warp-pointer-relative *display* jump.offset 0)")
 ((KBD "s") "eval-line (xlib:warp-pointer-relative *display* (- jump.offset) 0)")
 ((KBD "d") "eval-line (xlib:warp-pointer-relative *display* 0 jump.offset)")
 ((KBD "r") "eval-line (xlib:warp-pointer-relative *display* 0 (- jump.offset))"))
Eval: (eval make.jump.map)
#S(STUMPWM::COMMAND :NAME EXIT-JUMP.MAP :CLASS T :ARGS NIL)

# steadfast and resilient:  escape key for pursuit or curiosity

A set of defined buttons are always available (except when typing in prompts) by means of the list of keymaps in *group-top-maps*, though indirectly.

By default, the *top-map* keymap has a button paired with the *root-map* keymap (StumpWM keymap: *top-map*). By default, the *root-map* keymap has the buttons for invoking prompts and querying for help (StumpWM keymap: *root-map*).

Invoking a command that provides an "interactive keymap" (StumpWM 3.2 Interactive Keymaps), f.e. the iresize StumpWM command, displaces the *top-map* keymap with the keymap for the command [ The button listing for an "interactive keymap" itself has no name of its own (StumpWM version 1.0.1, "interactive-keymap.lisp": let at 71, then 89). ] . There is no persistent indication what keymap is currently active, nor a default means for querying the button list of the *top-map* (Reveal buttons for stumpwm:*top-map*).

That means no access to the *root-map* keymap, thereby no access to prompts or Help documentation.

Experience steadfast access to a personally refined and fully-equipped keymap (Make a StumpWM keymap and pair a button), even during an "interactive keymap" as long as the stumpwm::*escape-key* is never paired to a command (There can be only one command).

# requirement #1:
"top map" + "root map"

A separate "top map" keymap with the stumpwm::*escape-key* assigned to the name of the new "root map" keymap that is desired to be always accessible. No need for the "root map" to exist yet.

Eval: resilient.top-map
The variable RESILIENT.TOP-MAP is unbound.Backtrace...
Eval: (setf resilient.top-map  (stumpwm::make-kmap))
Eval: resilient.root-map
The variable RESILIENT.ROOT-MAP is unbound.Backtrace...
Eval: (define-key resilient.top-map  stumpwm::*escape-key*  'resilient.root-map)

# requirement #2:
*group-top-maps*

Modify the list of "top map" keymaps listed within stumpwm:*group-top-maps* either before or after its new "root map" keymap is ready (Requirement #1: "top map" + "root map"). Either add another "top map" to the list, or remove any that are undesired, or replace the whole list.

Eval: *group-top-maps*
((STUMPWM::FLOAT-GROUP STUMPWM::*FLOAT-GROUP-TOP-MAP*)
 (STUMPWM::TILE-GROUP STUMPWM::*TILE-GROUP-TOP-MAP*)
 (GROUP STUMPWM::*GROUP-TOP-MAP*))
Eval: (setf *group-top-maps*  '((group resilient.top-map)))
((GROUP RESILIENT.TOP-MAP))

A group-type must precede each "top map", f.e. group, and the same type is fine. Each specified "top map" keymap must exist at least as a blank keymap, but never unbound nor nil [ Otherwise, the screen becomes blank and the buttonboard unresponsive. However, disconnecting and reconnecting the power to the computer has worked for restarting it, so far. ] . The leftmost "top map" in *group-top-maps* will have its buttons listed first when queried with "?", and its assigned buttons favored over the same buttons in later keymaps.

Eliminating the three default "top map" keymaps reduces the "Control-t" menu to only the stumpwm:*root-map*. That is fine because that has the command abbreviations for all the prompts (Interactive curiosity), as well as the Help keymap "Control-t h" abbreviations.

# example #1:
displace stumpwm:*root-map*

Ensure desired commands are available from *group-top-maps*, then undefine from the *top-map* the stumpwm::*escape-key* for the *root-map*.

  1. The setf can set multiple memos at once (An intro for Lisp with StumpWM).

    A "top map" must exist as a keymap before adding it to *group-top-maps* (Requirement #2: stumpwm::*group-top-maps*). The stumpwm::fill-keymap needs named memory that references only nil (Fill a StumpWM keymap).

    Eval: (setf  sturdy.top (stumpwm::make-kmap)  *group-top-maps* '((group sturdy.top))  sturdy.root nil)
    
  2. Provide a substitute keymap for the "root map" of the new "top map", perhaps filling a new keymap (Examples of custom keymaps).

    Eval: (stumpwm::fill-keymap sturdy.root (kbd";") "colon")
    
  3. Ensure the new "root map" is associated with its "top map" before undefining the *root-map* from *top-map*.

    Otherwise, the only commands available will be whatever is still defined in the *top-map* (usually none), and the "root map" associated with each "top map" listed in *group-top-maps* (Requirement #2: stumpwm::*group-top-maps*).

    Eval: (define-key sturdy.top  stumpwm::*escape-key* 'sturdy.root)
    
    Eval: (define-key *top-map*  stumpwm::*escape-key* nil)
    

Thereon, define additional buttons for the "root map" of any "top map" of *group-top-maps* with the define-key.

# example #2:
repurpose default StumpWM keymaps

Prefix: C-t
b     bind

StumpWM provides two conveniences for defining and undefining buttons specifically in the *root-map*: bind and unbind.

In contrast to define-key, no need to specify the *root-map* and no need for the kbd. Additionally, no need for double-quotes when invoking them as commands with colon (StumpWM keymap: *root-map*).

As aforementioned, availability of the *root-map* is unreliable by default (Steadfast and resilient: escape key to pursuit or curiosity). Consider adding the *root-map* to the *group-top-maps* list, thereby having bind and unbind for convenient button changing.

  1. A "top map" is needed for the *root-map* when adding it to *group-top-maps* (Requirement #2: stumpwm::*group-top-maps*). Either name a new "top map" with the setf and add it to *group-top-maps* list, or repurpose an undesired one in *group-top-maps*.

    Then, undefine from the *top-map* the stumpwm::*escape-key* for the *root-map*.

    Eval: *group-top-maps*
    
    ((STUMPWM::FLOAT-GROUP STUMPWM::*FLOAT-GROUP-TOP-MAP*)
     (STUMPWM::TILE-GROUP STUMPWM::*TILE-GROUP-TOP-MAP*)
     (GROUP STUMPWM::*GROUP-TOP-MAP*))
    
    Eval: (setf *group-top-maps* (cddr *group-top-maps*))
    
    ((GROUP STUMPWM::*GROUP-TOP-MAP*))
    
    Eval: (define-key *group-top-map*  stumpwm::*escape-key* '*root-map*)
    
    Eval: (define-key *top-map*  stumpwm::*escape-key* nil)
    

    Ensure the *root map* is associated with its new "top map" before undefining the *root-map* from *top-map*.

    Otherwise, the only commands available will be whatever is still defined in the *top-map* (usually none), and the "root map" associated with each "top map" listed in *group-top-maps* (Requirement #2: stumpwm::*group-top-maps*).

  2. Consider replacing the contents of *root-map* with a new personalized keymap (Examples of custom keymaps). Perhaps start over with only the bind command, then add additional buttons easily by invoking the bind command.

    Eval: (setf new.map  nil)
    
    Eval: (stumpwm::fill-keymap new.map  (kbd"b") "bind")
    
    Eval: (setf *root-map*  new.map)
    

Immediately setting the *root-map* to a blank keymap is more direct, but that would eliminate all of its buttons, therefore the prompts would be unavailable. In that case, consider defining at least the bind command in it at the same time (Multiple instructions at once).

Eval: (cons  (setf *root-map*  (stumpwm::make-kmap))  (bind "b" "bind"))
Prefix: C-t
b     bind
;     colon

Then, invoke the bind and consider adding the colon command immediately for access to all commands (Invoke a StumpWM command by its name), and anything else gradually.

Key Chord: ;
Command: colon

# examples of custom keymaps

# the most minimal keymap

Prefix: 
ESC   colon

The smallest keymap is only one button, therefore only one command. A truly single button has no modifiers, f.e. no Control button.

Assign the command to the stumpwm::*escape-key* button of the *top-map* keymap, then all the default keymaps become unavailable (Just one command from the stumpwm::*escape-key* button).


Change the stumpwm::*escape-key* from its default "C-t" by invoking the set-prefix-key (Invoke a StumpWM command by its name). Type the name of an unmodified button, f.e. ESC for the ESC button, or F12 for the F12 button, or any letter or number (Type the stumpwm::*escape-key* button).

Key: ESC

The colon command does everything, because it provides the prompt for invoking any StumpWM command (Invoke a StumpWM command by its name). Define for the *top-map* keymap the stumpwm::*escape-key* button with the colon command.

Eval: (define-key *top-map*  stumpwm::*escape-key*  "colon")

Invoke the commands command for a list of all StumpWM commands (Invoke a StumpWM command by its name). Invoke the eval-line and evaluate define-key for the *top-map* keymap for pairing other buttons with commands as desired (Pair a button with a command or keymap).

Consider enabling the button list for the *top-map* (Reveal buttons for stumpwm:*top-map*).

# the beginner keymap

Prefix: j
b     bind

Beginning from scratch means everything desired emerges when it is desired.

Eliminate or displace all default StumpWM keymaps. Repurpose the *root-map* as the sole keymap. Begin with only the bind command for pairing additional buttons with commands when desired.

The set-prefix-key is a command (Invoke a StumpWM command by its name). It prompts with "Key: " for the name of the button to set as the stumpwm::*escape-key* (The stumpwm::*escape-key* button).

Key: j

The *root-map* keymap is modifiable with the convenience commands bind and unbind. Repurposing it and eliminating all other default keymaps leaves only the *root-map* keymap (Example #2: repurpose default StumpWM keymaps).

Eval: (define-key *group-top-map*  stumpwm::*escape-key* '*root-map*)
Eval: (define-key *top-map*  stumpwm::*escape-key* nil)
Eval: (setf *group-top-maps* (cddr *group-top-maps*))
((GROUP STUMPWM::*GROUP-TOP-MAP*))

Replace the *root-map* keymap with a blank keymap, and add the bind command for adding additional buttons gradually as needed. Must do both within the same invocation of the eval-line (Multiple instructions at once).

Eval: (cons  (setf *root-map*  (stumpwm::make-kmap))  (bind "b" "bind"))

# the magnificient seven commands

Prefix: j
j     send-escape
o     pull-hidden-other
l     windowlist
;     colon
e     eval-line
r     run-shell-command
t     echo-date

[ ...describe... ]

# refine the *root-map*

Prefix: C-t
;     colon
m     lastmsg
g     *GROUPS-MAP*
h     *HELP-MAP*
b     bind
u     unbind
e     eval-line
r     run-shell-command
t     time
o     pull-hidden-other
l     windowlist
h     hsplit
v     vsplit
R     remove-split
f     fselect
=     balance-frames
C-t   send-escape

There are a lot of duplicate commands in the default *root-map* keymap (StumpWM keymap: *root-map*).


It is also perhaps a bit over prepared for managing groups of frames. Similar commands are already being kept in the stumpwm::*group-root-map* keymap and the *groups-map* keymap.


The bind and the unbind commands make modifying the *root-map* very convenient. Either invoke them by name (Invoke a StumpWM command by its name) each time, or add them to the *root-map*, at least temporarily.

: bind
Key Chord: b
Command: bind
Key Chord: u
Command: unbind

Eliminate the duplicates with the unbind by typing the name (no need for "double-quotes"), and perhaps unbind the extra commands for groups, too.

Key Chord: C-c
Key Chord: C-e
...
Key Chord: F1
...

The *root-map* already has the commands for the basic prompts (Interactive curiosity: typing for actions and help), but maybe rebind them to more familiar buttons. Consider adding or rebinding some basic view management commands with the bind, too (Essential split-view commands).

Key Chord: o
Command: pull-hidden-other
Key Chord: l
Command: windowlist
Key Chord: h
Command: hsplit
Key Chord: v
Command: vsplit
...

Consider making the send-escape more convenient (Typing the stumpwm::*escape-key* button).

Eval: (define-key *root-map*  stumpwm::*escape-key*  "send-escape")

# an ESC button *root-map*

Prefix: ESC
ESC   send-escape
F1    pull-hidden-other
F2    windowlist
F3    echo-date
1     colon
2     eval-line
3     run-shell-command
w     where-is
d     describe-command
f     describe-function
v     describe-variable
k     describe-key
z     lastmsg
x     remove.message
c     copy-last-message
/     help.top-map

Prepare a list of some basic needs. Consider buttons near the ESC button the stumpwm::*escape-key*.

 _____ _____ _____ _____ ..
|     |     |     |     |
| ESC | F1  | F2  | F3  |
|_____|_____|_____|_____|..
|     |     |     |     |
|  `  |  1  |  2  |  3  |
|_____|_____|_____|_____|..
:     :     :     :     :

Either add each to the beginner keymap with the bind (The beginner keymap), or create a new keymap with stumpwm::fill-keymap as a replacement "root map".

Eval: (setf personal.map  nil)
Eval: (stumpwm::fill-keymap  personal.map   stumpwm::*escape-key* "send-escape"   (kbd "F1")"pull-hidden-other"   (kbd "F2")"windowlist"   (kbd "F3")"echo-date"   (kbd "1")"colon"   (kbd "2")"eval-line"   (kbd "3")"run-shell-command"   (kbd "w")"where-is"   (kbd "d")"describe-command"   (kbd "f")"describe-function"   (kbd "v")"describe-variable"   (kbd "k")"describe-key"   (kbd "z")"lastmsg"   (kbd "x")"remove.message"   (kbd "c")"copy-last-message"   (kbd "/")"display.top-map")

Either gently disassociate the stumpwm:*root-map* from the stumpwm:*top-map* by assigning the stumpwm::*escape-key* to the replacement keymap, or obliterate the stumpwm:*root-map* by setting it to the new keymap with setf.

Eval: (define-key *top-map*  stumpwm::*escape-key* 'personal.map)

Change the stumpwm::*escape-key* to the ESC button (Change the stumpwm::*escape-key* button). Simply invoke the set-prefix-key by its name (Invoke a StumpWM command by its name), then type the three letters of the name of the ESC button, which is all uppercase for it.

Key: ESC

Consider creating a new "top map" for *group-top-maps* with access to this keymap (Steadfast and resilient: escape key for pursuit or curiosity).

# swap keymaps from a resilient keymap

Consider buttons for setting and syncing the *top-map* with custom keymaps. Perhaps use the numbers zero through nine.

(setf replace.top-map
 '(defun replace.top-map
   (Fnew-map)
   "Replace the *top-map* with the Fnew-map keymap."
   (setf *top-map* Fnew-map)
   (stumpwm::sync-keys)))

Consider a blank keymap for resetting the stumpwm:*top-map* keymap.

(kbd "0") "eval-line (replace.top-map (stumpwm::make-kmap))"

# the stumpwm::*escape-key* button

Outside of the StumpWM prompts, the stumpwm::*escape-key* button is the first button for any abbreviation in the default StumpWM keymaps (A resilient set of keymaps).

The stumpwm::*escape-key* button is the only button StumpWM persistently intercepts from the Xserver. It is the reliable entry point for accessing a StumpWM command regardless of what happens to the *top-map* keymap (StumpWM keymap: *top-map*).

In other words, typing the stumpwm::*escape-key* button is meant to temporarily change the layout for the buttonboard for the next typed button (Understanding buttonboard keymaps), but with no need to hold the button. That very next button typed invokes the command associated with it, or temporarily changes the layout to yet another keymap for the next typed button.

It can be defined in the *top-map* for a command instead (There can be only one command), in which case that command will be invoked instead of changing the buttonboard layout to the keymaps of *group-top-maps* (A resilient set of keymaps). That might happen unintentionally when replacing the *top-map* with another keymap [ Any changes to *top-map* by means of setf should be immediately followed by the sync-keys instruction. ] , such as the interactive keymap from the iresize.

It is "C-t" by default, which means hold the Control button before typing the letter t.

Eval: (stumpwm::print-key stumpwm::*escape-key*)
"C-t"

Consider changing the stumpwm::*escape-key* to another button, perhaps without need for a modifier button like Control or Alt (Change the stumpwm::*escape-key* button). For example, the very convenient "j" might be rather uncommonly typed, or perhaps "q" or "z".

When typing in other programs, the stumpwm:send-escape command enables typing whatever the stumpwm::*escape-key* button itself would be normally, instead of the keymap or command paired to the button (Type the stumpwm::*escape-key* button).

# there can be only one command from the stumpwm::*escape-key* button

Pair the stumpwm::*escape-key* with a command in the*top-map*, then that is the only StumpWM command that can be invoked with it.

Most useful is the stumpwm:colon command (Invoke a StumpWM command by name), because any command can be invoked by name. The next time, use the up arrow button once in the prompt to recall the name previously typed (Typing within a line of text).

Eval: (define-key *top-map* stumpwm::*escape-key* "colon")

Invoke the stumpwm:send-escape command to type the stumpwm::*escape-key* button itself normally. Just type "sen" in the prompt and then the TAB button to automaticaly complete the name. Compare that to its default abbreviation "Control-t t" which uses a sequence of buttons unrelated to the name, and is typed invisibly.

: send-escape

Easily restore the *root-map* keymap, or any other keymap, whenever desired (Merge any keymap with the resilient keymaps).

: eval-line
Eval: (define-key *top-map* stumpwm::*escape-key* '*root-map*)

# a resilient set of keymaps for the stumpwm::*escape-key* button

Never pair the stumpwm::*escape-key* with anything in the*top-map*, then the set of StumpWM keymaps specified in *group-top-maps* is immediately accessible with it (Requirement #2: stumpwm:*group-top-maps*).

Eval: *group-top-maps*
((STUMPWM::FLOAT-GROUP STUMPWM::*FLOAT-GROUP-TOP-MAP*)
 (STUMPWM::TILE-GROUP STUMPWM::*TILE-GROUP-TOP-MAP*)
 (GROUP STUMPWM::*GROUP-TOP-MAP*))

By default, they include commands for groups of framed views in StumpWM.

Type the stumpwm::*escape-key* button and then a question mark "?" to reveal their combined list of buttons (Make a StumpWM keymap and pair a button). Or, pair a button to one of the keymaps, and then use that button with a question mark to reveal its listing separately.

Modify any of the default keymaps with the define-key, or replace any with the setf and the stumpwm::make-kmap (Make a StumpWM keymap and pair a button). Consider supplanting them with a different set of keymaps, or simply one keymap (Steadfast and resilient: escape key for pursuit or curiosity).

# merge any keymap with the resilient keymaps

Pair the stumpwm::*escape-key* with a keymap in the*top-map* and the buttons of that keymap are grouped with buttons from the *group-top-maps* keymaps (A resilient set of keymaps for the stumpwm::*escape-key* button).

For example, the stumpwm:*root-map* is paired the stumpwm::*escape-key* in the *top-map* by default (StumpWM keymap: *top-map*).

Eval: (define-key *top-map* stumpwm::*escape-key* '*root-map*)

# view the stumpwm::*escape-key* button

The stumpwm::*escape-key* is actually a key description. Reveal the button name with the stumpwm::print-key instruction.

Eval: stumpwm::*escape-key*
#S(STUMPWM::KEY
   :KEYSYM 116
   :SHIFT NIL
   :CONTROL T
   :META NIL
   :ALT NIL
   :HYPER NIL
   :SUPER NIL)
Eval: (stumpwm::print-key  stumpwm::*escape-key*)
"C-t"

# change the stumpwm::*escape-key* button

The stumpwm:set-prefix-key instruction is for changing the stumpwm::*escape-key* button. It also changes the stumpwm::*escape-fake-key* button, which is paired with send-escape in the *root-map* by default (StumpWM keymap: *root-map*).

For example, the default "C-t" for the stumpwm::*escape-key* means the stumpwm::*escape-fake-key* is "t", therefore the send-escape is invoked by "Control-t t". Changing to "C-s" with the set-prefix-key automatically re-assigns the stumpwm::*escape-fake-key* to "s", therefore the send-escape becomes "Control-s s".

Eval: (set-prefix-key (kbd "C-s"))
Eval: stumpwm::*escape-key*
#S(STUMPWM::KEY
   :KEYSYM 115
   :SHIFT NIL
   :CONTROL T
   :META NIL
   :ALT NIL
   :HYPER NIL
   :SUPER NIL)
Eval: (stumpwm::print-key stumpwm::*escape-key*)
"C-s"
Eval: (stumpwm::print-key stumpwm::*escape-fake-key*)
"s"
: where-is
Where is command: send-escape
"send-escape" is on C-s s.

Specifically, the set-prefix-key ensures when the stumpwm::*escape-key* is assigned a button needing modifier buttons such as Control or Meta, that the stumpwm::*escape-fake-key* is without such modifier buttons.

Interestingly, even a single alphabetic or numeric button can be assigned as the stumpwm::*escape-key* button. As a lowercase letter, the uppercase can be typed without the send-escape command, and the reverse is also true [ However, be sure to assign the capital letter as is rather than with "S-", f.e. "J" rather than "S-j". The latter has seemed untypable or unnoticible by StumpWM. ].

Eval: (set-prefix-key (kbd "j"))
: where-is
Where is command: send-escape
"send-escape" is on j NIL.

Unfortunately, the set-prefix-key will assign the untypable "NIL" [ "Control-@" or ^@ is NUL ] as a button to stumpwm::*escape-fake-key* when the stumpwm::*escape-key* is set to a button without modifiers such as Control or Meta.

In that case, it is impossible to use the send-escape from the default keymap. On the other hand, including such modifier buttons the next time set-prefix-key is invoked will enable the stumpwm::*escape-fake-key* again, thereby the button for the send-escape, too.

Otherwise, simply assign a different button directly for the send-escape (Pair a button with a command or keymap), or even invoke it by name (Invoke a StumpWM command by its name).

# type the stumpwm::*escape-key* button

Rest assured, it is always possible to type normally in a StumpWM prompt. Neither the stumpwm::*escape-key* button nor the *top-map* is ever in effect in the StumpWM prompts (Typing within a line of text).


When typing in other programs, the stumpwm:send-escape command enables typing whatever the stumpwm::*escape-key* button itself would be normally, instead of the keymap or command paired to the button.

That means the stumpwm::*escape-key* button can be a letter or number, because it can still be typed normally when needed (Change the stumpwm::*escape-key* button).

For example, after defining the stumpwm::*escape-key* as the "j" button, typing the "j" button either temporarily activates the collection of keymaps from the *group-top-maps* list (A resilient set of keymaps), or it invokes a command that has been paired either to the stumpwm::*escape-key* or to "j" in the *top-map* (There can be only one command). Invoking the send-escape command types an actual "j", but no need for it when simply typing a capital "J" (Change the stumpwm::*escape-key* button).


The stumpwm::*escape-fake-key* button is paired with the send-escape in the *root-map* by default. The stumpwm:where-is command reveals the abbreviation for send-escape (Invoke a StumpWM command by its name).

Eval: (stumpwm::print-key stumpwm::*escape-key*)
"C-t"
Eval: (stumpwm::print-key stumpwm::*escape-fake-key*)
"t"
: where-is
Where is command: send-escape
"send-escape" is on C-t t.

The button for the stumpwm::*escape-key* is probably easiest to type when send-escape is the same button, with or without a modifier button like Control. However, the pull-hidden-other command has been favored instead for that sameness in the *root-map* by default (StumpWM keymap: *root-map*).

Consider swapping the two buttons for those two commands.

Eval: (define-key *root-map*  stumpwm::*escape-key*  "send-escape")
Eval: (define-key *root-map*  stumpwm::*escape-fake-key*  "pull-hidden-other")

Or, choose an entirely different button, and undefine stumpwm::*escape-key* and/or stumpwm::*escape-fake-key* in the *root-map*.

Eval: (define-key *root-map*  stumpwm::*escape-fake-key*  nil)
Eval: (define-key *root-map*  (kbd "o")  "pull-hidden-other")

# StumpWM default keymaps

# StumpWM keymap: *top-map*

Prefix:
C-t   *ROOT-MAP*

There is no default button paired with the *top-map* keymap, as there is no need. It is always active.

By default the *top-map* has only one button defined, the stumpwm::*escape-key* (The stumpwm::*escape-key* button).

Eval: (stumpwm::print-key  stumpwm::*escape-key*)
"C-t"

That button is associated with the *root-map* keymap (StumpWM keymap: *root-map). Any keymap paired with the stumpwm::*escape-key* button within the *top-map* keymap is combined with the three other default keymaps (A specific set of keymaps for the stumpwm::*escape-key* button).

All other buttons are available for normal typing in other programs, including any abbreviations other programs might have.

Prefix: F12
C-t   *ROOT-MAP*
F12   *TOP-MAP*

Like with any other keymap, pairing a button with the *top-map* allows for typing that button and then a question mark "?" to reveal its listing (Make a StumpWM keymap and pair a button).

: describe-key
F12 is not bound.
Eval: (define-key *top-map* (kbd "F12") '*top-map*)

Unfortunately, that also makes the *top-map* recursive, which interferes with describe-key and where-is commands, and causes StumpWM to crash and restart. Instead, consider making a new StumpWM command for revealing the buttons for the *top-map* (Reveal buttons for stumpwm:*top-map*).


The stumpwm::sync-keys instruction must be used whenever replacing the *top-map* with another keymap. Consider evaluating both instructions at once (Two instructions at once).

Eval: (cons (setf *top-map* another-keymap) (stumpwm::sync-keys))

# StumpWM keymap: *root-map*

Prefix: F12
c     exec xterm
C-c   exec xterm
e     emacs
C-e   emacs
b     banish
C-b   banish
a     time
C-a   time
!     exec
C-g   abort
t     send-escape
;     colon
:     eval
v     version
m     lastmsg
C-m   lastmsg
G     vgroups
g     *GROUPS-MAP*
x     *EXCHANGE-WINDOW-MAP*
F1    gselect 1
F2    gselect 2
F3    gselect 3
F4    gselect 4
F5    gselect 5
F6    gselect 6
F7    gselect 7
F8    gselect 8
F9    gselect 9
F10   gselect 10
h     *HELP-MAP*

Assign a button to the *root-map*. Type the button and then a question mark "?" to reveal its listing.

: describe-key
F12 is not bound.
Eval: (define-key *top-map* (kbd "F12") '*root-map*)

The *root-map* keymap has command abbreviations for invoking prompts. It also has a few buttons assigned to other keymaps, such as for Help documentation.

Initially, the *root-map* is available only because it is paired with the stumpwm::*escape-key* button in the *top-map* (StumpWM keymap: *top-map*).


StumpWM provides two conveniences for defining and undefining buttons specifically in the *root-map*: bind and unbind.

In contrast to define-key, no need to specify the *root-map* and no need for the kbd.

Eval: (unbind "F1")
Eval: (bind "o"  "pull-hidden-other")

Additionally, no need for double-quotes for the button name or command when invoking bind or unbind as commands with the colon (Invoke a StumpWM command by its name).

: bind
Key Chord: l
Command: windowlist
: unbind
Key Chord: F2

# StumpWM keymap: *float-group-root-map*

Prefix: F12
(EMPTY MAP)

Assign a button to the stumpwm::*float-group-root-map*. Type the button and then a question mark "?" to reveal its listing.

: describe-key
F12 is not bound.
Eval: (define-key *top-map* (kbd "F12") 'stumpwm::*float-group-root-map*)

[ ...apparently intentionally left empty,
 but describe anyway... ]

# StumpWM keymap: *help-map*

Prefix: F12
v     describe-variable
f     describe-function
k     describe-key
c     describe-command
w     where-is

Discover the command assigned to a button by using "Control-t h k" for the describe-key command (Invoke a StumpWM command by its name). Fail to completely type the "h" and kill a program with delete-window instead. Disaster.

Consider making the Help commands more convenient, and averting a none too happy slip, by choosing a single button for the stumpwm:*help-map* keymap. Check it by typing the new button then the "?".

: describe-key
F12 is not bound.
Eval: (stumpwm:define-key stumpwm:*top-map* (stumpwm:kbd "F12") (quote stumpwm:*help-map*))

Or, use the abbreviated names (Optional or required collection names).

Eval: (define-key *top-map* (kbd "F12") '*help-map*)

# essential split-view commands

There are about a half-dozen essential StumpWM commands for splitting the screen area for viewing different documents and programs.

StumpWM favors abbreviations for its commands (StumpWM 2. Key Bindings), short sequences of buttons for its predefined sets of instructions. One of those commands also provides a prompt for visibly typing any command name (Invoke a StumpWM command by its name).

StumpWM uses "Control-t" as the prefix for segregating its own commands from other programs (The stumpwm::*escape-key* button). Use the Control button in the same manner as the Shift button, t.i. hold the Control button before typing a letter (skip the hyphen), then afterwards let go of it.

Though typing a button sequence is invisible, typing a prefix like "Control-t" in StumpWM changes the pointer cursor from an X or arrow into a square as an indicator until the button sequence is completed or canceled.


All StumpWM commands are in the "stumpwm:" collection. That collection name can be included for the commands, f.e. stumpwm:fselect, but is unnecessary for them.

There are some details that might be worth noting for each of those essential StumpWM commands.


Control-t ?

Show the abbreviations for StumpWM commands prefixed with "Control-t".
Invoking any command will remove that message from the screen.

Also shows at its top "Prefix: " with the name of the StumpWM prefix button. That means the prefix must be typed first before typing any of the listed buttons for their commands.

Note "C-" means hold the Control button before typing the next letter or character.

Note "M-" means hold the Meta button before typing the next letter or character. The Meta button is probably the same as either the Alt button or the Option button, depending on the buttonboard.

Note the "*HELP-MAP*" entry for "h" means "Control-t h" is another prefix. Therefore, type "Control-t h ?" to show the commands of that keymap (StumpWM keymap: *help-map*).

Note typing a button for any keymap then a question mark "?" will list all the abbreviations assigned to that keymap (Make a StumpWM keymap and pair a button).

pull-hidden-other
or Control-t Control-t

Show the most recently hidden document or program, while hiding the current one.

windowlist
or Control-t "

List all managed documents and programs. Select one with the arrow buttons, then type the Return button or Enter button. The current document or program will be hidden, and the selected item will be shown. Or, type the ESC button to cancel.

Typing a letter or a sequence of letters will reduce the list to items matching that. The arrow buttons can still be used to select from the reduced list, but the typed letters disappear. Typing letters again will start over. Deleting the letters will start over.

hsplit
or Control-t S

Split in half the width of the current frame, which makes room for another document or program, especially the most recently hidden.

Note that is a capital S, the same as Shift-s.

Note typing a lowercase s instead invokes vsplit for splitting in half the height of the current frame.

remove-split
or Control-t R

Remove the current frame and hide the document or program that was in it.

Note that is a capital R, the same as Shift-r.

Note typing a lowercase r instead begins interactive resize (iresize) of current frame (when more than one frame) by means of the arrow buttons. Up and left decrease the frame size; down and right increase the frame size. The ESC button finishes resizing.

Many default button bindings for StumpWM commands are temporarily removed until resizing is completed. Consider that possibility when messages appear unexpectedly stating a button sequence is "not bound". Try typing the ESC button for finishing an interactive command. When effective, a confirmation message appears as either "finished." or "Abort.".

balance-frames
or Control-t +

Equally divide width and height of screen amongst frames.

Consider splitting the screen into three frames and then equalize them. Each frame is then one-third the screen. Then remove one of the frames. Two frames remain: one frame is two-thirds, and the other is one-third.

fselect
or Control-t f

Select another split-view frame. Type the number or letter that temporarily appears in the upper left corner of each split-view frame, or type the ESC button to cancel.

# roots of StumpWM

The split-view manager StumpWM is a Lisp image exported from SBCL (Steel Bank Common Lisp), and is intended for managing the Xwindows of an Xserver (Essential split-view commands).

Split-views are adjacent non-intersecting areas, like tiles, thereby efficiently encompassing the whole screen. Initially, StumpWM was known as "ratpoison" because it focused on eliminating the electronic rodent (mouse) and the toggling of its buttocks.

As an SBCL Lisp image, StumpWM is actually a copy of the SBCL Lisp interpreter with the code for StumpWM pre-loaded. That means starting StumpWM is the same as starting a Lisp interpreter, and any new Lisp can be typed and evaluated instantly.

While it is typical to modify a Lisp interpreter while using it, in this case that means being able to modify StumpWM while using StumpWM, too. No need to start over, just keep going.

Additionally, StumpWM is written entirely in Common Lisp, and SBCL is written mostly with Common Lisp. So, both the Xwindow manager and the Lisp environment can be personalized with the familiarity of Common Lisp, either instantly or for a permanent copy.

Eval:            

After starting the Xserver with StumpWM as the Xwindows manager, access the Lisp interpreter anytime with "Control-t :" (Compose a Lisp instruction). That is, hold the Control button then type the letter t, then let go of the Control button, then type a colon. The prompt "Eval: " will appear for typing a line of Common Lisp.

Personalize StumpWM with its initialization file "~/.stumpwm.d/init.lisp", such as assigning names to Lisp instructions or assigning buttons to evaluate them. Include Lisp from other files when starting by using load (CLHS).

(load "~/common-lisp/something-new-with-lisp")

Instantly assign a button to any command, create a new Xserver Xwindow and draw in it, or add more commands from any file with load, all with the Lisp instruction prompt (...an outlet for ingenuity). In a nutshell: an interactive extensible computer interface.

# X Window System and its protocol

# a translation of a misnamed paradigm

A "window" is a misnomer for a designated area, typically rectangular. An area is simply the coordinates for its left-top corner associated with its width and height (rather than its kittycorner coordinates): (x, y) (w, h).

Various shapes within an area are displayed by declaring two different colors (background and foreground), the type of shape, and the method of merging the intersection with other prior drawn shapes within the same area. That is, each area constrains its own content, but shapes merge by a variety of methods (sixteen) within the area, f.e. merging of a red shape and a blue shape can make their intersection purple.

Abutting each designated area along their edges is akin to tiling the areas, such as when creating split-views. The X Window System protocol limitedly supports intersection of the designated areas themselves by means of a single priority list for the areas. Intersecting areas of higher priority are subtracted from areas of lesser priority, like what remains as each area is cut from a piece of paper.

Therefore, the designated area that has the highest priority maintains its rectangular shape because it has no intersecting areas subtracted from it. The other areas maintain their shape when intersecting only lesser priority shapes, if any intersection at all. This also implies there is no true transparency effect for an area, because designated areas are only subtracted and never merged.

In other words, the designated areas are meant to be rectangular and their intersections are subtracted, whereas a variety of additionally described shapes can merge with each other within a single designated area.

Furthermore, a designated area can have areas designated within its bounds prioritized amongst themselves, but those internal areas are forbidden from extending beyond the outer area. Obviously, those subregions are intersecting with whatever shapes have been described within the overall area, but only by means of subtraction because they are designated areas instead of shapes.

A pixmap, t.i. a picture map, is a simple list of dots (pixels) associated with a color for each dot. The content of a designated area can be exported as a pixmap. A pixmap can be applied fully or partially anywhere within any area, and can be assigned as the background of any area. The Xserver automatically applies the background of a designated area for the pixels that area has priority, but any other described content is managed separately by external software (t.i. a client) when it receives notifications from the Xserver.

An intersection is visibly changed by the higher priority area for that intersection. As such, a designated area with no content and no background seemingly acquires all pixels within its boundaries from either the overall backdrop of the Xserver or from lesser priority areas, with no further visible changes from modifications of intersections with lesser priority areas.

# color names

Acceptable color names are the X11 rgb colors (freedesktop.org), which might be also located on the computer with the Xserver as "/usr/local/share/X11/rgb.txt".

Acceptable RGB hexadecimal numbers for the red, green, and blue hues of a color are similar to HTML colors, with an octothorpe # followed by either three or six digits.

Hex #  0 1 2 3 4 5 6 7 8 9 A B C D E F
  Red  0 1 2 3 4 5 6 7 8 9 a b c d e #f00 or #ff0000
Green  0 1 2 3 4 5 6 7 8 9 a b c d e #0f0 or #00ff00
 Blue  0 1 2 3 4 5 6 7 8 9 a b c d e #00f or #0000ff
All 3                                #fff or #ffffff

For example, orange is either "orange" or "Orange". As a hexadecimal number, orange is more red than green, like "#f60", "#D40", or "#FA8038". Compare with "yellow" which is red and green somewhat equal, like "#ff0".

# discover keycodes for buttons

Each button on a buttonboard has an id often known as a "keycode". A symbol or icon on a button is often known as a "key symbol" or "keysym". Associating a keysym with a keycode is often known as "keymapping". Changing the keysym associated with a keycode is often known as "remapping".

The Xserver keeps a list of keycodes for the buttons on a buttonboard, and each keycode is associated with seven keysyms (U.S. English). For example, the button labeled with "A" likely has the keysyms for at least "a" and "A".

Use the Lisp instruction prompt (...an outlet for ingenuity) to discover the keycode for a button after it is typed by using the xlib:grab-key, the stumpwm::read-key (two colons!), and the xlib:ungrab-key functions.

Eval: (xlib:grab-key (stumpwm:screen-root (stumpwm:current-screen) :any))
42004
Eval: (stumpwm::read-key)
(66 . 0)
Eval: (xlib:ungrab-key (stumpwm:screen-root (stumpwm:current-screen) :any))
46422

The stumpwm::read-key instruction (StumpWM version 1.0.1, "input.lisp": 262–267) reveals the keycode for the next button pressed, paired with a number representing which modifiers were active. No prompt. Only the keycode (the left half) is useful for the purpose of remapping. A button used as a modifier, like Shift, will reveal its own keycode when it is pressed by itself.

Eval: (stumpwm::read-key)
(28 . 4)
Eval: (car (stumpwm::read-key))
28

However, StumpWM normally grabs only the keys that were defined for commands, like the "Control-t" prefix. According to the documentation for xlib:grab-key, use :any (with the colon) as the keycode for accepting any button pressed.

The xlib:grab-key needs both an Xwindow and a keycode, and then returns a number that has nothing to do with keycodes, so ignore that number. StumpWM provides screen-root for extracting the root Xwindow from the results of the current-screen instruction. The root Xwindow for the current screen is often appropriate for generic introspection like this.

Predictably, specifying :any like this means StumpWM will notice any button pressed. Thereby, StumpWM will seek a command defined for each, and provide a message each time that fails. Obviously, this interferes with using other programs. Conveniently, StumpWM ceases looking for commands whenever it provides a prompt, like for Lisp evaluation.

In the mean time, use stumpwm::read-key from the Lisp instruction prompt. It will now reveal the keycode for the very next button pressed, even for a button like Caps Lock. Write on paper the label on the desired button, press the button, then write on the paper the keycode (the left half) that is revealed. Keycodes are often somewhat sequenced from left to right, top to bottom on a buttonboard.

Use stumpwm::read-key again for another button, or use the xlib:ungrab-key instruction with the exact same info that was given to xlib:grab-key to return typing to normal. Just like xlib:grab-key, the xlib:ungrab-key produces an arbitrary number, no need to record it.

The only difference between the grab/ungrab instructions is the "un" of xlib:ungrab-key. Recall, the up/down arrow buttons in the evaluation prompt reveal the prior/next lines that were typed, for less re-typing (The Lisp instruction prompt: an outlet for ingenuity). The Home button or "Control-a" moves the text cursor to the beginning of the line in the prompt quicker than the left arrow button.

For a bit more convenience and less clutter in the prompt history, assign a button to a command using eval-line (Any instruction at the press of a button) with stumpwm::read-key (because it is was defined with defun rather than defcommand). Then, just press that button to invoke the command instead of using the Lisp instruction prompt each time.

: describe-key
F16 is not bound.
Eval: (stumpwm:define-key stumpwm:*top-map* (stumpwm:kbd "F16") "eval-line (car(stumpwm::read-key))")

# change button symbols for keycodes

[ ...rewriting... ...no need for "xmodmap", there are at least two simple approaches, either with aref or a foldy, while using CLX... ]
[ ...hmm, Xserver seems unaffected by the change...and sometimes StumpWM crashes...see xlib:change-keyboard-mapping pecularities... ]

Use the work-on-a-copy approach: obtain a copy of a current setting, modify the copy, replace the current setting with the modified copy.

The xlib:keyboard-mapping (CLX 15.4.2) provides a copy of each keycode (0–255) and its keysyms (probably seven each).

Eval: keymap.my
The variable KEYMAP.MY is unbound.Backtrace...
Eval: (setf keymap.my(xlib:keyboard-mapping stumpwm:*display*))
#2A((0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (65307 0 65307 0 0 0 0)
 (49 33 49 33 0 0 0)
 (50 64 50 64 0 0 0)
 ...)

The xlib:keyboard-mapping provides a two-dimensional array. An array looks like a list of lists preceded by an octothorpe "#" and its number of dimensions, but an array is accessed or modified with only array instructions (CLHS 15.2 The Arrays Dictionary).

Congruently, the xlib:change-keyboard-mapping (CLX 15.4.2) requires a two-dimensional array. It is also important to specify the :end as 255, or the final keycode.

Eval: (xlib:change-keyboard-mapping stumpwm:*display* keymap.my :end 255)

The aref (CLHS) gives the array reference for an item when given its position for each dimension. The position is the number of other items before the desired item, for each dimension from outside to inside. For example, there are zero items before the first item so it is at the zeroth position, there are forty-two items before the forty-third item so it is at the forty-second position, and so forth.

The two-dimensional keycode array is sized as [256 7], so the array indices are 0–255. That allows for the subrange of 8–255 to match exactly with the keycodes 8–255, so specifying the keycode number is conveniently the same as the array position. The extra few at the beginning are of no matter.

The seven keysyms are referenced by 0–6 for the second dimension by the conventional skip-index approach. So, skip 0 items for access to the first keysym, skip 1 item for access to the second, and so on.

Eval: (aref keymap.my 66 0)
65490
Eval: (setf (aref keymap.my 66 0) #xff0d)
65293
Eval: (aref keymap.my 66 0)
65293

It might be more convenient to replace a whole list of keysyms for a keycode rather than change each of its keysyms individually.

Convert the two-dimensional array of individual keysyms into a one-dimensional array of lists of keysyms with write-to-string (CLHS), then read-from-string (CLHS), and then make-array (CLHS).

The write-to-string converts any Lisp form into "double-quoted text". The read-from-string converts "double-quoted text" into a Lisp form, but can also skip characters at the beginning and ending. Simply skip the description of the array, t.i. the text before the first parenthesis.

Eval: (setf keymap.my (write-to-string keymap.my))
"#2A((0 0 0 0 0 0 0)...)"
Eval: (setf keymap.my (read-from-string keymap.my nil nil :start 3))
((0 0 0 0 0 0 0)...)

The read-from-string has two other options prior the options to skip characters. Just provide nil for each before specifying :start for skipping the first three characters ("#2A") of the text. It then becomes an ordinary list of lists.

Give the make-array the number of items of only the outer list to make a one-dimensional array. Either presume 256 keycodes, or confirm with length (CLHS). The result will be a list prepended with an octothorpe, indicating it is actually an array.

Eval: (length keymap.my)
256
Eval: (setf keymap.my (make-array '(256) :initial-contents keymap.my))
#((0 0 0 0 0 0 0)...)

The solitary octothorpe is the abbreviation for "#1A", a one dimensional list. That means this is now an array of lists, so a whole list of keysyms is accessible and replaceable with aref. Individual keysyms are still accessible and replaceable within the lists, but by means of cdr and car.

Eval: (aref keymap.my 66)
(65293 0 65490 0 0 0 0)
Eval: (setf (aref keymap.my 66) '(#xff0d 0 #xff0d 0 0 0 0))
(65293 0 65293 0 0 0 0)
Eval: (cadr (aref keymap.my 66))
0
Eval: (setf (cadr (aref keymap.my 66)) #xff09)
65289
Eval: (aref keymap.my 66)
(65293 65289 65293 0 0 0 0)

Ultimately, the keycodes need to be a two-dimensional array for xlib:change-keyboard-mapping. Use the same technique: write as text, read the text without the array prefix, make a new array from the list of lists. Recall, count, or confirm with length there are 7 items for the second dimension.

Eval: (setf keymap.my (write-to-string keymap.my))
"#((0 0 0 0 0 0 0)...)"
Eval: (setf keymap.my (read-from-string keymap.my nil nil :start 1))
((0 0 0 0 0 0 0)...)
Eval: (setf keymap.my (make-array '(256 7) :initial-contents keymap.my))
#2A((0 0 0 0 0 0 0)...)
Eval: (xlib:change-keyboard-mapping stumpwm:*display* keymap.my :end 255)

[ ...See xlib:change-keyboard-mapping pecularities... ]




[ ...likely the modifier buttons section... ]


[ ...

The U.S. English buttonboards have 47 buttons for letters and symbols. Typically, holding down the Shift modifier button signals the computer to provide another 47 alternate symbols, such as capital letters and more punctuation.

The Control and Alt modifier buttons individually provide 47 additional alternate possibilities each. Holding two modifier buttons at the same time is another distinct signal for the computer for three more sets of 47 possibilities: Shift+Control, or Shift+Alt, or Control+Alt. Holding all three is yet another 47 possibilities.

Eight layouts overall, each providing 47 possibilites, totals a minimum of 376 possibilities. That is a minimum because there are other buttons, like F1–F12 or Home/End/Help or Tab/Return/Space or arrow buttons and more, and all can be combined with any combination of modifier buttons.

As such, there really is no need for so many (three!) modifier buttons. Also, a modifier button held with a thumb enables typing with the other fingers of the same hand, thereby making two of each modifier redundant.


... ]

[ ...some ideas or inspiration... ]


[ ...

Consider swapping "QWE" for the familiar sequence "ABC", or "123" to "012". Make the caps lock button the prefix for commands. Consider putting the braces "( )" (unshifted) and brackets "[ ]" (shifted) in the center at T Y (left and right), maybe the comma/double-quote at G and period/apostrophe at H, and rearrange the letters some.

Consider having the hands one row up, thereby the thumbs can easily type the buttons on the bottom row above the barbutton. Make each of those bottom buttons a space button and Return, and one each of Shift, Control, and Alt.

Consider rotating the buttonboard 180 degrees. The function buttons F1–F12 are then physically at the bottom for the thumbs. Assign a function button for the new space button, a new Return button, and single modifier buttons for Shift, Control, and Alt. Assign "Return" to a button somewhere left of the space button, since that is what each actually does anyway.

In essence, make it familiar and personally convenient, or continue using what was manufactured for no one in particular. Different is okay, likely no one else will ever notice, as it is a personalized computer. Either way, consider keeping notes on paper for each layout associated with each modifier button.


... ]

# Common Lisp X Interface (CLX)

For now, these are attempts at unraveling some obstinate functions of the Common Lisp X Interface, because every programming fad on the planet was used to implement any and every part, likely in the name of "modern programming" or "robustness". To be fair, many of the fads were in the Common Lisp HyperSpec, rather than as a separate set of approaches (like a cookbook).

On the other hand, some paradigms from other computer programming writing systems (misnomered as "computer languages") were prostheticized into CLX for the sake of whomever wrote it. That is fine, except there is no workflow or intent included, so there is no record of actual usage, no shared experience, and so no inspiration for extensibility.

Let it be made clear: There is no extensibility from "extended". The latter is merely the footprint of a dinosaur, what the computer manufacturers and operating system companies provide for free (extendedness) with the fantasies (marketing) they sell in the name (branding) of their own personal charities (online stores).

Source code is worthless when there is too much of it. Modular is only worthwhile when actually used, rather than made "just in case" or to fluff out all the possibilities.

Prefabricated is lifeless and unadaptable. Lack of intent and real world usage is uninformative and uninspiring. Perfectness itself never sits still and it is pointless as a goal, but is experienced in the flow of everyday life, beyond the dead written past of history or the freshly mummified bleeding edge computer programs.

Both CLX and Common Lisp were clearly too much for the people involved in writing them to handle, and they did the best they could with those two behemoths. They can only be torn apart, most of the pieces thrown aside, and maybe something familiar and inspiring will provide an outlet for ingenuity. They are clearly worthless for the everyday individual, for they are unspoken in the vernacular of the layman and fail to fit with what emerges from the split second moment of life.

# xlib:change-keyboard-mapping pecularities

For whatever reason the Xserver seems to be unaffected by the changes from xlib:change-keyboard-mapping (CLX 15.4.2). CLX documentation says use NIL for NoSymbol, though X11 protocol says zero is fine. NIL sometimes produces an error. Zero is without error, but so far the changes to zero for the first keysym position for a keycode are unchangeable thereafter.

Most notable is an "unsigned byte 8" error occurring for values greater than 255 for :end, possibly from type checking done with the functions/macros named with the prefix "index..." that are from text.lisp of CLX source.

The xlib:keyboard-mapping returns an array sized as [256 7] by default, and is therefore unreturnable to xlib:change-keyboard-mapping because its :end is documented as (array-dimensions keysyms 0) by default, t.i. 256.

xlib:change-keyboard-mapping breaks (xlib::display-keysym-mapping stumpwm:*display*) sometimes by leading to 20 entries per keycode rather than just 7, and at other times inserts the wrong keysyms for a keycode.
The source code requires :end be one more than the final keycode because length equals ":end - :start", but it also rejects 256 as a value for including the final possible keycode 255, t.i. only 0–254 is possible even though 8–255 is what is specified in the X protocol.
A potential workaround is to provide a smaller array, such as [248 7] for 8–255 (seven keysyms each), and specify :first-keycode as greater than 0, such as 9 (typically the first on the buttonboard anyway, as Escape). Then :start is 0 and :end is number of keycodes plus one. However, additional testing suggests a smaller array fails.

The REWRITE would be to make :end be the actual final keycode position in the supplied array, then have the function calculate the count inclusively of the specified indices by ":end - :start + 1", and have the loop cease at ">" rather than ">=".
But xlib:change-keyboard-mapping fails to make correct changes, so there is no point normalizing its interface. It simply needs to be abandoned (or the funicular spaghetti code further untangled).
The xlib:process-event (CLX 13.2) documentation points out the CLX cache of keysyms needs to be invalidated, and that xlib:mapping-notify (StumpWM version 1.0.1, "translate.lisp": 494–506) is for helping with that. However, the latter takes four values and there is no example workflow. Prior experience and knowledge and intent is just supposed to be magically known for a custom CLX function with an indirect relation to the X protocol. Internally, there are just two significant lines, the most notable being (setf(xlib::display-keysym-mapping stumpwm:*display*)nil), which seems to have no effect when used from the Lisp evaulation prompt provided by eval-line from StumpWM. But that apparent ineffectiveness might be because of the failure or incorrect usage of xlib:change-keyboard-mapping (presuming there is a correct way of using it).

When no error or crashing, ineffectiveness is confirmed with xlib:keycode->keysym (CLX 15.4.3).

Eval: (xlib:keycode->keysym stumpwm:*display* 66 0)
0

But, confirmed it does work with prior xmodmap instructions:

(stumpwm:run-shell-command "xmodmap -e 'keycode 66 = Return Tab'")

However, consider changing keycode 66 to the keysyms for Return (#xff0d) and Tab (#xff09) with the xlib:change-keyboard-mapping. StumpWM crashes, but at the console. [StumpWM seems unrestartable after killing it, just repeats the same error at the console. Seem to need to kill both StumpWM and Xserver, then restart them, then everything seems fine again.]

Eval: (xlib:change-keyboard-mapping stumpwm:*display* (make-array '(1 7) :initial-contents '((65293 65289 65293 65289 0 0 0))) :first-keycode 66 :start 0 :end 1)

Or, consider swapping "@" (keysym 64) with "2" (keysym 50) for its typical keycode 11. Normally, the keysyms are (50 64 50 64 0 0 0). No error, and there is a change for keycode 11, but to all zeros, meaning there is now no way to type "2" or "@" (hence why it was chosen as a test rather than "1", so its keycode could be typed in the prompt afterwards).
[Hmm, does it really want an array with at least that many keycodes? If so, then the aforementioned workaround of using a smaller array simply avoids the error without ever being possible to set all keycodes.]

Eval: (xlib::display-keysym-mapping stumpwm:*display*)
#2A((0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (65307 0 65307 0 0 0 0)
 (49 33 49 33 0 0 0)
 (50 64 50 64 0 0 0)
 ...)
Eval: (xlib:change-keyboard-mapping stumpwm:*display* (make-array '(1 7) :initial-contents '((64 50 64 50 0 0 0))) :first-keycode 11 :start 0 :end 1)
Eval: (xlib::display-keysym-mapping stumpwm:*display*)
#2A((0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (0 0 0 0 0 0 0)
 (65307 0 65307 0 0 0 0)
 (49 33 49 33 0 0 0)
 (0 0 0 0 0 0 0)
 ...)
Eval: (xlib:keycode->keysym stumpwm:*display* 11 0)
0

Sometimes there is an error at the console with varying number for "the value". StumpWM crashes (maybe?) as it is no longer available, but ps shows its process still listed.
Rather repeatable, something to do with attempting to change keyboard mapping more than once, perhaps when trying something different. Try 12 keycodes in array with only two keysyms, t.i. size of [12 2], and include the first 12 keycodes, but specify only :first-keycode 11, :start 0, :end 1.
[ Ran out of room on paper...write the rest next time. ]

Caught 'The value
          1476395008
        is not of type
          (UNSIGNED BYTE 29)' at the top level. Please report this...
...
0:(XLIB::AREF-CARD29 #<unavailable argument> #<unavailable argument>)
1:(XLIB:KEYBOARD-MAPPING #<XLIB:DISPLAY :0 ...> :FIRST-KEYCODE NIL :START NIL :END NIL :DATA NIL)
...
6:(STUMPWM:UPDATE-MODIFIER-MAP)
...
8:(STUMPWM::HANDLE-EVENT :EVENT-KEY :MAPPING-NOTIFY :EVENT-CODE 34 ...)

Perhaps re-check stumpwm:handle-event (StumpWM version 1.0.1, "events.lisp": 634–671) and the :mapping-notify handler (StumpWM version 1.0.1, "events.lisp": 380–385), as StumpWM might be causing interference. The latter is evoking stumpwm:update-modifier-map (StumpWM version 1.0.1, "input.lisp": 836–838; but consider 796–838). (Note: personal keymap has no Meta, and StumpWM does something special when that is the case.) Probably just a distraction from the main concern of xlib:change-keyboard-mapping.

Restarts are advertised but impossible. Afterwards, there is a reference to the CLX source, though it claims the file has been modified since compilation (doubtful).

(XLIB::AREF-CARD29 #<unavailable argument> #<unavailable argument>)
; File has been modified since compilation:
;   /.../common-lisp/clx-0.7.5/dependent.lisp
; Using form offset instead of character position.
   source: (THE CARD29 (ASH (THE CARD8 (AREF A (INDEX+ I +LONG-2+))) 16))

# additions for StumpWM and an Xserver

The most immediate change to StumpWM is applied with the eval-line command, available with Control-t then colon, usually notated as "C-t :" (The Lisp instruction prompt: an outlet for ingenuity).

That is also the means for loading a file with a more comprehensive change written with Common Lisp, by using load (CLHS). For example:

(load "~/.stumpwm.d/custom/points-later.lisp.html")

The ".lisp" suffix is common for files with Lisp, but is optional because Lisp is just plain text, just like HTML and CSS.

# mathemagical Xserver cursor placement

Much like split-view management, the Xserver cursor can be placed anywhere within the bounds of a screen by halving it. Begin in the center of a screen, then split it (left, right, top, or bottom) and center the cursor within one of the halves.

Xserver cursor placement by mathemagically halving the screen, rather than arbitrary pointer motion. That is, no more need to use the force of dramatic physical gestures to move anything. Basic center, left, right, up, and down for positioning quickly, or go back to previous point or the screen center.

Includes pointer activation, and keybindings (for numeric pad), and inspiration...and a "Content outline" for the copious documentation. It is all quite simple, really; the fluff is in the doc rather than the code.

Or, recenter the Xserver cursor at any halving point and it becomes the beginning point. Going back stops at that halving point. Returning to the beginning returns to that recenter point, then returning once more makes the screen center as the beginning point once again.

# mathemagical pointer and cursor placement

A single destination:

         y axis
         |
x axis --+--------------------------------
         | origin       up
         |              |
         |              |    # destination
         |              |
         | left --------+-------- right
         |        point |
         |              |
         |              |
         |             down

Extending lines from the point isolates the destination within a quadrant and reveals the pointer trajectories for intersecting with the destination. Limiting the length of the lines to the width and height of the narrowed region reveals the current precision and the progress.


Many potential destinations:

         y axis
         |
x axis --+---------------------------------------
         | origin           up
         |                  |
         |                  |
         |                  | destinations
         | left ------------+--#--#--#--#-- right
         |            point |
         |                  |
         |                  |
         |                 down

Multiple potential destinations might be axially aligned, f.e. a menu of options or a toolbar of outlined regions. Placing the pointer first along their axial alignment frees the other axis for selecting any of the items. Another option can be chosen by backtracking a little rather than starting over at the center of the screen.

The pointer has four parts that imply the crossing of a horizontal line with a vertical line. A gap for the implied intersection also provides the visual clearance needed for the Xserver cursor when activating the pointer buttons.

Other programs continue controlling the appearance of the Xserver cursor within their views without interference from the halving pointer.

Pointer placement by mathemagically halving the screen, rather than arbitrary pointer motion includes buttonboard bindings (for numeric pad) for multidirectional placement, and complementary commands for activation of the pointer without the pointer-box.

Consider recentering the pointer and Xserver cursor at any halving point and it becomes the beginning point. Going back stops at that halving point. Returning to the beginning returns to that recenter point, then returning once more makes the screen center as the beginning point once again.

Either way, the pointer-halving-show command conveniently returns the cursor that has been moved (f.e. by a pointer-box) back to the pointer position, and pointer-halving-hide hides the pointer without hiding the Xserver cursor. Or, consider combining the commands into pointer-halving-reveal-toggle for toggling revealing and hiding of the pointer.

# make a point, collect them all, restore them later

Convert a pointer interface into a selection interface. First, move the Xserver cursor by whatever means available, then mark the location for returning the cursor to it later. Each point is then available as next or prior. Eliminate traversal of a vast void, and never miss a point.

With the convenience commands points-write and points-read, write a list of marked points to a document, then later read and apply that list of points to restore them for use again. Perhaps collect a group of preferred points for a specific program, then swap them for a group of points from another document for another program.

Convert "drag and drop" into "select and put" by adding pointer button activation commands for toggling the press or release of the primary pointer button from the buttonboard.


The hot spot for the Xserver cursor must have clearance when activating a pointer button. A point is drawn as a white perimeter of a square with a black mask, made from four Xwindows.

 ______        _   __   _
|  __  |      | | |__| | |
| |  | |  ==  | |      | |
| |__| |      | |  __  | |
|______|      |_| |__| |_|

The left and right sides each have a black background, and a subwindow with a black background and a white border as thick as the line for the square perimeter.

For example, the left side (though taller than this):

  left
 window              -->   cropped
 ______                    ______
|  ____|__                |  ____|<-mask
| |       |               | |    |
|b| w _   |               |b| w _|<-perimeter
|l| h| |  |               |l| h| |
|a| i| |  |               |a| i| |<-black mask
|c| t|_|  |               |c| t|_|
|k| e     |               |k| e  |
| |_______|subwindow      | |____|
|______|                  |______|

The top and bottom sides each have a black background, and a subwindow with a white background as wide as the sides and as tall as the perimeter height.

 top or bottom
    window
 ____________
|____________|<-black mask
|subwindow   |<-white perimeter
|____________|
|____________|<-black mask

# modifications for StumpWM

Some slight changes to consider.

# reveal buttons for stumpwm:*top-map*

Prefix: 
C-t   *ROOT-MAP*

Assigning a button to stumpwm:*top-map* should allow for typing that button and then a question mark "?" to reveal its button listing, like with other keymaps. But invoking the listing fails with disaster.

: describe-key
Delete is not bound.
Eval: (define-key *top-map* (kbd "F12") '*top-map*)

Unfortunately, StumpWM attempts to gather all the keymaps with handle-keymap prior to searching them whenever using describe-key or where-is (Invoke a StumpWM command by its name). The gathering becomes recursive because of the button for the *top-map*, then StumpWM crashes and sort of recovers.

StumpWM Crashed With An Unhandled Error!
Copy the error to the clipboard with the 'copy-unhandled-error' command.

Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.

PROCEED WITH CAUTION.

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {1234567890}>
0: (STUMPWM::BACKTRACE-STRING)

1: ((:METHOD STUMPWM::HANDLE-TOP-LEVEL-CONDITION (SERIOUS-CONDITION)) #<SB-KERNEL::CONTROL-STACK-EXHAUSTED {0123456789}>) [fast-method]

2: (SB-KERNEL::%SIGNAL #<SB-KERNEL::CONTROL-STACK-EXHAUSTED {0123456789}>)
3: (ERROR SB-KERNEL::CONTROL-STACK-EXHAUSTED)
4: (SB-KERNEL::CONTROL-STACK-EXHAUSTED-ERROR)
5: ("bogus stack frame")

6: ((LABELS STUMPWM::SEARCH-IT :IN STUMPWM::SEARCH-KMAP) "colon" #S(STUMPWM::KMAP :BINDINGS (#S(STUMPWM::BINDING :KEY #S(STUMPWM::KEY :KEYSYM 116 :SHIFT NIL :CONTROL T :META NIL :ALT NIL :HYPER NIL :SUPER NIL) :COMMAND *ROOT-MAP*) #S(STUMPWM::BINDING :KEY #S(STUMPWM::KEY :KEYSYM 65481 :SHIFT NIL :CONTROL NIL :META NIL :ALT NIL :HYPER NIL :SUPER NIL) :COMMAND *TOP-MAP*))) (#1=#S(STUMPWM::KEY :KEYSYM 65481 :SHIFT NIL :CONTROL NIL :META NIL :ALT NIL :HYPER NIL :SUPER NIL) #1# #1# #1# #1# #1# #1# #1# #1# #1# #1# #1# ...))

...exactly the same from 6 to 99...

99: ((LABELS STUMPWM::SEARCH-IT :IN STUMPWM::SEARCH-KMAP) "colon" #S(STUMPWM::KMAP :BINDINGS (#S(STUMPWM::BINDING :KEY #S(STUMPWM::KEY :KEYSYM 116 :SHIFT NIL :CONTROL T :META NIL :ALT NIL :HYPER NIL :SUPER NIL) :COMMAND *ROOT-MAP*) #S(STUMPWM::BINDING :KEY #S(STUMPWM::KEY :KEYSYM 65481 :SHIFT NIL :CONTROL NIL :META NIL :ALT NIL :HYPER NIL :SUPER NIL) :COMMAND *TOP-MAP*))) (#1=#S(STUMPWM::KEY :KEYSYM 65481 :SHIFT NIL :CONTROL NIL :META NIL :ALT NIL :HYPER NIL :SUPER NIL) #1# #1# #1# #1# #1# #1# #1# #1# #1# #1# #1# ...))

The search algorithm never considers the possibility of a keymap having a button paired with itself within itself. Similarly, keymaps that have buttons to each other become circular, thereby recursive.

The stumpwm:display-bindings-for-keymaps provides the listing for a keymap, however, a custom command with eval-line (Any instruction at the press of a button) displays "NIL" when evaluating it and inconveniently obliterates the button listing.


For the *top-map*, consider making a new StumpWM command with stumpwm:defcommand that uses the stumpwm:display-bindings-for-keymaps instruction (An introspective approach for defun).

Eval: display.top-map
The variable DISPLAY.TOP-MAP is unbound.Backtrace...
Eval: (setf display.top-map '(defcommand display.top-map () () "Reveal buttons for *top-map*." (stumpwm::display-bindings-for-keymaps nil *top-map*)))
Eval: (eval display.top-map)

Either define a new button for it (Pair a button with a command or keymap), or invoke the command from the prompt provided by the colon command (Invoke a StumpWM command by its name).

: describe-key
C-t / is not bound.
Eval: (define-key *root-map*  (kbd "/") "display.top-map")
: describe-key
C-t / is bound to "display.top-map".
Reveal buttons for *top-map*.

# remove the message from the screen

Some messages from StumpWM stay on the screen, such as Help documentation or error messages. Any message is removed from the screen when the next StumpWM command is invoked, usually by typing the button assigned to it.

Some commands give a message that disappears after a few seconds. But, any message shown is also added to the message history.

Consider a new command with stumpwm:defcommand to remove the message from the screen that also never gives a message, perhaps a command that does nothing.

Eval: remove.message
The variable REMOVE.MESSAGE is unbound.Backtrace...
Eval: (defcommand remove.message nil nil "Remove the message from the screen.")

The "Forward Delete" button is named "Delete" according to the describe-key command (Invoke a StumpWM command by its name), and is probably seldom used.

: describe-key
Delete is not bound.
Eval: (define-key *top-map* (kbd "Delete") "remove.message")
: describe-key
Delete is bound to "remove.message".
Remove the message from the screen.

# alternative for stumpwm:eval-line

Sometimes evaluate a Lisp form without showing a message with results, such as for CLX "xlib:" instructions that return arbitrary numbers. Errors will still be shown, but without a backtrace. A short StumpWM command with stumpwm:defcommand (StumpWM 3.1).

Eval: (defcommand eval-quiet (Ftext) ((:rest "Lisp: ")) "Evaluate one Lisp form.  No result, usually." (eval (read-from-string Ftext)))
#S(STUMPWM::COMMAND :NAME EVAL-QUIET :CLASS T :ARGS ((:REST "Lisp: ")))

# replacement for stumpwm:err

stumpwm:err in "message-window.lisp": 301–308 (StumpWM version 1.0.1)

The stumpwm:err (StumpWM 4. Message and Input Bar) concatenates the backtrace for an error without ensuring it begins on a newline.

Eval: something
The variable SOMETHING is unbound.Backtrace...
Eval: (cons)
invalid number of arguments: 0Backtrace...

Consider inserting a newline with format and "~%" (CLHS 23.3.1.2). (Additional blank lines would require digging deeper into StumpWM, f.e. starting with stumpwm:echo-string in "message-window.lisp" at lines 292–294 (StumpWM version 1.0.1).)


(defun err (fmt &rest args)
 "Modified: [insert original description...]"
 (let ((stumpwm:*suppress-echo-timeout* t))
  (stumpwm:echo-string
   (stumpwm:current-screen)
   (stumpwm:concat
    (apply 'format nil fmt args)
    (format nil "~%")               ;;<-- the difference
    (stumpwm::backtrace-string)))))

When typing it all at once into the evaluation prompt (The Lisp instruction prompt: an outlet for ingenuity), perhaps start from the right end with stumpwm:concat (StumpWM version 1.0.1, "primitives.lisp": 1069–1070) and all the closing parenthesis marks, then type the earlier parts.

Otherwise, consider gradually forming an abdextrally half-paired list (Contrary formation and Lisp instructions) starting with nil for each sublist. The sublist for stumpwm:concat (see also concatenate (CLHS)) is a rather short beginning.

Eval: make.err
The variable MAKE.ERR is unbound.Backtrace...
Eval: (setf make.err '(concat (apply 'format nil fmt args) (format nil "~%") (stumpwm::backtrace-string)))
Eval: make.err
(CONCAT (APPLY 'FORMAT NIL FMT ARGS)
 (FORMAT NIL "~%") (STUMPWM::BACKTRACE-STRING))

The next outer list is for stumpwm:echo-string (StumpWM 4.3).

Eval: (setf make.err (cons make.err nil))
Eval: (setf make.err (cons '(current-screen) make.err))
Eval: (setf make.err (cons 'echo-string make.err))
Eval: make.err
(ECHO-STRING (CURRENT-SCREEN)
 (CONCAT (APPLY 'FORMAT NIL FMT ARGS)
  (FORMAT NIL "~%") (STUMPWM::BACKTRACE-STRING)))

Then the next outer list is for let (CLHS).

Eval: (setf make.err (cons make.err nil))
Eval: (setf make.err (cons '((*suppress-echo-timeout* t)) make.err))
Eval: (setf make.err (cons 'let make.err))
Eval: make.err
(LET ((*SUPPRESS-ECHO-TIMEOUT* T))
 (ECHO-STRING (CURRENT-SCREEN)
  (CONCAT (APPLY 'FORMAT NIL FMT ARGS)
   (FORMAT NIL "~%") (STUMPWM::BACKTRACE-STRING))))

The final outer list is for defun (CLHS).

Eval: (setf make.err (cons make.err nil))
Eval: (setf make.err (cons "Modified: [insert original description...]" make.err))
Eval: (setf make.err (cons '(fmt &rest args) make.err))
Eval: (setf make.err (cons 'err make.err))
Eval: (setf make.err (cons 'defun make.err))
Eval: make.err
(DEFUN ERR (FMT &REST ARGS)
 "Modified: [insert original description...]"
 (LET ((*SUPPRESS-ECHO-TIMEOUT* T))
  (ECHO-STRING (CURRENT-SCREEN)
   (CONCAT (APPLY 'FORMAT NIL FMT ARGS)
    (FORMAT NIL "~%") (STUMPWM::BACKTRACE-STRING)))))

Review and confirm, and then evaluate it. Try out some errors.

Eval: (eval make.err)
ERR
Eval: something
The variable SOMETHING is unbound.
Backtrace...
Eval: (cons)
invalid number of arguments: 0
Backtrace...

# replacement for stumpwm::print-key

The StumpWM prompts (Interactive curiosity...) have a specialized approach to interpreting abbreviations for commands for the stumpwm:*input-map* keymap.

New commands for the stumpwm:*input-map* keymap require accepting two pieces of info: a reference to the current prompt, and the buttons that invoked the command. The latter is mostly for stumpwm:input-self-insert, and usually ignored by other commands.


# The error from stumpwm::print-key.

The stumpwm:input-self-insert command is assigned as t (meaning all unassigned buttons) instead of a specific button sequence. That leads to an error from stumpwm::print-mods.

For example, assign a button to stumpwm:*input-map* in order to use the button as a prefix for it, as with any keymap (Make a StumpWM keymap and pair a button). Then, type the button and then a question mark "?" to reveal the button list.

StumpWM Crashed With An Unhandled Error!
Copy the error to the clipboard with the 'copy-unhandled-error' command.
The value
    T
  is not of type
    STUMPWM::KEY
Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {0123456789}>
0: (STUMPWM::PRINT-MODS T)
1: (STUMPWM::PRINT-KEY T)
2: (STUMPWM::DISPLAY-BINDINGS-FOR-KEYMAPS ...)
...

Tracing backwards through the source files leads to stumpwm::display-bindings-for-keymaps inappropriately passing T to stumpwm::print-key. But the latter is much smaller and simpler to rewrite in the Lisp instruction prompt for a quick resolution.


# The original and a replacement for stumpwm::print-key.

The stumpwm::print-key function is in "kmap.lisp": 174–177 (StumpWM version 1.0.1).

174  (defun print-key (key)
175    (format nil "~a~a"
176            (print-mods key)
177            (keysym->stumpwm-name (key-keysym key))))

One approach is to include a conditional such as if (CLHS) with eq (CLHS) for matching T that returns "double-quoted text", otherwise it does what it would have done. Notice stumpwm::print-key and all the StumpWM functions in it need "stumpwm::" prepended.

(defun
 stumpwm::print-key
 (Fkey)
 (if (eq t Fkey) "All else"       ;;<-- the difference
  (format nil "~a~a"
   (stumpwm::print-mods Fkey)
   (stumpwm::keysym->stumpwm-name
    (stumpwm::key-keysym Fkey)))))

When typing it in all at once (The Lisp instruction prompt: an outlet for ingenuity), perhaps start with the final Lisp form at the right end and all the closing parenthesis marks, then type the earlier parts (Typing within a line of text).

Consider storing both versions in memory with the same name as the function (An introspective approach for defun).


# Typing and storing the original stumpwm::print-key.

Consider storing the original in memory with the same name as the function itself (An introspective approach for defun). Prepend "stumpwm::" to other function names as needed.

Consider gradually forming an abdextrally half-paired list (Contrary formation and Lisp instructions) starting with nil for each sublist. The sublist for stumpwm::keysym->stumpwm-name is a rather short beginning.

Eval: stumpwm::print-key
The variable STUMPWM::PRINT-KEY is unbound.Backtrace...
Eval: (setf stumpwm::print-key '(stumpwm::keysym->stumpwm-name (stumpwm::key-keysym Fkey)))

The next outer list is for the format Lisp instruction. Pair it with nil, then add the four additional parts individually, and use quote as needed. Remember to prepend "stumpwm::" as needed.

Eval: (setf stumpwm::print-key (cons stumpwm::print-key nil))
Eval: (setf stumpwm::print-key (cons '(stumpwm::print-mods Fkey) stumpwm::print-key))
Eval: (setf stumpwm::print-key (cons "~a~a" stumpwm::print-key))
Eval: (setf stumpwm::print-key (cons nil stumpwm::print-key))
Eval: (setf stumpwm::print-key (cons 'format stumpwm::print-key))
Eval: stumpwm::print-key
(FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
        (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY)))

Finishing the original instruction, the next outer list is for the defun Lisp instruction. Pair it with nil, then add the three additional parts individually, and use quote as needed.

Eval: (setf stumpwm::print-key (cons stumpwm::print-key nil))
Eval: (setf stumpwm::print-key (cons '(Fkey) stumpwm::print-key))
Eval: (setf stumpwm::print-key (cons 'stumpwm::print-key stumpwm::print-key))
Eval: (setf stumpwm::print-key (cons 'defun stumpwm::print-key))
Eval: stumpwm::print-key
(DEFUN STUMPWM::PRINT-KEY (FKEY)
  (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
          (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))

Consider prepending a double-quoted description identifying it. Then, the car is the description and the cdr is the instruction to evaluate.

Eval: (setf stumpwm::print-key (cons "original" stumpwm::print-key))
("original" DEFUN STUMPWM::PRINT-KEY (FKEY)
 (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
         (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))
Eval: (cdr stumpwm::print-key)
(DEFUN STUMPWM::PRINT-KEY (FKEY)
  (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
          (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))

# Typing and storing the replacement stumpwm::print-key.

Consider storing the replacement in memory with the same name as the function itself (An introspective approach for defun).

The replacement pairs a conditional with part of the original (The original and a replacement for stumpwm::print-key). Perhaps start by typing in the original (Typing and storing the original stumpwm::print-key), then duplicate it (Re-listing rather than re-arranging).

Eval: stumpwm::print-key
("original" DEFUN STUMPWM::PRINT-KEY (FKEY)
 (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
         (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))
Eval: (setf stumpwm::print-key (cons stumpwm::print-key (read-from-string (format nil "~s" stumpwm::print-key)))
(("original" DEFUN STUMPWM::PRINT-KEY (FKEY)
 (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
         (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))
"original" DEFUN STUMPWM::PRINT-KEY (FKEY)
 (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
         (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))

Consider changing the description of the abdexter half to indicate it is the replacement, leaving the dexter half as the original.

Eval: (setf (caar stumpwm::print-key) "replacement")

Confirm the reference with car and cdr, then consider using "Control-k" and "Control-y" rather than retyping the reference later.

Eval: (car (cddddr (car stumpwm::print-key)))
(FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
        (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY)))

As usual, begin a sublist by pairing the reference with nil, then abdextrally pair the additional items.

Eval: (setf (car (cddddr (car stumpwm::print-key))) (cons (car (cddddr (car stumpwm::print-key))) nil))
Eval: (setf (car (cddddr (car stumpwm::print-key))) (cons "All else" (car (cddddr (car stumpwm::print-key)))))
Eval: (setf (car (cddddr (car stumpwm::print-key))) (cons '(eq t Fkey) (car (cddddr (car stumpwm::print-key)))))
Eval: (setf (car (cddddr (car stumpwm::print-key))) (cons 'if (car (cddddr (car stumpwm::print-key)))))
Eval: (car (cddddr (car stumpwm::print-key)))
(IF (EQ T FKEY)
    "All else"
    (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
            (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY))))

Confirm the replacement instruction, and then evaluate it to replace stumpwm::print-key.

Eval: (car stumpwm::print-key)
("replacement" DEFUN STUMPWM::PRINT-KEY (FKEY)
 (IF (EQ T FKEY)
     "All else"
     (FORMAT NIL "~a~a" (STUMPWM::PRINT-MODS FKEY)
             (STUMPWM::KEYSYM->STUMPWM-NAME (STUMPWM::KEY-KEYSYM FKEY)))))
Eval: (eval (cdar stumpwm::print-key))

Pair a button with the stumpwm::*input-map* keymap, but within some other keymap (Make a StumpWM keymap and pair a button), then type the button and then a question mark "?" to reveal the button list for editing commands (The button list for text editing).

# Type more characters with Mode_switch

[ ...describe enabling group 2 characters with xmodmap for typing within programs for an Xserver or in StumpWM prompts... ]
[ ...copy or rephrase explanation about StumpWM from custom xmodmap buttonmap (xmodmap-compact: buttons for typing symbols)... ]

The X Window System Protocol, Chapter 5, states Mode_switch is for group 2 of the four pairs of keysyms for a keycode (x.org: "X Window System protocol"). The CLX library has xlib:keycode->keysym which expects a keysym index from 0 to 6, according to the error it gives when beyond.

StumpWM favors ISO_Level3_Shift and equates it with the traditional AltGr/Compose button, but associates it with group 2. However, it also matches with the modifier group mask, which allows it to work when added to the same modifier group as Mode_switch. See "input.lisp" for code-state->key at 511-528, which references stumpwm:*modifiers* which is set by stumpwm::get-modifier-map at 800-834.

Need Mode_switch (or its alias) for the button that is held for programs abiding the X11 protocol. Need ISO_Level3_Shift (erroneously) added to the same modifier group for StumpWM, because StumpWM matches that modifier group.

The Xserver starts with ISO_Level3_Shift assigned to a sometimes non-existent button, but that is desired for this circumstance.

Consider repurposing the Caps Lock or Shift Lock button into a button for only the Mode_switch keysym, unless there is already a button for it.

! Remove all keysyms from the "lock" modifier group.
clear lock
keycode 66 = Mode_switch

! Pick an empty modifier group, or clear one.
clear mod2
add mod2 = Mode_switch ISO_Level3_Shift


! An easy way of typing a non-breaking space.
! For example:
!  press the Mode_switch button,
!  type the barbutton (space).
keycode 65 = space space  nobreakspace nobreakspace


! The ʻokina consonant (Unicode hexidecimal "02bb")
! and the kahakō accent (macron) for vowels,
! for words of the language of Hawaiʻi.
!
! Add them to the "k" button.
! For example:
!  press the Mode_switch button,
!  type the "k" button.
!   --> ʻ
!  Release the Mode_switch button.
!
! Or:
!  press the Mode_switch and Shift buttons,
!  type the "k" button,
!  release the Mode_switch and Shift buttons,
!  type a vowel.
!   --> ā ē ī ō ū
!
keycode 45 = k K  U02bb dead_macron

sharing