I use Stumpwm as my primary window manager on my desktop at home. Stumpwm is actually a pretty neat window manager: it’s tiled, provides facilities for group and be controlled completely from the keyboard, no mouse necessary, but it’s chief advantage to me is that it’s written and configured with Common Lisp, which make it much easier for me to script and modify. I can arbitrarily load programs, libraries, and code into the Stumpwm runtime in realtime while it is still running just to see if and how it works. This actually makes it much more deeply modifiable than most other windows managers (or indeed, programs of any sort,) and I’ve taken advantage of this from time to time.
One of my more perennial problems is a sort of insomnia that I have. I’ve found however, that if I limit my computer usage in the evening and spend a couple hours away from it before going to bed, it becomes much less of an issue. This presents a bit of a discipline problem however with me having to remember and be willing to do so every night. That’s a pain so I figured why the hell not write a program that helps me with this? Stumpwm seemed like a natural place to put it.
So, what I was thinking was to make a script which would be triggered at a certain time in the evening and would shutdown the computer. This is pretty simple and could be done with a simple cronjob but it has the issue that it’s also a little abrupt. It wold only take a few nights of me loosing work to it for me to turn it off. So what about a program which launches at a certain moment and then nags me until I turn off the computer? This is much better because it would allow me to finish whatever I’m doing but would still encourage me to turn off the machine.
I settled on a script which would, at the specified time, launch a prompts telling me it was time to shutdown the compute and giving me the option to snooze. If I press the snooze it will go away, but pop up again in a few minutes. Each time I press the snooze, the snoze gets shorter which makes the program more annoying and impractical to just keep snoozing. The program locks down my input while prompting me and the only option other than snooze is immediate shutdown. Because the program runs as part of the window manager, I can’t shut it down using usual process management tools like ps and kill.
To make the program start at only certain times, I used the cl-cron library and loaded it into Stumpwm using this code in my .stumpwmrc:
(require 'cl-cron)
(use-package 'cl-cron)
(start-cron)
Stumpwm has a few functions for creating prompts and asking for input but it doesn’t really have a simple y/n prompt. Fortunately, this was simple to write:
(defun y-n-prompt (prompt &optional (y-answer "OK") (n-answer "OK") wrong-char)
"Asks user a yes or no question and returns a boolean based on user response."
(message (if wrong-char "~A (type \"Y\" or \"N\")" "~A (y/n)") prompt)
(let ((input (read-one-char (current-screen))))
(case input
(#\y (stumpwm::echo y-answer) t)
(#\Y (stumpwm::echo y-answer) t)
(#\n (stumpwm::echo n-answer) nil)
(#\N (stumpwm::echo n-answer) nil)
(t (y-n-prompt prompt y-answer n-answer t)))))
Now I can actually write the nag function. The logic is pretty simple: initiate a y/n prompt asking the using if he wants to shutdown the computer just yet. If the user answers yes, shut everything down, otherwise wait a little while and relaunch. Here’s the code:
(defun night-time (&optional (snooze 900) (speedup-rate 1/3))
"Bedtime nag. Asks user to shutdown computer with increasing frequency."
(if (y-n-prompt "Time for bed. Shutdown now?"
"Shutting Down"
(format nil "Snoozing for ~A:~A minutes"
(floor (/ snooze 60))
(round (mod snooze 60))))
(stumpwm::quit)
(progn
(sleep snooze)
(night-time (- snooze (* snooze speedup-rate))
speedup-rate))))
Pretty simple right? Notice that it reduces the snooze time with each iteration. Anyway, all I have to do is add it to cl-cron:
(make-cron-job 'night-time
:minute 0
:hour 22)
Now it will run at ten every night. Problem solved.
I actually have a couple of tricks in my .stumpwmrc so I’ll probably give it a home on this site at one point, probably after my .emacs has gotten it’s place.