Refactor, add SystemD Journaling
This commit is contained in:
parent
c47bb3d4c6
commit
a864b85df1
|
@ -1,29 +1,32 @@
|
||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
# TODO: configure systemD logging
|
# TODO: add option to allow recursive sub-directories (in choose_image())
|
||||||
# TODO: refactor sloppy use of global variables
|
|
||||||
# TODO: clean up debugging output
|
|
||||||
# TODO: license, etc.
|
# TODO: license, etc.
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use POSIX;
|
use POSIX;
|
||||||
|
use File::Copy;
|
||||||
|
|
||||||
use lib "$ENV{HOME}/perl5/lib/perl5";
|
use lib "$ENV{HOME}/perl5/lib/perl5";
|
||||||
|
$ENV{PWD} = '/tmp' unless (defined($ENV{PWD}));
|
||||||
|
|
||||||
|
use constant ERROR => {
|
||||||
|
LOG_EMERG => 8,
|
||||||
|
LOG_ALERT => 7,
|
||||||
|
LOG_CRIT => 6,
|
||||||
|
LOG_ERR => 5,
|
||||||
|
LOG_WARNING => 4,
|
||||||
|
LOG_NOTICE => 3,
|
||||||
|
LOG_INFO => 2,
|
||||||
|
LOG_DEBUG => 1
|
||||||
|
};
|
||||||
|
|
||||||
our $debug = 1; # For testing, will output configuration and errors if true
|
|
||||||
our %settings;
|
|
||||||
our @e;
|
our @e;
|
||||||
our $pidfile = "/tmp/$ENV{USER}-wallpaper.pid";
|
|
||||||
|
|
||||||
use AnyEvent::Sway;
|
|
||||||
our $s = AnyEvent::Sway->new();
|
|
||||||
|
|
||||||
our $o = $s->get_outputs->recv();
|
|
||||||
die "No outputs detected.\n" unless (scalar(@$o));
|
|
||||||
|
|
||||||
sub usage()
|
sub usage()
|
||||||
{
|
{
|
||||||
|
my $self = shift;
|
||||||
print("$0 [output(s)] [-d|--daemon]\n
|
print("$0 [output(s)] [-d|--daemon]\n
|
||||||
Sets a wallpaper by cropping an appropriate sized section of a larger image.\n
|
Sets a wallpaper by cropping an appropriate sized section of a larger image.\n
|
||||||
All arguments other than the below are assumed to be output names, as defined
|
All arguments other than the below are assumed to be output names, as defined
|
||||||
|
@ -36,6 +39,9 @@ are currently enabled will be set.\n
|
||||||
each rotation, if provided (default: 300).\n
|
each rotation, if provided (default: 300).\n
|
||||||
--nocrop Don't crop a selection from the image. Instead, pass the whole
|
--nocrop Don't crop a selection from the image. Instead, pass the whole
|
||||||
-n image to swaybg and let it handle the scaling\n
|
-n image to swaybg and let it handle the scaling\n
|
||||||
|
--verbose=N Define minimum log level. Counting from 1: LOG_DEBUG, LOG_INFO,
|
||||||
|
-v N LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT, LOG_ALERT, LOG_EMERG
|
||||||
|
Default: 5; If provided without a value for N then all (1).
|
||||||
--help This menu
|
--help This menu
|
||||||
-h\n
|
-h\n
|
||||||
You can send SIGUSR1 to force the daemon to reload immediately. Rotation timer
|
You can send SIGUSR1 to force the daemon to reload immediately. Rotation timer
|
||||||
|
@ -43,45 +49,136 @@ will be reset.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub new
|
||||||
|
{
|
||||||
|
my ($class, %args) = @_;
|
||||||
|
|
||||||
|
use AnyEvent::Sway;
|
||||||
|
$args{ipc} = AnyEvent::Sway->new();
|
||||||
|
use Image::Magick;
|
||||||
|
$args{im} = Image::Magick->new();
|
||||||
|
$args{error} = ();
|
||||||
|
|
||||||
|
$args{pidfile} = "/tmp/$ENV{USER}-wallpaper.pid";
|
||||||
|
|
||||||
|
return bless { %args };
|
||||||
|
}
|
||||||
|
|
||||||
|
my $wp = new("Wallpapers");
|
||||||
|
|
||||||
|
if (-e $wp->{pidfile}) {
|
||||||
|
if (-r $wp->{pidfile}) {
|
||||||
|
if (open(my $fh, '<', $wp->{pidfile})) {
|
||||||
|
my $pid = <$fh>;
|
||||||
|
chomp($pid);
|
||||||
|
use Proc::ProcessTable;
|
||||||
|
my $pt = Proc::ProcessTable->new();
|
||||||
|
foreach my $p ( @{ $pt->table() } ) {
|
||||||
|
if ($p->{pid} eq $pid) {
|
||||||
|
my $name = $0;
|
||||||
|
$name =~ s/$ENV{PWD}//;
|
||||||
|
if ($p->{'cmndline'} =~ m#$name#) {
|
||||||
|
$wp->do_log("LOG_CRIT", "Another process is already running with PID: $pid (running and listed in $wp->{pidfile})");
|
||||||
|
# Die locally because do_log will remove pidfile that this iteration does not belong to
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
$wp->do_log("LOG_CRIT", "Found matching $pid with different cmdline: $p->{cmndline} (not $0)",1);
|
||||||
|
# PID in pidfile doesn't look like it is another wallpaper
|
||||||
|
unlink($wp->{pidfile});
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
return $p->{'pid'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$wp->do_log("LOG_CRIT", "Pidfile $wp->{pidfile} exists, but cannot be opened. Assuming it is running already.");
|
||||||
|
# Die locally because do_log will remove pidfile that this iteration does not belong to
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$wp->do_log("LOG_CRIT", "Pidfile $wp->{pidfile} exists, but is not readable. Assuming it is running already.");
|
||||||
|
# Die locally because do_log will remove pidfile that this iteration does not belong to
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# SIGUSR reset the timer, force immediate reload, continue looping
|
# SIGUSR reset the timer, force immediate reload, continue looping
|
||||||
$SIG{USR1} = sub {
|
$SIG{USR1} = sub {
|
||||||
alarm 0;
|
alarm 0;
|
||||||
run(%settings);
|
$wp->do_log("LOG_INFO", "Reloading due to SIGUSR1");
|
||||||
};
|
};
|
||||||
|
|
||||||
# SIGTERM reset the timer, clean pid, and allow for the main loop to finish run
|
# SIGTERM reset the timer, clean pid, and allow for the main loop to finish run
|
||||||
$SIG{TERM} = sub {
|
$SIG{TERM} = sub {
|
||||||
alarm 0;
|
$wp->do_log("LOG_INFO", "Going down clean due to SIGTERM");
|
||||||
clean();
|
clean($wp);
|
||||||
$settings{daemon} = 0;
|
$wp->{daemon} = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
# SIGKILL clean pid then exit immediately
|
# SIGKILL clean pid then exit immediately
|
||||||
$SIG{KILL} = sub {
|
$SIG{KILL} = sub {
|
||||||
clean();
|
$wp->do_log("LOG_INFO", "Hard kill with SIGKILL, attempting to remove pidfile");
|
||||||
|
clean($wp);
|
||||||
exit(0);
|
exit(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# simply returns the array of hashes provided by swaymsg
|
||||||
|
sub get_outputs
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
my $o = $self->{ipc}->get_outputs->recv() || $self->do_log('LOG_WARNING',"Failed to query 'get_outputs'");
|
||||||
|
die "No outputs detected.\n" unless (scalar(@$o) > 0);
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns the same as above but with the 'name' as a hash key for easier lookup
|
||||||
|
sub get_active
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
if (defined($self->{outputs}) && scalar($self->{outputs})) {
|
||||||
|
my %active = ();
|
||||||
|
foreach my $o (@{$self->{outputs}}) {
|
||||||
|
my $name;
|
||||||
|
my %details;
|
||||||
|
next unless ($o->{active});
|
||||||
|
$active{$o->{name}} = ();
|
||||||
|
foreach (keys(%$o)) {
|
||||||
|
$active{$o->{name}}->{$_} = $o->{$_} unless ($_ eq 'name');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$self->do_log('LOG_WARNING',"No outputs detected.") unless (scalar(keys(%active)));
|
||||||
|
return \%active;
|
||||||
|
} else {
|
||||||
|
print "You haven't initialized get_outputs";
|
||||||
|
$self->do_log('LOG_WARNING',"Output list not defined yet. Try 'get_outputs()' first");
|
||||||
|
return \{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub clean
|
sub clean
|
||||||
{
|
{
|
||||||
if (-e $pidfile) {
|
my $self = shift;
|
||||||
open (my $fh, '<', $pidfile);
|
if (-e $self->{pidfile}) {
|
||||||
|
open (my $fh, '<', $self->{pidfile});
|
||||||
my $p = <$fh>;
|
my $p = <$fh>;
|
||||||
close($fh);
|
close($fh);
|
||||||
chomp $p;
|
chomp $p;
|
||||||
kill($p);
|
kill($p);
|
||||||
unlink($pidfile);
|
unlink($self->{pidfile});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub choose_image
|
sub choose_image
|
||||||
{
|
{
|
||||||
my @w = glob("$settings{path}/*");
|
my $self = shift;
|
||||||
|
my @w = glob($self->{'path'}."/*");
|
||||||
return undef unless (scalar(@w));
|
return undef unless (scalar(@w));
|
||||||
|
$self->do_log("LOG_DEBUG", "Found ".scalar(@w)." files in $self->{path}");
|
||||||
|
|
||||||
my @i;
|
my @i;
|
||||||
foreach (@w) {
|
foreach (@w) {
|
||||||
if (-d "$settings{path}/$_") {
|
if (-d $_) {
|
||||||
|
$self->do_log("LOG_DEBUG", "Ignoring sub-directory $_");
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
if ($_ =~ m/\.(png|jpg)$/) {
|
if ($_ =~ m/\.(png|jpg)$/) {
|
||||||
|
@ -92,24 +189,9 @@ sub choose_image
|
||||||
return $i[rand(scalar(@i))] || return undef;
|
return $i[rand(scalar(@i))] || return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_size
|
|
||||||
{
|
|
||||||
my $target = shift;
|
|
||||||
foreach my $output (@$o) {
|
|
||||||
if ($output->{'name'} eq $target) {
|
|
||||||
return (
|
|
||||||
#$output->{'current_mode'}->{'width'},
|
|
||||||
#$output->{'current_mode'}->{'height'}
|
|
||||||
$output->{'rect'}->{'width'},
|
|
||||||
$output->{'rect'}->{'height'}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub crop
|
sub crop
|
||||||
{
|
{
|
||||||
|
my $self = shift;
|
||||||
my $image = shift;
|
my $image = shift;
|
||||||
my $ow = shift;
|
my $ow = shift;
|
||||||
my $oh = shift;
|
my $oh = shift;
|
||||||
|
@ -117,25 +199,21 @@ sub crop
|
||||||
my $cropped = $image;
|
my $cropped = $image;
|
||||||
$cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#;
|
$cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#;
|
||||||
|
|
||||||
|
#$image = "/tmp/Pharma-out.png.jpg";
|
||||||
use Image::Magick;
|
use Image::Magick;
|
||||||
my $im = Image::Magick->new();
|
my $im = Image::Magick->new();
|
||||||
|
die "$image is not readable" unless (-r $image);
|
||||||
$im->Read($image);
|
my $ret = $im->Read($image);
|
||||||
|
return 0 if ($ret);
|
||||||
my ($iw, $ih) = $im->Get("columns", "rows");
|
my ($iw, $ih) = $im->Get("columns", "rows");
|
||||||
|
$self->do_log("LOG_DEBUG", "Image has dimensions ${iw}x${ih}");
|
||||||
|
|
||||||
# Return full size if it is smaller in either dimension then the output
|
# Return full size if it is smaller in either dimension then the output
|
||||||
if ($iw <= $ow || $ih <= $oh) {
|
if ($iw <= $ow || $ih <= $oh) {
|
||||||
print "Not cropping $image because it is too small\n";
|
$self->do_log("LOG_DEBUG", "Not cropping because ${iw}x${ih} is smaller or equal to the output (${ow}x${oh}) in at least 1 dimension.");
|
||||||
$cropped =~ s#-cropped\.([^\.]+)$#\.$1#;
|
|
||||||
use File::Copy;
|
|
||||||
File::Copy::copy($image,$cropped);
|
|
||||||
return $cropped if (-e $cropped);
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Image size: $iw $ih\n";
|
|
||||||
print "output size: $ow $oh\n";
|
|
||||||
|
|
||||||
my ($x, $y);
|
my ($x, $y);
|
||||||
$x = int(rand($iw-$ow));
|
$x = int(rand($iw-$ow));
|
||||||
$y = int(rand($ih-$oh));
|
$y = int(rand($ih-$oh));
|
||||||
|
@ -149,76 +227,119 @@ sub crop
|
||||||
return $cropped if ( -e $cropped );
|
return $cropped if ( -e $cropped );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_active
|
|
||||||
{
|
|
||||||
my @targets;
|
|
||||||
foreach (@$o) {
|
|
||||||
push (@targets, $_->{name});
|
|
||||||
}
|
|
||||||
return @targets;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_background
|
sub set_background
|
||||||
{
|
{
|
||||||
|
my $self = shift;
|
||||||
my $target = shift || return "No target or image provided";
|
my $target = shift || return "No target or image provided";
|
||||||
my $cropped = shift || return "No image provided";
|
my $cropped = shift || return "No image provided";
|
||||||
# TODO get fallback from javascript
|
# TODO get fallback from javascript
|
||||||
my $cmd = "output $target background $cropped fill #000000";
|
my $cmd = "output $target background $cropped fill #000000";
|
||||||
print "Running $cmd\n";
|
$self->do_log("LOG_DEBUG", "Running $cmd\n");
|
||||||
my $ret = $s->message(0,$cmd)->recv;
|
my $ret = $self->{ipc}->message(0,$cmd)->recv;
|
||||||
if ($ret->[0]->{success}) {
|
if ($ret->[0]->{success}) {
|
||||||
print "Success!\n";
|
$self->do_log("LOG_DEBUG", "Success!");
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
return "Failed to run Sway IPC command '$cmd'";
|
return "Failed to run Sway IPC command '$cmd'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub do_log
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
my $level = shift;
|
||||||
|
my $msg = shift;
|
||||||
|
my $die = shift || 0;
|
||||||
|
my $min = $self->{verbose} || 5;
|
||||||
|
|
||||||
|
if ($self->{daemon}) {
|
||||||
|
use Log::Journald qw(send);
|
||||||
|
send(
|
||||||
|
PRIORITY => ERROR->{$level},
|
||||||
|
MESSAGE => $msg,
|
||||||
|
PERL_PACKAGE => 'Sway Wallpapers'
|
||||||
|
) || warn "Could not send log ($level $msg): $!";
|
||||||
|
if ($die) {
|
||||||
|
$msg = '(FATAL) ' . $msg;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ERROR->{$level} >= $min) {
|
||||||
|
printf("%11s %s\n", $level, $msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($die) {
|
||||||
|
$self->clean();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub run
|
sub run
|
||||||
{
|
{
|
||||||
my @err;
|
my $self = shift;
|
||||||
|
$self->do_log("LOG_DEBUG", "Fetching outputs from IPC");
|
||||||
|
$self->{outputs} = $self->get_outputs();
|
||||||
# Local copy of targets so that it will re-check active every time
|
# Local copy of targets so that it will re-check active every time
|
||||||
my @t = $settings{targets} if (defined($settings{targets}));
|
my @t = @{$self->{targets}} if (scalar(@{$self->{targets}}));
|
||||||
|
$self->do_log("LOG_DEBUG", "Removing inactive ouputs");
|
||||||
|
my $active = $self->get_active();
|
||||||
|
# If specific targets were not defined, use all active
|
||||||
unless (scalar(@t)) {
|
unless (scalar(@t)) {
|
||||||
@t = get_active();
|
@t = keys(%$active);
|
||||||
push(@err, "No target outputs") unless (scalar(@t));
|
push(@{$self->{error}}, "No target outputs") unless (scalar(@t));
|
||||||
}
|
}
|
||||||
foreach my $a (@t) {
|
$self->do_log("LOG_DEBUG", "Looping desired ouputs");
|
||||||
my $image = choose_image($settings{path});
|
foreach my $target (@t) {
|
||||||
if (defined($image)) {
|
$self->do_log("LOG_DEBUG", "Ensuring that desired output is active");
|
||||||
if ( -r "$image" ) {
|
unless (defined($active->{$target})) {
|
||||||
print "selected $image\n";
|
$self->do_log('LOG_DEBUG', "Target $target is not an active output");
|
||||||
my $cropped;
|
|
||||||
if ($settings{crop}) {
|
|
||||||
if ($settings{debug}) {
|
|
||||||
print "Cropping image for '$a' using '$image'\n";
|
|
||||||
}
|
|
||||||
my ($ow, $oh) = get_size($a);
|
|
||||||
$cropped = crop($image, $ow, $oh);
|
|
||||||
unless ($cropped) {
|
|
||||||
push(@err, "Failed to generate cropped image") unless ($cropped);
|
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
$self->do_log("LOG_DEBUG", "Selecting image for $target");
|
||||||
|
my $image = $self->choose_image();
|
||||||
|
if (defined($image)) {
|
||||||
|
$self->do_log('LOG_DEBUG', "Selected $image");
|
||||||
|
if ( -r "$image" ) {
|
||||||
|
my $cropped;
|
||||||
|
if ($self->{crop}) {
|
||||||
|
$self->do_log('LOG_DEBUG',"Cropping image for '$target' using '$image'");
|
||||||
|
$cropped = $self->crop(
|
||||||
|
$image,
|
||||||
|
$active->{$target}->{rect}->{width},
|
||||||
|
$active->{$target}->{rect}->{height}
|
||||||
|
);
|
||||||
|
if ($cropped) {
|
||||||
} else {
|
} else {
|
||||||
|
# Create a tmp copy since it will be deleted later
|
||||||
|
# If PWD is the wallpaper path, make the tmp in /tmp
|
||||||
|
if ($self->{path} eq $ENV{PWD}) {
|
||||||
|
$cropped = $image;
|
||||||
|
$cropped =~ s%$ENV{PWD}%/tmp%;
|
||||||
|
# Else make the tmp in PWD
|
||||||
|
} else {
|
||||||
|
$cropped = '/'.$image;
|
||||||
|
$cropped =~ s%.*/([^/+])%$ENV{PWD}/$1%;
|
||||||
|
}
|
||||||
|
$self->do_log('LOG_DEBUG',"Creating copy of original: $cropped");
|
||||||
|
File::Copy::copy($image,$cropped) || $self->do_log('LOG_WARNING',"Failed to copy to $cropped: $!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$self->do_log('LOG_DEBUG', "Cropping is disabled");
|
||||||
$cropped = $image;
|
$cropped = $image;
|
||||||
}
|
}
|
||||||
my $e = set_background($a,$cropped);
|
$self->set_background($target,$cropped);
|
||||||
push(@err, $e) if (defined($e));
|
if ($self->{crop}) {
|
||||||
if ($settings{crop}) {
|
$self->do_log('LOG_DEBUG', "Deleting $cropped");
|
||||||
print "Deleting $cropped\n";
|
# Give swaybg a second, otherwise the file will be missing before it ends
|
||||||
#unlink($cropped) || push(@err, "Failed to delete $cropped after setting: $!");
|
sleep(1);
|
||||||
|
unlink($cropped) || $self->do_log("LOG_WARNING", "Failed to delete $cropped after setting: $!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
push(@err, "$a: Unable to read image $image");
|
$self->do_log("LOG_WARNING", "Failed to read $image");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
push(@err, "$a: Unable to select image from $settings{path}");
|
$self->do_log("LOG_WARNING", "Failed to select image from $self->{path}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($settings{debug} && $settings{daemon}) {
|
|
||||||
print STDERR join("\n",@err);
|
|
||||||
} else {
|
|
||||||
@e = @err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -229,27 +350,39 @@ my $daemon;
|
||||||
my $delay;
|
my $delay;
|
||||||
my $crop;
|
my $crop;
|
||||||
my $path;
|
my $path;
|
||||||
|
my $verbose;
|
||||||
while (my $arg = shift(@ARGV)) {
|
while (my $arg = shift(@ARGV)) {
|
||||||
if ($arg eq '-h' || $arg eq '--help') {
|
if ($arg eq '-h' || $arg eq '--help') {
|
||||||
usage();
|
$wp->usage();
|
||||||
} elsif ($arg =~ m/^\-\-path=?(.+)$/) {
|
} elsif ($arg =~ m/^\-\-path=?(.+)$/) {
|
||||||
die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path);
|
die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path);
|
||||||
$path = $1;
|
$path = $1;
|
||||||
} elsif ($arg eq '-p') {
|
} elsif ($arg eq '-p') {
|
||||||
die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path);
|
die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path);
|
||||||
$path = shift(@ARGV);
|
$path = shift(@ARGV);
|
||||||
} elsif ($arg =~ m/^\-\-daemon=?(.+)$/) {
|
} elsif ($arg =~ m/^\-\-daemon=?(.+)?$/) {
|
||||||
die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon);
|
die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon);
|
||||||
$delay = $1;
|
$delay = $1 || 300;
|
||||||
$daemon = 1;
|
$daemon = 1;
|
||||||
} elsif ($arg eq '-d') {
|
} elsif ($arg eq '-d') {
|
||||||
die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon);
|
die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon);
|
||||||
if ($ARGV[0] =~ m/^\d+$/) {
|
if (scalar(@ARGV) && $ARGV[0] =~ m/^\d+$/) {
|
||||||
$delay = shift(@ARGV);
|
$delay = shift(@ARGV);
|
||||||
}
|
}
|
||||||
$daemon = 1;
|
$daemon = 1;
|
||||||
} elsif ($arg eq '--nocrop' || $arg eq '-') {
|
} elsif ($arg eq '--nocrop' || $arg eq '-n') {
|
||||||
die "Redundant argument '$arg'. No-crop already set.\n" unless ($crop);
|
die "Redundant argument '$arg'. No-crop already set.\n" if (defined($crop));
|
||||||
|
$crop = 0;
|
||||||
|
} elsif ($arg =~ m/^\-\-verbose=?(.+)?$/) {
|
||||||
|
die "Redundant argument '$arg'. Verbosity already set.\n" if ($verbose);
|
||||||
|
$verbose = $1 || 1;
|
||||||
|
} elsif ($arg eq '-p') {
|
||||||
|
die "Redundant argument '$arg'. Verbosity already set.\n" if ($verbose);
|
||||||
|
if (scalar(@ARGV) && $ARGV[0] =~ m/^\d$/) {
|
||||||
|
$verbose = shift(@ARGV);
|
||||||
|
}
|
||||||
|
} elsif ($arg =~ m/^-/) {
|
||||||
|
die "Unrecognized argument: $arg\n";
|
||||||
} else {
|
} else {
|
||||||
push(@targets,$arg);
|
push(@targets,$arg);
|
||||||
}
|
}
|
||||||
|
@ -259,51 +392,41 @@ while (my $arg = shift(@ARGV)) {
|
||||||
# Validate arguments
|
# Validate arguments
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
$wp->do_log("LOG_DEBUG", "Validating arguments");
|
||||||
die "Invalid rotation delay: $delay" if (defined($delay) && $delay !~ m/^\d+$/);
|
die "Invalid rotation delay: $delay" if (defined($delay) && $delay !~ m/^\d+$/);
|
||||||
|
|
||||||
die "Invalid wallpaper path '$path'. Not a directory." if (defined($path) && !-d $path);
|
die "Invalid wallpaper path '$path'. Not a directory." if (defined($path) && !-d $path);
|
||||||
|
die "Invalid verbosity level: '$verbose'\n" if (defined($verbose) && $verbose =~ m/^[1-8]$/);
|
||||||
|
|
||||||
if (scalar(@targets)) {
|
$wp->do_log("LOG_DEBUG", "Configuring object");
|
||||||
my @kept;
|
$wp->{targets} = \@targets || undef;
|
||||||
foreach my $t (@targets) {
|
$wp->{daemon} = $daemon || 0;
|
||||||
my $hit = 0;
|
$wp->{path} = $path || "$ENV{HOME}/wallpapers";
|
||||||
foreach (@$o) {
|
$wp->{crop} = $crop || 1;
|
||||||
if ($_->{name} eq $t) {
|
$wp->{delay} = $delay || 300;
|
||||||
push(@kept, $t);
|
$wp->{verbose} = $verbose || 0;
|
||||||
$hit++;
|
$wp->{error} = [];
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print STDERR "Requested output '$t' not found\n" unless ($hit);
|
|
||||||
}
|
|
||||||
die "None of the requested outputs are active" unless (scalar(@kept));
|
|
||||||
@targets = @kept;
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings{targets} = @targets || undef;
|
|
||||||
$settings{daemon} = $daemon || 0;
|
|
||||||
$settings{path} = $path || "$ENV{HOME}/wallpapers";
|
|
||||||
$settings{crop} = $crop || 1;
|
|
||||||
$settings{delay} = $delay || 300;
|
|
||||||
$settings{debug} = $debug || 0;
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# For if daemonized
|
# Fork if daemonized
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
if ($settings{daemon}) {
|
if ($wp->{daemon}) {
|
||||||
|
$wp->do_log("LOG_DEBUG", "Forking daemon");
|
||||||
my $p = fork();
|
my $p = fork();
|
||||||
if ($p) {
|
if ($p) {
|
||||||
if (open(my $fh, ">", $pidfile)) {
|
$wp->do_log("LOG_DEBUG", "Writing PID ($p) to pidfile ($wp->{pidfile})");
|
||||||
print $fh "$p" || die "Failed to write pid ($p) to pidfile $pidfile";
|
if (open(my $fh, ">", $wp->{pidfile})) {
|
||||||
|
print $fh "$p" || die "Failed to write pid ($p) to pidfile ".$wp->{pidfile};
|
||||||
close($fh);
|
close($fh);
|
||||||
} else {
|
} else {
|
||||||
print "Failed to open pidfile: $pidfile: $!\n";
|
print "Failed to open pidfile ".$wp->{pidfile}.": $!\n";
|
||||||
}
|
}
|
||||||
|
# Short delay necessary for SystemD to find PID
|
||||||
|
sleep(1);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
#setpgrp;
|
$wp->do_log("LOG_DEBUG", "Daemon running");
|
||||||
#setsid;
|
setpgrp(0, 0);
|
||||||
umask 0;
|
umask 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,31 +434,24 @@ if ($settings{daemon}) {
|
||||||
# Main
|
# Main
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
my $first = 1;
|
||||||
do {
|
do {
|
||||||
run(%settings);
|
$wp->do_log("LOG_INFO", "Reloading wallpaper") unless ($first);
|
||||||
if ($settings{daemon}) {
|
$wp->run();
|
||||||
|
if ($wp->{daemon}) {
|
||||||
my $normal = "reload wallpaper";
|
my $normal = "reload wallpaper";
|
||||||
eval {
|
eval {
|
||||||
$SIG{ALRM} = sub { print "$normal\n" };
|
$SIG{ALRM} = sub { return "$normal" };
|
||||||
alarm $settings{delay};
|
alarm $wp->{delay};
|
||||||
POSIX::pause();
|
POSIX::pause();
|
||||||
alarm 0;
|
alarm 0;
|
||||||
};
|
};
|
||||||
if ($@ && $@ !~ quotemeta($normal)) {
|
$wp->do_log("LOG_WARNING", "Reload failed: $@") if ($@ && $@ !~ quotemeta($normal));
|
||||||
if ($settings{debug}) {
|
|
||||||
print $normal;
|
|
||||||
}
|
}
|
||||||
}
|
$first = 0 if ($first);
|
||||||
}
|
} while ($wp->{daemon});
|
||||||
} while ($settings{daemon});
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# If we made it to here, it was not daemonized. Output errors and exit
|
# If we made it to here, it was not daemonized. Output errors and exit
|
||||||
################################################################################
|
$wp->do_log("LOG_DEBUG", "Finishing") unless ($wp->{daemon});
|
||||||
|
|
||||||
if (scalar(@e)) {
|
|
||||||
die "Failure while not running as daemon:\n" .
|
|
||||||
join("\n",@e);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
Loading…
Reference in New Issue