#!/usr/bin/perl
#
# random_wallpaper.pl
#
# Copyright (C) 2009 Nathan Shafer
#
# This program is free software; you can redistribute it and/or              *
# modify it under the terms of the GNU General Public License                *
# as published by the Free Software Foundation; either version 2             *
# of the License, or (at your option) any later version.                     *
#                                                                            *
# This program is distributed in the hope that it will be useful,            *
# but WITHOUT ANY WARRANTY; without even the implied warranty of             *
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
# GNU General Public License for more details.                               *
#                                                                            *
# You should have received a copy of the GNU General Public License          *
# along with this program; if not, write to the Free Software                *
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.*
#
# ------------------------------------------------------------------------------
# Description
# ------------------------------------------------------------------------------
# This script will randomly change Gnome's wallpaper.  It supports a single
# monitor or multiple monitors by stitching together different wallpapers for
# each screen.  Simply configure a few options below then run this script.
#
# Here are a few notes for multiple monitors:
# - The monitors can be stacked vertically or set up horizontally side by side,
#   but no other physical setups are supported.  The reason is that we're
#   creating one big image to make this work, so the image has to be a rectangle.
#   So for example, with 2 monitors of 1600x1200, the script creates an image
#   that is 3200x1200 in size for a horizontal layout.  A vertical layout would
#   create 1600x2400.
# - If you have mismatched resolution sizes, we will create the image based on
#   the smallest resolution of the monitors.  So for example, a 1600x1200 next
#   to a 1024x768 will result in an image of (horizontally) 2048x768.  I don't
#   know what will happen if it creates the image at the max resolution of the
#   monitors... I don't have mismatched resolutions.  If someone wants to test
#   the two options and tell me which is better, I would appreciate it.
#
# ------------------------------------------------------------------------------
# Requirements
# ------------------------------------------------------------------------------
# This script was developed and tested on linux.  Other OSes will probably work
#
# It requires Perl of course.
#
# It also only works with Gnome
#
# This script requires you have PerlMagick installed.  This can be installed
# from CPAN, but on debian based linux distros, you can install it with
#   sudo apt-get install perlmagick
# and on redhat based linux distros, this should work:
#   sudo yum install ImageMagick-perl
#
# ------------------------------------------------------------------------------
# Installation
# ------------------------------------------------------------------------------
# Simply put the script somewhere and execute it.
#
# This script works really well as a startup item to change your wallpaper
# every time you log in, or as a cron to change it on a set schedule.  For
# example, edit your crontab with "crontab -e" and put this in it:
#
#   */30 * * * * /path/to/random_wallpaper.pl
#
# That will change it every 30 minutes.  Change the 30 to whatever interval you want
#

use strict;
use Image::Magick;
use vars qw($x);

################################################################################
# OPTIONS
################################################################################

# This is an array of arrays, each being the dimensions of each of your
# monitors.  List each monitor's resolution on its own line like the example
# below.  You can have as many screens listed as you want, as long as they are
# all in a straight line.  So either all horizontal or all vertical.
my @screens = (
  ['1600', '1200'], # Left monitor
  ['1600', '1200'], # Right monitor
);

# Specify the orientation of your monitors as either "horizontal" or "vertical"
my $orientation = "horizontal";

# Add the full path to each directory you want to pull images from randomly
my @wallpaper_dirs = (
  '/home/nicodemus/wallpapers',
);

# Specify the file to output the final image to
my $output_file = "/tmp/change_wallpaper_output.jpg";

# Turn debugging on or off with either 1 or 0
my $debug = 0;


################################################################################
# END CONFIG - DO NOT EDIT ANYTHING BEYOND THIS UNLESS YOU KNOW WHAT YOU'RE DOING
################################################################################

# Load the list of possible wallpapers into memory
my @wallpapers;
foreach my $dir (@wallpaper_dirs) {
  opendir(DIR, $dir) or die("Could not open directory $dir: $!\n");
  while(my $file = readdir DIR) {
    next if $file =~ /^\./;
    if($file =~ /.jpg|.jpeg|.png|.bmp$/i) {
      push(@wallpapers, "$dir/$file");
    } else {
      print "invalid file in $dir: $file\n" if $debug;
    }
  }
}

# Fetch a random wallpaper for each screen
my @selected_wallpapers;
foreach (@screens) {
  push(@selected_wallpapers, $wallpapers[int(rand(@wallpapers))]);
}

print "selected: @selected_wallpapers\n" if $debug;

# figure out our target tile orientation and minimum screen size
my $rows  = 0;
my $columns = 0;
my $tile_width  = 1_000_000;
my $tile_height = 1_000_000;
foreach my $screen (@screens) {
  if($orientation eq 'vertical') {
    $columns = 1;
    $rows++;
  } else {
    $columns++;
    $rows = 1;
  }
  if($screen->[0] < $tile_width || $screen->[1] < $tile_height) {
    $tile_width = $screen->[0];
    $tile_height = $screen->[1];
  }
}

print "Target layout: $rows x $columns\n" if $debug;

# Now load the selected wallpapers
my $input = new Image::Magick();
$x = $input->Read(@selected_wallpapers);
warn($x) if $x;

# Get the size of the input images
for ($x = 0; $input->[$x]; $x++) {
  print "image $x geometry: " . $input->[$x]->Get('width') . 'x' . $input->[$x]->Get('height') . "\n" if $debug;
}

# Create the output file as a "Montage" of the input files
my $output = $input->Montage(geometry=>"${tile_width}x${tile_height}", background=>"black", tile=>"${columns}x${rows}");

# Get the output geometry
print "Output geometry: " . $output->Get('width') . 'x' . $output->Get('height') . "\n" if $debug;

# Write it
$x = $output->Write($output_file);
warn($x) if $x;

# Now tell Gnome to change the wallpaper
system("/usr/bin/gconftool-2 --type string --set /desktop/gnome/background/picture_filename $output_file");