URI: 
       tpop-it-up.txt - monochromatic - monochromatic blog: http://blog.z3bra.org
  HTML git clone git://z3bra.org/monochromatic
   DIR Log
   DIR Files
   DIR Refs
       ---
       tpop-it-up.txt (11141B)
       ---
            1 # Pop it up !
            2 
            3 30 April, 2014
            4 
            5 So you know how to build a status bar to get informations about your computer?
            6 That's **cute**. How about bringing it to the next level?
            7 
            8 Let's go through another way to display informations from your lovely
            9 computer: popup notifications !
           10 
           11 ## What's that ?
           12 Popup notifications (I'll call them "popup" from now) are a tiny window that
           13 will appear on your screen with an informative text on it, and then disappear
           14 after a certain amount of time, or a user interaction.
           15 
           16 The important part is that the popups show up when an event occur, not upon user
           17 request (well, if the user request a popup, it can still appear, obviously).
           18 
           19 ## Usefulness
           20 Well, most of the popup we have to deal with are annoying most of the time
           21 (except those that notify me that I won an IPad by being the visitor number
           22 1 000 000, it's nice to tell me!). But if you choose wisely the content and the
           23 event to pop it, it can become really useful, and help you to unclutter your
           24 desktop by removing useless informations.
           25 
           26 Do you really need to know that your laptop battery is at 78% ? **NO**
           27 Do you really need to know that you have 0 new mails ? **NO**
           28 
           29 This can apply to many other informations (RAM, CPU, current workspace,..). You
           30 don't need the information to be displayed all the time.  You just need it when
           31 it's relevant, like battery under 10%, or new mail incoming.
           32 
           33 But if you just LIKE to have it displayed all the time (Sometime, I enjoy a nice
           34 status bar with the fine infos in it), then it's okay! Remember that you can
           35 have both anyway ;)
           36 
           37 Moreover, you can use popups to notify you when a task running in the
           38 background has finished, or that a torrent has finished downloading, or
           39 whatever weird usage you can find!
           40 
           41 ## Existing software
           42 There are in fact, many notification systems that you can use:
           43 [libnotify](http://library.gnome.org/devel/notification-spec/),
           44 [notify-osd](https://launchpad.net/notify-osd),
           45 [twmn](https://github.com/sboli/Twmn), etc...
           46 
           47 These are fine. But as always, it's just funnier to build your own!
           48 And in order to do so, we will need an important program:
           49 [bar](https://github.com/lemonboy/bar)! (note that you can use
           50 [dzen](https://github.com/robm/dzen) too)
           51 
           52 I love this one, because it's really light and simple to use. Moreover, I
           53 contributed to it to complete the geometry setting. You can now create a window
           54 of any size and place it wherever you want!
           55 
           56 ## Popup itself
           57 This part is the most simple in fact. `bar` will do anything for us.
           58 
           59 All you have to do is to create a script that will take a serie of argument and
           60 put them in a resized bar on your screen.
           61 
           62 The simplest script I can think of is:
           63 
           64     #!/bin/sh
           65 
           66     Create the popup and make it live for 3 seconds
           67     (echo " $@"; sleep 3) | bar -g 120x20+20+20
           68 
           69 And it's working, already!
           70 After that, you can style it to make it look like you want:
           71 
           72     #!/bin/sh
           73 
           74     # how long should the popup remain?
           75     duration=3
           76 
           77     # define geometry
           78     barx=10
           79     bary=10
           80     barw=120
           81     barh=20
           82 
           83     # colors
           84     bar_bg='#ff333333'
           85     bar_fg='#ffffffff' # white is default
           86 
           87     # font used
           88     bar_font='-*-gohufont-medium-*-*--11-*-*-*-*-*-iso10646-1'
           89 
           90     # compute all this
           91     baropt='-g ${barw}x${barh}+${barx}+${bary} -B${bar_bg} -f ${bar_font}'
           92 
           93     Create the popup and make it live for 3 seconds
           94     (echo " $@"; sleep ${duration}) | bar ${baropt}
           95 
           96 [![simple popup](http://pub.z3bra.org/monochromatic/img/thumb/2014-04-29-popup-simple.png)](http://pub.z3bra.org/monochromatic/img/2014-04-29-popup-simple.png)
           97 *The simple script above, started with a random text.
           98 It's my upper left hand-corner*
           99 
          100 Obviously, that's not an informative popup at all (is it?). All you need now is
          101 to write some simple script to grab the informations you will need to display in
          102 your popup.  I'll not develop it here, as I already wrote a not-so-tiny section
          103 on a subjet in my [previous
          104 post](http://blog.z3bra.org/2014/04/meeting-at-the-bar.html#grab).
          105 
          106 You could then just pop notifications using:
          107 
          108     popup $(~/bin/volume)
          109 
          110 
          111 ## Automate the popups
          112 The best thing about popups is that they spawn when it's relevent, eg: when a
          113 new mail arrived, volume is changing or battery is low.
          114 
          115 To catch those event there are many way. We will run through three of them:
          116 
          117 * infinite loop
          118 * inotify event
          119 * key presses
          120 
          121 ### infinite loop
          122 This one is easy. We just check whatever we want at regular interval, and
          123 depending on some conditions, we raise a notification. That's what I use for my
          124 battery:
          125 
          126     #!/bin/sh
          127     #
          128     # z3bra - (c) wtfpl 2014
          129     # check battery level, and raise a notification if the capacity is
          130     # under a defined level
          131 
          132     LEVL=7
          133     BATC=$(sed 's/%//' /sys/class/power_supply/BAT0/capacity)
          134 
          135     test ${BATC} -le ${LEVL} && popup battery level: ${BATC}
          136 
          137 Then run this every 2 minutes or so, and it will notify you when your battery is
          138 running low. You can put it in your `.xinitrc` or as a cron job:
          139 
          140     # .xinitrc
          141     while :; do ~/bin/battery_check; sleep 120; done &
          142 
          143     # crontab
          144     */2 * * * * DISPLAY=0 ~/bin/battery_check
          145 
          146 
          147 ### inotify event
          148 [Inotify (inode notify) is a Linux kernel subsystem that acts to extend
          149 filesystems to notice changes to the
          150 filesystem](https://en.wikipedia.org/wiki/Inotify). That strange sentence means
          151 that you can catch an event when a node (file, socket, fifo, directory, ...) is
          152 modified. There are many events like modification, access to a node, node moved,
          153 etc...
          154 
          155 To catch those event, there are really few tools.. I wrote mine,
          156 [wendy](http://blog.z3bra.org/2014/03/toolbox.html#wendy), but there are other.
          157 Just take a look at this [reddit
          158 thread](http://www.reddit.com/r/linux/comments/1y5iqy/wendy_watch_files_in_your_file_system_and_launch/)
          159 to find out more.
          160 
          161 So let's define the environnment. There is that directory:
          162 
          163     $ ls ~/var/mail/INBOX
          164     cur/ new/ tmp/
          165 
          166 I use `fdm` (see [this blog
          167 post](http://blog.z3bra.org/2013/11/plain-old-mails.html) to retrieve my mails
          168 from my POP3 server. Each new mail creates a file in `~/var/mail/INBOX/new`, so
          169 we will just need to watch file creation in that folder, and pop a notification
          170 at each new mail. It's done like this in my `~/.xinitrc`
          171 
          172     # .xinitrc
          173     # note that $MAIL is set to my inbox through my ~/.profile
          174     wendy -m 256 -q -f ${MAIL}/new -e popup 'new mail(s)!' &
          175 
          176 And there we go. each time `fdm` will fetch mails to your inbox, a wild popup
          177 will appear!
          178 
          179 ### key presses
          180 The last type of popup I use is those that occur when a key is pressed. The best
          181 exemple for that are the volume keys. I don't know how you handle this, but
          182 personnally, <s>I use `xbindkeys` for that. It's a software that let the user map
          183 commands to hotkeys, which is totally useful for everything. I know some people
          184 (`bspwm` users, mostly) use baskerville's `sxhkd` to do so. I have nothing against this soft, but it will just not cut it here. For further explanations, see [this comment
          185 @nixers.net](http://nixers.net/showthread.php?tid=888&pid=9444#pid9444).</s>
          186 ([/u/jumpwah](http://reddit.com/u/jumpwah) pointed that `sxhkd` can run
          187 multiple commands using a single keybind, as shown in
          188 [`examples/sxhkdrc`](https://github.com/baskerville/bspwm/blob/master/examples/sxhkdrc#L26-29)).
          189 
          190 So, if you already use `xbindkeys` to change your volume level, probably already
          191 know what to do.
          192 
          193 I personally have a script to manage my volume level:
          194 
          195     #!/bin/sh
          196     #
          197     # z3bra - (c) wtfpl 2014
          198     # Manage ALSA Master channel
          199 
          200     test "$1" = "-h" && echo "usage `basename $0` [+|-|!]" && exit 0
          201 
          202     level() {
          203         amixer get Master | sed -n 's/^.*\[\([0-9]\+%\).*$/\1/p' | uniq
          204     }
          205 
          206     state() {
          207         amixer get Master | sed -n 's/^.*\[\(o[nf]\+\)]$/\1/p' | uniq
          208     }
          209 
          210     test $# -eq 0 && echo "`level` `state`" && exit 0
          211 
          212     case $1 in
          213         +)      amixer set Master 5%+ >/dev/null;;
          214         -)      amixer set Master 5%- >/dev/null;;
          215         !)      amixer set Master toggle >/dev/null;;
          216         state|level) $1;;
          217         *)    amixer set Master $1 >/dev/null;;
          218     esac
          219 
          220 It's quite simple. `volume +|-` will raise|lower volume, `volume !` will toggle
          221 on/off, `volume level|state` will output the level or state, and `volume
          222 whatever` will execute `whatever` through amixer (exemple: `volume on|off`).
          223 
          224 Back to the topic. Here is my `.xbindkeysrc`
          225 
          226     "~/bin/volume +"
          227         XF86AudioRaiseVolume
          228 
          229     "~/bin/volume -"
          230         XF86AudioLowerVolume
          231 
          232     "~/bin/volume !"
          233         XF86AudioMute
          234 
          235     "~/bin/popup volume: $(~/bin/volume level)"
          236         XF86AudioRaiseVolume
          237 
          238     "~/bin/popup volume: $(~/bin/volume level)"
          239         XF86AudioLowerVolume
          240 
          241     "~/bin/popup volume: $(~/bin/volume level)"
          242         XF86AudioMute
          243 
          244 There, simple. The popup command is bound to my volume keys, so each time I
          245 press them, the notification comes up! It's quite simple.
          246 
          247 ## Improvements
          248 This system is not perfect at all, because popup overlap, the width and timing
          249 is fixed, ... But it's also a bare simple system, easily hackable. You could use
          250 it to build a more complex system on top of that. For example, you can easily
          251 write a simple daemon that will read messages from a fifo and stack popups
          252 together:
          253 
          254 
          255     #!/bin/sh
          256     #
          257     # z3bra - (c) wtfpl 2014
          258     # Popup wrapper used to stack notifications together
          259 
          260     # fifo that we'll use to feed the popups
          261     test -p /tmp/popup.fifo || mkfifo /tmp/popup.fifo
          262 
          263     # popup definition
          264     w=150
          265     h=20
          266     x=1930
          267     y=10
          268 
          269     # popup counter (starts at -1 so that the first popup has no offset
          270     n=-1
          271 
          272     # get messages from the fifo
          273     tail -f /tmp/popup.fifo | while IFS= read -r message; do
          274         # increment the counter
          275         n=$((n + 1))
          276 
          277         {
          278             # display the popup under the others
          279             ~/bin/popup -g ${w}x${h}+${x}+$((y + (h+y) * n)) $n ${message}
          280 
          281             # decrement the counter
          282             n=$((n - 1))
          283         } &
          284     done
          285 
          286 Then, write your messages to `/tmp/popup.fifo` to see your popup stacking
          287 together (`echo shblah > /tmp/popup.fifo`). It will probably require
          288 improvements, but it's a good starting point!
          289 
          290 Here are a few other ideas I had (but did not bother trying :P):
          291 
          292 * Using [txtw](https://github.com/baskerville/txtw) to change width dynamically
          293 * Make use of the clickable area of `bar` to get rid of the popup
          294 * Make long notifications scroll using `skroll`
          295 * shampoo / soap
          296 * 4 apples
          297 * <del>some fresh meat</del> <em>Ah, wrong list...</em>
          298 * ...
          299 * Be creative, as usual!
          300 
          301 ## Good bye
          302 I hope this will be helpful to someone. It's not meant to make you throw your
          303 status bar away, or switch from libnotify and such. It's just a bare simple
          304 alternative to those, as I like to have :)
          305 
          306 [![popup show
          307 off](http://pub.z3bra.org/monochromatic/img/thumb/2014-04-30-popup-showoff.png)](http://pub.z3bra.org/monochromatic/img/2014-04-30-popup-showoff.png)
          308 *Here is a little show case of what you can achieve. I
          309 used `stlarch_font` for the icon.
          310 the first popup is the volume bar. It goes red when it's muted.
          311 Next is a new mail (spawned via `touch $MAIL/new/shblah`). And finally, the
          312 battery level, bound to a key for the purpose of the gif. Otherwise it only
          313 shows up under 15% (written in red)*
          314 
          315 Enjoy!