- I’m not responsible for any system breakage due to my code.
- If you’re unsure, refer to THE LICENSE to see how seriously I take this.
- Use with *caution*
Note this may become out of date, please refer to the code for the binds
Prefix | Bind | Function |
---|---|---|
M-a | c OR C-c | open suckless term |
M-a | f | open firefox |
M-a | F | open pcmanfm |
M-a | E | open claws-mail |
M-a | e OR C-e | open emacs daemon OR open client |
M-a | / | open ssh menu |
M-a | s-e | force kill emacs daemon |
M-a | Space | rofi drun menu |
M-a | Return | stumpwm window select menu |
M-a | M-b | shuffle background |
M-a | l | lock screen with slock |
Prefix | Bind | Function |
---|---|---|
M-m | p | play/pause |
M-m | s | stop |
M-m | n | next |
M-m | b | previous |
M-m | z | toggle shuffle |
M-m | XF86AudioRaiseVolume | player volume up 5% |
M-m | XF86AudioLowereVolume | player volume down 5% |
Prefix | Bind | Function |
---|---|---|
C-t | s | vertical split |
C-t | S | horizontal split |
C-t | Q | maximize frame |
C-t | <Direction-Key> OR <Click> | select frame to focus |
C-t | C-<Direction-Key> | swap frame in direction |
C-t | k | kill active frame |
C-t | m | select frame for bulk move |
C-t | M | move bulk select to group |
C-t | FnKey | switch to group |
C-t | n | rotate frame |
C-t | R | resize mode |
C-t | x | open xkill (like force-quit on macOS X) |
C-t | p | toggle push/pop frame to/from floating group |
C-t | M-p | “flatten” all floating windows to frame |
C-t | q | Prompt to exit session |
C-t | M-q | Quick exit session |
C-t | M-Escape | Toggle Modeline |
C-t | B | Yank mouse focus to current window |
C-t | C-b | Hide mouse cursor |
C-t | / | Toggle Gaps |
NONE | M-Tab | Switch to previous frame |
NONE | s-Tab | list last open window in windowlist |
Prefix | Bind | Function |
---|---|---|
NONE | PrintScreen | screenshot full |
NONE | M-PrintScreen | screenshot interactive select |
NONE | s-PrintScreen | screenshot active frame/window |
Prefix | Bind | Function |
---|---|---|
M-s | C-s | Search Duckduckgo for selection |
M-s | s | Search Duckduckgo for prompt |
M-s | C-l | Search LibreY for selection |
M-s | l | Search LibreY for prompt |
M-s | C-o | Search Package Web for selection |
M-s | o | Search Package Web for prompt |
M-s | C-w | Search Wikipedia for selection |
M-s | w | Search Wikipedia for prompt |
M-s | C-d | Search Witionary for selection |
M-s | d | Search Wiktionary for prompt |
M-s | C-c | Search Clew Blogs for selection |
M-s | c | Search Clew Blogs for |
M-s | o | Search Package Web for prompt |
M-s | m | Search Manpages |
M-s | M | Open Manpage |
M-s | p | Search Package Name |
M-s | P | Search Package File |
when a window is in floating mode,
- the
Super
key is the prefix - left click (and drag) is move
- right click (and drag) is resize
- you can only mark (and move) frames, so flatten any floating windows before swapping groups
This is the first thing the WM Loads.
;;;
;; StumpWM Boilerplate
;;;
;; Quicklisp Setup
(let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp"
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
;; Load Quicklisp Packages
(ql:quickload '("stumpwm"
"clx"
"cl-ppcre"
"alexandria"
"cl-fad"
"xembed"
"anaphora"
"drakma"
"slynk"))
;; no style-warns
(declaim #+sbcl(sb-ext:muffle-conditions style-warning))
;; Optimize
(declaim (optimize (speed 3) (safety 3)))
;; Compile FASL
(setq *block-compile-default* t)
;; this automatically prefixes 'stumpwm:' to commands that need it
(in-package :stumpwm)
(setf *default-package* :stumpwm)
;; Set Modules
; (set-contrib-dir) is deprecated, this is the method now
(set-module-dir "~/.stumpwm.d/modules")
;;;
;; Colors
;;;
;; Define a list of color names and their corresponding hex codes
(defvar *color-map*
'((iz-black . "#282828")
(iz-red . "#CC241D")
(iz-softred . "#FB4934")
(iz-green . "#98971A")
(iz-softgreen . "#B8BB26")
(iz-yellow . "#D79921")
(iz-softyellow . "#FABD2F")
(iz-blue . "#458588")
(iz-softblue . "#83A598")
(iz-purple . "#B16286")
(iz-softpurple . "#D3869B")
(iz-aqua . "#689D6A")
(iz-softaqua . "#8EC07C")
(iz-orange . "#D65D0E")
(iz-softorange . "#FE8019")
(iz-white . "#EBDBB2")
(iz-gray . "#928374")))
;; Directly create *colors* by selecting the desired colors from *color-map*
(setf *colors*
(mapcar (lambda (color-name)
(cdr (assoc color-name *color-map*)))
'(iz-black ;; ^0
iz-softred ;; ^1
iz-softgreen ;; ^2
iz-softyellow ;; ^3
iz-softblue ;; ^4
iz-softpurple ;; ^5
iz-softaqua ;; ^6
iz-white ;; ^7
iz-softorange ;; ^8
iz-gray))) ;; ^9
;; Set those colors
(update-color-map (current-screen))
;;;
;; Styling
;;;
;; Set font and colors for the message window
(set-fg-color "#EBDBB2")
(set-bg-color "#282828")
(set-border-color "#EBDBB2")
(set-msg-border-width 1)
(set-font "-misc-spleen-medium-r-normal--16-160-72-72-c-80-iso10646-1")
;; MouseKeys
(setf *mouse-focus-policy* :click
*float-window-modifier* :super)
;; Welcome
(setq *startup-message* (format nil "^b^8Welcome Izzy!")) ;; Orange
;; Set focus and unfocus colors
(set-focus-color "#EBDBB2")
(set-unfocus-color "#928374")
(set-float-focus-color "#8EC07C")
(set-float-unfocus-color "#689D6A")
;;;
;; Env Vars
;;;
;; Set env vars
(setf (getenv "PAGER") "less -R")
;;;
;; Modules & their config
;;;
;; Init modules
(add-to-load-path "~/.stumpwm.d/extras/scratchpad")
(add-to-load-path "~/.stumpwm.d/extras/stumpwm-window-switch")
;; Load that module shizz in
(init-load-path *module-dir*)
(defvar *modulenames*
(list
"swm-gaps" ;; gaps
"swm-emacs" ;; emacs
"swm-ssh" ;; ssh
"stumptray" ;; System tray
"scratchpad" ;; floating scratchterm
"window-switch" ;; switch windows
"hostname" ;; native hostname
"battery-portable" ;; battery level
"stumpwm-sndioctl" ;; sound
"searchengines" ;; search macros
"beckon" ;; yank mouse cursor focus
"globalwindows" ;; navigate windows in all spacs
"urgentwindows" ;; get urgent windows
))
(dolist (modulename *modulenames*)
(load-module modulename))
;;
;; Module Settings
;;
;; swm-gapes
;; Set Gaps
(setf swm-gaps:*inner-gaps-size* 2
swm-gaps:*outer-gaps-size* 4)
;; Turn em on
(swm-gaps:toggle-gaps-off)
;; SSH
(setq swm-ssh:*swm-ssh-default-term* "st")
;; urgent window
(setf urgentwindows:*urgent-window-message* "Application ~a has just finished!")
;; Oneko command
(defcommand oneko () ()
"Oneko Start Command"
(bt:make-thread
(lambda ()
(run-shell-command "oneko -tora -tofocus -name 'neko'"))))
(defcommand kill-oneko () ()
"Oneko Stop Command"
(bt:make-thread
(lambda ()
(run-shell-command "pkill -9 oneko"))))
;; scratchpad
;; define default scratchpad term
(defcommand scratchpad-term () ()
(scratchpad:toggle-floating-scratchpad "term" "st"
:initial-gravity :center
:initial-width 720
:initial-height 480))
;; Bind Scratchpad to Super+t
(define-key *top-map* (kbd "s-t") "scratchpad-term")
;;;
;; Load in other files
;;;
;; pre-binds
(load "~/.stumpwm.d/pre-bind.lisp")
;; binds
(load "~/.stumpwm.d/bind.lisp")
;; jumps
(load "~/.stumpwm.d/jumps.lisp")
;; Rename and create new groups
(when *initializing*
(grename "Ness")
(gnewbg "Jeff")
(gnewbg "Paula")
(gnewbg "Poo"))
;; Clear rules
(clear-window-placement-rules)
;; Group format
(setf *group-format* "%n")
;; Window format
(setf *window-format* (format NIL "^(:fg \"~A\")<%25t>" "#B8BB26")
*window-border-style* :tight
*normal-border-width* 1
*hidden-window-color* "^**")
;; Time format
(setf *time-modeline-string* "%I:%M%p")
;; Message window settings
(setf *message-window-padding* 1
*message-window-y-padding* 1
*message-window-gravity* :bottom)
;; Input window settings
(setf *input-window-gravity* :center)
;;;
;; Define Functions
;;;
;; Normalize String
(defun normalize-string (string)
"remove weird whitespace or rubbish in strings"
(string-trim
'(#\Space #\Newline #\Backspace #\Tab #\Linefeed #\Page #\Return #\Rubout)
string))
;; Run a shell command and format the output
(defun run-shell-command-and-format (command)
"run a shell command, if output is empty reverse coloring and return string 'nil'"
(let ((output (run-shell-command command t)))
(if (string= output "")
"^Rnil^r"
(normalize-string output))))
;; Show the temperature
(defun show-temp ()
"get temp data from sysctl"
(run-shell-command-and-format "sysctl -n hw.sensors.cpu0.temp0"))
;; Show Volume
(defun show-volume (type)
"show current volume given a (type) argument"
(format nil "~,1f%" (* 100 (read-from-string (run-shell-command-and-format (format nil "sndioctl -n ~a.level" type))))))
;; Show the window title
(defun show-window-title ()
"show the title of the active window"
(normalize-string (window-title (current-window))))
;;;
;; Formatting
;;;
;; Constants
(defparameter pipe " | ")
(defparameter group-bracket-color "^8") ;; Soft Orange
(defparameter group-content-color "^6") ;; Soft Aqua
(defparameter audio-bracket-color "^7") ;; White
(defparameter audio-content-color "^B^2*^b") ;; Soft Green
(defparameter status-bracket-color "^5") ;; Soft Magenta
(defparameter status-content-color "^3*") ;; Soft Yellow
(defparameter win-bracket-color "^1") ;; Soft Red
(defparameter win-content-color "^2" ) ;; Soft Green
;; Components
(defvar group-fmt "%g")
(defvar status-fmt (list "%B" pipe ;; Battery
'(:eval (show-temp)) pipe ;; Cpu Temp
"%d" ;; Date
))
(defvar audio-fmt (list '(:eval (show-volume "output"))
"/"
'(:eval (show-volume "input"))))
(defvar win-fmt "%v")
;; Generate a Component of a given color
(defun generate-mode-line-component (out-color in-color component &optional right-alignment)
"Generate a Component of a given color, by default the component is Left aligned. set right-alignment to not nil for Right alignment"
(if right-alignment
(list "^>" out-color "[" in-color component out-color "]")
(list out-color "[" in-color component out-color "]")))
(defun generate-mode-line ()
"build a modeline"
(setf *screen-mode-line-format*
(list
(generate-mode-line-component group-bracket-color group-content-color group-fmt)
(generate-mode-line-component status-bracket-color status-content-color status-fmt)
(generate-mode-line-component audio-bracket-color audio-content-color audio-fmt)
(generate-mode-line-component win-bracket-color win-content-color win-fmt))))
;; Actually load my modeline
(generate-mode-line)
;; Format Modeline
(setf *mode-line-background-color* "#282828"
*mode-line-border-color* "#EBDBB2"
*mode-line-border-width* 1
*mode-line-pad-x* 1
*mode-line-pad-y* 1
*mode-line-timeout* 1)
;; mode line
(mode-line)
;; Load in StumpTray
(stumptray::stumptray)
;; cleanup/autostart
(load "~/.stumpwm.d/autostart.lisp")
Handling basic bind boilerplate that I will definitely never touch.
;;;
;; Pre-Bindings
;;;
;; Set prefix key
(set-prefix-key (kbd "C-t"))
;;;
;; Browser Notices for search engine module
;;;
;; Firefox
(defcommand firefox-esr () ()
"Set notice to Firefox ESR Opening"
(bt:make-thread
(lambda () (message "Opening Firefox"))))
;; surf
(defcommand surf () ()
"Set notice to Suckless SURF Opening"
(bt:make-thread
(lambda () (message "Opening Suckless SURF"))))
;; gross binds
(defvar *gross-default-binds*
(list "c" "C-c" "e" "C-e" "d" "C-d" "SPC"
"i" "f" "C-k" "w" "C-w" "a" "C-a"
"C-t" "R" "o" "TAB" "F" "C-h" "v"
"#" "m" "C-m" "l" "C-l" "G" "C-N"
"A" "X" "C-SPC" "I" "r" "W" "+"
"RET" "C-RET" "C-0" "C-1" "C-2"
"C-3" "C-4" "C-5" "C-6" "C-7"
"C-8" "C-9" "0" "1" "2" "3" "4"
"5" "6" "7" "8" "9"))
;; yuck!
(dolist (bind *gross-default-binds*)
(define-key *root-map* (kbd bind) NIL))
Handling bindings
;;;
;; Make New Keymaps
;;;
(defmacro make-keymap (map-name key-binding &optional root top)
`(progn
(defvar ,map-name
(let ((map (make-sparse-keymap)))
map))
(when ,root
(define-key *root-map* (kbd ,key-binding) ,map-name))
(when ,top
(define-key *top-map* (kbd ,key-binding) ,map-name))))
(make-keymap *search-map* "M-s" t t)
(make-keymap *media-map* "M-m" t t)
(make-keymap *app-map* "M-a" t t)
;;;
;; Bind Macro
;;;
;; Bind shell command to a specified map (default is *root-map*)
(defmacro bind-shell-to-key (key command &optional (map *root-map*))
`(define-key ,map (kbd ,key) (concatenate 'string "run-shell-command " ,command)))
;; Bind stumpwm command to a specified map (default is *root-map*)
(defmacro bind-to-key (key command &optional (map *root-map*))
`(define-key ,map (kbd ,key) ,command))
;;;
;; Loop & Bind Macro
;;;
;; Loop through keybind lists and bind them
(defmacro loop-and-bind (key-cmd-list bind-macro &optional (map *root-map*))
`(bt:make-thread
(lambda ()
(dolist (key-cmd ,key-cmd-list)
(,bind-macro (first key-cmd) (second key-cmd) ,map)))))
;; Push/Pop Current Window Into a Floating group
(defcommand toggle-float () ()
(if (float-window-p (current-window))
(unfloat-this)
(float-this)))
;;;
;; Bind Key Lists
;;;
;; Set Special keys
(defvar *my-special-key-commands*
'(("Print" "scrot -z -Z 0 -q 100 -e 'oxipng $f' -F ~/Pictures/screenshot-`date +%F`.png")
("M-Print" "scrot -s -z -Z 0 -q 100 -f -e 'oxipng $f' -F ~/Pictures/screenshot-split-`date +%F`.png")
("s-Print" "scrot -z -Z 0 -q 100 -u -b -e 'oxipng $f' -F ~/Pictures/screenshot-activewin-`date +%F`.png")))
;; Set Shell Keys
(defvar *my-shell-key-commands*
'(("c" "st")
("C-c" "st")
("l" "slock")
("M-b" "feh --bg-fill --randomize /usr/local/share/backgrounds")))
;; Set App Keys
(defvar *my-app-key-commands*
'(("E" "claws-mail")
("d" "deadbeef")
("F" "pcmanfm")
("f" "firefox-esr")))
;; Set Rofi Keys
(defvar *my-rofi-key-commands*
'(("SPC" "rofi -i -show-icons -matching fuzzy -show drun")))
;; Set Playerctl Keys
(defvar *my-media-key-commands*
'(("p" "playerctl play-pause")
("s" "playerctl stop")
("b" "playerctl previous")
("n" "playerctl next")
("z" "playerctl shuffle toggle")
("XF86AudioRaiseVolume" "playerctl volume 0.05+")
("XF86AudioLowerVolume" "playerctl volume 0.05-")))
;; Raw StumpWM Window-managing Commands
(defvar *my-wm-window-commands*
'(("M-ESC" "mode-line")
("M-q" "quit")
("m" "mark")
("M" "gmove-marked")
("x" "xkill")
("B" "beckon")
("C-b" "banish")
("RET" "expose")
("C-Up" "exchange-direction up")
("C-Down" "exchange-direction down")
("C-Left" "exchange-direction left")
("C-Right" "exchange-direction right")
("p" "toggle-float")
("M-p" "flatten-floats")
("/" "toggle-gaps")))
;; Raw StumpWM Module Commands
(defvar *my-wm-module-commands*
'(("/" "swm-ssh-menu")
("s-e" "emacs-daemon-kill-force")
("e" "swm-emacs")
("C-e" "swm-emacs")))
;; Unprefixed Module Commands
(defvar *my-unprefixed-module-commands*
'(("M-Tab" "select-previous-window")
("s-Tab" "windowlist-last")
("XF86AudioRaiseVolume" "volume-up")
("XF86AudioLowerVolume" "volume-down")
("XF86AudioMute" "toggle-mute")))
;;;
;; Loop & Bind with Macros from earlier
;;;
;; List of binds
(defparameter *key-bindings*
'((*my-shell-key-thread* *my-shell-key-commands* bind-shell-to-key *app-map*)
(*my-app-key-thread* *my-app-key-commands* bind-shell-to-key *app-map*)
(*my-rofi-key-thread* *my-rofi-key-commands* bind-shell-to-key *app-map*)
(*my-wm-module-thread* *my-wm-module-commands* bind-to-key *app-map*)
(*my-unprefixed-module-thread* *my-unprefixed-module-commands* bind-to-key *top-map*)
(*my-special-key-thread* *my-special-key-commands* bind-shell-to-key *top-map*)
(*my-media-key-thread* *my-media-key-commands* bind-shell-to-key *media-map*)
(*my-wm-window-thread* *my-wm-window-commands* bind-to-key *root-map*)))
;; Loop over list
(dolist (binding *key-bindings*)
(destructuring-bind (name commands binding-fn map) binding
(eval `(defvar ,name
(loop-and-bind ,commands ,binding-fn ,map)))))
These are my Web/Term jump macros for easy-peasy manpage searching or websurfing
;;;
;; Jump Macros
;;;
;; Term Jump commands
(defmacro make-term-jump (name command term)
`(defcommand ,(intern name) (search)
((:rest ,(concatenate 'string name " termsearch: ")))
(nsubstitute #\+ #\Space search)
(run-shell-command
(format nil "~a -e sh -c '~a ~a | less -R'" ,term ,command search))))
;;;
;; Module Settings
;;;
;; Set browser exe
(setf searchengines:*search-browser-executable* "firefox-esr")
;; Macro for search engine defines
(defmacro define-searchengine (selection-name prompt-name url description key-selection key-prompt)
`(progn
(searchengines:make-searchengine-selection ,selection-name ,url ,description :map *search-map* :key ,key-selection)
(searchengines:make-searchengine-prompt ,prompt-name ,description ,url ,description :map *search-map* :key ,key-prompt)))
;; Set Search Engine Params
(defparameter *URL-DDG* "https://duckduckgo.com/?q=~a")
(defparameter *URL-LIBRE* "https://search.ahwx.org/search.php?q=~a")
(defparameter *URL-PORTS* "https://openports.eu/search?q=~a")
(defparameter *URL-WIKIPEDIA* "https://en.wikipedia.org/w/index.php?title=Special:Search&search=~a")
(defparameter *URL-WIKTIONARY* "https://en.wiktionary.org/w/index.php?title=Special:Search&search=~a")
(defparameter *URL-CLEW* "https://clew.se/search?q=~a")
;; Create threads
(define-searchengine "search-wikipedia-selection" "search-wikipedia-prompt" *URL-WIKIPEDIA* "Wikipedia search" "C-w" "w")
(define-searchengine "search-wiktionary-selection" "search-wiktionary-prompt" *URL-WIKTIONARY* "Wiktionary search" "C-d" "d")
(define-searchengine "search-ddg-selection" "search-ddg-prompt" *URL-DDG* "DuckDuckGo search" "C-s" "s")
(define-searchengine "search-libre-selection" "search-libre-prompt" *URL-LIBRE* "LibreY search" "C-l" "l")
(define-searchengine "search-ports-selection" "search-ports-prompt" *URL-PORTS* "Ports Search" "C-o" "o")
(define-searchengine "search-clew-selection" "search-clew-prompt" *URL-CLEW* "Clew Blog Search" "C-c" "c")
;;;
;; Define Jumps
;;;
;; Define Terminal Jumps
(make-term-jump "mansearch" "apropos" "st")
(make-term-jump "manpage" "man" "st")
(make-term-jump "pkgname" "pkg_info -Q" "st")
(make-term-jump "pkgloc" "pkg_locate" "st")
;;;
;; Bind Jump Defines from Earlier
;;;
;; Keybindings for Terminal Jumps
(define-key *search-map* (kbd "m") "mansearch")
(define-key *search-map* (kbd "M") "manpage")
(define-key *search-map* (kbd "p") "pkgname")
(define-key *search-map* (kbd "P") "pkgloc")
;; Play Startup sound
(defun play-startup-sound ()
(run-shell-command "sleep 1 && ffplay -autoexit -nodisp ~/.local/sfx/okdesuka.wav"))
(defun set-default-sounds ()
(run-shell-command "sndioctl input.level=0.74")
(run-shell-command "sndioctl output.level=1.00"))
;; Start
(when *initializing*
;; Startup Sound
(set-default-sounds)
(play-startup-sound)
;; re/start slynk server
(slynk:create-server
:dont-close t))
;; Quit
(when *quit-hook*
;; Kill emacs
(swm-emacs:emacs-daemon-kill-force))
;; Finish Threads
(defvar *bind-thread-list*
(list
*my-special-key-thread*
*my-wm-window-thread*
*my-shell-key-thread*
*my-app-key-thread*
*my-rofi-key-thread*
*my-media-key-thread*
*my-wm-module-thread*
*my-unprefixed-module-thread*))
(dolist (threadname *bind-thread-list*)
(bt:join-thread threadname))