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)