diff --git a/data/org.gnome.hamster.gschema.xml b/data/org.gnome.hamster.gschema.xml index dce4c1611..d952b0f47 100644 --- a/data/org.gnome.hamster.gschema.xml +++ b/data/org.gnome.hamster.gschema.xml @@ -7,6 +7,14 @@ The folder the last report was saved to + + + false + Stop tracking on shutdown + + Stop tracking current activity on shutdown + + 330 diff --git a/data/preferences.ui b/data/preferences.ui index 37c81ecb3..fd9b67351 100644 --- a/data/preferences.ui +++ b/data/preferences.ui @@ -40,6 +40,22 @@ start vertical 8 + + + Stop tracking on shutdown (GNOME only) + True + True + False + True + 0.5 + True + + + False + True + 0 + + True @@ -54,7 +70,7 @@ False True 4 - 0 + 1 diff --git a/src/hamster-service.py b/src/hamster-service.py index 4b1e43a71..fb3cae146 100644 --- a/src/hamster-service.py +++ b/src/hamster-service.py @@ -13,6 +13,7 @@ i18n.setup_i18n() # noqa: E402 from hamster.storage import db +from hamster.session import DbusSessionListener from hamster.lib import datetime as dt from hamster.lib import default_logger from hamster.lib.dbus import ( @@ -26,6 +27,7 @@ to_dbus_fact_json ) from hamster.lib.fact import Fact, FactError +from hamster.lib.configuration import conf logger = default_logger(__file__) @@ -38,7 +40,7 @@ quit() -class Storage(db.Storage, dbus.service.Object): +class Storage(db.Storage, dbus.service.Object, DbusSessionListener): __dbus_object_path__ = "/org/gnome/Hamster" def __init__(self, loop): @@ -50,6 +52,7 @@ def __init__(self, loop): db.Storage.__init__(self, unsorted_localized="") self.mainloop = loop + DbusSessionListener.__init__(self) self.__file = gio.File.new_for_path(__file__) self.__monitor = self.__file.monitor_file(gio.FileMonitorFlags.WATCH_MOUNTS | \ @@ -79,6 +82,12 @@ def run_fixtures(self): self.add_activity(activity, cat_id) + # stop current task on log out if requested + def end_session(self): + """Stop tracking on logout.""" + if conf.get("stop-on-shutdown"): + self.stop_tracking(None) + # stop service when we have been updated (will be brought back in next call) # anyway. should make updating simpler def _on_us_change(self, monitor, gio_file, event_uri, event): diff --git a/src/hamster/preferences.py b/src/hamster/preferences.py index c41b1d35c..1a44fa12d 100644 --- a/src/hamster/preferences.py +++ b/src/hamster/preferences.py @@ -169,6 +169,8 @@ def show(self): self.window.show_all() def load_config(self, *args): + conf.bind("stop-on-shutdown", self.get_widget("shutdown_track"), "active") + self.day_start.time = conf.day_start self.tags = [tag["name"] for tag in runtime.storage.get_tags(only_autocomplete=True)] diff --git a/src/hamster/session.py b/src/hamster/session.py new file mode 100644 index 000000000..75dcaed36 --- /dev/null +++ b/src/hamster/session.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2020 Sébastien Granjoux + +# This file is part of Project Hamster. + +# Project Hamster 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, either version 3 of the License, or +# (at your option) any later version. + +# Project Hamster 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 Project Hamster. If not, see . + +import dbus +import logging +logger = logging.getLogger(__name__) + +class DbusSessionListener(object): + """Listen for GNOME manager end session event.""" + + + def end_session(self): + """Override this method to do something at the end of a session. + It must not attempt to interact with the user and will be given + a maximum of ten seconds to perform the actions.""" + pass + + + def __init__(self): + """Connect to the GNOME manager session signals""" + + # Get SessionManager interface + session_bus = dbus.SessionBus() + try: + session_manager = session_bus.get_object("org.gnome.SessionManager", + "/org/gnome/SessionManager") + self.__session_manager_iface = dbus.Interface(session_manager, + dbus_interface="org.gnome.SessionManager") + self.__client_id = self.__session_manager_iface.RegisterClient("", "") + + # Get SessionManager.ClientPrivate interface + session_client = session_bus.get_object("org.gnome.SessionManager", + self.__client_id) + self.__session_client_private_iface = dbus.Interface(session_client, + dbus_interface="org.gnome.SessionManager.ClientPrivate") + + # Connect to the needed signals + session_bus.add_signal_receiver(self.__query_end_session_handler, + signal_name = "QueryEndSession", + dbus_interface = "org.gnome.SessionManager.ClientPrivate", + bus_name = "org.gnome.SessionManager") + + session_bus.add_signal_receiver(self.__end_session_handler, + signal_name = "EndSession", + dbus_interface = "org.gnome.SessionManager.ClientPrivate", + bus_name = "org.gnome.SessionManager") + + session_bus.add_signal_receiver(self.__stop_handler, + signal_name = "Stop", + dbus_interface = "org.gnome.SessionManager.ClientPrivate", + bus_name = "org.gnome.SessionManager") + except dbus.exceptions.DBusException: + logger.info("Unable to connect to GNOME session manager, stop tracking on logout won't work") + + def __query_end_session_handler(self, flags): + """Inform that the session is about to end. It must reply with + EndSessionResponse within one second telling if it is ok to proceed + or not and why. If flags is true, the session will end anyway.""" + self.__session_client_private_iface.EndSessionResponse(True, "") + + def __end_session_handler(self, flags): + """Inform that the session is about to end. It must reply with + EndSessionResponse within ten seconds.""" + self.end_session() + self.__session_client_private_iface.EndSessionResponse(True, "") + + def __stop_handler(self): + """Remove from the session.""" + self.__session_manager_iface.UnregisterClient(self.__client_id)