在GNU/Linux下设置与定时更换桌面壁纸
1 简介
在电脑桌面设置一组可以定时更换的壁纸已经不是什么新奇的功能了。比如,Windows 7、KDE桌面环境都可以实现这样的效果。可是,自己目前使用的Debian系统并未安装KDE、GNOME这样的桌面环境,只是简单的X视窗系统与Sawfish窗口管理。因此,要想实现加载壁纸并定时更换的功能就需要另想办法了。经过一番思考与编程,我现在可以用如下一系列脚本程序来完成这个任务:
- get_img_size.sh :调用 identify 命令显示图片信息并使用 gawk 命令从中提取出图片的尺寸。
- set_wallpaper.sh :调用 xloadimage 程序,加载单张图片作为壁纸。其中,该脚本会调用 get_img_size.sh 以获取该图片的尺寸,并根据指定的屏幕大小与其所在位置,对该图片进行适当的缩放与平移,使其显示于屏幕中间,且保持原比例充满屏幕。
- set_multi_wallpapers.sh :读入包含壁纸图片列表的配置文件,以指定的时间间隔来调用 set_wallpaper.sh ,从而逐个将这些图片加载为壁纸。
- gen_multi_wallpapers.sh :根据指定的匹配模式,使用 find 命令列出匹配到的图片文件,并生成能被 set_multi_wallpapers.sh 使用的配置文件。
下面对上述脚本进行具体说明。
2 加载单张图片作为壁纸: set_wallpaper.sh
将图片作为壁纸显示是通过 xloadimage 命令来实现的。通常,可以按如下的方式使用它:
xloadimage -fullscreen -onroot -border black -zoom 100 -rotate 90 -at 0,0 image_file
其中, -fullscreen 与 -onroot 的使用就可以将图片作为壁纸显示而不是被放到一个窗口里。其余的命令行选项的含义都是不言自明的。 set_wallpaper.sh 脚本程序并不是简单地调用 xloadimage ,其还会根据图片的大小与屏幕尺寸计算出 -zoom 选项的值,从而自动缩放图片,使其恰好完整地填满屏幕。此外,若电脑连接有多个显示器,可以通过设置 set_wallpaper.sh 的 -x 与 -y 选项来指定待加载壁纸屏幕左上角的坐标,以及设置 -W 与 -H 选项来指定该屏幕的宽和高。最终,图片就会只在该屏幕上显示了。
set_wallpaper.sh 的源码如下:
#!/bin/bash script_name="set_wallpaper.sh" script_usage=$(cat <<EOF $script_name [OPTION] image_file EOF ) script_function=$(cat <<EOF This script is used to load an image onto root screen as wallpaper. EOF ) script_doc=$(cat <<EOF -h Display this help. -r Set the rotation angle of the image. -W Screen width. -H Screen height. -x X position of the image to be loaded onto root screen. -y Y position of the image to be loaded onto root screen. EOF ) script_examples=$(cat <<EOF $script_name -r 0 -W 1920 -H 1080 -x 1280 -y 0 $picture/wallpapers/sunflower.jpg EOF ) state_prefix="===" warning_prefix="***" error_prefix="!!!" function display_help() { if [ -n "$script_usage" ]; then echo -e "Usage: $script_usage" fi if [ -n "$script_function" ]; then echo -e "$script_function" fi if [ -n "$script_doc" ] ; then echo -e "\n$script_doc" fi if [ -n "$script_examples" ]; then echo -e "\nExamples" echo -e "$script_examples" fi } # Default parameters declare -i rot_angle=0 screen_width=1920 screen_height=1080 screen_x=0 screen_y=0 zoom_factor=100 x_res=0 y_res=0 x_res_scaled=0 y_res_scaled=0 at_x=0 at_y=0 while getopts ":r:W:H:x:y:h" opt; do case $opt in r ) rot_angle=$OPTARG if [ $(((($rot_angle % 90) != 0) || (($rot_angle < 90) && ($rot_angle != 0)))) = 1 ]; then echo "The rotation angle of the image should be 0 or multiple of 90 degrees!" exit 1 fi ;; W ) screen_width=$OPTARG ;; H ) screen_height=$OPTARG ;; x ) screen_x=$OPTARG ;; y ) screen_y=$OPTARG ;; h ) display_help exit 0 ;; \? ) display_help exit 1 ;; esac done shift $(($OPTIND - 1)) if [ -n "$1" ]; then echo "Loading image $1" resolution=`get_img_size.sh "$1"` x_res=`echo $resolution | gawk -F x '{print $1}'` y_res=`echo $resolution | gawk -F x '{print $2}'` # If the rotation angle is odd times of 90 degrees swap x and y # resolutions of the image if [ $((($rot_angle / 90 % 2) == 1)) = 1 ]; then tmp_res=$x_res x_res=$y_res y_res=$tmp_res fi echo "Image resolution is ${x_res}x${y_res}" # Calculate the scaling factor of the image to fit to the screen if [ $((($x_res * 100 / $y_res) < ($screen_width * 100 / $screen_height))) = 1 ]; then # Scale the height of the image if [ $(($y_res > $screen_height)) = 1 ]; then zoom_factor=$(($screen_height * 100 / $y_res)) else zoom_factor=$(($y_res * 100 / $screen_height)) fi echo "Scaling in the y direction!" at_y=$screen_y at_x=$((($screen_width - $x_res * $zoom_factor / 100) / 2 + $screen_x)) else # Scale the width of the image if [ $(($x_res > $screen_width)) = 1 ]; then zoom_factor=$(($screen_width * 100 / $x_res)) else zoom_factor=$(($x_res * 100 / $screen_width)) fi echo "Scaling in the x direction!" at_x=$screen_x at_y=$((($screen_height - $y_res * $zoom_factor / 100) / 2 + $screen_y)) fi echo "Zoom factor is $zoom_factor" echo "Image location is $at_x,$at_y" rot_opt="" if [ $(($rot_angle != 0)) = 1 ]; then rot_opt="-rotate $rot_angle" fi xloadimage -fullscreen -onroot -border black -zoom $zoom_factor $rot_opt -at $at_x,$at_y "$1" else echo "Please provide an image!" exit 1 fi
其中,用于获取图片大小的脚本 get_img_size.sh 内容如下:
#!/bin/bash if [ -n "$1" ]; then identify "$1" | gawk '{if(match($0, /([[:digit:]]+)x([[:digit:]]+)/, res) != 0) print res[0];}' else echo "Please provide an image!" exit 1 fi
3 定时加载多张壁纸: set_multi_wallpapers.sh
通过 -s 选项,可以指定配置文件,其由该脚本读入后以默认的时间间隔60秒或由 -t 选项指定的时间间隔来逐个显示列表中的图片。配置文件的格式如下:
# Configuration file storing list of images to be loaded onto root screen as wallpapers. # Description of data columns (columns are separated by TAB): # Column 1: Absolute path to image # Column 2: Rotation angle applied to the image # Column 3: X position of the image to be loaded onto the root screen # Column 4: Y position of the image to be loaded onto the root screen /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/02 - wqQXJGJ.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/03 - jVKcv41.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/04 - wPpANVz.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/05 - yGQyrcX.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/07 - XaanvJe.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/08 - zl3dIFY.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/09 - VD7t2al.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/10 - GjUEn90.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/11 - qX58uOK.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/20 - 1QqFwJU.jpg 0 1280 0 /home/orlando/Pictures/wallpapers/Windows 10 wallpapers/Diver.jpg 0 1280 0
set_multi_wallpapers.sh 脚本内容如下:
#!/bin/bash script_name="set_multi_wallpapers.sh" script_usage=$(cat <<EOF $script_name [OPTION] EOF ) script_function=$(cat <<EOF This script is used to display a set of images onto root screen as wallpapers. EOF ) script_doc=$(cat <<EOF -h Display this help. -s Source file storing list of image paths and parameters. If this is not given, ~/.multi_wallpapers will be used. -t Time interval between each image. If this is not given, default interval is 60 seconds. -W Screen width. -H Screen height. EOF ) script_examples=$(cat <<EOF $script_name # Load images in ~/.multi_wallpapers as wallpapers with an interval of 60 seconds. $script_name -s /path/to/image_list_file -t 5 # Specify image list file and time interval. EOF ) state_prefix="===" warning_prefix="***" error_prefix="!!!" function display_help() { if [ -n "$script_usage" ]; then echo -e "Usage: $script_usage" fi if [ -n "$script_function" ]; then echo -e "$script_function" fi if [ -n "$script_doc" ] ; then echo -e "\n$script_doc" fi if [ -n "$script_examples" ]; then echo -e "\nExamples" echo -e "$script_examples" fi } # Default parameters image_source_file="/home/orlando/.multi_wallpapers" time_interval=60 screen_width=1920 screen_height=1080 # Process command options while getopts ":ht:s:W:H:" opt; do case $opt in h ) display_help exit 0 ;; s ) image_source_file=$OPTARG ;; t ) time_interval=$OPTARG ;; W ) screen_width=$OPTARG ;; H ) screen_height=$OPTARG ;; \? ) display_help exit 1 ;; esac done shift $(($OPTIND - 1)) # Start execute the command IFS=$'\n' if [ -e "$image_source_file" ]; then while [ 1 ]; do for image_info in `cat "$image_source_file" | grep "^[^#].*"`; do image_name=`echo "$image_info" | cut -f 1` rot_angle=`echo "$image_info" | cut -f 2` x_pos=`echo "$image_info" | cut -f 3` y_pos=`echo "$image_info" | cut -f 4` if [ -e "$image_name" ]; then set_wallpaper.sh -r "$rot_angle" -W "$screen_width" -H "$screen_height" -x "$x_pos" -y "$y_pos" "$image_name" else echo -e "$error_prefix Image $image_name does not exist!" fi sleep $time_interval done done else echo -e "$error_prefix Configuration file $image_source_file does not exist!" fi
4 生成多张壁纸配置文件: gen_multi_wallpapers.sh
该脚本可以在指定的目录下(第一个参数),根据指定的正则表达式(第二个参数)来搜索出匹配的图片文件,然后将其按上述配置文件的格式显示出来。脚本内容如下:
#!/bin/bash script_name="gen_multi_wallpapers.sh" script_usage=$(cat <<EOF $script_name [OPTION] path_name regex_pattern EOF ) script_function=$(cat <<EOF Generate configuration for a list of wallpaper images. EOF ) script_doc=$(cat <<EOF -h Display this help. -c Display the comment for configuration file. -x X position of the image to be loaded onto root screen. -y Y position of the image to be loaded onto root screen. EOF ) script_examples=$(cat <<EOF $script_name -x 1280 ./ "\\(.*jpg\\)\\|\\(.*JPG\\)" EOF ) state_prefix="===" warning_prefix="***" error_prefix="!!!" function display_help() { if [ -n "$script_usage" ]; then echo -e "Usage: $script_usage" fi if [ -n "$script_function" ]; then echo -e "$script_function" fi if [ -n "$script_doc" ] ; then echo -e "\n$script_doc" fi if [ -n "$script_examples" ]; then echo -e "\nExamples" echo -e "$script_examples" fi } # Default parameters x_pos=0 y_pos=0 comment_string=$(cat <<EOF # Configuration file storing list of images to be loaded onto root screen as wallpapers. # Description of data columns (columns are separated by TAB): # Column 1: Absolute path to image # Column 2: Rotation angle applied to the image # Column 3: X position of the image to be loaded onto the root screen # Column 4: Y position of the image to be loaded onto the root screen EOF ) is_display_comment=0 # Process command options while getopts ":chx:y:" opt; do case $opt in x ) x_pos=$OPTARG ;; y ) y_pos=$OPTARG ;; c ) is_display_comment=1 ;; h ) display_help exit 0 ;; \? ) display_help exit 1 ;; esac done shift $(($OPTIND - 1)) # Start execute the command if [ -n "$1" ] && [ -n "$2" ]; then if [ "$is_display_comment" = 1 ]; then echo -e "$comment_string\n" fi gawk_cmd=`echo "gawk '{print \\$0\"\\t0\\t$x_pos\\t$y_pos\"}'"` find "$1" -regex "$2" -print0 | xargs -n 1 -0 fullpath.sh | eval "$gawk_cmd" else echo "$error_prefix Please specify search path name and file name pattern!" fi
可以看出,该脚本又用到了 fullpath.sh ,用于显示图片文件的绝对路径。 fullpath.sh 的内容如下:
#!/bin/bash echo $(cd $(dirname "$1") && pwd -P)/$(basename "$1")
5 脚本的使用
至此,一切都准备就续,可以按下面的步骤来实战了:
首先,切换到包含自己喜欢图片的文件夹,执行下面的命令生成配置文件:
gen_multi_wallpapers.sh -c -x 1280 ./ "\\(.*jpg\\)\\|\\(.*JPG\\)" > ./.multi_wallpapers
接下来,将下面的命令加入到 ~/.xinitrc 中:
set_multi_wallpapers.sh -s ./.multi_wallpapers -t 300 &
最后,重启X server即可生效。截了一个视频在这里(不好意思,用的是微软最新发布的Windows 10壁纸)。