55f2d029742ebea21bf8519b3644cc117803e42b
[clearscm.git] / bin / setbg
1 #!/usr/bin/perl
2
3 =pod
4
5 =head1 NAME $RCSfile: setbg,v $
6
7 Set background
8
9 =head1 VERSION
10
11 =over
12
13 =item Author
14
15 Andrew DeFaria <Andrew@ClearSCM.com>
16
17 =item Revision:
18
19 $Revision: 1.10 $
20
21 =item Created:
22
23 Fri Mar 18 01:14:38 PST 2005
24
25 =item Modified:
26
27 $Date: 2012/11/09 15:31:30 $
28
29 =back
30
31 =head1 SYNOPSIS
32
33  Usage: setbg [-u|sage] [-h|elp] [-ve|rbose] [-d|ebug] [-s|leep <n>]
34               [-bgdirs <bgdir> -bgdirs ...]
35  
36  Where:
37
38  -u|sage:      Displays this usage
39  -h|elp:       Display full help
40  -ve|rbose:    Be verbose
41  -d|ebug:      Output debug messages
42
43  -s|leep:      Number of minutes to sleep between setting the background
44                (Default: 1 hour)
45  -l|ockscreen: Change lockscreen backround (Default: False)
46  -b|gdirs:     Directories to scan for images
47
48 =head1 DESCRIPTION
49
50 This script sets the background image randomly based on images found in bgdirs.
51 Note if this script is run again it senses that it was previously run and sends
52 the previous script a SIGUSR2 which the script intrprets as "Change the
53 background now", then exits.
54
55 Data is written to the following files:
56
57  ~/.setbg:      Contains the filename of the current background image
58  ~/.setbg.hist  Contains a history of all images displayed for this run
59  ~/.setbg.stats Contains statistical information for the current run
60
61 Also note that this script will process a SIGUSR1 to mean "re-evaluate the
62 contents of the bgdirs incase it has changed and display a new image". This is
63 useful for script to be able to alert setbg that something has changed. For
64 example, a script named rmbg might look at ~/.setbg to get the name of the
65 current background image file and remove it then signal setbg with SIGUSR1 to
66 have it re-evaluate the state of bgdirs. 
67
68 Finally setbg will perform the this re-evaluation at midnight everyday. This is
69 useful because we point setbg to look at -bgdirs from Dropbox where Camera 
70 Uploads is included and new pictures can arrive everyday.
71
72 =cut
73
74 use strict;
75 use warnings;
76
77 use FindBin;
78 use Getopt::Long;
79 use Proc::ProcessTable;
80 use File::Spec;
81 use CGI qw/:standard/;
82
83 use lib "$FindBin::Bin/../lib";
84
85 use Pod::Usage;
86
87 use DateUtils;
88 use Display;
89 use Logger;
90 use Utils;
91
92 my $VERSION  = '$Revision: 1.12 $';
93   ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
94
95 my $processes = Proc::ProcessTable->new;
96 my %opts = (
97   sleep      => 60,
98   lockscreen => 0,
99   usage      => sub { pod2usage },
100   help       => sub { pod2usage (-verbose => 2)},
101   verbose    => sub { set_verbose },
102   debug      => sub { set_debug },
103 );
104
105 my %totals;
106
107 sub displayStats () {
108   my $statsFile = Logger->new(
109     name      => ".$FindBin::Script.stats",
110     path      => $ENV{HOME},
111     extension => '',
112   );
113
114   $statsFile->log('At ' . localtime());
115   $statsFile->log('Sleep: ' . $opts{sleep});
116   $statsFile->log('Image directories:');
117
118   for (my $i = 0; $i < scalar @{$opts{bgdirs}}; $i++) {
119     $statsFile->log("\t$opts{bgdirs}[$i]: $opts{bgdircnt}[$i]")
120   } # for
121
122   Stats \%totals, $statsFile;
123
124   return;
125 } # displayStats
126
127 sub fillPictures () {
128   my @images;
129
130   $totals{bgdirs} = 0;
131
132   for (@{$opts{bgdirs}}) {
133     my ($status, @pics) = Execute "find \"$_\" -type f";
134
135     chomp @pics;
136
137     push @images, grep(/jpg$|png$|gif$/i, @pics);
138
139     push @{$opts{bgdircnt}}, scalar @pics;
140
141     $totals{bgdirs}++;
142   } # for
143
144   $totals{images} = scalar @images;
145
146   return @images;
147 } # fillPictures
148
149 sub updateSetBG ($$) {
150   my ($bgimage, $lockimage) = @_;
151
152   open my $setbg, '>', "$ENV{HOME}/.$FindBin::Script"
153     or error "Unable to open $ENV{HOME}/.$FindBin::Script for writing - $!", 1;
154
155   display $bgimage, $setbg;
156
157   close $setbg;
158
159   my $msg  = localtime() . ":$bgimage";
160      $msg .= " lock:$lockimage" if $opts{lockscreen};
161
162   open my $hist, '>>', "$ENV{HOME}/.$FindBin::Script.hist"
163     or error "Unable to open $ENV{HOME}/.$FindBin::Script.hist for append - $!", 1;
164
165   display $msg, $hist;
166
167   close $hist;
168
169   return;
170 } # updateSetBG
171
172 sub SwitchWallPaper {
173   # We don't need to do anything here, just handle the interrupt and
174   # let the while loop continue.
175   debug 'SwitchWallPaper: Interrupt received';
176   displayStats;
177
178   return;
179 } # SwitchWallPaper
180
181 ## Main
182 verbose "$FindBin::Script v$VERSION";
183
184 my @argvCopy = @ARGV;
185
186 GetOptions (
187   \%opts,
188   'usage',
189   'help',
190   'verbose',
191   'debug',
192   'sleep=i',
193   'lockscreen',
194   'bgdirs=s@',
195 ) || Usage;
196
197 local $0 = "$FindBin::Script " . join ' ', @argvCopy;
198
199 for my $process (@{$processes->table}) {
200   if ($process->cmndline =~ /setbg/ and
201       $process->pid != $$) { 
202     kill 12, $process->pid;
203
204     exit 0;
205   } # if
206 } # for
207
208 for (my $i = 0; $i < scalar @{$opts{bgdirs}}; $i++) {
209   error "$opts{bgdirs}[$i] is not a directory", 1 unless -d $opts{bgdirs}[$i];
210
211   $opts{bgdirs}[$i] = File::Spec->rel2abs ($opts{bgdirs}[$i]);
212 } # for
213
214 # Using gsettings
215 my $setbg       = "gsettings";
216 my $setbgOpts   = "set org.gnome.desktop.background picture-uri \"file://";
217 my $setLockOpts = "set org.gnome.desktop.screensaver picture-uri \"file://";
218
219 my @images = fillPictures;
220
221 Usage "No images to display. Must specify -bgdirs" unless @images;
222
223 $SIG{USR2} = \&SwitchWallPaper;
224 $SIG{USR1} = \&fillPictures;
225
226 my $debugger = $DB::OUT;
227 my $today;
228
229 truncate "$ENV{HOME}/.$FindBin::Script.hist", 0;
230
231 EnterDaemonMode unless defined $DB::OUT;
232
233 while () {
234   my $bgimage   = escapeHTML ($images[int (rand $#images)]);
235   my $lockimage = escapeHTML ($images[int (rand $#images)]);
236
237   my $monitorIsOn;
238
239   my ($status, @output) = Execute("xset q | grep Monitor | awk '{print \$3}'");
240
241   next if $status or $output[0] eq 'Off';
242
243   my $cmd = "$setbg $setbgOpts$bgimage\" 2> /dev/null";
244
245   ($status, @output) = Execute $cmd;
246
247   if ($status) {
248     error "Trying to set background - command used \"$cmd\"\n\nOutput\n\n" . 
249       join "\n", @output;
250     $totals{errors}++;
251   } else {
252     $totals{'Images displayed'}++;
253   } # if
254
255   if ($opts{lockscreen}) {
256     $cmd = "$setbg $setLockOpts$lockimage\" 2> /dev/null";
257
258     ($status, @output) = Execute $cmd;
259
260     if ($status != 0) {
261       error "Trying to set lock screen - command used \"$cmd\"\n\nOutput\n\n" .
262         join "\n", @output;
263       $totals{errors}++;
264     } else {
265       $totals{'Lock screens displayed'}++;
266     } # if
267   } # if
268
269   updateSetBG $bgimage, $lockimage;
270
271   displayStats;
272
273   $today = YMD;
274
275   sleep $opts{sleep} * 60;
276
277   if ($today ne YMD){
278     @images = fillPictures;
279
280     displayStats;
281   } # if
282 } # while