monochromatic

monochromatic blog: http://blog.z3bra.org
git clone git://z3bra.org/monochromatic
Log | Files | Refs

pop-it-up.txt (11297B)


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