package App::XScreenSaver::DBus::Saver;
use Moo;
use experimental 'signatures';
use curry;
use Log::Any;
use Try::Tiny;
use App::XScreenSaver::DBus::SaverProxy;
has reactor => ( is => 'ro', required => 1 );
has bus => ( is => 'lazy', builder => sub { Net::DBus->session() } );
has dbus_srv => (
is => 'lazy',
builder => sub { shift->bus->get_service('org.freedesktop.DBus') },
);
has dbus_obj => (
is => 'lazy',
builder => sub { shift->dbus_srv->get_object('/org/freedesktop/DBus') },
);
has service => (
is => 'lazy',
builder => sub {
shift->bus->export_service('org.freedesktop.ScreenSaver');
},
);
has paths => (
is => 'ro',
default => sub { [qw(/ScreenSaver /org/freedesktop/ScreenSaver)] },
);
has log => ( is => 'lazy', builder => sub { Log::Any->get_logger } );
has _impls => ( is => 'rw' );
has _prod_id => ( is => 'rw' );
has _inhibits => ( is => 'rw', default => sub { +{} } );
sub start($self) {
my $inhibit_cb = $self->curry::weak::inhibit;
my $uninhibit_cb = $self->curry::weak::uninhibit;
$self->_impls([ map {
App::XScreenSaver::DBus::SaverProxy->new(
$self->service,
$_,
$inhibit_cb,
$uninhibit_cb,
)
} $self->paths->@* ]);
$self->_prod_id(
$self->reactor->add_timeout(
60_000,
Net::DBus::Callback->new(
method => $self->curry::weak::prod_screensaver
),
0,
),
);
$self->dbus_obj->connect_to_signal(
'NameOwnerChanged',
$self->curry::weak::name_owner_changed,
);
return;
}
sub inhibit($self,$name,$reason,$message) {
my $cookie;
do {
$cookie = int(rand(2**31))
} until !exists $self->_inhibits->{$cookie};
my $sender = $message->get_sender;
$self->_inhibits->{$cookie} = [ $name, $reason, $sender ];
$self->log->debugf(
'<%s> (%s) stops screensaver for <%s> (cookie %d) - %d active',
$name, $sender, $reason, $cookie, scalar(keys $self->_inhibits->%*),
);
$self->reactor->toggle_timeout($self->_prod_id, 1);
return $cookie;
}
sub uninhibit($self,$cookie,$message) {
my $inhibit = delete $self->_inhibits->{$cookie}
or return;
my ($name, $reason, $sender) = @$inhibit;
my $this_sender = $message->get_sender;
$self->log->debugf(
'<%s> (was %s, is %s) resumed screensaver for <%s> (cookie %d) - %d left',
$name, $sender, $this_sender, $reason, $cookie, scalar(keys $self->_inhibits->%*),
);
$self->reactor->toggle_timeout($self->_prod_id, 0)
unless $self->_inhibits->%*;
return;
}
sub name_owner_changed($self,$bus_name,$old,$new) {
$self->log->tracef('<%s> changed from <%s> to <%s>',
$bus_name, $old, $new);
for my $cookie (sort keys $self->_inhibits->%*) {
my ($name, $reason, $sender) = @{$self->_inhibits->{$cookie}};
next unless $sender && $sender eq $bus_name;
next unless $old && !$new;
my $inhibit = delete $self->_inhibits->{$cookie};
$self->log->debugf(
'<%s> (%s) disconnected from the bus (it stopped screensaver for <%s>, cookie %d) - %d left',
$name, $bus_name, $reason, $cookie, scalar(keys $self->_inhibits->%*),
);
}
unless ($self->_inhibits->%*) {
$self->reactor->toggle_timeout($self->_prod_id, 0);
}
}
sub prod_screensaver($self) {
$self->log->debug('prodding xscreensaver');
system(qw(xscreensaver-command -deactivate));
}
1;