User:Gwern/.stumpwmrc

From Wikipedia, the free encyclopedia

   ;; -*-lisp-*-
   ;;.stumpwmrc --- my own Stumpwm customizations
   ;;Copyright (C) 2006 by gwern
   ;;Author: gwern <gwern0@gmail.com>
   ;;License: public domain
   ;;Where: <http:en.wikipedia.org/wiki/User:Gwern/.stumpwmrc>
   ;;When:  Time-stamp: "2007-01-28 22:04:22 gwern"
   ;;Keywords: local,customization,Stumpwm
   ;;Commentary: Modifies visual appearance of mode-line, input box, X windows; adds numerous key bindings
   ;;and heavily integrates Surfraw shortcuts. Includes some helper/utility functions.
   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;Global variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;Declare our default programs for certain things, and how visually things will look,
   ;;;for the mode line, the input box, etc.
   
   ;;Declare what this file is for.
   (in-package :stumpwm)
   
   ;;Stumpwm crashes or freezes too much. If we set the debug up to ludicoursly high levels, maybe we'll learn something.
   (setf stumpwm::*debug-level* 10)
   
   ;Variables
   ;;Terminals are important.(
   (defparameter X-TERM "exec aterm -fn '-lispm-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*' -sh 15 -tr -trsb -cr yellow -pr green -bl +vb -ut +sr -sl 1000 +rv -fade 50 -fg white -bgtype scale -txttype true -bd black +sb -tint purple "
     "What shall be the command run when we want an X terminal?")
   
   ;;I don't really want to be constantly typing "concatenate 'string" - this simplifies things.
   ;;Thanks to sabetts of #stumpwm
   (defun cat (&rest strings) "Concatenates strings, like the Unix command 'cat'. A shortcut for (concatenate 'string foo bar)."
          (apply 'concatenate 'string strings))
   
   ;;Text browsers are good, too.
   (defparameter X-TERM-BROWSER (cat X-TERM  " -e elinks")
     "We will want to open up our chosen CLI web browser in our chosen X terminal. What is it?")
   
   ;;Yay for GUI web browsing!
   (defparameter X-WWW-BROWSER "exec firefox "
     "What GUI WWW browser shall we use?")
   
   ;;Image viewers can be useful.
   (defparameter X-IMAGE-VIEWER "exec gqview "
     "Sometimes I like to look at images. We need some sort of client for that.")
   
   ;;Set the default shell
   (setf *shell-program* (stumpwm::getenv "SHELL")) ;getenv is not exported
   
   ;;Window border colors
   (setf *focus-color* "green")
   (setf *unfocus-color* "black")
   
   ;;Set the font for the input box. I have a nifty Lisp machine font.
   (set-font "-lispm-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*")
   
   ;;Set the message and input box to the bottom right. This way it overlaps with mode-line.
   (setf *message-window-gravity* :bottom-right)
   (setf *input-window-gravity* :bottom-right)
   
   ;;Colors for the input box; these should fairly self-explanatory. 'set-fg-color' will change the color
   ;;of the font in the echo area, for example, and the background will be green,
   ;;and the rectangle's lines will be a thin yellow, of course.
   (set-bg-color "black")
   (set-fg-color "lightgreen")
   (set-border-color "yellow")
   
   ;;Specifically, I want mode line to display the result of having the shell create a string
   ;;of the concatenation of a space and the output of the 'date' program.
   (setf stumpwm:*screen-mode-line-format*
         (list "%w|%g|"
            '(:eval (stumpwm:run-shell-command "date +%_I:%M:%S%p--%e-%a|tr -d [:cntrl:]" t))))
   
   (defun update-mode-line () "Update the mode-line sooner than usual."
     (let ((screen (current-screen)))
       (when (screen-mode-line screen)
         (redraw-mode-line-for (screen-mode-line screen) screen))))
   
   ;;SBCL-specific; only runs if SBCL is running
   ;;Call update-mode-line in such and such a way. Borrowed from Luigi Panzeri.
   #+sbcl (defparameter *mode-line-timer* (sb-ext:make-timer
                                 #'update-mode-line
                                 :name "mode-line-updating"
                                 :thread (car (last (sb-thread:list-all-threads)))))
   ;;Call a function given by the parameter every 30 seconds. This will increment the stuff in the mode-line.
   #+sbcl (sb-ext:schedule-timer *mode-line-timer* 5 :repeat-interval 60 :absolute-p nil)
   
   ;;I just don't like zero indexing frames/windows. 0 is not next to 1
   ;;on the keyboard!  See
   ;;<http://lists.gnu.org/archive/html/stumpwm-devel/2006-08/msg00002.html>
   (setf *frame-number-map* "1234567890") ;doesn't seem to work right now
   
   ;; Colors for the mode-line. Should be fairly self-explanatory.
   ;;"Where should the mode line be displayed? :top or :bottom."
   (setf *mode-line-screen-position* :bottom)
   
   ;;"Where should the mode line be displayed? :top or :bottom."
   (setf *mode-line-frame-position* :bottom)
   
   ;;"How thick shall the mode line border be?"
   (setf *mode-line-border-width* 0)
   
   ;;"How much padding should be between the mode line text and the sides?"
   (setf *mode-line-pad-x* 6)
   
   ;;"Define mode line background color."
   (setf *mode-line-background-color* "black")
   
   ;;"Define mode line foreground color."
   (setf *mode-line-foreground-color* "lightgreen")
   
   ;;"Define mode line border color."
   (setf *mode-line-border-color* "lightyellow")
   
   ;;Call our first group Firefox, since that's what I usually use in it.
   (setf (group-name (first (screen-groups (current-screen)))) "Firefox")
   (stumpwm::run-commands "gkill Emacs"
                       "gnewbg Emacs") ;Remember, only one group exists by default
   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;Functions, aliases, macros;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;Useful things. Usually defining new Stumpwm commands.
   
   (defun shell-command (command) "Run a shell command and display output to screen.
   This must be used in a functional side-effects-free style! If a program does not
   exit of its own accord, Stumpwm might hang!"
          (check-type command string)
          (echo-string (current-screen) (run-shell-command command t)))
   
   (define-stumpwm-command "shell-command" ((command :string "sh: " :string))
     (check-type command string)
     (shell-command command))
   
   ;;Leaving open the option to use Conkeror, a skin over Firefox.
   ;;Wish I could get sane tabbed browsing in it...
   (define-stumpwm-command "conkeror" ()
     (run-or-raise "firefox -chrome chrome://conkeror/content"
                   :class "Firefox-bin"))
   
   ;;Query ACPI and show the battery's status.
   (define-stumpwm-command "show-battery" ()
     (echo-string (current-screen) (run-shell-command "acpi" t)))
   
   ;;Briefly display a single frame from the top command and bind to a key.
   ;;Inspiration: <http://hocwp.free.fr/temp/stumpwmrc>
   (define-stumpwm-command "run-top" ()
     (shell-command "top -b -n 1 -c -d 1"))
   
   (define-stumpwm-command "emacs" ()
     (run-or-raise "emacs -T EMACS" :title "EMACS"))
   
   (define-stumpwm-command "firefox" ()
     (run-or-raise "firefox" :class "Firefox-bin"))
   
   (define-stumpwm-command "image-viewer" ()
     (run-or-raise X-IMAGE-VIEWER :class "Image-viewer"))
   
   ;;;;Automatically dump a core file when we quit. .xinitrc will try to exec ~/bin/sbcl-stumpwm-core
   (define-stumpwm-command "quit" ()
     (sb-ext:save-lisp-and-die "/home/gwern/bin/sbcl-stumpwm-core" :executable t :toplevel #'stumpwm:stumpwm))
   
   ;;;Web browsing commands
   ;;Get the X selection and order the GUI browser to open it. Presumably it is a HTTP address.
   (define-stumpwm-command "open-selection-browser" ()
     (run-shell-command (cat X-WWW-BROWSER (get-x-selection))))
   
   ;;Ask user for a search string and search Wikipedia for it.
   (define-stumpwm-command "wikipedia" ((search-string :string "wikipedia " :string))
     (check-type search-string string)
     (run-shell-command (cat "surfraw wikipedia " search-string)))
   
   ;;Get the X selection and search for it in Wikipedia.
   (define-stumpwm-command "wikipedia-selection" ()
     (run-shell-command (cat "exec surfraw wikipedia " (get-x-selection))))
   
   ;;Ask user for a search string and search Google for it.
   (define-stumpwm-command "google" ((search-string :string "google " :string))
     (check-type search-string string)
     (run-shell-command (cat "surfraw google " search-string)))
   
   ;;Get the X selection and search for it through Google.
   (define-stumpwm-command "google-selection" ()
     (run-shell-command (cat "exec surfraw google " (get-x-selection))))
   
   ;;Ask user for a search string and search the Internet Archive/Wayback Machine for it.
   (define-stumpwm-command "wayback" ((search-string :string "wayback " :string))
     (check-type search-string string)
     (run-shell-command (cat "surfraw wayback " search-string)))
   
   ;;Get the X selection (an HTTP address) and search for it in the Internet Archive.
   (define-stumpwm-command "wayback-selection" ()
     (run-shell-command (cat "exec surfraw wayback " (get-x-selection))))
   
   ;;Ask user for a search string and look for a Debian package of the same name.
   (define-stumpwm-command "debpackages" ((search-string :string "debpackages " :string))
     (check-type search-string string)
     (run-shell-command (cat "surfraw debpackages " search-string)))
   
   ;;Ask user for a search string and search the Debian BTS for a package of that name.
   (define-stumpwm-command "debbugs" ((search-string :string "debbugs " :string))
     (check-type search-string string)
     (run-shell-command (cat "surfraw debbugs " search-string)))
   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;Startup programs;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;What programs do we run on startup?
   
   ;;Great! Let's start mode-line for all screens!
   (screen-mode-line-mode (current-screen) t)
   
   ;;Do some key re-mapping; it is crucial that this get run first, because otherwise
   ;;the remapping later on of Insert and less to the prefix key simply will not work.
   (run-shell-command "xmodmap -quiet ~/.Xmodmap")
   
   ;;Apparently modifies some low-level GUI bits of X.
   (run-shell-command "xrdb -load ~/.Xresources -quiet")
   
   ;;Change the background and pointer in X
   (run-shell-command "xsetroot -cursor_name left_ptr -gray -fg darkgreen -bg black -name root-window")
   
   ;;Always good to have a shell
   (run-shell-command X-TERM)
   
   ;;Have a nice, randomly selected image from my ~/pics directory made the root window background.
   ;;This is actually a shell script command; one needs the #!/bin/bash shebang in the shell script
   ;;or an explicit invocation of the shell, like "bash ~/bin/random-picture.sh".
   (run-shell-command "random-picture")
   ;;(run-shell-command "bash xsetbg -border black -fork -type png -fit -onroot -fullscreen
   ;;~/pics/`w=(*.png); n=${#w[@]}; echo ${w[RANDOM%n]}`") ;full version
   
   ;;;This is an alternative- setting Electric Sheep as the background.
   ;;(run-shell-command "killall electricsheep 2>/dev/null; electricsheep --root 1 --nick gwern --zoom 1 --mplayer 1 --history 50")
   
   ;;Run unclutter so the mouse hangs around no longer than needed.
   (run-shell-command "unclutter -idle 1 -jitter 2 -root")
   
   ;;I use Xscreensaver as a screensaver. The first line makes sure any running Xscreensaver is killed.
   ;;The second run regardless of the success of the first & starts a background Xscreensaver daemon
   (run-shell-command "xscreensaver-command -exit; killall xscreensaver 2>/dev/null; xscreensaver")
   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;Key binding;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;Make the bindings more comfortable.
   
   ;;Set the *prefix-key*. The main feature of note is the changing of
   ;;the escape sequence from 2 keys, C-t, to a single key,
   ;;and the mirroring of less with another key, so there are actually 2 equivalent escape keys.
   (set-prefix-key (kbd "<"))
   
   ;;When not in Stumpwm mode, we want Insert to be bound to enter Stumpwm mode
   (define-key *top-map* (kbd "Insert") '*root-map*)
   (define-key *root-map* (kbd "Insert") "next") ;;When in Stumpwm mode, act like hitting the prefix again would.
   
   ;;You remember what run-top did, don't you? Defined in the functions section.
   (define-key *root-map* (kbd "&") "run-top")
   
   ;;Ditto for show-battery.
   (define-key *root-map* (kbd "*") "show-battery")
   
   ;;Allow short displays of shell output. Don't run GUI programs through this! Overrides default.
   (define-key *root-map* (kbd "!") "shell-command")
   
   ;;Browse somewhere with the GUI WWW browser.
   (define-key *root-map* (kbd "b") (cat "colon " X-WWW-BROWSER " http://www."))
   (define-key *root-map* (kbd "B") "open-selection-browser")
   
   ;;SSH somewhere in the default terminal.
   (define-key *root-map* (kbd "C-s") (cat "colon " X-TERM " -e ssh "))
   
   ;;More SSH.
   (define-key *root-map* (kbd "X")  (cat X-TERM "-e ssh -X root@127.0.0.1 aterm"))
   
   ;;Terminals. S-c does a regular terminal, and S-C allows a single command.
   (define-key *root-map* (kbd "c") X-TERM)
   
   ;;S-C is supposed to ask for a command to run in a new terminal. So, we need the colon command,
   ;;combined with our default X terminal, and since that is Aterm, the option to run a command is '-e', so we need that as well.
   (define-key *root-map* (kbd "C") (cat "colon " X-TERM " -e "))
   
   ;;Firefox binding.
   (define-key *root-map* (kbd "d") "firefox") ;"firefox" is defined in functions
   
   ;;Bindings for minimalistic CLI/GUI web browsers.
   (define-key *root-map* (kbd "D") X-TERM-BROWSER)
   
   ;;Shortcut for Emacs. Emacsclient is called, but it expects a filename.
   ;;This can be circumvented by instructing it to instead evaluate a Emacslisp expression -
   ;;the current one - says "open up a new frame on the current display device".
   ;;It has to be quoted or else sh will try to open up the lisp expression in a sub-shell
   ;;as a shell command. Neatly, if an Emacs isn't already running, then Emacsclient runs
   ;;$EDITOR, which points back to regular Emacs!
   (define-key *root-map* (kbd "E") "exec emacsclient -a emacs -t EMACS")
   (define-key *root-map* (kbd "e") "emacs") ;"emacs" is defined in functions.
   
   ;;Shortcut for Nano
   (define-key *root-map* (kbd "M-E") (cat "colon " X-TERM " -e nano"))
   
   ;;Image viewer
   (define-key *root-map* (kbd "v") "image-viewer") ;;"image-viewer" is defined in functions.
   
   ;;Apparently stump's default does something weird on my latop's screen. This should fix it.
   (define-key *root-map* (kbd "s") "vsplit")
   (define-key *root-map* (kbd "S") "hsplit")
   
   ;;Binding for Xpdf
   (define-key *root-map* (kbd "x") "exec xpdf")
   
   ;;Make prtscreen work, as long as in command mode. "import" is an Imagemagick command.
   (define-key *root-map* (kbd "Print") "exec import -window root png:$HOME/xwd-$(date +%s)$$.png")
   
   ;;'Swounds, I'm gonna need a separate section just for Surfraw shortcuts.
   ;;Anyway, the model for these (thanks to aon) is to bind a key to "colon exec surfraw wikipedia "
   ;;(or whatever the site is) note the space. If the space isn't there, then the user will need to
   ;;manually add a space, which is not good. In the shell, one can omit the surfraw command, but
   ;;not in stumpwm, as stumpwm's PATH currently does not seem to include the directory with the elvi in it.
   ;;List of useful surfraw elvi follows:
   ;;amazon bbcnews cia cite cnn debbugs debcontents deblists deblogs debpackages debpts deja dmoz ebay etym
   ;;freshmeat google imdb rfc rhyme slashdot sourceforgen translate
   
   ;;Surfraw keybindings.
   (define-key *root-map* (kbd "t") "wikipedia")
   (define-key *root-map* (kbd "T") "wikipedia-selection")
   
   (define-key *root-map* (kbd "g") "google ")
   (define-key *root-map* (kbd "G") "google-selection")
   
   (define-key *root-map* (kbd "y") "wayback ")
   (define-key *root-map* (kbd "Y") "wayback-selection")
   
   (define-key *root-map* (kbd "u") "debbugs ")
   (define-key *root-map* (kbd "U") "debpackages ")
   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;Groups;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;Change various group things.
   
   ;;Refer to user.lisp
   ;;Currently, when one hits S-g, one enters group-mode, wherein the keys
   ;;are rebound to serve as group movement commands. I might want to change this.
   ;;(define-key (kbd "`") '*groups-map*)
   
   ;;Two quick and easy shortcuts - one to switch rapidly between groups and another to list them.
   ;;Anything more elaborate can be done by going through group-mode.
   (define-key *root-map* (kbd "~") "vgroups")
   (define-key *root-map* (kbd "quoteleft") "gprev")
   
   
   ;;If the current window is Emacs, let's ban it to the Emacs group. This loses a bit of flexibility,
   ;;but it means startups will be more pleasant. The remove-hook should mean Emacs gets moved only once.
   ;;And yes, you do actually need a defun and a add-hook to guarantee sticking an application into a particular group.
   ;;TODO: generalize this
   (defun move-emacs (window)  "Move emacs to the Emacs group."
          (if (string= (window-class window) "Emacs")
           (stumpwm::run-commands "gmove Emacs"))
          (remove-hook stumpwm::*map-window-hook* 'move-emacs)
          )
   (stumpwm:add-hook *map-window-hook* 'move-emacs)
   
   ;;Automatically open up another virtual desktop; in a surprising show of originality, I will name it Emacs,
   ;;since that's what I usually use in it.
   (stumpwm::run-commands
    "gselect Emacs"
    "emacs") ;;Because of the previous defun and hook, the emacs will be moved to the right group automatically
   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;Pasting;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;;Loads in some functions to allow multiple registers (think Emacs-style). Binds to numerical keys.
   ;;See <http://stumpwm.elektrubadur.se/cgi-bin/wiki/paste.lisp>
   (load "/home/gwern/bin/paste.lisp")
   
   
   ;;;;I don't quite understand this stuff yet. It's ripped from Luigi Panzeri's .stumpwmrc, and he's doing some interesting stuff
   ;;;;which seems powerful but which I haven't yet figured out what it is doing, much less why.
   ;;   ____
   ;;  / ___|_ __  ___  _   _ _ __   ___
   ;; | |  _| '__|/ _ \| | | | '_ \ / __|
   ;; | |_| | |  | (_) | |_| | |_) |\__ \
   ;;  \____|_|   \___/ \__,_| .__/ |___/
   ;;                        |_|
   
   (defun find-group-by-name (name)
    (find name (screen-groups (current-screen)) :test #'string-equal :key #'group-name))
   
   (defun place-windows-on-group (group &key class)
    (lambda (win)
      (when (string-equal (window-class win) class)
        (move-window-to-group win group))))
   
   (defun place-windows-on-frame (group frame &key class)
    (lambda (win)
      (when (string-equal (window-class win) class)
        (move-window-to-group win group)
        (setf (window-frame win) frame)
   ;      (sync-frame-windows group frame)
        (echo-string (current-screen) (format nil "Window ~a placed in group ~a" (window-name win) (group-name group))))))
   
   (defun horiz-split-frame-and-resize (group fraction)
    (horiz-split-frame group)
    (let ((frame (tile-group-current-frame group)))
      (resize-frame group
                    frame
                    (truncate (* (- (* 2 fraction) 1) (frame-width frame)))
                    'width)))
   
   (defun vert-split-frame-and-resize (group fraction)
    (vert-split-frame group)
    (let ((frame (tile-group-current-frame group)))
      (resize-frame group
                    frame
                    (truncate (* (- (* 2 fraction) 1) (frame-height frame)))
                    'height)))
   
   (defmacro horizontally (&rest frame-specs)
    `(let ((accum 1)
           (frame-specs (sort ',frame-specs (lambda (el1 el2)
                                                 (cond
                                                   ((not (numberp el1)) nil)
                                                   ((not (numberp el2)) t))))))
       (dolist (frame-spec (butlast frame-specs))
         (destructuring-bind (fraction window-queries) frame-spec
           (when (numberp fraction)
             (decf accum fraction))
           (horiz-split-frame-and-resize group (if (numberp fraction) fraction accum))
           (dolist (window-query window-queries)
             (ecase (car window-query)
               (:class (add-hook *map-window-hook*
                                 (place-windows-on-frame group (tile-group-current-frame group) :class (cadr window-query)))))))
           (focus-frame-sibling group))
       (destructuring-bind (fraction window-queries) (car (last frame-specs))
         (declare (ignore fraction))
         (dolist (window-query window-queries)
           (ecase (car window-query)
             (:class (add-hook *map-window-hook* (place-windows-on-frame group
                                                                         (tile-group-current-frame group)
                                                                         :class (cadr window-query)))))))))
   
   (defmacro define-group-layout (group-name layout-spec)
    `(let* ((group (or (find-group-by-name ,group-name)
                       (add-group (current-screen) ,group-name))))
   
       ,layout-spec))
   
   ;(define-group-layout "Chat"
    ;  (horizontally
     ;     (1/4 ((:class "Amsn")))
      ;  (:fill ((:class "Chatwindow")))))
   ;;EOF