guest@dotshare [~/groups/wms/stumpwm] $ ls stumpwmrc-divided-version/ | cat

stumpwmrc (divided version) (scrot) (+5 likes)

milomouse Jun 23, 2011 (wms/stumpwm)

.stumpwmrc(raw, dl)

SCROT

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
;;--------------------------------------------------------------------------;;
;; ${XDG_CONFIG_DIR:-/howl/conf}/.stumpwmrc                                 ;;
;;--------------------------------------------------------------------------;;
;; author: milomouse <vincent[at]fea.st>                                    ;;
;;--------------------------------------------------------------------------;;
;; versions used ATOC:                                                      ;;
;; |  sbcl             -> 1.1.1-2                                           ;;
;; |  clx              -> 0.7.4-2                                           ;;
;; |  cl-ppcre         -> 2.0.3-2                                           ;;
;; |  stumpwm          -> 0.9.7-80-gb1271a9 Compiled On Thu Dec 08 10:46:16 ;;
;;-TODO/CHANGELOG:----------------------------------------------------------;;
;; >>>-: create a 'dedicate' and 'catchall' window-rule (remember * *)      ;;
;; >>--: create a 'dedicate' and 'catchall' hook for changing focus color   ;;
;; >>--: have mifo(mplayer-daemon) prompts use filename completion          ;;
;; >---: better resize; if neighbour {above} then +ARG else -ARG, etc.      ;;
;; >>>-: show frame-indicator for 'resize' only if no window in frame       ;;
;; >>>>? command for dedicating current win/frame as the Master win/frame   ;;
;; >---: better command for Master; remember Master thru re{loadrc,start}   ;;
;; >>>>! command for swapping current window with the Master win/frame      ;;
;; >>>>! exchange two windows but keep focus in current frame               ;;
;; >>>>! dynamically dump group|screen|desktop|rules to *data-dir* by type  ;;
;; >>>>! dynamically load group|screen|desktop|rules from *data-dir* by type;;
;; >>>>! have my 'undo' use group and check current group for undos first   ;;
;; >>>>! create a togglable, on-the-fly scratchpad group                    ;;
;;--------------------------------------------------------------------------;;
;; files: *data-dir*/../{commands,functions,hooks,key-maps,macros}.lisp     ;;
;;--------------------------------------------------------------------------;;

(in-package :stumpwm)

