一个动态设置壁纸的脚本的设计与实现

这是我想在Awesome的设置中添加的一个有特色的功能,壁纸随着时间变动,而且可以直观地感受到时间。我花了半天时间找了24张壁纸,都是一些CG图片,按照上面的光照什么的设定与其相对应的时间,与一天的24个小时一一对应。

原本的设计是用Awesome自己提供的一个定时器钩子函数来更新壁纸,这样最终是用的是Lua脚本,但是与Awesome耦合性太强。我觉得完全可以用一个Shell脚本来完成。这个脚本的主要流程是这样:

首先根据当前的时间来找到对应的图片然后设置之,然后隔一段时间到下一个整点,再更新之,以后都是休息一小时更新一次,为了增强效果,每次更新壁纸时都会发出“嘀”的一声。

这里有几点,一是如何设置壁纸。设置壁纸似乎有许多程序,我在Awesome默认的设置壁纸的脚本awsetbg里看了一下,发现它是通过探测系统中的壁纸设置程序来设置的,在我的系统中是使用的ImageMagick套件中的display来设置的。了解了这一点,就可以直接用display来设置了,不过如果KDE在运行,就直接使用kdesktop的DCOP接口来设置了,再调用play来播放声效。

第二点,就是保持此程序单实例运行,即任何时候此程序都只能有一个进程。我目前的实现是使用pgrep来获得最早运行进程的id,若与当前进程id相同则说明只有一个实例,反之则说明已有实例在运行,当前进程是重复进程,需退出。

还有一点,就是计算当前时间到下一个整点所需的秒数。能进行简单计算的程序很多。如expr,但这个程序是将所有的操作数和操作符作为他的参数,而很多操作符本身可能被Shell转义,如乘号*,这导致expr的使用非常麻烦。Lua也可以非常方便地计算,不过为了使用更为通用的程序,我选择了bc。这是GNU的一个并不太出名的程序,它可以计算任意精度的计算。其实还有一个dc,不过他的表达式是所谓的逆波兰式,也就是后缀表达式,写起来就特别怪异。

下面是完整的脚本: 

#!/bin/sh

function show_wallpaper() {
        if pgrep kdesktop >/dev/null ; then
                dcop kdesktop KBackgroundIface setWallpaper "$1" 1
        else
                display -sample 1440x900+0+0 -window root "$1"
        fi
    play "/usr/share/sounds/KDE_TypeWriter_Bell.wav" -q
}

if [ -n "$1" ]; then
    show_wallpaper "$1"
    exit 0
fi

function update_wallpaper() {
    wallpaper_path="$HOME/.config/awesome/wallpapers"
    hour=`/bin/date +%H`
    wallpaper="$wallpaper_path/$hour.jpg"
    show_wallpaper "$wallpaper"
}

update_wallpaper

# keep the previous running instance
[ `pgrep -f "$0" -o` != $$ ] && exit

# another way to using dc instead of bc is
# sleep `/bin/date "+60 %M - 60 * %S - p" | dc`s
sleep `/bin/date "+print((60-%M)*60-%S)" | bc`s

update_wallpaper

while true ; do
    sleep 1h
    update_wallpaper
done

 

Linux Comments(0) 2009年1月18日 03:34