From 698ae2a31e586d6a4b655d3d77f84177a9b6c3a7 Mon Sep 17 00:00:00 2001 From: "Matthew W. S. Bell" Date: Fri, 21 Sep 2018 05:16:41 +0100 Subject: [PATCH] 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 --- gajim/common/dbus/logind.py | 135 ++++++++++++++++++++++++++++++++++++ gajim/gui_interface.py | 3 +- gajim/logind_listener.py | 116 ------------------------------- 3 files changed, 137 insertions(+), 117 deletions(-) create mode 100644 gajim/common/dbus/logind.py delete mode 100644 gajim/logind_listener.py diff --git a/gajim/common/dbus/logind.py b/gajim/common/dbus/logind.py new file mode 100644 index 000000000..0b415ddf5 --- /dev/null +++ b/gajim/common/dbus/logind.py @@ -0,0 +1,135 @@ +# Copyright (C) 2014 Kamil Paral +# +# 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 . + +''' +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() diff --git a/gajim/gui_interface.py b/gajim/gui_interface.py index 8055ff0db..0f12ae9ee 100644 --- a/gajim/gui_interface.py +++ b/gajim/gui_interface.py @@ -59,6 +59,7 @@ from gajim.common import events from gajim.common.dbus import screensaver from gajim.common.dbus import location from gajim.common.dbus import music_track +from gajim.common.dbus import logind from gajim import gtkgui_helpers from gajim import gui_menu_builder @@ -2723,7 +2724,7 @@ class Interface: # Handle screensaver if sys.platform == 'linux': - from gajim import logind_listener # pylint: disable=unused-variable + logind.enable() screensaver.enable() self.show_vcard_when_connect = [] diff --git a/gajim/logind_listener.py b/gajim/logind_listener.py deleted file mode 100644 index 9c56de76e..000000000 --- a/gajim/logind_listener.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2014 Kamil Paral -# -# 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 . - -''' -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)