;; set a home-dir. not relative *default-pathname-defaults*.
;; set a data-dir for storing debug-file, group and placement dumps, etc.
;; set undo directory to store each group (and desktop) undo states.
;; set scratchpad group name for when it's created on the fly (.NAME to hide)
(setf *home-dir* (make-pathname :directory "/howl")
      *data-dir* (merge-pathnames (make-pathname :directory
                 '(:relative "conf" "stumpwm" "storage")) *home-dir*)
      *undo-data-dir* (make-pathname :directory "/tmp/user-keep/h")
      *scratchpad-group-name* ".scratchpad"
      *debug-level* 1)

;; setup a quick function for redirecting debug information directly to file.
;; (didn't want to use (redirect-all-output) as that's not what i want..)
;; (prefer internal handling as opposed to redirecting via exec $ >>! file)
(defvar *debug-restream* nil)
(defun redirect-debug (file) "Redirect *debug-stream* directly to a file."
  (when (typep *debug-restream* 'file-stream)
    (close *debug-restream*))
  (setf *debug-restream* (open file :direction :output :if-exists :append
                         :if-does-not-exist :create)
        *debug-stream* *debug-restream*))

;; setup debug-file variable for referencing (e.g. quitting) purposes.
(defvar *debug-file* (data-dir-file "log" "lisp"))
(redirect-debug *debug-file*)

;; define a background-image-path for random image setting function.
;; (will soon change this to accept optional sub-dir for situations where
;; user wants to use 'work' or 'family' wallpapers instead)
(defvar *background-image-path*
  (merge-pathnames
    (make-pathname :directory '(:relative "foto" "wall")) *home-dir*))

;; gravities.
(setf *mouse-focus-policy* :click
      *window-border-style* :thin
      *message-window-gravity* :top-right
      *input-window-gravity* :top-right)
(set-normal-gravity :top) ; top for terminals
(set-maxsize-gravity :center) ; center for floating X apps
(set-transient-gravity :center) ; center for save-as/open popups

;; borders.
(setf *resize-hides-windows* T
      *normal-border-width* 3
      *maxsize-border-width* 2
      *transient-border-width* 2
      *float-window-border* 1
      *float-window-title-height* 1)
(set-msg-border-width 3)

;; fonts/colors. (custom font; full unicode "Fixed" with emphasized numeric 0's <> alphabetic O's)
(set-font "-misc-fixedzero-medium-r-semicondensed-*-12-110-75-75-c-60-iso10646-1")
;(set-font "-misc-fixed-medium-r-semicondensed-*-12-110-75-75-c-60-koi8-r")
(set-fg-color        "grey64")
;(set-bg-color        "grey14")
(set-bg-color        "grey10")
(set-focus-color     "grey22")
;(set-focus-color     "thistle4")
;(set-focus-color     "cyan3")
;(set-focus-color     "cadetblue")
;(set-focus-color     "orchid3")
;(set-unfocus-color   "grey16")
(set-unfocus-color   "grey10")
;(set-border-color    "grey44")
(set-border-color    "grey10")
(set-win-bg-color    "grey6")
(setf *colors* (list "grey9"          ; 0 black
                     "deeppink"       ; 1 red
                     "chartreuse3"    ; 2 green
                     "gold1"          ; 3 yellow
                     "steelblue3"     ; 4 blue
                     "mediumpurple4"  ; 5 magenta
                     "cyan3"          ; 6 cyan
                     "honeydew4"      ; 7 white
                     "thistle4"       ; 8 user
                     "lightskyblue4")); 9 user
(update-color-map (current-screen))

;; text formatting (mode-line unused).
(setf *startup-message*
       ;"^B^5*writers write^7*|^B^4*always^n"
       ;"^B^5*Make Voyages!^7*|^B^4*Attempt Them!^7*|^B^5There's Nothing Else^n"
       "^B^5*together we ate the king^7*|^B^4*and laughed ourselves to death^n"
      *time-format-string-default* "^B^5*%b.%d^n ^7*|^n|^B^7*|^n ^B^4*%T^n ^B^7*|^n|^7*|^n ^B^5*%A^n"
      *group-format*    "^B^0*%t^7*%s^07|^n"
      *window-format*   "^B^87%s^9*%m^0*%16t^n"
      *screen-mode-line-format* nil
      *timeout-wait* 6)

;; windows/frames. use more intuitive frame-numbers (with 'fselect').
(setf *default-window-name* "null"
      *new-frame-action* :empty
      *min-frame-width* 25
      *min-frame-height* 25
      *resize-increment* 2
      *frame-number-map* "yhjukilop")

;; mode-line and input. (mode-line unused)
(setf *mode-line-background-color* "grey5"
      *mode-line-border-color* "grey10"
      *mode-line-foreground-color* "azure4" *mode-line-border-width* 1
      *mode-line-pad-x* 1
      *mode-line-pad-y* 0
      *mode-line-timeout* 6000
      *mode-line-position* :top
      *input-history-ignore-duplicates* 0)

;; load external settings files. these are the bulk of setup/optimizations.
(loop for file in '("functions" "macros" "commands" "hooks" "key-maps")
  do (load (merge-pathnames (make-pathname :name file :type "lisp"
           :directory '(:relative "conf" "stumpwm")) *home-dir*)))

;; restore data from previous exit (state StumpWM was last using),
(clear-window-placement-rules)
(setf (group-name (first (screen-groups (current-screen)))) "1")
(make-groups-bg "2" "3" "4" "5" "6")
(if (probe-file (data-dir-file "desktop.lisp"))
    (restore-from-file (data-dir-file "desktop.lisp")))
(if (probe-file (data-dir-file "tile-rules.lisp"))
    (restore-window-placement-rules (data-dir-file "tile-rules.lisp")))
(cond ((string-equal (group-name (current-group)) *scratchpad-group-name*) (gother)))

#|
;; display a random background image on root window.
(display-random-bg)
|#

#|
;; resize display head and [re]start 'dzen2'.
(resize-head 0 0 22 1600 878)
(if (probe-file (merge-pathnames (make-pathname :name "dzen4stumpwm" :type "zsh"
                :directory '(:relative "conf" "stumpwm")) *home-dir*))
    (run-shell-command "pkill -9 -g $(ps -C dzen2 hopgrp) &>/dev/null \
                        ; exec /bin/zsh -c \"source /howl/conf/stumpwm/dzen4stumpwm.zsh &\""))
|#

;; EOF

CLICK TO VIEW

x

functions.lisp(raw, dl)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
;;-----------------------------------------
;; author: milomouse <vincent[at]fea.st> ;;
;; *data-dir*/../functions.lisp          ;;
;;-----------------------------------------

(defun fmt-group-status (group)
  (let ((screen (group-screen group)))
    (cond ((eq group (screen-current-group screen))
           #\*)
          ((and (typep (second (screen-groups screen)) 'group)
                (eq group (second (screen-groups screen))))
           #\+)
          (t #\-))))

(defun move-window-to-next-group (current list)
"Move current window to next group but keep focus on current frame."
  (let ((next (next-group current (non-hidden-groups list)))
        (win (group-current-window current)))
    (when (and next win) (move-window-to-group win next))))

(defun exchange-windows-remain (win1 win2)
"Exchange windows but keep focus on current frame, unlike exchange-windows."
  (let ((f1 (window-frame win1))
        (f2 (window-frame win2)))
    (unless (eq f1 f2)
      (pull-window win1 f2)
      (pull-window win2 f1))))

(defun shift-windows-forward (frames win)
"Exchange windows through cycling frames."
  (when frames
          (let ((frame (car frames)))
                  (shift-windows-forward (cdr frames)
                                         (frame-window frame))
                  (when win
                           (pull-window win frame)))))

(defun remember-group (&optional (group (current-group))) ()
"Remember current group information before calling another command or
function. Combined with 'undo' command this allows for toggling between
the two undo states."
  (if (ensure-directories-exist *undo-data-dir*)
    (when group
      (dump-group-to-file
        (make-pathname :name (format nil "screen_~{~A~}_group_~{~A~}"
        (list (char (getenv "DISPLAY") 1)) (list (group-name (current-group))))
        :type "lisp" :defaults *undo-data-dir*)))))

(defun remember-all () ()
"Similiar to remember-group except all information is dumped, useful
for next startup or recalling all undo actions."
  (dump-to-datadir "rules") (dump-to-datadir "desktop"))

(defun select-random-bg-image ()
"Select a random image from *background-image-path* and display it
on the root window. This is a rewrite of another function to check
for errors and allow more than one picture type, as display command
will only display valid files anyway."
  (if (ensure-directories-exist *background-image-path*)
    (let ((file-list (directory (make-pathname :defaults *background-image-path*
            :name :wild :type :wild :case :common)))
          (*random-state* (make-random-state t)))
      (namestring (nth (random (length file-list)) file-list)))))

(defun print-key-seq (seq) (format nil "^B^9*~{~a~^ ~}^n^1*" (mapcar 'print-key seq)))
(defun display-bindings-for-keymaps (key-seq &rest keymaps)
"Display key-bindings for a given keymap, using a simple and clean format."
  (let* ((screen (current-screen))
         (data (mapcan (lambda (map)
                         (mapcar (lambda (b) (format nil "^B^5*~5a^n ~a" (print-key (binding-key b)) (binding-command b))) (kmap-bindings map)))
                       keymaps))
         (cols (ceiling (1+ (length data))
                        (truncate (- (head-height (current-head)) (* 2 (screen-msg-border-width screen)))
                                  (font-height (screen-font screen))))))
    (message-no-timeout "Prefix: ~a~%~{~a~^~%~}"
                        (print-key-seq key-seq)
                        (columnize data cols))))

(defun focus-frame (group f)
"Focus frame but do not show-frame-indicator in certain cases."
  (let ((w (frame-window f))
        (last (tile-group-current-frame group))
        (show-indicator nil))
    (setf (tile-group-current-frame group) f)
    (unless (eq f last)
      (setf (tile-group-last-frame group) last)
      (run-hook-with-args *focus-frame-hook* f last)
      (setf show-indicator t))
    (if w (focus-window w) (no-focus group (frame-window last)))
    (if show-indicator (show-frame-outline group))))

(defun split-frame-in-dir (group dir &optional (ratio 1/2))
  (let ((f (tile-group-current-frame group)))
    (if (split-frame group dir ratio)
        (progn
          (when (frame-window f)
            (update-decoration (frame-window f)))
          (show-frame-indicator group))
        (message "Cannot split smaller than minimum size."))))

(defun run-shell-command-output (command)
"Run a shell command and display results (may hang if used wrong)."
  (check-type command string)
  (echo-string (current-screen) (run-shell-command command t)))

#|
(defun expand-file-name (path &optional default-directory)
;"Expand filenames with special focus on home dir."
  (let ((first-char (subseq path 0 1))
    (home-dir *home-dir*)
    (dir (if default-directory
      (if (string= (subseq (reverse default-directory) 0 1) "/")
        default-directory
        (concatenate 'string default-directory "/")))))
  (cond ((string= first-char "~") (concatenate 'string home-dir (subseq path 2)))
        ((string= first-char "/") path)
        (dir (if (strings= (subseq 0 1) "/")
          (concatenate 'string dir path)
          (expand-file-name (concatenate 'string dir path))))
        (t (concatenate 'string home-dir path)))))
|#

(defun eval-command (cmd &optional interactivep)
"Execute a lisp command and display the result, skipping mode-line updates."
  (labels ((parse-and-run-command (input)
             (let* ((arg-line (make-argument-line :string input :start 0))
                    (cmd (argument-pop arg-line)))
               (let ((*interactivep* interactivep))
      (call-interactively cmd arg-line)))))
    (multiple-value-bind (result error-p)
      ;; #(original quote=
      ;; this fancy footwork lets us grab the backtrace from where the error actually happened.)
      (restart-case (handler-bind
          ((error (lambda (c)
                    (invoke-restart 'eval-command-error
                          (format nil "^B^0*{{ ^9*~a ^0*}} ^n~A~a" 
                                cmd c (if *show-command-backtrace* 
                                          (backtrace-string) ""))))))
            (parse-and-run-command cmd))
        (eval-command-error (err-text)
          (values err-text t)))
      (cond ((stringp result)
             (if error-p  (message-no-timeout "~a" result)
                          (message "~a" result)))
            ((eq result :abort)
             (unless *suppress-abort-messages* (message "Abort.")))))))

(defun update-resize-map ()
"Update the (i)resize map, using cleaner key-bindings."
  (let ((m (setf *resize-map* (make-sparse-keymap))))
    (let ((i *resize-increment*))
    (labels ((dk (m k c) (define-key m k (format nil c i))))
      (dk m (kbd "k") "resize 0 -~D")
      (dk m (kbd "(") "resize 0 -~D")
      (dk m (kbd "j") "resize 0 ~D")
      (dk m (kbd ")") "resize 0 ~D")
      (dk m (kbd "h") "resize -~D 0")
      (dk m (kbd "9") "resize -~D 0")
      (dk m (kbd "l") "resize ~D 0")
      (dk m (kbd "0") "resize ~D 0")
      (dk m (kbd "RET") "exit-iresize")
      (dk m (kbd "ESC") "abort-iresize")
    M)))) (update-resize-map)

;; incomplete, was just testing ALSA out..
;; (may try to redo this since I am now using ALSA/PulseAudio)
;(defcommand amixer-control (channel arg)
;  (let ((variance (run-shell-command (concatenate 'string
;      "print ${$(amixer sget " channel ")[-2,-1]//(\[|\]|.*dB|-)}"))))
;    (cond ((and (eq channel "PCM") (not (eq arg "toggle")))
;          (message (first (concatenate 'string variance))))
;          (t (message (second (concatenate 'string variance))))
;          )))

#|
;; for use with dzen2 (a bit awkward..)
(defun update-fullscreen (window action)
  (let ((fullscreen-p (window-fullscreen window)))
    (case action
      (0                                ; _NET_WM_STATE_REMOVE
       (when fullscreen-p
         (progn (deactivate-fullscreen window)
         (resize-head 0 0 22 1600 878))))
      (1                                ; _NET_WM_STATE_ADD
       (unless fullscreen-p
         (progn (activate-fullscreen window)
         (resize-head 0 0 0 1600 900))))
      (2                                ; _NET_WM_STATE_TOGGLE
       (if fullscreen-p
           (progn (deactivate-fullscreen window)
           (resize-head 0 0 22 1600 878))
           (progn (activate-fullscreen window)
           (resize-head 0 0 0 1600 900)))))))
|#

;; EOF
 

x

macros.lisp(raw, dl)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
;;-----------------------------------------
;; author: milomouse <vincent[at]fea.st> ;;
;; *data-dir*/../macros.lisp             ;;
;;-----------------------------------------

;; create given groups while keeping focus on current.
(defmacro make-groups-bg (&rest names)
  (let ((ns (mapcar #'(lambda (n) (concatenate 'string "gnewbg " n)) names)))
  `(run-commands ,@ns)))

;; faster hook management.
(defmacro replace-hook (hook fn)
  `(remove-hook, hook, fn)
  `(add-hook, hook, fn))

;; Last rule to match takes precedence!
;; TIP: if the argument to :title or :role begins with an ellipsis, a substring
;; match is performed.
;; TIP: if the :create flag is set then a missing group will be created and
;; restored from *data-dir*/create file.
;; TIP: if the :restore flag is set then group dump is restored even for an
;; existing group using *data-dir*/restore file.

;; (define-frame-preference "WORKSPACE#"
;;   (frame(number) | raise(boolean) | lock(boolean) [lock AND raise == jumpto]))

;; internet related workspace:
(define-frame-preference "3"
  (0    nil   t     :instance "luakit")
  (0    nil   t     :instance "Navigator"))

;; largely undefined, temporal workspace:
(define-frame-preference "6"
  (0    t     t     :class "Ossxmix")
  (0    t     t     :class "Gliv"))

;; EOF
 

x

commands.lisp(raw, dl)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
;;-----------------------------------------
;; author: milomouse <vincent[at]fea.st> ;;
;; *data-dir*/../commands.lisp           ;;
;;-----------------------------------------

;; before we go further, rewrite colon command to old behavior.
;; (this should already be fixed in newest version)
(defcommand colon (&optional initial-input) (:rest)
  (let ((cmd (completing-read (current-screen) ": "
          (all-commands) :initial-input (or initial-input ""))))
    (unless cmd
      (throw 'error :abort))
    (when (plusp (length cmd))
      (eval-command cmd t))))

;; redefine run-shell-command for 'zsh', change :shell "", and fix a typo.
(defcommand run-shell-command (cmd &optional collect-output-p)
  ((:shell "execute: "))
  "Run the specified shell command. If @var{collect-output-p} is @code{T}
then run the command synchronously and collect the output."
  (if collect-output-p
    (run-prog-collect-output *shell-program* "-c" cmd)
    (run-prog *shell-program* :args (list "-c" cmd) :wait nil)))
(setf *shell-program* "/bin/zsh")
;(setf *shell-program* (stumpwm::getenv "SHELL"))
(defcommand-alias exec run-shell-command)

;; create a scratchpad group if none exist and toggle between viewing current group and scratchpad group.
;; (idea from Ion3+ window-manager except scratchpad is a group and not a floating frame)
;; (also inspired by another users 'scratchpad' command set, although i found all the functions
;;  and parameters to be wasteful, especially since this creates it per screen anyway)
(defcommand scratchpad () ()
"Create a scratchpad group for current screen, if not found, and toggle between the scatchpad group
and the current group upon reissue of the same command."
  (let* ((sg (find-group (current-screen) *scratchpad-group-name*)) (cg (current-group)))
    (if sg
        (cond ((eq cg sg) (gother)) (t (switch-to-group sg) (message "scratchpad")))
      (progn (gnew *scratchpad-group-name*) (message "scratchpad")))))

;; undo to last state in current-group (set by calling 'remember-group' in various commands/functions),
;; unless no state found. (once i learn more about lisp i'll try removing the use of a second temp file)
(defcommand undo (&optional (group (current-group))) ()
"If an undo state exists for group, revert to last state. Multiple calls toggle between the two states."
  (when group
    (let* ((i (make-pathname :name (format nil "screen_~{~A~}_group_~{~A~}"
              (list (char (getenv "DISPLAY") 1)) (list (group-name (current-group))))
              :type "lisp" :defaults *undo-data-dir*)))
      (if (probe-file i)
        (progn
          (let* ((o (make-pathname :name (format nil "screen_~{~A~}_group_~{~A~}"
                    (list (char (getenv "DISPLAY") 1)) (list (group-name (current-group))))
                    :type "bak" :defaults *undo-data-dir*)))
            (dump-group-to-file o)
          (restore-from-file i)
          (rename-file o i)
          (let ((f (tile-group-current-frame group)))
            (progn
              (when (frame-window f)
                (update-decoration (frame-window f)))
              (show-frame-indicator group)))))
        (message "Cannot undo previous state. Nothing found for group ~A" (list (group-name group)))))))

;; dump [current-]group (for current-screen), [current-]screen, desktop or window-placement-rules
;; to a dynamically named file in user defined *data-dir*.
(defcommand dump-to-datadir (expr) (:rest)
"Dump group (from current-screen), screen (current-screen), desktop or rules to file in data-dir.
Just specify what you want to dump and this will dynamically create and name file accordingly."
  (cond ((string-equal expr 'group)
          (let* ((o (make-pathname :name (format nil "screen_~{~A~}_group_~{~A~}"
                    (list (char (getenv "DISPLAY") 1)) (list (group-name (current-group))))
                    :type "lisp" :defaults *data-dir*)))
            (dump-group-to-file o) (message "~A dumped" expr)))
        ((string-equal expr 'screen)
          (let* ((o (make-pathname :name (format nil "screen_~{~A~}" (list (char (getenv "DISPLAY") 1)))
                    :type "lisp" :defaults *data-dir*)))
            (dump-screen-to-file o) (message "~A dumped" expr)))
        ((string-equal expr 'rules)
          (let* ((o (make-pathname :name "tile-rules" :type "lisp" :defaults *data-dir*)))
            (dump-window-placement-rules o) (message "~A dumped" expr)))
        ((string-equal expr 'desktop)
          (let* ((o (make-pathname :name "desktop" :type "lisp" :defaults *data-dir*)))
            (dump-desktop-to-file o) (message "~A dumped" expr)))
        (t (message "don't know how to dump ~a" expr))))

;; restore [current]-group (for current-screen), [current]-screen, desktop or window-placement-rules
;; from a previously created file (more correctly from DUMP-TO-DATADIR) in user defined *data-dir*.
(defcommand restore-from-datadir (expr) (:rest)
"Restore file from data-dir, previously created by 'dump-to-datadir', according to what you specify.
You may restore group (for current-screen), screen (for current-screen), desktop or rules. This will
restore file dynamically by pattern patching, according to what you're restoring, to file name by
looking at what you're currently using.

E.g. if you're in group 2 on screen 0 and you enter 'restore-from-datadir group' it will look for a
file named 'screen_0_group_2.lisp' (created by accompanying 'dump-to-datadir') in your data-dir and
restore it. If no matching file is found it will skip loading of any files and print an error message.

Note: if restoring a group file was successful then an undo state is created so you can technically
undo the loading of that file. There are no undo states when loading 'screen', 'desktop' or 'rules'."
  (cond ((string-equal expr 'group)
          (let* ((i (make-pathname :name (format nil "screen_~{~A~}_group_~{~A~}"
                    (list (char (getenv "DISPLAY") 1)) (list (group-name (current-group))))
                    :type "lisp" :defaults *data-dir*)))
            (if (probe-file i)
                (progn (restore-from-file i) (remember-group) (message "~A restored" expr))
              (message "unable to find valid ~A file in data dir" expr))))
        ((string-equal expr 'screen)
          (let* ((i (make-pathname :name (format nil "screen_~{~A~}" (list (char (getenv "DISPLAY") 1)))
                    :type "lisp" :defaults *data-dir*)))
            (if (probe-file i)
                (progn (restore-from-file i) (message "~A restored" expr))
              (message "unable to find valid ~A file in data dir" expr))))
        ((string-equal expr 'rules)
          (if (probe-file (data-dir-file "tile-rules.lisp"))
              (progn (restore-window-placement-rules (data-dir-file "tile-rules.lisp"))
                     (message "~A restored" expr))
            (message "unable to find valid ~A file in data dir" expr)))
        ((string-equal expr 'desktop)
          (if (probe-file (data-dir-file "desktop.lisp"))
              (progn (restore-from-file (data-dir-file "tile-rules.lisp")) (message "~A restored" expr))
            (message "unable to find valid ~A file in data dir" expr)))
        (t (message "dont know how to restore ~a" expr))))

;; swap neighbors but do not change focus to specified neighbor direction.
(defcommand (exchange-direction-remain tile-group) (dir &optional (win (current-window)))
    ((:direction "Direction: "))
    "If neighbor window exists, swap current window with neighbor in specified direction while
keeping focus on current frame, unlike 'exchange-direction' where focus moves to neighbor."
  (if win
      (let* ((frame-set (group-frames (window-group win)))
             (neighbour (neighbour dir (window-frame win) frame-set)))
        (if (and neighbour (frame-window neighbour))
            (exchange-windows-remain win (frame-window neighbour))
            (message "No window in direction ~A!" dir)))
      (message "No window in current frame!")))

;; move focused window to next/prev group without following it. focus remains on current frame.
(defcommand gmove-next () ()
"Move focused window to next group without switching to it. Unlike behavior in gnext-with-window."
  (move-window-to-next-group (current-group) (sort-groups (current-screen))))
(defcommand gmove-prev () ()
"Move focused window to previous group without switching to it. Unlike behavior in gprev-with-window."
  (move-window-to-next-group (current-group) (reverse (sort-groups (current-screen)))))

;; from simias: rotate windows.
(defcommand rotate-windows () ()
  (let* ((frames (group-frames (current-group)))
            (win (frame-window (car (last frames)))))
          (shift-windows-forward frames win)))

;; rework of original random-bg command, display random wallpaper on root window.
(defcommand display-random-bg () () "Display a random background image on root window."
  (run-shell-command
    (concatenate 'string "display -window root -resize 1600x900! " (select-random-bg-image))))

;; designate master window/frame (should probably use current frame number, but less dynamic?)
(defcommand (master-make tile-group) () () "Designate current window as Master."
  (renumber 0) (repack-window-numbers) (remember-group))
(defcommand (master-focus tile-group) () () "Focus on designated Master window." (select-window-by-number 0))

;; swap current window with master (should be 0 (from master-make)) and desginate it as the new master.
(defcommand (master-swap tile-group) (num &optional (group (current-group))) ((:window-number t))
  "If current window is not Master and Master exists, swap current
window with Master and designate this as the new Master."
  (labels ((match (win)
              (= (window-number win) num)))
  (let ((win (find-if #'match (group-windows group))))
    (when (and win group) (exchange-windows (current-window) win) (master-make)))))

;; [with *shell-program* "/bin/zsh"] look for detached 'tmux [socket] xorg' session and attach, else create new.
;; (also useful for StumpWM crashes, as tmux windows survive crashes and this command brings them back)
(defcommand tmux-attach-else-new () () "Find detached tmux session and attach, else create new session."
  (run-shell-command
  "if [[ -n ${$(tmux -S /tmp/user-keep/${USER}/tmux/xorg list-session|grep -v attached)[1]//:} ]]; then
    urxvt -e tmux -S /tmp/user-keep/${USER}/tmux/xorg attach-session -t ${$(tmux -S /tmp/user-keep/${USER}/tmux/xorg list-session|grep -v attached)[1]//:}
  else
    urxvt -e tmux -S /tmp/user-keep/${USER}/tmux/xorg new-session
  fi"))

;; [with *shell-program* "/bin/zsh"] look for detached 'tmux [socket] rtorrent' session and attach, else nothing.
(defcommand tmux-attach-rtorrent () () "Find detached rtorrent session and attach, else not running so do nothing."
  (run-shell-command
  "if [[ -n ${$(tmux -S /tmp/user-keep/${USER}/tmux/rtorrent list-session|grep -v attached)[1]//:} ]]; then
    urxvt -e tmux -S /tmp/user-keep/${USER}/tmux/rtorrent attach-session -t ${$(tmux -S /tmp/user-keep/${USER}/tmux/rtorrent list-session|grep -v attached)[1]//:}
  fi"))

;; reassign original commands to *-forget
(defcommand quit-forget () () "Quit StumpWM without remembering current state."
  (with-open-file (stream *debug-file* :direction :io :if-exists :supersede))
  (cond ((find-group (current-screen) *scratchpad-group-name*)
    (if (eq (current-group) (find-group (current-screen) *scratchpad-group-name*))
        (gkill)
      (progn
        (gnext) (kill-group
        (find-group (current-screen) *scratchpad-group-name*)
        (current-group))))))
  (throw :top-level :quit))

(defcommand restart-soft-forget () () "Soft Restart StumpWM without remembering current state.
The lisp process isn't restarted. Instead, control jumps
to the very beginning of the stumpwm program. This
differs from RESTART, which restarts the unix process.

Since the process isn't restarted, existing customizations remain
after the restart." (throw :top-level :restart))

(defcommand loadrc-forget () () "Reload the @file{~/.stumpwmrc} file without remembering current state."
  (handler-case
      (progn
        (with-restarts-menu (load-rc-file nil)))
      (error (c)
        (message "^B^1*Error loading rc file:^n ~A" c))
      (:no-error (&rest args)
        (declare (ignore args))
        (message "rc file loaded successfully."))))

(defcommand loadrc () () "Reload the @file{~/.stumpwmrc} file while remembering current state."
  (remember-all) (loadrc-forget))

(defcommand restart-soft () () 
"Soft Restart StumpWM while remembering current state.
The lisp process isn't restarted. Instead, control jumps
to the very beginning of the stumpwm program. This
differs from RESTART, which restarts the unix process.

Since the process isn't restarted, existing customizations remain
after the restart." (remember-all) (restart-soft-forget))
(defcommand-alias restart restart-soft)

(defcommand quit () ()
"Quit StumpWM while remembering current state."
  (cond ((find-group (current-screen) *scratchpad-group-name*)
    (if (eq (current-group) (find-group (current-screen) *scratchpad-group-name*))
        (gkill)
      (progn
        (gnext) (kill-group
        (find-group (current-screen) *scratchpad-group-name*)
        (current-group))))))
  (remember-all) (quit-forget))

;; redefine resize commands
(defcommand (resize tile-group) (width height) ((:number "+ Width: ")
                                                (:number "+ Height: "))
  "Resize the current frame by @var{width} and @var{height} pixels."
  (let* ((group (current-group))
         (f (tile-group-current-frame group)))
    (if (atom (tile-group-frame-tree group))
        (message "No more frames!")
        (progn
          (clear-frame-outlines group)
          (resize-frame group f width :width)
          (resize-frame group f height :height)
          (draw-frame-outlines group (current-head))
          (curframe))))) (defcommand (iresize tile-group) () ()
  "Remember current state before starting the interactive resize mode. A new keymap
specific to resizing the current frame is loaded. Hit @key{C-g}, @key{RET},
or @key{ESC} to exit." (let ((frame (tile-group-current-frame (current-group))))
    (if (atom (tile-group-frame-head (current-group) (frame-head (current-group) frame)))
        (message "There's only 1 frame!")
        (progn
          (remember-group)
          (when *resize-hides-windows*
            (dolist (f (head-frames (current-group) (current-head)))
              (clear-frame f (current-group))))
          (push-top-map *resize-map*)
          (draw-frame-outlines (current-group) (current-head)))
        ))) (defcommand (exit-iresize tile-group) () ()
  "Exit from the interactive resize mode, quietly." (resize-unhide) (pop-top-map) (redisplay))
(defcommand (quiet-resize tile-group) (width height) ((:number "+ Width: ")
                                                      (:number "+ Height: "))
  "Resize the current frame by @var{width} and @var{height} pixels without highlighting frames."
  (let* ((group (current-group))
         (f (tile-group-current-frame group)))
    (if (atom (tile-group-frame-tree group))
        (message "No more frames!")
        (progn
          (resize-frame group f width :width)
          (resize-frame group f height :height)))))
(defcommand (abort-iresize tile-group) () () "Undo resize changes if aborted."
  (resize-unhide) (undo) (message "Abort resize") (pop-top-map))

;; remove frame and reallocate space while remembering removed frame position, also hiding frame-indicator.
(defcommand (remove-split tile-group)
(&optional (group (current-group)) (frame (tile-group-current-frame group))) ()
"Remove the specified frame in the specified group (defaults to current group, current
frame). Windows in the frame are migrated to the frame taking up its space but not before
remembering their previous positions, also hiding frame highlights."
  (let* ((head (frame-head group frame))
         (current (tile-group-current-frame group))
         (tree (tile-group-frame-head group head))
         (s (closest-sibling (list tree) frame))
         (l (tree-accum-fn s
                           (lambda (&rest siblings)
                             (car siblings))
                           #'identity)))
    ;; <only remove the current frame if it has a sibling>
    (if (atom tree)
        (message "No more frames!")
        (when s
          (remember-group)
          (when (frame-is-head group frame)
            (setf (frame-number l) (frame-number frame)))
          ;; <move the windows from the removed frame to its sibling>
          (migrate-frame-windows group frame l)
          ;; <if the frame has no window, give it the current window of the current frame.>
          (unless (frame-window l)
            (setf (frame-window l)
                  (frame-window frame)))
          ;; <unsplit>
          (setf (tile-group-frame-head group head) (remove-frame tree frame))
          ;; <update the current frame and sync all windows>
          (when (eq frame current)
            (setf (tile-group-current-frame group) l))
          (tree-iterate tree
                        (lambda (leaf)
                          (sync-frame-windows group leaf)))
          (frame-raise-window group l (frame-window l) nil)
          (when (frame-window l)
            (update-decoration (frame-window l)))))))


;; remember states if not already in 'only' mode (e.g., one frame).
(defcommand only () () "Delete all the frames but the current one and grow it
to take up the entire head and remember previous states if entire head
is not already taken up (e.g. already in 'only' mode)."
  (let* ((screen (current-screen))
         (group (screen-current-group screen))
         (win (group-current-window group))
         (head (current-head group))
         (frame (copy-frame head)))
    (if (atom (tile-group-frame-head group head))
      (message "Will not remember state, already using one frame.")
      (progn
        (remember-group)
        (mapc (lambda (w)
                (unless (eq (window-frame w) (tile-group-current-frame group))
                  (hide-window w))
                (setf (window-frame w) frame))
              (head-windows group head))
        (setf (frame-window frame) win
              (tile-group-frame-head group head) frame
              (tile-group-current-frame group) frame)
        (focus-frame group frame)
        (if (frame-window frame)
            (update-decoration (frame-window frame))
            (show-frame-indicator group))
        (sync-frame-windows group (tile-group-current-frame group))))))

;; remember frame positions before splitting (do not edit split-frames function for this)
(defcommand (hsplit tile-group) () () "Remember current state before splitting the
current frame into 2 side-by-side frames." (remember-group) (split-frame-in-dir (current-group) :column))
(defcommand (vsplit tile-group) () ()  "Remember current state before splitting the
current frame into 2 frames, one on top of the other." (remember-group) (split-frame-in-dir (current-group) :row))

;; dump to file, which is silent, but with more informative prompts.
(defcommand dump-group-to-file (file) ((:rest "group to file: "))
  "Dumps the frames of the current group of the current screen to the named file."
  (dump-to-file (dump-group (current-group)) file))
(defcommand dump-screen-to-file (file) ((:rest "screen to file: "))
  "Dumps the frames of all groups of the current screen to the named file."
  (dump-to-file (dump-screen (current-screen)) file))
(defcommand dump-desktop-to-file (file) ((:rest "desktop to file: "))
  "Dumps the frames of all groups of all screens to the named file."
  (dump-to-file (dump-desktop) file))

;; predefined echoes for speed, else use 'shell-command-output'.
(defcommand echo-highcpu-user () () "" (message-no-timeout (run-shell-command "ps -U root,privoxy,15,daemon,nobody,unbound --deselect -C tmux,urxvt k -%cpu opid,nice,args:70,etime:10,%cpu,pmem | head -75" t)))
(defcommand echo-highcpu-root () () "" (message-no-timeout (run-shell-command "ps -U h,privoxy,15,daemon,nobody,unbound --deselect -C tmux,urxvt k -%cpu opid,nice,args:70,etime:10,%cpu,pmem | head -75" t)))
(defcommand echo-highcpu-rest () () "" (message-no-timeout (run-shell-command "ps -U root,h --deselect -C tmux,urxvt k -%cpu opid,nice,args:70,etime:10,%cpu,pmem | head -75" t)))
(defcommand echo-mifo-stumpwm () () "" (echo-string (current-screen) (run-shell-command "mifo --announce '(%c/%C)  %D / %b'" t)))
(defcommand echo-mifo-raw () () "" (echo-string (current-screen) (run-shell-command "mifo --announce" t)))
(defcommand echo-mifo-current-list () () "" (echo-string (current-screen) (run-shell-command "mifo --shown |grep -m 1 -A 7 -B 7 $(mifo -a)|sed 's|'$(mifo -a)'|^B^4*&^n|'" t)))
(defcommand echo-mifo-show () () "" (echo-string (current-screen) (run-shell-command "mifo --show" t)))
(defcommand echo-mifo-shown () () "" (echo-string (current-screen) (run-shell-command "mifo --shown" t)))
(defcommand echo-mifo-playlists () () "" (echo-string (current-screen) (run-shell-command "mifo --printp" t)))
(defcommand echo-mifo-add () () "" (echo-string (current-screen) (run-shell-command "mifo --add" t)))
(defcommand echo-mifo-remove () () "" (echo-string (current-screen) (run-shell-command "mifo --remove" t)))
(defcommand echo-mifo-next () () "" (echo-string (current-screen) (run-shell-command "mifo --next ; sleep 1s ; mifo --stumpwm" t)))
(defcommand echo-mifo-prev () () "" (echo-string (current-screen) (run-shell-command "mifo --prev ; sleep 1s ; mifo --stumpwm" t)))
(defcommand echo-mifo-random () () "" (echo-string (current-screen) (run-shell-command "mifo -r ; sleep 1s ; mifo --stumpwm" t)))
(defcommand echo-volume () () "" (echo-string (current-screen) (run-shell-command "pulsevol -a" t)))
(defcommand echo-mail () () "" (echo-string (current-screen) (run-shell-command "print - '^5:'@fea.st: '^B'${#$(find /howl/mail/FastMail/*/new -type f)}" t)))
(defcommand echo-wlan () () "" (echo-string (current-screen) (run-shell-command "ifconfig;iwconfig" t)))
(defcommand echo-free-hdd () () "" (echo-string (current-screen) (run-shell-command "df -hTP -x debugfs" t)))
(defcommand echo-free-mem () () "" (echo-string (current-screen) (run-shell-command "print '^B^3/free^1* used^5* base^n';free -m|awk 'NR==2 {print $4,$3,$2}'" t)))
(defcommand echo-battery () () "" (echo-string (current-screen) (run-shell-command "acpi -tf;repeat 36; do printf '='; done;print;ibam --percentbattery" t)))
(defcommand echo-loadavg () () "" (echo-string (current-screen) (run-shell-command "print ${$(</proc/loadavg)[1,3]}" t)))
(defcommand echo-colors-brief () () "Output a brief list of currently defined colors." (echo-string (current-screen) (eval "
BOLD ^B^0*black ^1*red ^2*green ^3*yellow ^4*blue ^5*magenta ^6*cyan ^7*white ^8*user ^9*user^n
NONE ^0*black ^1*red ^2*green ^3*yellow ^4*blue ^5*magenta ^6*cyan ^7*white ^8*user ^9*user^n")))
(defcommand echo-colors-full () () "Output a full list of currently defined colors." (echo-string (current-screen) (eval "
BOLD ^B^0*black ^1*red ^2*green ^3*yellow ^4*blue ^5*magenta ^6*cyan ^7*white ^8*user ^9*user^n
NONE ^0*black ^1*red ^2*green ^3*yellow ^4*blue ^5*magenta ^6*cyan ^7*white ^8*user ^9*user^n
B->0 ^B^00black^n ^B^10red^n ^B^20green^n ^B^30yellow^n ^B^40blue^n ^B^50magenta^n ^B^60cyan^n ^B^70white^n ^B^80user^n ^B^90user^n
N->0 ^00black^n ^10red^n ^20green^n ^30yellow^n ^40blue^n ^50magenta^n ^60cyan^n ^70white^n ^80user^n ^90user^n
B->1 ^B^01black^n ^B^11red^n ^B^21green^n ^B^31yellow^n ^B^41blue^n ^B^51magenta^n ^B^61cyan^n ^B^71white^n ^B^81user^n ^B^91user^n
N->1 ^01black^n ^11red^n ^21green^n ^31yellow^n ^41blue^n ^51magenta^n ^61cyan^n ^71white^n ^81user^n ^91user^n
B->2 ^B^02black^n ^B^12red^n ^B^22green^n ^B^32yellow^n ^B^42blue^n ^B^52magenta^n ^B^62cyan^n ^B^72white^n ^B^82user^n ^B^92user^n
N->2 ^02black^n ^12red^n ^22green^n ^32yellow^n ^42blue^n ^52magenta^n ^62cyan^n ^72white^n ^82user^n ^92user^n
B->3 ^B^03black^n ^B^13red^n ^B^23green^n ^B^33yellow^n ^B^43blue^n ^B^53magenta^n ^B^63cyan^n ^B^73white^n ^B^83user^n ^B^93user^n
N->3 ^03black^n ^13red^n ^23green^n ^33yellow^n ^43blue^n ^53magenta^n ^63cyan^n ^73white^n ^83user^n ^93user^n
B->4 ^B^04black^n ^B^14red^n ^B^24green^n ^B^34yellow^n ^B^44blue^n ^B^54magenta^n ^B^64cyan^n ^B^74white^n ^B^84user^n ^B^94user^n
N->4 ^04black^n ^14red^n ^24green^n ^34yellow^n ^44blue^n ^54magenta^n ^64cyan^n ^74white^n ^84user^n ^94user^n
B->5 ^B^05black^n ^B^15red^n ^B^25green^n ^B^35yellow^n ^B^45blue^n ^B^55magenta^n ^B^65cyan^n ^B^75white^n ^B^85user^n ^B^95user^n
N->5 ^05black^n ^15red^n ^25green^n ^35yellow^n ^45blue^n ^55magenta^n ^65cyan^n ^75white^n ^85user^n ^95user^n
B->6 ^B^06black^n ^B^16red^n ^B^26green^n ^B^36yellow^n ^B^46blue^n ^B^56magenta^n ^B^66cyan^n ^B^76white^n ^B^86user^n ^B^96user^n
N->6 ^06black^n ^16red^n ^26green^n ^36yellow^n ^46blue^n ^56magenta^n ^66cyan^n ^76white^n ^86user^n ^96user^n
B->7 ^B^07black^n ^B^17red^n ^B^27green^n ^B^37yellow^n ^B^47blue^n ^B^57magenta^n ^B^67cyan^n ^B^77white^n ^B^87user^n ^B^97user^n
N->7 ^07black^n ^17red^n ^27green^n ^37yellow^n ^47blue^n ^57magenta^n ^67cyan^n ^77white^n ^87user^n ^97user^n
B->8 ^B^08black^n ^B^18red^n ^B^28green^n ^B^38yellow^n ^B^48blue^n ^B^58magenta^n ^B^68cyan^n ^B^78white^n ^B^88user^n ^B^98user^n
N->8 ^08black^n ^18red^n ^28green^n ^38yellow^n ^48blue^n ^58magenta^n ^68cyan^n ^78white^n ^88user^n ^98user^n
B->9 ^B^09black^n ^B^19red^n ^B^29green^n ^B^39yellow^n ^B^49blue^n ^B^59magenta^n ^B^69cyan^n ^B^79white^n ^B^89user^n ^B^99user^n
N->9 ^09black^n ^19red^n ^29green^n ^39yellow^n ^49blue^n ^59magenta^n ^69cyan^n ^79white^n ^89user^n ^99user^n")))

;; sent output of command to echo-string (may hang if used wrong).
(defcommand shell-command-output (command) ((:string "execute/output: "))
  "Take output of command and display it. This may hang if used wrong."
  (check-type command string) (run-shell-command-output command))
(defcommand pout (&optional (initial "")) (:rest)
  "Prompt with the given argument as command, await any additional arguments
and then run as shell command, displaying a message with any of the
command's output. This may hang if used wrong."
  (let ((cmd (read-one-line (current-screen) ": " :initial-input initial)))
    (when cmd (shell-command-output cmd))))

;; manpage reader. needs filename completion, etc.. very simple right now
(defcommand manpage (command) ((:rest "manpage: ")) ""
  (run-shell-command (format nil "urxvt -e man ~a" command)))

;; prompt for X selection to transfer, or prompt for X selection to echo
(defcommand prompt-xclip (filename) ((:rest "xclip -selection ")) ""
  (run-shell-command (format nil "xclip -selection ~a" filename)))
;; prompt for X selection to display contents of.
(defcommand echo-xclip (filename) ((:rest "echo.selection: ")) ""
  (echo-string (current-screen) (run-shell-command (format nil "xclip -selection ~a -o" filename) t)))

;; i don't like 'Colon' showing editable command in prompt
;; perhaps i'll figure out a global macro/function for this..
(defcommand prompt-mifo-command (filename) ((:rest "mifo.command: ")) ""
  (run-shell-command (format nil "mifo --command ~a" filename)))
(defcommand prompt-mifo-next (filename) ((:rest "mifo.next: ")) ""
  (echo-string (current-screen) (run-shell-command (format nil "mifo --next ~a && sleep 2" filename) t))
  (echo-mifo-stumpwm))
(defcommand prompt-mifo-prev (filename) ((:rest "mifo.previous: ")) ""
  (echo-string (current-screen) (run-shell-command (format nil "mifo --prev ~a && sleep 2" filename) t))
  (echo-mifo-stumpwm))
(defcommand prompt-mifo-save (filename) ((:rest "mifo.save-as: ")) ""
  (echo-string (current-screen) (run-shell-command (format nil "mifo --save ~a" filename) t)))
(defcommand prompt-mifo-find (match) ((:rest "mifo.find: ")) ""
  (echo-string (current-screen) (run-shell-command (format nil "mifo --find ~a" match) t)))
(defcommand prompt-mifo-findn (match) ((:rest "mifo.findn: ")) ""
  (echo-string (current-screen) (run-shell-command (format nil "mifo --findn ~a" match) t)))
(defcommand prompt-mifo-load (filename) ((:rest "mifo.load: "))
  (run-shell-command (format nil "mifo --load ~a" filename))) ""
(defcommand prompt-mifo-append (filename) ((:rest "mifo.append: "))
  (run-shell-command (format nil "mifo --append ~a" filename))) ""
(defcommand prompt-mifo-playlist (filename) ((:rest "mifo.playlist: "))
  (run-shell-command (format nil "mifo --playlist ~a" filename))) ""
(defcommand prompt-mifo-begin (filename) ((:rest "mifo.begin: ")) ""
  (run-shell-command (format nil "mifo --begin ~a" filename)))
(defcommand prompt-mifo-seek (filename) ((:rest "mifo.seek: ")) ""
  (run-shell-command (format nil "mifo --seek ~a" filename)))

;; evaluate string, with prettier color.
(defcommand eval-line (cmd) ((:rest "eval: "))
  "Evaluate the s-expression and display the result(s)."
  (handler-case
    (message "^B^10~{~a~^~%~}"
      (mapcar 'prin1-to-string
        (multiple-value-list (eval (read-from-string cmd)))))
    (error (c)
      (err "^B^5*~A" c))))

;; run or raise.
(defcommand ror_luakit () () "" (setf *run-or-raise-all-groups* t) (run-or-raise "luakit" '(:class "luakit")))
(defcommand ror_mutt () () "" (setf *run-or-raise-all-groups* t)
  (run-or-raise "urxvt -title '[urxvt] mutt' -e mutt -F ${XDG_CONFIG_DIR:-${HOME}}/mutt/muttrc" '(:title "\\[urxvt\\] mutt")))

;; EOF
 

x

hooks.lisp(raw, dl)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
;;-----------------------------------------
;; author: milomouse <vincent[at]fea.st> ;;
;; *data-dir*/../hooks.lisp              ;;
;;-----------------------------------------

#|
;; show local windows in frame when focusing on it.
;; unfortunately the echo command is cropped when
;; focused frame overlaps part of it's output.
(defun local-list (from-frame to-frame)
  (run-commands "echo-frame-windows"))
add-hook *focus-frame-hook* 'local-list)
|#

#|
;; display the keysequence in progress (found this).
(defun key-press-hook (key key-seq cmd)
  (declare (ignore key))
  (unless (eq *top-map* *resize-map*)
    (let ((*message-window-gravity* :top-right))
      (message "Key sequence: ~A" (print-key-seq (reverse key-seq))))
    (when (stringp cmd)
      (sleep 0.1))))
(replace-hook *key-press-hook* 'key-press-hook)
|#

;; EOF
 

x

key-maps.lisp(raw, dl)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
;;-----------------------------------------
;; author: milomouse <vincent[at]fea.st> ;;
;; *data-dir*/../key-maps.lisp           ;;
;;-----------------------------------------

;; export custom maps.
(export '(*echo-map* *xsel-map* *xclip-clipboard-map* *xclip-primary-map* *frequent-map*
          *win-frame-map* *mplayer-map1* *mplayer-map2* *dump-map1* *dump-map2*))

;; set a few undefined keysyms, unavailable in */stumpwm/keysyms.lisp
(define-keysym #x1008ff02 "XF86MonBrightnessUp")
(define-keysym #x1008ff03 "XF86MonBrightnessDown")
(define-keysym #x1008ff2f "XF86Sleep")

;; set "Super+Shift+\" as prefix for root-map bindings (i will not be using this)
(set-prefix-key (kbd "s-|"))

;; some useful window/frame commands.
(defvar *win-frame-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "r")   "remember")
    (dk m (kbd "f")   "forget")
    (dk m (kbd "p")   "place-existing-windows")
    (dk m (kbd "n")   "repack-window-numbers")
    (dk m (kbd "ESC") "abort")
   M)))

;; transfer contents of clipboard into other buffers, or manually type cmd.
(defvar *xclip-clipboard-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "b") "exec xclip -selection clipboard -o | xclip -selection buffer-cut -i")
    (dk m (kbd "p") "exec xclip -selection clipboard -o | xclip -selection primary -i")
    (dk m (kbd "s") "exec xclip -selection clipboard -o | xclip -selection secondary -i")
    (dk m (kbd ";") "prompt-xclip")
    (dk m (kbd ":") "echo-xclip")
    (dk m (kbd "ESC") "abort")
   M)))

(defvar *xclip-primary-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "b") "exec xclip -selection primary -o | xclip -selection buffer-cut -i")
    (dk m (kbd "c") "exec xclip -selection primary -o | xclip -selection clipboard -i")
    (dk m (kbd "s") "exec xclip -selection primary -o | xclip -selection secondary -i")
    (dk m (kbd ";") "prompt-xclip")
    (dk m (kbd ":") "echo-xclip")
    (dk m (kbd "ESC") "abort")
   M)))

;; interact with the xselection and meta commands.
(defvar *xsel-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "c")   "copy-last-message")
    (dk m (kbd "g")   "getsel")
    (dk m (kbd "m")   "meta")
    (dk m (kbd "p")   "putsel")
    (dk m (kbd "s")   "window-send-string")
    (dk m (kbd "ESC") "abort")
  M)))

;; frequently used echoes for quick information grabbing.
(defvar *echo-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "b")   "echo-battery")
    (dk m (kbd "c")   "echo-colors-brief")
    (dk m (kbd "C")   "echo-colors-full")
    (dk m (kbd "d")   "echo-date")
    (dk m (kbd "f")   "echo-free-mem")
    (dk m (kbd "h")   "echo-free-hdd")
    (dk m (kbd "l")   "echo-loadavg")
    (dk m (kbd "m")   "echo-mifo-stumpwm")
    (dk m (kbd "M")   "echo-mifo-raw")
    (dk m (kbd "C-m") "echo-mifo-current-list")
    (dk m (kbd "n")   "echo-wlan")
    (dk m (kbd "p")   "echo-highcpu-user")
    (dk m (kbd "P")   "echo-highcpu-root")
    (dk m (kbd "C-p") "echo-highcpu-rest")
    (dk m (kbd "u")   "echo-mail")
    (dk m (kbd "v")   "echo-volume")
    (dk m (kbd "w")   "pout exec sdcv -nu WordNet ")
    (dk m (kbd "W")   "pout exec sdcv -nu \"English Thesaurus\" ")
    (dk m (kbd "ESC") "abort")
   M)))

;; keyboard layouts.
(defvar *xmod-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "1") "exec xmodmap /howl/conf/keymaps/dvausler1.xmodmap")
    (dk m (kbd "2") "exec xmodmap /howl/conf/keymaps/dvausler2.xmodmap")
    (dk m (kbd "3") "exec xmodmap /howl/conf/keymaps/dvausler3.xmodmap")
    (dk m (kbd "4") "exec xmodmap /howl/conf/keymaps/dvausler4.xmodmap")
    (dk m (kbd "5") "exec xmodmap /howl/conf/keymaps/dvausler5.xmodmap")
    (dk m (kbd "6") "exec xmodmap /howl/conf/keymaps/dvausler6.xmodmap")
    (dk m (kbd "a") "exec xmodmap /howl/conf/keymaps/arensito.xmodmap")
    (dk m (kbd "d") "exec xmodmap /howl/conf/keymaps/dvausler.xmodmap")
    (dk m (kbd "k") "exec xmodmap /howl/conf/keymaps/klausler2.xmodmap")
    (dk m (kbd "q") "exec xmodmap /howl/conf/keymaps/qwerty.xmodmap")
    (dk m (kbd "v") "exec xmodmap /howl/conf/keymaps/dvorak.xmodmap")
   M)))

;; frequently used commands.
(defvar *frequent-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "1") "exec pulsevol --port-toggle")
    (dk m (kbd "2") "exec pulsevol --speaker")
    (dk m (kbd "3") "exec pulsevol --headphones")
    (dk m (kbd "b") "display-random-bg")
    (dk m (kbd "B") "exec display -window root -resize 1600x900! /howl/foto/wall/wallpaper-31278.png")
    (dk m (kbd "C-b") "exec display -window root -resize 1600x900! /howl/foto/wall/yulia_by_wolf_parade_by_notagoat-d39avt7.jpg")
    (dk m (kbd "M-b") "exec display -window root -resize 1600x900! /howl/foto/wall/indian_by_aalexandrin-d3g7bej_2.jpg")
    (dk m (kbd "s-b") "exec display -window root -resize 1600x900! /howl/foto/wall/christmas_ghost_trip3.png")
    (dk m (kbd "g") "exec gimp -s --stack-trace-mode=never")
    (dk m (kbd "h") "exec urxvt -e htop")
    (dk m (kbd "l") "ror_luakit")
    (dk m (kbd "m") "exec pulsevol --mute")
    (dk m (kbd "r") "exec urxvt -e ranger /howl")
    (dk m (kbd "s") "exec urxvt -e nsudoku 12")
    (dk m (kbd "u") "ror_mutt")
    (dk m (kbd "x") "exec xskat -opt /howl/conf/xorg/xskat.opt -list /howl/conf/xorg/xskat.lst")
    (dk m (kbd "ESC") "abort")
   M)))

;; mplayer daemon (mifo) frequently used commands.
(defvar *mplayer-map1*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "0")     "exec mifo --begin list")
    (dk m (kbd "1")     "exec mifo --begin song")
    (dk m (kbd "2")     "exec mifo --begin last")
    (dk m (kbd "a")     "prompt-mifo-load")
    (dk m (kbd "A")     "prompt-mifo-append")
    ;(dk m (kbd "d")     "exec mifo --daemon")
    ;(dk m (kbd "d")     "exec sudo /etc/rc.d/mifo start")
    ;(dk m (kbd "f")     "exec mifo --fullscreen")
    (dk m (kbd "f")     "prompt-mifo-find")
    (dk m (kbd "F")     "prompt-mifo-findn")
    ;(dk m (kbd "h")     "echo-mifo-prev")
    (dk m (kbd "h")     "exec mifo --prev")
    (dk m (kbd "H")     "prompt-mifo-prev")
    (dk m (kbd "C-h")   "prompt-mifo-prev +")
    ;(dk m (kbd "l")     "echo-mifo-next")
    (dk m (kbd "l")     "exec mifo --next")
    (dk m (kbd "L")     "prompt-mifo-next")
    (dk m (kbd "C-l")   "prompt-mifo-next +")
    (dk m (kbd "p")     "prompt-mifo-playlist")
    (dk m (kbd "P")     "echo-mifo-playlists")
    ;(dk m (kbd "q")     "exec mifo --quit")
    ;(dk m (kbd "q")     "exec sudo /etc/rc.d/mifo stop")
    ;(dk m (kbd "Q")     "exec sudo /etc/rc.d/mifo purge")
    (dk m (kbd "r")     "exec mifo --repeat on")
    (dk m (kbd "R")     "exec mifo --repeat off")
    (dk m (kbd "s")     "exec mifo --stop")
    (dk m (kbd "S")     "prompt-mifo-save")
    (dk m (kbd "t")     "exec mifo --toggle")
    (dk m (kbd "*")     "exec mifo --random")
    (dk m (kbd "+")     "echo-mifo-add")
    (dk m (kbd "-")     "echo-mifo-remove")
    (dk m (kbd ":")     "prompt-mifo-command")
    (dk m (kbd "BackSpace")"prompt-mifo-begin")
    (dk m (kbd "ESC")   "abort")
   M)))

;; mplayer daemon (mifo) useful seek commands.
(defvar *mplayer-map2*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "h")     "exec mifo --seek -7")
    (dk m (kbd "H")     "exec mifo --seek -17")
    (dk m (kbd "C-h")   "exec mifo --seek -47")
    (dk m (kbd "M-h")   "exec mifo --seek -407")
    (dk m (kbd "l")     "exec mifo --seek 5")
    (dk m (kbd "L")     "exec mifo --seek 15")
    (dk m (kbd "C-l")   "exec mifo --seek 45")
    (dk m (kbd "M-l")   "exec mifo --seek 405")
    (dk m (kbd "!")     "exec mifo -c seek_chapter -1")
    (dk m (kbd "@")     "exec mifo -c seek_chapter 1")
    (dk m (kbd ":")     "prompt-mifo-seek")
    (dk m (kbd "BackSpace") "exec mifo --seek 0%")
    (dk m (kbd "ESC")   "abort")
   M)))

;; quickly dump rules, desktop, screen, or group
(defvar *dump-map1*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "r") "dump-to-datadir rules")
    (dk m (kbd "d") "dump-to-datadir desktop")
    (dk m (kbd "s") "dump-to-datadir screen")
    (dk m (kbd "g") "dump-to-datadir group")
   M)))

;; quickly restore rules, desktop, screen, or group
(defvar *dump-map2*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    (dk m (kbd "r") "restore-from-datadir rules")
    (dk m (kbd "d") "restore-from-datadir desktop")
    (dk m (kbd "s") "restore-from-datadir screen")
    (dk m (kbd "g") "restore-from-datadir group")
   M)))

(setf *top-map*
  (let ((m (make-sparse-keymap)))
    (labels ((dk (m k c) (define-key m k c)))
    ;; <numerical bindings>
    (dk m (kbd "s-1")    "gselect 1")
    (dk m (kbd "s-2")    "gselect 2")
    (dk m (kbd "s-3")    "gselect 3")
    (dk m (kbd "s-4")    "gselect 4")
    (dk m (kbd "s-5")    "gselect 5")
    (dk m (kbd "s-6")    "gselect 6")
    (dk m (kbd "s-8")    "mark")
    (dk m (kbd "s-C-8")  "clear-window-marks")
    (dk m (kbd "s-M-8")  "gmove-marked")
    (dk m (kbd "s-9")    "quiet-resize -10 0")
    (dk m (kbd "s-0")    "quiet-resize  10 0")
    (dk m (kbd "C-1")    "select-window-by-number 1")
    (dk m (kbd "C-2")    "select-window-by-number 2")
    (dk m (kbd "C-3")    "select-window-by-number 3")
    (dk m (kbd "C-4")    "select-window-by-number 4")
    (dk m (kbd "C-5")    "select-window-by-number 5")
    (dk m (kbd "C-6")    "select-window-by-number 6")
    (dk m (kbd "C-7")    "select-window-by-number 7")
    (dk m (kbd "C-8")    "select-window-by-number 8")
    (dk m (kbd "C-9")    "select-window-by-number 9")
    (dk m (kbd "C-0")    "select-window-by-number 0")
    ;; <special-char bindings>
    (dk m (kbd "s-quoteleft") "scratchpad")
    (dk m (kbd "s-!")    "gmove 1")
    (dk m (kbd "s-@")    "gmove 2")
    (dk m (kbd "s-#")    "gmove 3")
    (dk m (kbd "s-$")    "gmove 4")
    (dk m (kbd "s-%")    "gmove 5")
    (dk m (kbd "s-^")    "gmove 6")
    (dk m (kbd "s-*")    "pull-marked")
    (dk m (kbd "s-(")    "quiet-resize 0 -10")
    (dk m (kbd "s-)")    "quiet-resize 0  10")
    (dk m (kbd "s--")    "vsplit")
    (dk m (kbd "s-=")    "hsplit")
    (dk m (kbd "s-+")    "balance-frames")
    (dk m (kbd "s-;")    "colon")
    (dk m (kbd "s-:")    "manpage")
    (dk m (kbd "s-C-;")  "eval")
    (dk m (kbd "s-,")    "gprev")
    (dk m (kbd "s-<")    "gmove-prev")
    (dk m (kbd "s-C-,")  "gprev-with-window")
    (dk m (kbd "s-.")    "gnext")
    (dk m (kbd "s->")    "gmove-next")
    (dk m (kbd "s-C-.")  "gnext-with-window")
    (dk m (kbd "s-/")    "gother")
    (dk m (kbd "s-?")    "lastmsg")
    (dk m (kbd "s-ESC")  "exec zaprat --toggle")
    (dk m (kbd "s-Tab")  "fother")
    (dk m (kbd "s-S-SPC")"rotate-windows")
    (dk m (kbd "s-BackSpace")       "fclear")
    (dk m (kbd "s-S-BackSpace")     "delete-window")
    (dk m (kbd "s-C-BackSpace")     "kill-window")
    (dk m (kbd "s-Return")          "exec urxvt -e tmux -S /tmp/user-keep/${USER}/tmux/xorg new-session")
    (dk m (kbd "s-S-Return")        "tmux-attach-else-new")
    (dk m (kbd "s-C-Return")        "exec urxvt")
    (dk m (kbd "s-M-Return")        "tmux-attach-rtorrent")
    (dk m (kbd "s-SunPrint_Screen") "exec import -window root ${XDG_PICTURES_DIR:-${H:-/howl}/foto}/shot/$(date +%Y_%m_%d-%H%M%S).png")
    (dk m (kbd "C-M-Delete")        "exec xlock -mode slip -font fixed -grabmouse -sound -fg purple")
    (dk m (kbd "C-s-Delete")        "exec xlock -mode slip -font fixed -grabmouse -sound -fg purple")
    ;; <alphabetic bindings>
    (dk m (kbd "s-a")    *echo-map*)
    (dk m (kbd "s-b")    "refresh")
    (dk m (kbd "s-B")    "exec xrefresh")
    (dk m (kbd "s-C-b")  "redisplay")
    (dk m (kbd "s-c")    *xclip-primary-map*)
    (dk m (kbd "s-C")    *xclip-clipboard-map*)
    (dk m (kbd "s-d")    *mplayer-map1*)
    (dk m (kbd "s-D")    "prompt-mifo-command")
    (dk m (kbd "s-e")    "exec ")
    (dk m (kbd "s-E")    "shell-command-output")
    (dk m (kbd "s-f")    *frequent-map*)
    (dk m (kbd "s-F")    *win-frame-map*)
    (dk m (kbd "s-g")    "vgroups")
    (dk m (kbd "s-G")    "grouplist")
    (dk m (kbd "s-h")    "move-focus left")
    (dk m (kbd "s-H")    "move-window left")
    (dk m (kbd "s-C-h")  "exchange-direction left")
    (dk m (kbd "s-M-h")  "exchange-direction-remain left")
    (dk m (kbd "s-i")    "fselect")
    (dk m (kbd "s-j")    "move-focus down")
    (dk m (kbd "s-J")    "move-window down")
    (dk m (kbd "s-C-j")  "exchange-direction down")
    (dk m (kbd "s-M-j")  "exchange-direction-remain down")
    (dk m (kbd "s-k")    "move-focus up")
    (dk m (kbd "s-K")    "move-window up")
    (dk m (kbd "s-C-k")  "exchange-direction up")
    (dk m (kbd "s-M-k")  "exchange-direction-remain up")
    (dk m (kbd "s-l")    "move-focus right")
    (dk m (kbd "s-L")    "move-window right")
    (dk m (kbd "s-C-l")  "exchange-direction right")
    (dk m (kbd "s-M-l")  "exchange-direction-remain right")
    (dk m (kbd "s-m")    "master-focus")
    (dk m (kbd "s-M")    "master-swap 0")
    (dk m (kbd "s-C-m")  "master-make")
    (dk m (kbd "s-n")    "next-in-frame")
    (dk m (kbd "s-N")    "pull-hidden-next")
    (dk m (kbd "s-o")    "fullscreen")
    (dk m (kbd "s-O")    "only")
    (dk m (kbd "s-p")    "prev-in-frame")
    (dk m (kbd "s-P")    "pull-hidden-previous")
    (dk m (kbd "s-Q")    "quit")
    (dk m (kbd "s-r")    "loadrc")
    (dk m (kbd "s-R")    "restart")
    (dk m (kbd "s-s")    *mplayer-map2*)
    (dk m (kbd "s-t")    *dump-map1*)
    (dk m (kbd "s-T")    *dump-map2*)
    (dk m (kbd "s-u")    "undo")
    (dk m (kbd "s-v")    "show-window-properties")
    (dk m (kbd "s-V")    "list-window-properties")
    (dk m (kbd "s-w")    "echo-frame-windows")
    (dk m (kbd "s-W")    "windowlist")
    (dk m (kbd "s-x")    *xsel-map*)
    (dk m (kbd "s-X")    *xmod-map*)
    (dk m (kbd "s-y")    "iresize")
    (dk m (kbd "s-z")    "remove-split")
    ;; <function-key bindings>
    (dk m (kbd "XF86AudioMute")         "exec pulsevol --mute")
    (dk m (kbd "XF86AudioRaiseVolume")  "exec pulsevol --increase")
    (dk m (kbd "XF86AudioLowerVolume")  "exec pulsevol --decrease")
    (dk m (kbd "XF86AudioNext") "exec mifo --next")
    (dk m (kbd "XF86AudioPrev") "exec mifo --prev")
    (dk m (kbd "XF86AudioPlay") "exec mifo --toggle")
    (dk m (kbd "XF86AudioPause") "exec mifo --toggle")
    (dk m (kbd "XF86AudioStop") "exec mifo --stop")
;    (dk m (kbd "XF86Sleep")             "exec sudo systemctl suspend")
   M)))

;; EOF
 

x

Notes

UPDATED (updated due to dotshare.it multi-file update)

Examine .stumpwmrc file, then
1) set home-dir to static start path (useful if startx from different directory, etc, otherwise stumpwm uses relative)
2) set data-dir for storing log & group/tile/desktop/screen dumps (dump-to-datadir, data-dir-file,..).
3) set undo-data-dir for storing group/tile/desktop/screen undo states.
4) place functions.lisp, macros.lisp, commands.lisp, hooks.lisp, key-maps.lisp into home-dir/conf/stumpwm (or edit the end of .stumpwmrc and change the directory for loading these files)

The loop should load all functions, commands, etc, in a cycle, thus allowing each function to work together with externally defined command (from commands.lisp), etc. This is easier than one big file where you have to define a function needed in a command or vise versa, before or after as everything is looped back around to each other. Aye?

This isn’t as confusing as it seems. :P But if you really want the bulk version I posted earlier, you can find a static (2011-06-21) version here: http://pastebin.com/TT1L43e8

Comments

dipilibupap said about 13 years ago

This is really nice. I really like this, i will take time to study everything in detail! +1

crshd said about 13 years ago

Just started using Stump a couple of days ago, I think I can learn quite a bit from this :D

milomouse said about 13 years ago

Glad you guys like it. If you have any questions or suggestions, please let me know!

crshd said about 13 years ago

Why not:
(setf home-dir (make-pathname :directory (getenv “HOME”)))

Would be more portable…

edited about 13 years ago

milomouse said about 12 years ago

You’re right, but I also need a different directory than ENV HOME because mine is “/howl/conf” for configuration files, etc., and my start/base directory I use for my pseudo-home is “/howl”. It’s a bit complicated but for everyone else’s purposes they could use getenv in their rcs. :)

crshd said about 11 years ago

That new bar is the shit! I love it :D