From fd536fdc56ff709dc3bb47ea311a795600641608 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 2 Nov 2019 13:06:34 -0400 Subject: [PATCH] Move to GSettings This refactors the configuration infrastructure away from the deprecated GConf library and towards GSettings. --- README.md | 4 +- data/apps.hamster-time-tracker.gschema.xml.in | 96 ++++++++++++ data/hamster-time-tracker.schemas.in | 143 ----------------- data/preferences.ui | 12 +- data/wscript_build | 4 +- src/hamster/external.py | 2 +- src/hamster/idle.py | 9 +- src/hamster/lib/configuration.py | 145 +++--------------- src/hamster/lib/desktop.py | 8 +- src/hamster/preferences.py | 30 +--- src/hamster/widgets/reportchooserdialog.py | 2 +- wscript | 19 +-- 12 files changed, 153 insertions(+), 321 deletions(-) create mode 100644 data/apps.hamster-time-tracker.gschema.xml.in delete mode 100644 data/hamster-time-tracker.schemas.in diff --git a/README.md b/README.md index bbc7caa83..405658817 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ pgrep -af hamster ###### Ubuntu (tested in 19.04 and 18.04) ```bash -sudo apt install gettext intltool gconf2 gir1.2-gconf-2.0 python3-gi-cairo python3-distutils python3-dbus python3-xdg +sudo apt install gettext intltool python3-gi-cairo python3-distutils python3-dbus python3-xdg # and for documentation sudo apt install gnome-doc-utils yelp ``` @@ -70,7 +70,7 @@ sudo zypper install gnome-doc-utils xml2po yelp *RPM-based instructions below should be updated for python3 (issue [#369](https://github.com/projecthamster/hamster/issues/369)).* -`yum install gettext intltool gnome-python2-gconf dbus-python` +`yum install gettext intltool dbus-python` If the hamster help pages are not accessible ("unable to open `help:hamster-time-tracker`"), then a [Mallard](https://en.wikipedia.org/wiki/Mallard_(documentation))-capable help reader is required, diff --git a/data/apps.hamster-time-tracker.gschema.xml.in b/data/apps.hamster-time-tracker.gschema.xml.in new file mode 100644 index 000000000..ea425a187 --- /dev/null +++ b/data/apps.hamster-time-tracker.gschema.xml.in @@ -0,0 +1,96 @@ + + + + true + Stop tracking on idle + + Stop tracking current activity when computer becomes idle + + + + + false + Stop tracking on shutdown + + Stop tracking current activity on shutdown + + + + + 27 + Remind of current task every x minutes + + Remind of current task every specified amount of minutes. + Set to 0 or greater than 120 to disable reminder. + + + + + false + Also remind when no activity is set + + Also remind every notify_interval minutes if no activity + has been started. + + + + + "" + Source for external activity information + + Which external program activity information should be taken from. + + + + + 330 + At what time does the day start (defaults to 5:30AM) + + Activities will be counted as to bedescription to yesterday if + the current time is less than the specified day start; and + today, if it is over the time. + Activities that span two days, will tip over to the side + where the largest part of the activity is. + + + + + [] + Should workspace switch trigger activity switch + + List of enabled tracking methods. "name" will enable + switching activities by name defined in workspace_mapping. + "memory" will enable switching to the last activity when + returning to a previous workspace. + + + + + [] + Switch activity on workspace change + + If switching by name is enabled, this list sets the activity + names that should be switched to, workspaces represented by + the index of item. + + + + + "" + Show / hide Time Tracker Window + Keyboard summarycut for showing / hiding the Time Tracker window. + + + + "hamster-time-tracker toggle" + Toggle hamster application window action + Command for toggling visibility of the hamster application window. + + + + "Toggle hamster application window" + Toggle hamster application window + Toggle visibility of the hamster application window. + + + diff --git a/data/hamster-time-tracker.schemas.in b/data/hamster-time-tracker.schemas.in deleted file mode 100644 index a7dc2f78c..000000000 --- a/data/hamster-time-tracker.schemas.in +++ /dev/null @@ -1,143 +0,0 @@ - - - - /schemas/apps/hamster-time-tracker/enable_timeout - /apps/hamster-time-tracker/enable_timeout - hamster-time-tracker - bool - true - - Stop tracking on idle - - Stop tracking current activity when computer becomes idle - - - - - /schemas/apps/hamster-time-tracker/stop_on_shutdown - /apps/hamster-time-tracker/stop_on_shutdown - hamster-time-tracker - bool - false - - Stop tracking on shutdown - - Stop tracking current activity on shutdown - - - - - /schemas/apps/hamster-time-tracker/notify_interval - /apps/hamster-time-tracker/notify_interval - hamster-time-tracker - int - 27 - - Remind of current task every x minutes - - Remind of current task every specified amount of minutes. - Set to 0 or greater than 120 to disable reminder. - - - - - /schemas/apps/hamster-time-tracker/notify_on_idle - /apps/hamster-time-tracker/notify_on_idle - hamster-time-tracker - bool - false - - Also remind when no activity is set - - Also remind every notify_interval minutes if no activity - has been started. - - - - - /schemas/apps/hamster-time-tracker/day_start_minutes - /apps/hamster-time-tracker/day_start_minutes - hamster-time-tracker - int - 330 - - At what time does the day start (defaults to 5:30AM) - - Activities will be counted as to belong to yesterday if - the current time is less than the specified day start; and - today, if it is over the time. - Activities that span two days, will tip over to the side - where the largest part of the activity is. - - - - - /schemas/apps/hamster-time-tracker/workspace_tracking - /apps/hamster-time-tracker/workspace_tracking - hamster-time-tracker - list - string - [] - - Should workspace switch trigger activity switch - - List of enabled tracking methods. "name" will enable - switching activities by name defined in workspace_mapping. - "memory" will enable switching to the last activity when - returning to a previous workspace. - - - - - /schemas/apps/hamster-time-tracker/workspace_mapping - /apps/hamster-time-tracker/workspace_mapping - hamster-time-tracker - list - string - [] - - Switch activity on workspace change - - If switching by name is enabled, this list sets the activity - names that should be switched to, workspaces represented by - the index of item. - - - - - - - /schemas/desktop/gnome/keybindings/hamster-time-tracker/activate_hamster_window - /desktop/gnome/keybindings/hamster-time-tracker/activate_hamster_window - hamster-time-tracker - string - - - Show / hide Time Tracker Window - Keyboard shortcut for showing / hiding the Time Tracker window. - - - - /schemas/desktop/gnome/keybindings/hamster-time-tracker/action - /desktop/gnome/keybindings/hamster-time-tracker/action - hamster-time-tracker - string - hamster-time-tracker toggle - - Toggle hamster application window action - Command for toggling visibility of the hamster application window. - - - - /schemas/desktop/gnome/keybindings/hamster-time-tracker/name - /desktop/gnome/keybindings/hamster-time-tracker/name - hamster-time-tracker - string - Toggle hamster application window - - Toggle hamster application window - Toggle visibility of the hamster application window. - - - - diff --git a/data/preferences.ui b/data/preferences.ui index 492be5884..0397ebea1 100644 --- a/data/preferences.ui +++ b/data/preferences.ui @@ -1,5 +1,5 @@ - + @@ -20,6 +20,9 @@ True hamster-time-tracker + + + True @@ -63,7 +66,6 @@ True 0.5 True - False @@ -80,7 +82,6 @@ True 0.5 True - True @@ -137,7 +138,6 @@ True 0.5 True - @@ -332,10 +332,10 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 _Categories True category_list + 0 False @@ -484,10 +484,10 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 _Activities True activity_list + 0 False diff --git a/data/wscript_build b/data/wscript_build index e07abfbee..cbadf6983 100644 --- a/data/wscript_build +++ b/data/wscript_build @@ -27,8 +27,8 @@ bld.add_group() # process .in files with intl_tool bld(features = 'intltool_in', - source = 'hamster-time-tracker.schemas.in', - target = 'hamster-time-tracker.schemas', + source = 'apps.hamster-time-tracker.gschema.xml.in', + target = 'apps.hamster-time-tracker.gschema.xml', install_path = bld.env.schemas_destination, podir = '../po', flags = ['-s', '-u']) diff --git a/src/hamster/external.py b/src/hamster/external.py index 2426652b8..3d181da07 100644 --- a/src/hamster/external.py +++ b/src/hamster/external.py @@ -40,7 +40,7 @@ class ActivitiesSource(gobject.GObject): def __init__(self): gobject.GObject.__init__(self) - self.source = conf.get("activities_source") + self.source = conf.get("activities-source") self.__gtg_connection = None if self.source == "evo" and not evolution: diff --git a/src/hamster/idle.py b/src/hamster/idle.py index 5d70e019d..2974bbab3 100644 --- a/src/hamster/idle.py +++ b/src/hamster/idle.py @@ -26,8 +26,7 @@ from dbus.lowlevel import Message -gi.require_version('GConf', '2.0') -from gi.repository import GConf as gconf +from gi.repository import Gio as gio from gi.repository import GObject as gobject class DbusIdleListener(gobject.GObject): @@ -37,7 +36,7 @@ class DbusIdleListener(gobject.GObject): Monitors org.gnome.ScreenSaver for idleness. There are two types, implicit (due to inactivity) and explicit (lock screen), that need to be handled differently. An implicit idle state should subtract the - time-to-become-idle (as specified in the gconf) from the last activity, + time-to-become-idle (as specified in GSettings) from the last activity, but an explicit idle state should not. The signals are inspected for the "ActiveChanged" and "Lock" @@ -102,8 +101,8 @@ def bus_inspector(self, bus, message): else: delay_key = "/desktop/gnome/session/idle_delay" - client = gconf.Client.get_default() - self.timeout_minutes = client.get_int(delay_key) + settings = gio.Settings() + self.timeout_minutes = client.get_value(delay_key) else: self.screen_locked = False diff --git a/src/hamster/lib/configuration.py b/src/hamster/lib/configuration.py index 1ab045ae0..b2bf8c004 100644 --- a/src/hamster/lib/configuration.py +++ b/src/hamster/lib/configuration.py @@ -18,7 +18,6 @@ # along with Project Hamster. If not, see . """ -gconf part of this code copied from Gimmie (c) Alex Gravely via Conduit (c) John Stowers, 2006 License: GPLv2 """ @@ -30,12 +29,12 @@ from xdg.BaseDirectory import xdg_data_home import datetime as dt +from gi.repository import GLib as glib from gi.repository import GObject as gobject from gi.repository import Gtk as gtk import gi -gi.require_version('GConf', '2.0') -from gi.repository import GConf as gconf +from gi.repository import Gio as gio class Controller(gobject.GObject): @@ -191,154 +190,58 @@ def get_prefs_class(): dialogs = Dialogs() -class GConfStore(gobject.GObject, Singleton): +class GSettingsStore(gobject.GObject, Singleton): """ - Settings implementation which stores settings in GConf + Settings implementation which stores settings in GSettings Snatched from the conduit project (http://live.gnome.org/Conduit) """ - GCONF_DIR = "/apps/hamster-time-tracker/" - VALID_KEY_TYPES = (bool, str, int, list, tuple) - DEFAULTS = { - 'enable_timeout' : False, # Should hamster stop tracking on idle - 'stop_on_shutdown' : False, # Should hamster stop tracking on shutdown - 'notify_on_idle' : False, # Remind also if no activity is set - 'notify_interval' : 27, # Remind of current activity every X minutes - 'day_start_minutes' : 5 * 60 + 30, # At what time does the day start (5:30AM) - 'overview_window_box' : [], # X, Y, W, H - 'overview_window_maximized' : False, # Is overview window maximized - 'standalone_window_box' : [], # X, Y, W, H - 'standalone_window_maximized' : False, # Is overview window maximized - 'activities_source' : "", # Source of TODO items ("", "evo", "gtg") - 'last_report_folder' : "~", # Path to directory where the last report was saved - } __gsignals__ = { - "conf-changed": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)) + "changed": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)) } + def __init__(self): gobject.GObject.__init__(self) - self._client = gconf.Client.get_default() - self._client.add_dir(self.GCONF_DIR[:-1], gconf.ClientPreloadType.PRELOAD_RECURSIVE) - self._notifications = [] - - def _fix_key(self, key): - """ - Appends the GCONF_PREFIX to the key if needed + self._settings = gio.Settings('apps.HamsterTimeTracker') - @param key: The key to check - @type key: C{string} - @returns: The fixed key - @rtype: C{string} + def _key_changed(self, client, key, data=None): """ - if not key.startswith(self.GCONF_DIR): - return self.GCONF_DIR + key - else: - return key - - def _key_changed(self, client, cnxn_id, entry, data=None): + Callback when a GSettings key changes """ - Callback when a gconf key changes - """ - key = self._fix_key(entry.key)[len(self.GCONF_DIR):] - value = self._get_value(entry.value, self.DEFAULTS[key]) - - self.emit('conf-changed', key, value) - - - def _get_value(self, value, default): - """calls appropriate gconf function by the default value""" - vtype = type(default) - - if vtype is bool: - return value.get_bool() - elif vtype is str: - return value.get_string() - elif vtype is int: - return value.get_int() - elif vtype in (list, tuple): - l = [] - for i in value.get_list(): - l.append(i.get_string()) - return l - - return None + value = self._settings.get_value(key) + self.emit('changed', key, value) def get(self, key, default=None): """ Returns the value of the key or the default value if the key is - not yet in gconf + not yet in GSettings """ - - #function arguments override defaults - if default is None: - default = self.DEFAULTS.get(key, None) - vtype = type(default) - - #we now have a valid key and type - if default is None: - logger.warn("Unknown key: %s, must specify default value" % key) - return None - - if vtype not in self.VALID_KEY_TYPES: - logger.warn("Invalid key type: %s" % vtype) - return None - - #for gconf refer to the full key path - key = self._fix_key(key) - - if key not in self._notifications: - self._client.notify_add(key, self._key_changed, None) - self._notifications.append(key) - - value = self._client.get(key) + value = self._settings.get_value(key) if value is None: - self.set(key, default) - return default - - value = self._get_value(value, default) - if value is not None: - return value + logger.warn("Unknown GSettings key: %s" % key) - logger.warn("Unknown gconf key: %s" % key) - return None + return value.unpack() def set(self, key, value): """ - Sets the key value in gconf and connects adds a signal + Sets the key value in GSettings and connects adds a signal which is fired if the key changes """ logger.debug("Settings %s -> %s" % (key, value)) - if key in self.DEFAULTS: - vtype = type(self.DEFAULTS[key]) - else: - vtype = type(value) - - if vtype not in self.VALID_KEY_TYPES: - logger.warn("Invalid key type: %s" % vtype) - return False - - #for gconf refer to the full key path - key = self._fix_key(key) - - if vtype is bool: - self._client.set_bool(key, value) - elif vtype is str: - self._client.set_string(key, value) - elif vtype is int: - self._client.set_int(key, value) - elif vtype in (list, tuple): - #Save every value as a string - strvalues = [str(i) for i in value] - #self._client.set_list(key, gconf.VALUE_STRING, strvalues) - + default = self._settings.get_default_value(key) + assert default is not None + self._settings.set_value(key, glib.Variant(default.get_type().dup_string(), value)) return True + def bind(self, key, obj, prop): + self._settings.bind(key, obj, prop, gio.SettingsBindFlags.DEFAULT) + @property def day_start(self): """Start of the hamster day.""" - day_start_minutes = self.get("day_start_minutes") + day_start_minutes = self.get("day-start-minutes") hours, minutes = divmod(day_start_minutes, 60) return dt.time(hours, minutes) -conf = GConfStore() +conf = GSettingsStore() diff --git a/src/hamster/lib/desktop.py b/src/hamster/lib/desktop.py index b6cea944a..5a2c4077a 100644 --- a/src/hamster/lib/desktop.py +++ b/src/hamster/lib/desktop.py @@ -38,10 +38,10 @@ def __init__(self, storage): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) self.bus = dbus.SessionBus() - self.conf_enable_timeout = conf.get("enable_timeout") - self.conf_notify_on_idle = conf.get("notify_on_idle") - self.conf_notify_interval = conf.get("notify_interval") - conf.connect('conf-changed', self.on_conf_changed) + self.conf_enable_timeout = conf.get("enable-timeout") + self.conf_notify_on_idle = conf.get("notify-on-idle") + self.conf_notify_interval = conf.get("notify-interval") + conf.connect('changed', self.on_conf_changed) self.idle_listener = idle.DbusIdleListener() self.idle_listener.connect('idle-changed', self.on_idle_changed) diff --git a/src/hamster/preferences.py b/src/hamster/preferences.py index 38ade3803..c27c4253d 100755 --- a/src/hamster/preferences.py +++ b/src/hamster/preferences.py @@ -194,24 +194,21 @@ def show(self): def on_todo_combo_changed(self, combo): - conf.set("activities_source", self.activities_sources[combo.get_active()][0]) + conf.set("activities-source", self.activities_sources[combo.get_active()][0]) def load_config(self, *args): - self.get_widget("shutdown_track").set_active(conf.get("stop_on_shutdown")) - self.get_widget("idle_track").set_active(conf.get("enable_timeout")) - self.get_widget("notify_interval").set_value(conf.get("notify_interval")) - - self.get_widget("notify_on_idle").set_active(conf.get("notify_on_idle")) - self.get_widget("notify_on_idle").set_sensitive(conf.get("notify_interval") <=120) + conf.bind("stop-on-shutdown", self.get_widget("shutdown_track"), "active") + conf.bind("enable-timeout", self.get_widget("idle_track"), "active") + conf.bind("notify-interval", self.get_widget("notify_interval").props.adjustment, "value") + conf.bind("notify-on-idle", self.get_widget("notify_on_idle"), "active") self.day_start.time = conf.day_start self.tags = [tag["name"] for tag in runtime.storage.get_tags(only_autocomplete=True)] self.get_widget("autocomplete_tags").set_text(", ".join(self.tags)) - - current_source = conf.get("activities_source") + current_source = conf.get("activities-source") for i, (code, label) in enumerate(self.activities_sources): if code == current_source: self.todo_combo.set_active(i) @@ -560,15 +557,6 @@ def on_activity_remove_clicked(self, button): runtime.storage.remove_activity(removable_id) - def on_shutdown_track_toggled(self, checkbox): - conf.set("stop_on_shutdown", checkbox.get_active()) - - def on_idle_track_toggled(self, checkbox): - conf.set("enable_timeout", checkbox.get_active()) - - def on_notify_on_idle_toggled(self, checkbox): - conf.set("notify_on_idle", checkbox.get_active()) - def on_notify_interval_format_value(self, slider, value): if value <=120: # notify interval slider value label @@ -583,7 +571,6 @@ def on_notify_interval_format_value(self, slider, value): def on_notify_interval_value_changed(self, scale): value = int(scale.get_value()) - conf.set("notify_interval", value) self.get_widget("notify_on_idle").set_sensitive(value <= 120) def on_day_start_changed(self, widget): @@ -592,10 +579,7 @@ def on_day_start_changed(self, widget): return day_start = day_start.hour * 60 + day_start.minute - - conf.set("day_start_minutes", day_start) - - + conf.set("day-start-minutes", day_start) def on_close_button_clicked(self, button): self.close_window() diff --git a/src/hamster/widgets/reportchooserdialog.py b/src/hamster/widgets/reportchooserdialog.py index 5ff2822f3..3bb8b2dff 100644 --- a/src/hamster/widgets/reportchooserdialog.py +++ b/src/hamster/widgets/reportchooserdialog.py @@ -43,7 +43,7 @@ def __init__(self): gtk.ResponseType.OK)) # try to set path to last known folder or fall back to home - report_folder = os.path.expanduser(conf.get("last_report_folder")) + report_folder = os.path.expanduser(conf.get("last-report-folder")) if os.path.exists(report_folder): self.dialog.set_current_folder(report_folder) else: diff --git a/wscript b/wscript index 49a40f08e..88d6ecea1 100644 --- a/wscript +++ b/wscript @@ -23,16 +23,13 @@ def configure(conf): conf.env.GETTEXT_PACKAGE = "hamster-time-tracker" conf.env.PACKAGE = "hamster-time-tracker" - # gconf_dir is defined in options - conf.env.schemas_destination = '{}/schemas'.format(conf.options.gconf_dir) + # gsettings_schema_dir is defined in options + conf.env.schemas_destination = '${DATADIR}/glib-2.0/schemas' conf.recurse("help") def options(opt): - opt.add_option('--gconf-dir', action='store', default='/etc/gconf', dest='gconf_dir', - help='gconf base directory [default: /etc/gconf]') - # the waf default value is /usr/local, which causes issues (e.g. #309) # opt.parser.set_defaults(prefix='/usr') did not update the help string, # hence need to replace the whole option @@ -94,14 +91,10 @@ def build(bld): assert action in ("install", "uninstall") if ctx.cmd == action: - schemas_file = "{}/hamster-time-tracker.schemas".format(ctx.env.schemas_destination) - cmd = 'GCONF_CONFIG_SOURCE=$(gconftool-2 --get-default-source) gconftool-2 --makefile-{}-rule {} 1> /dev/null'.format(action, schemas_file) - err = ctx.exec_command(cmd) - if err: - Logs.warn('The following command failed:\n{}'.format(cmd)) - else: - Logs.pprint('YELLOW', 'Successfully {}ed gconf schemas'.format(action)) - + schemas_file = "{}/apps.hamster-time-tracker.gschema.xml".format(ctx.env.schemas_destination) + bld.install_files(schemas_file, 'data/apps.hamster-time-tracker.gschema.xml') + cmd = 'glib-compile-schemas {}'.format(ctx.env.schemas_destination) + bld(rule=cmd, always=True) def update_icon_cache(ctx): """Update the gtk icon cache."""