Obtain sleep inhibitor again after every sleep

- There is a PrepareForSleep signal before and after every sleep event.
The expectation is that before sleep, gajim cleans up and then releases
the sleep inhibitor. Accordingly, we must reacquire the inhibitor after
sleeping, which can helpfully be done with the other signal.

- Moved module to the dbus folder

- Embed logic in a LogindListener object so we can import the module
without listening to dbus
This commit is contained in:
Matthew W. S. Bell 2018-09-21 05:16:41 +01:00 committed by Philipp Hörist
parent 7bb4d07d2e
commit 698ae2a31e
3 changed files with 137 additions and 117 deletions

135
gajim/common/dbus/logind.py Normal file
View File

@ -0,0 +1,135 @@
# Copyright (C) 2014 Kamil Paral <kamil.paral AT gmail.com>
#
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
'''
Watch for system sleep using systemd-logind.
Documentation: http://www.freedesktop.org/wiki/Software/systemd/inhibit
'''
import os
import logging
from gi.repository import Gio
from gi.repository import GLib
from gajim.common import app
from gajim.common.i18n import _
log = logging.getLogger('gajim.c.dbus.logind')
class LogindListener:
_instance = None
@classmethod
def get(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance
def __init__(self):
# file descriptor object of the inhibitor
self._inhibit_fd = None
Gio.bus_watch_name(
Gio.BusType.SYSTEM,
'org.freedesktop.login1',
Gio.BusNameWatcherFlags.NONE,
self._on_appear_logind,
self._on_vanish_logind)
def _on_prepare_for_sleep(self, connection, _sender_name, _object_path,
interface_name, signal_name, parameters,
*_user_data):
'''Signal handler for PrepareForSleep event'''
log.debug('Received signal %s.%s%s', interface_name, signal_name, parameters)
before = parameters[0] # Signal is either before or after sleep occurs
if before:
warn = self._inhibit_fd is None
log.log(
logging.WARNING if warn else logging.INFO,
'Preparing for sleep by disconnecting from network%s',
', without holding a sleep inhibitor' if warn else '')
for name, conn in app.connections.items():
if app.account_is_connected(name):
conn.old_show = app.SHOW_LIST[conn.connected]
st = conn.status
conn.change_status('offline', _('Machine is going to sleep'))
conn.status = st
conn.time_to_reconnect = 5
self._disinhibit_sleep()
else:
self._inhibit_sleep(connection)
for conn in app.connections.values():
if conn.connected <= 0 and conn.time_to_reconnect:
conn.reconnect()
def _inhibit_sleep(self, connection):
'''Obtain a sleep delay inhibitor from logind'''
if self._inhibit_fd is not None:
# Something is wrong, we have an inhibitor fd, and we are asking for
# yet another one.
log.warning('Trying to obtain a sleep inhibitor '
'while already holding one.')
ret, ret_fdlist = connection.call_with_unix_fd_list_sync(
'org.freedesktop.login1',
'/org/freedesktop/login1',
'org.freedesktop.login1.Manager',
'Inhibit',
GLib.Variant('(ssss)', (
'sleep', 'org.gajim.Gajim', _('Disconnect from the network'),
'delay' # Inhibitor will delay but not block sleep
)),
GLib.VariantType.new('(h)'),
Gio.DBusCallFlags.NONE, -1, None, None)
log.info('Inhibit sleep')
self._inhibit_fd = ret_fdlist.get(ret.unpack()[0])
def _disinhibit_sleep(self):
'''Relinquish our sleep delay inhibitor'''
if self._inhibit_fd is not None:
os.close(self._inhibit_fd)
self._inhibit_fd = None
log.info('Disinhibit sleep')
def _on_appear_logind(self, connection, name, name_owner, *_user_data):
'''Use signal and locks provided by org.freedesktop.login1'''
log.info('Name %s appeared, owned by %s', name, name_owner)
connection.signal_subscribe(
'org.freedesktop.login1',
'org.freedesktop.login1.Manager',
'PrepareForSleep',
'/org/freedesktop/login1',
None,
Gio.DBusSignalFlags.NONE,
self._on_prepare_for_sleep,
None)
self._inhibit_sleep(connection)
def _on_vanish_logind(self, _connection, name, *_user_data):
'''Release remaining resources related to org.freedesktop.login1'''
log.info('Name %s vanished', name)
self._disinhibit_sleep()
def enable():
LogindListener.get()

View File

@ -59,6 +59,7 @@ from gajim.common import events
from gajim.common.dbus import screensaver from gajim.common.dbus import screensaver
from gajim.common.dbus import location from gajim.common.dbus import location
from gajim.common.dbus import music_track from gajim.common.dbus import music_track
from gajim.common.dbus import logind
from gajim import gtkgui_helpers from gajim import gtkgui_helpers
from gajim import gui_menu_builder from gajim import gui_menu_builder
@ -2723,7 +2724,7 @@ class Interface:
# Handle screensaver # Handle screensaver
if sys.platform == 'linux': if sys.platform == 'linux':
from gajim import logind_listener # pylint: disable=unused-variable logind.enable()
screensaver.enable() screensaver.enable()
self.show_vcard_when_connect = [] self.show_vcard_when_connect = []

View File

@ -1,116 +0,0 @@
# Copyright (C) 2014 Kamil Paral <kamil.paral AT gmail.com>
#
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
'''
Watch for system suspend using systemd-logind.
Documentation: http://www.freedesktop.org/wiki/Software/systemd/inhibit
'''
import os
import logging
from gi.repository import Gio, GLib
from gajim.common import app
from gajim.common.i18n import _
log = logging.getLogger('gajim.logind_listener')
# file descriptor of the inhibitor; negative number means we don't
# hold any (yet)
fd = None
def signal_received(connection, sender_name, object_path,
interface_name, signal_name, parameters, *user_data):
'''Signal handler for suspend event'''
global fd
log.info('Signal received: %s - %s', interface_name, parameters)
# signal is sent right before (with the parameter True) and after
# (with the parameter False) the system goes down for suspend/hibernate
if not parameters[0]:
return
# we're going for suspend, let's disconnect
log.debug('System suspend detected, disconnecting from network…')
for name, conn in app.connections.items():
if app.account_is_connected(name):
conn.old_show = app.SHOW_LIST[conn.connected]
st = conn.status
conn.change_status('offline', _('Machine is going to sleep'))
conn.status = st
conn.time_to_reconnect = 5
# close the file descriptor and let the computer suspend
if fd is not None:
os.close(fd)
fd = None
else:
# something is wrong, the system is suspending but we don't have
# a lock file
log.warning("System suspend detected, but we don't seem to be holding "
"a file descriptor for sleep inhibitor")
def get_inhibitor(connection):
'''Ask for a suspend delay inhibitor'''
global fd
if fd is not None:
# something is wrong, we haven't closed the previous file descriptor
# and we ask for yet another one
log.warning('We are about to ask for a sleep inhibitor, but we seem '
'to be holding one already')
ret = connection.call_with_unix_fd_list_sync(
'org.freedesktop.login1',
'/org/freedesktop/login1',
'org.freedesktop.login1.Manager',
'Inhibit',
GLib.Variant('(ssss)', ('sleep', 'org.gajim.Gajim',
_('Disconnect from the network'), 'delay')),
GLib.VariantType.new('(h)'),
Gio.DBusCallFlags.NONE, -1, None, None)
fd = ret.out_fd_list.get(0)
def appeared(connection, name, name_owner, *user_data):
'''Set up a listener for suspend signals'''
log.info('%s appeared', name)
if name == 'org.freedesktop.login1':
connection.signal_subscribe(
'org.freedesktop.login1',
'org.freedesktop.login1.Manager',
'PrepareForSleep',
'/org/freedesktop/login1',
None,
Gio.DBusSignalFlags.NONE,
signal_received,
None)
get_inhibitor(connection)
Gio.bus_watch_name(
Gio.BusType.SYSTEM,
'org.freedesktop.login1',
Gio.BusNameWatcherFlags.NONE,
appeared,
None)