diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py index 1f1809f336678377c8be3dbf169b1e38a5ea4c60..d1a37b9d73f4a52d99bce54476dbda1392f64422 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py @@ -71,7 +71,6 @@ class GreeterApplication(object): persistence = PersistenceSettings() self.localisationsettings = LocalisationSettings( usermanager_loaded_cb=self.usermanager_loaded, - locale_selected_cb=self.on_language_changed ) self.admin_setting = AdminSetting() self.network_setting = NetworkSetting() @@ -79,7 +78,7 @@ class GreeterApplication(object): # Initialize the settings self.settings = GreeterSettingsCollection( - LanguageSettingUI(self.localisationsettings.language), + LanguageSettingUI(self.localisationsettings.language, self.on_language_changed), KeyboardSettingUI(self.localisationsettings.keyboard), FormatsSettingUI(self.localisationsettings.formats), AdminSettingUI(self.admin_setting), @@ -90,6 +89,10 @@ class GreeterApplication(object): # Initialize main window self.mainwindow = GreeterMainWindow(self, persistence, self.settings) + # Apply the default settings + for setting in self.settings: + setting.apply() + # Inhibit the session being marked as idle self.inhibit_idle() @@ -97,38 +100,15 @@ class GreeterApplication(object): """Translate all windows to target language""" TranslatableWindow.translate_all(lang) - def load_settings(self): - if self.localisationsettings.language.load(): - self.settings["language"].selected_code = self.localisationsettings.language.value - self.settings["language"].apply() - if self.localisationsettings.formats.load(): - self.settings["formats"].selected_code = self.localisationsettings.formats.value - self.settings["formats"].apply() - if self.localisationsettings.keyboard.load(): - self.settings["keyboard"].selected_code = self.localisationsettings.keyboard.value - self.settings["keyboard"].apply() - - if self.admin_setting.load(): - self.settings["admin"].password = self.admin_setting.password - self.mainwindow.add_setting("admin") - if self.network_setting.load(): - if self.network_setting.value != self.settings["network"].value: - self.settings["network"].value = self.network_setting.value - self.mainwindow.add_setting("network") - if self.macspoof_setting.load(): - if self.settings["macspoof"].spoofing_enabled != self.macspoof_setting.value: - self.settings["macspoof"].spoofing_enabled = self.macspoof_setting.value - self.mainwindow.add_setting("macspoof") - def login(self): """Login GDM to the server""" logging.debug("login called") # Apply settings + # We now apply all settings immediately when they are + # changed. The only thing that still happens here is + # concatenating the locale settings files. self.localisationsettings.apply_to_upcoming_session() - self.admin_setting.apply_to_upcoming_session() - self.macspoof_setting.apply_to_upcoming_session() - self.network_setting.apply_to_upcoming_session() self.mainwindow.hide() self.gdmclient.do_login() @@ -142,10 +122,9 @@ class GreeterApplication(object): def on_language_changed(self, locale_code: str): """Translate to the given locale""" - self.localisationsettings.formats.on_language_changed(locale_code) # XXX: notify - self.settings["formats"].update_value_label() - self.localisationsettings.keyboard.on_language_changed(locale_code) # XXX: notify - self.settings["keyboard"].update_value_label() + for setting in self.settings.region_settings: + setting.on_language_changed(locale_code) + self.translate_to(locale_code) self.mainwindow.current_language = localization.language_from_locale(locale_code) diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py index e8affe84eac5a08bb642897179b2400d9b8b9d99..aad0e3b7b3393289edd9f6f3438c66efb254a542 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py @@ -11,45 +11,38 @@ from tailsgreeter.settings.utils import read_settings, write_settings class AdminSetting(object): """Setting controlling the sudo password""" - def __init__(self): - self.password = None - self.settings_file = tailsgreeter.config.admin_password_path - - def apply_to_upcoming_session(self): - if self.password: - proc = subprocess.run( - ["mkpasswd", "-s", "--method=sha512crypt"], - input=pipes.quote(self.password).encode(), - capture_output=True, - check=True, - ) - hashed_and_salted_pw = proc.stdout.decode().strip() - - write_settings(self.settings_file, { - 'TAILS_USER_PASSWORD': pipes.quote(hashed_and_salted_pw), - }) - logging.debug('password written to %s', self.settings_file) - return - + settings_file = tailsgreeter.config.admin_password_path + + def save(self, password: str): + proc = subprocess.run( + ["mkpasswd", "-s", "--method=sha512crypt"], + input=pipes.quote(password).encode(), + capture_output=True, + check=True, + ) + hashed_and_salted_pw = proc.stdout.decode().strip() + + write_settings(self.settings_file, { + 'TAILS_USER_PASSWORD': pipes.quote(hashed_and_salted_pw), + }) + logging.debug('password written to %s', self.settings_file) + + def delete(self): # Try to remove the password file try: os.unlink(self.settings_file) logging.debug('removed %s', self.settings_file) except OSError: # It's bad if the file exists and couldn't be removed, so we - # we raise the exception in that case (which prevents the login) + # we raise the exception in that case if os.path.exists(self.settings_file): raise - def load(self) -> bool: + def load(self) -> {str, None}: try: settings = read_settings(self.settings_file) except FileNotFoundError: logging.debug("No persistent admin settings file found (path: %s)", self.settings_file) - return False + return None - password = settings.get('TAILS_USER_PASSWORD') - if password: - self.password = password - logging.debug("Loaded admin password setting") - return True + return settings.get('TAILS_USER_PASSWORD') diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py index 4e1283efe3d5969d3ba09079bab2eeb329f52073..13b1ca0dec5821435826347315511aa33ed8098f 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py @@ -1,6 +1,5 @@ import gi import logging -import os import tailsgreeter.config from tailsgreeter.settings.localization import LocalizationSetting, language_from_locale, country_from_locale @@ -15,30 +14,30 @@ from gi.repository import GObject, GnomeDesktop, Gtk class FormatsSetting(LocalizationSetting): def __init__(self, language_codes: [str]): super().__init__() - self.value = 'en_US' self.locales_per_country = self._make_locales_per_country_dict(language_codes) self.settings_file = tailsgreeter.config.formats_setting_path - def apply_to_upcoming_session(self): + def save(self, locale: str, is_default: bool): write_settings(self.settings_file, { - 'TAILS_FORMATS': self.get_value(), - 'IS_DEFAULT': str(not self.value_changed_by_user).lower(), + 'TAILS_FORMATS': locale, + 'IS_DEFAULT': str(is_default).lower(), }) - def load(self) -> bool: + def load(self) -> ({str, None}, bool): try: settings = read_settings(self.settings_file) except FileNotFoundError: logging.debug("No persistent formats settings file found (path: %s)", self.settings_file) - return False + return None, False formats = settings.get('TAILS_FORMATS') - if not formats: - return False + if formats is None: + logging.debug("No formats setting found in settings file (path: %s)", self.settings_file) + return None, False + is_default = settings.get('IS_DEFAULT') == 'true' - self.set_value(formats, chosen_by_user=not is_default) logging.debug("Loaded formats setting '%s' (is default: %s)", formats, is_default) - return True + return formats, is_default def get_tree(self) -> Gtk.TreeStore: treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id @@ -65,8 +64,8 @@ class FormatsSetting(LocalizationSetting): treestore.set(treeiter_locale, 1, self._locale_name(locale)) return treestore - def get_name(self) -> str: - return self._locale_name(self.get_value()) + def get_name(self, locale: str) -> str: + return self._locale_name(locale) def get_default_locale(self, country_code=None) -> str: """Return default locale for given country @@ -141,12 +140,3 @@ class FormatsSetting(LocalizationSetting): if language_code not in res[country_code]: res[country_code].append(language_code) return res - - def on_language_changed(self, language_code: str): - """Set the formats according to the new language""" - # Don't overwrite user chosen values - if self.value_changed_by_user: - return - - logging.debug("setting formats to %s", language_code) - self.set_value(language_code) diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py index 45fffc497b16917a4318328d7e0e182283623ba9..0d1f493473145a27c7965a0b1dfe0f782734dc4a 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py @@ -19,14 +19,13 @@ class KeyboardSetting(LocalizationSetting): def __init__(self): super().__init__() self.xkbinfo = GnomeDesktop.XkbInfo() - self.value = 'us' self.settings_file = tailsgreeter.config.keyboard_setting_path - def apply_to_upcoming_session(self): + def save(self, value: str, is_default: bool): try: - layout, variant = self.get_value().split('+') + layout, variant = value.split('+') except ValueError: - layout = self.get_value() + layout = value variant = '' write_settings(self.settings_file, { @@ -34,29 +33,28 @@ class KeyboardSetting(LocalizationSetting): 'TAILS_XKBMODEL': 'pc105', 'TAILS_XKBLAYOUT': layout, 'TAILS_XKBVARIANT': variant, - 'IS_DEFAULT': str(not self.value_changed_by_user).lower(), + 'IS_DEFAULT': str(is_default).lower(), }) - def load(self) -> bool: + def load(self) -> ({str, None}, bool): try: settings = read_settings(self.settings_file) except FileNotFoundError: logging.debug("No persistent keyboard settings file found (path: %s)", self.settings_file) - return False + return None, False keyboard_layout = settings.get('TAILS_XKBLAYOUT') - if not keyboard_layout: - return False + if keyboard_layout is None: + logging.debug("No keyboard setting found in settings file (path: %s)", self.settings_file) + return None, False keyboard_variant = settings.get('TAILS_XKBVARIANT') if keyboard_variant: keyboard_layout += "+" + keyboard_variant is_default = settings.get('IS_DEFAULT') == 'true' - self.set_value(keyboard_layout, chosen_by_user=not is_default) - logging.debug("Loaded keyboard setting '%s' (is default: %s)", keyboard_layout, is_default) - return True + return keyboard_layout, is_default def get_tree(self, layout_codes=None) -> Gtk.TreeStore: if not layout_codes: @@ -79,8 +77,8 @@ class KeyboardSetting(LocalizationSetting): treestore.set(treeiter_layout, 1, self._layout_name(layout_code)) return treestore - def get_name(self) -> str: - return self._layout_name(self.get_value()) + def get_name(self, value: str) -> str: + return self._layout_name(value) def get_all(self) -> [str]: """Return a list of all keyboard layout codes @@ -88,11 +86,6 @@ class KeyboardSetting(LocalizationSetting): """ return self.xkbinfo.get_all_layouts() - def set_value(self, layout, chosen_by_user=False): - super().set_value(layout) - self.value_changed_by_user = chosen_by_user - self._apply_layout_to_current_screen() - def _layout_name(self, layout_code) -> str: layout_exists, display_name, short_name, xkb_layout, xkb_variant = \ self.xkbinfo.get_layout_info(layout_code) @@ -192,13 +185,7 @@ class KeyboardSetting(LocalizationSetting): layouts = filtered_layouts return layouts - def on_language_changed(self, locale: str): - """Set the keyboard layout according to the new language""" - - # Don't overwrite a user chosen value - if self.value_changed_by_user: - return - + def get_layout_for_locale(self, locale: str): language = language_from_locale(locale) country = country_from_locale(locale) @@ -243,11 +230,10 @@ class KeyboardSetting(LocalizationSetting): else: default_layout = 'us' logging.debug("Using us as fallback default layout") - self.set_value(default_layout) + return default_layout - def _apply_layout_to_current_screen(self): - layout = self.get_value() - logging.debug("layout=%s", layout) + def apply_layout_to_current_screen(self, layout: str): + logging.debug("applying keyboard layout '%s'", layout) settings = Gio.Settings('org.gnome.desktop.input-sources') settings.set_value('sources', GLib.Variant('a(ss)', [('xkb', layout)])) diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py index 5a707848a1d269fb1884fee7d9d75a53926813d1..ccd8b6a512d4984741a714680428d8d5eac7afe4 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py @@ -21,7 +21,7 @@ from collections import OrderedDict import gi import logging import locale -from typing import Callable +import pipes import tailsgreeter.config from tailsgreeter.settings.localization import LocalizationSetting, \ @@ -37,11 +37,9 @@ from gi.repository import GLib, GObject, GnomeDesktop, Gtk class LanguageSetting(LocalizationSetting): - def __init__(self, locales: [str], language_changed_cb: Callable): + def __init__(self, locales: [str]): super().__init__() - self.value = 'en_US' self.locales = locales - self.language_changed_cb = language_changed_cb self._user_account = None self.settings_file = tailsgreeter.config.language_setting_path @@ -49,26 +47,27 @@ class LanguageSetting(LocalizationSetting): self.locales_per_language = self._make_language_to_locale_dict(locales) self.language_names_per_language = self._make_language_to_language_name_dict(self.lang_codes) - def apply_to_upcoming_session(self): + def save(self, language: str, is_default: bool): write_settings(self.settings_file, { - 'TAILS_LOCALE_NAME': self.get_value(), - 'IS_DEFAULT': str(not self.value_changed_by_user).lower(), + 'TAILS_LOCALE_NAME': pipes.quote(language), + 'IS_DEFAULT': str(is_default).lower(), }) - def load(self) -> bool: + def load(self) -> ({str, None}, bool): try: settings = read_settings(self.settings_file) except FileNotFoundError: logging.debug("No persistent language settings file found (path: %s)", self.settings_file) - return False + return None, False language = settings.get('TAILS_LOCALE_NAME') - if not language: - return False + if language is None: + logging.debug("No language setting found in settings file (path: %s)", self.settings_file) + return None, False + is_default = settings.get('IS_DEFAULT') == 'true' - self.set_value(language, chosen_by_user=not is_default) logging.debug("Loaded language setting '%s' (is default: %s)", language, is_default) - return True + return language, is_default def get_tree(self) -> Gtk.TreeStore: treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id @@ -92,8 +91,8 @@ class LanguageSetting(LocalizationSetting): treestore.set(treeiter_locale, 1, self._locale_name(locale_code)) return treestore - def get_name(self) -> str: - return self._locale_name(self.get_value()) + def get_name(self, value: str) -> str: + return self._locale_name(value) def get_default_locale(self, lang_code: str) -> str: """Try to find a default locale for the given language @@ -114,11 +113,6 @@ class LanguageSetting(LocalizationSetting): return locales[0] - def set_value(self, locale_code: str, chosen_by_user=False): - super().set_value(locale_code, chosen_by_user) - self._apply_language(locale_code) - self.language_changed_cb(locale_code) - def _language_name(self, lang_code: str) -> str: default_locale = 'C' @@ -189,7 +183,7 @@ class LanguageSetting(LocalizationSetting): except AttributeError: return locale_code - def _apply_language(self, language_code: str): + def apply_language(self, language_code: str): normalized_code = locale.normalize(language_code + '.' + locale.getpreferredencoding()) logging.debug("Setting session language to %s", normalized_code) if self._user_account: diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py index 8b0c6a395e82c8519bde762b9d1053c5241bc14c..73fec0926fff1de43fec1483787bc0cc571899cd 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py @@ -38,16 +38,18 @@ class LocalizationSetting(GObject.Object, object): def get_value(self) -> str: return self.value - def set_value(self, value, chosen_by_user=False): - self.value = value - self.value_changed_by_user = chosen_by_user - - def get_name(self) -> str: + def get_name(self, value: str) -> str: raise NotImplementedError def get_tree(self) -> "Gtk.Treestore": raise NotImplementedError + def save(self, value: str, is_default: bool): + pass + + def load(self) -> ({str, None}, bool): + pass + def ln_iso639_tri(ln_CC): """get iso639 3-letter code from a language code diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py index 18e1766d4773e564c1d3a3abb724d60ef5e4026a..820f6c62a2dba9701603660ac96cfb68e6c539a8 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py @@ -16,7 +16,7 @@ class LocalisationSettings(object): """Controller for localisation settings """ - def __init__(self, usermanager_loaded_cb: Callable, locale_selected_cb: Callable): + def __init__(self, usermanager_loaded_cb: Callable): self._usermanager_loaded_cb = usermanager_loaded_cb self._user_account = None @@ -28,7 +28,7 @@ class LocalisationSettings(object): self._actusermanager_loadedid = self._actusermanager.connect( "notify::is-loaded", self.__on_usermanager_loaded) - self.language = LanguageSetting(locales, locale_selected_cb) + self.language = LanguageSetting(locales) self.keyboard = KeyboardSetting() self.formats = FormatsSetting(locales) @@ -53,10 +53,6 @@ class LocalisationSettings(object): self._usermanager_loaded_cb() def apply_to_upcoming_session(self): - self.language.apply_to_upcoming_session() - self.formats.apply_to_upcoming_session() - self.keyboard.apply_to_upcoming_session() - with open(tailsgreeter.config.locale_setting_path, 'w') as outfile: for path in (tailsgreeter.config.language_setting_path, tailsgreeter.config.formats_setting_path, diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py index 5e5dcaa8bb3b1ddaaa0886bf7d1b3150d322bee9..d8033e61b1d36c4b69e691ca4c0885ab9cc79b05 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py @@ -9,24 +9,25 @@ class MacSpoofSetting(object): """Setting controlling whether the MAC address is spoofed or not""" def __init__(self): - self.value = True self.settings_file = tailsgreeter.config.macspoof_setting_path - def apply_to_upcoming_session(self): + def save(self, value: bool): write_settings(self.settings_file, { - 'TAILS_MACSPOOF_ENABLED': pipes.quote(str(self.value)).lower(), + 'TAILS_MACSPOOF_ENABLED': pipes.quote(str(value)).lower(), }) logging.debug('macspoof setting written to %s', self.settings_file) - def load(self) -> bool: + def load(self) -> {bool, None}: try: settings = read_settings(self.settings_file) except FileNotFoundError: logging.debug("No persistent macspoof settings file found (path: %s)", self.settings_file) - return False + return None - value = settings.get('TAILS_MACSPOOF_ENABLED') == "true" - if value: - self.value = value - logging.debug("Loaded macspoof setting '%s'", value) - return True + value_str = settings.get('TAILS_MACSPOOF_ENABLED') + if value_str is None: + logging.debug("No macspoof setting found in settings file (path: %s)", self.settings_file) + return None + value = value_str == "true" + logging.debug("Loaded macspoof setting '%s'", value) + return value diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py index f52fc4b8a82cd15021f5e84595d6864d80903e77..cb60bbffb33eb184821b4ba1c7752cc0fadf91ea 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py @@ -4,33 +4,34 @@ import pipes import tailsgreeter.config from tailsgreeter.settings.utils import read_settings, write_settings +NETCONF_DIRECT = "direct" +NETCONF_OBSTACLE = "obstacle" +NETCONF_DISABLED = "disabled" + class NetworkSetting(object): """Setting controlling how Tails connects to Tor""" - NETCONF_DIRECT = "direct" - NETCONF_OBSTACLE = "obstacle" - NETCONF_DISABLED = "disabled" - def __init__(self): - self.value = self.NETCONF_DIRECT self.settings_file = tailsgreeter.config.network_setting_path - def apply_to_upcoming_session(self): + def save(self, value: str): write_settings(self.settings_file, { - 'TAILS_NETCONF': pipes.quote(self.value), + 'TAILS_NETCONF': pipes.quote(value), }) logging.debug('network setting written to %s', self.settings_file) - def load(self) -> bool: + def load(self) -> {bool, None}: try: settings = read_settings(self.settings_file) except FileNotFoundError: logging.debug("No persistent network settings file found (path: %s)", self.settings_file) - return False + return None value = settings.get('TAILS_NETCONF') - if value: - self.value = value - logging.debug("Loaded network setting '%s'", value) - return True + if value is None: + logging.debug("No network setting found in settings file (path: %s)", self.settings_file) + return None + + logging.debug("Loaded network setting '%s'", value) + return value diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/utils.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/utils.py index f057726fae538c87194ccff6b794cd98301cd325..07536c4bf61cf0861bcb38aad4408494236a98ad 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/utils.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/utils.py @@ -1,14 +1,15 @@ import os +from typing import Dict -def write_settings(filename: str, settings: dict): +def write_settings(filename: str, settings: Dict[str, str]): with open(filename, 'w') as f: os.chmod(filename, 0o600) for key, value in settings.items(): f.write('%s=%s\n' % (key, value)) -def read_settings(filename: str) -> dict: +def read_settings(filename: str) -> Dict[str, str]: with open(filename) as f: lines = f.readlines() diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py index 57a247b2ead1c2a3377aa6c2493873fd04670088..6e55fa861ffee77144fd96c2e8c95e71107e8ab7 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py @@ -3,6 +3,7 @@ import gi from tailsgreeter import TRANSLATION_DOMAIN import tailsgreeter.config import tailsgreeter.utils +from tailsgreeter.settings.network import NETCONF_DIRECT, NETCONF_DISABLED, NETCONF_OBSTACLE from tailsgreeter.ui import _ from tailsgreeter.ui.setting import GreeterSetting from tailsgreeter.ui.popover import Popover @@ -42,6 +43,9 @@ class AdditionalSetting(GreeterSetting): def on_opened_in_dialog(self): pass + def load(self) -> bool: + pass + class AdminSettingUI(AdditionalSetting): @property @@ -114,9 +118,19 @@ class AdminSettingUI(AdditionalSetting): def apply(self): # This writes the password to a file from which it will be set # as the amnesia password when the greeter is closed. - self._admin_setting.password = self.password + if self.password: + self._admin_setting.save(self.password) + else: + self._admin_setting.delete() super().apply() + def load(self) -> bool: + password = self._admin_setting.load() + if password: + self.password = password + return True + return False + def cb_entry_admin_changed(self, editable, user_data=None): self.update_check_icon() passwords_match = self.passwords_match() @@ -176,9 +190,18 @@ class MACSpoofSettingUI(AdditionalSetting): self.listboxrow_macspoof_off = self.builder.get_object('listboxrow_macspoof_off') def apply(self): - self._macspoof_setting.value = self.spoofing_enabled + self._macspoof_setting.save(self.spoofing_enabled) super().apply() + def load(self) -> bool: + value = self._macspoof_setting.load() + if value is None: + return False + if value == self.spoofing_enabled: + return False + self.spoofing_enabled = value + return True + def cb_listbox_macspoof_row_activated(self, listbox, row, user_data=None): self.spoofing_enabled = row == self.listboxrow_macspoof_on self.image_macspoof_on.set_visible(self.spoofing_enabled) @@ -210,16 +233,16 @@ class NetworkSettingUI(AdditionalSetting): @property def value_for_display(self) -> str: - if self.value == self._network_setting.NETCONF_DIRECT: + if self.value == NETCONF_DIRECT: return _("Direct (default)") - if self.value == self._network_setting.NETCONF_OBSTACLE: + if self.value == NETCONF_OBSTACLE: return _("Bridge & Proxy") - if self.value == self._network_setting.NETCONF_DISABLED: + if self.value == NETCONF_DISABLED: return _("Offline") def __init__(self, network_setting: "NetworkSetting"): self._network_setting = network_setting - self.value = self._network_setting.NETCONF_DIRECT + self.value = NETCONF_DIRECT super().__init__() self.accel_key = Gdk.KEY_n self.icon_network_clear_chosen = self.builder.get_object('image_network_clear') @@ -233,11 +256,20 @@ class NetworkSettingUI(AdditionalSetting): self.listboxrow_network_off = self.builder.get_object('listboxrow_network_off') def apply(self): - self._network_setting.value = self.value - is_bridge = self.value == self._network_setting.NETCONF_OBSTACLE + self._network_setting.save(self.value) + is_bridge = self.value == NETCONF_OBSTACLE self.main_window.set_bridge_infobar_visibility(is_bridge) super().apply() + def load(self) -> bool: + value = self._network_setting.load() + if value is None: + return False + if value == self.value: + return False + self.value = value + return True + def cb_listbox_network_button_press(self, widget, event, user_data=None): # On double-click: Close the window and apply chosen setting if event.type == Gdk.EventType._2BUTTON_PRESS: @@ -250,13 +282,13 @@ class NetworkSettingUI(AdditionalSetting): self.icon_network_off_chosen.set_visible(False) if row == self.listboxrow_network_clear: - self.value = self._network_setting.NETCONF_DIRECT + self.value = NETCONF_DIRECT self.icon_network_clear_chosen.set_visible(True) elif row == self.listboxrow_network_specific: - self.value = self._network_setting.NETCONF_OBSTACLE + self.value = NETCONF_OBSTACLE self.icon_network_specific_chosen.set_visible(True) elif row == self.listboxrow_network_off: - self.value = self._network_setting.NETCONF_DISABLED + self.value = NETCONF_DISABLED self.icon_network_off_chosen.set_visible(True) if self.has_popover() and self.popover.is_open(): diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py index 3517a09180412c1ff6a1257d282743706ab7a8dd..997b8e4a462bed12ada1d011c4b587a9676f26d7 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py @@ -30,7 +30,7 @@ from tailsgreeter.ui import _ from tailsgreeter.ui.add_settings_dialog import AddSettingsDialog from tailsgreeter.ui.additional_settings import AdditionalSetting from tailsgreeter.ui.help_window import GreeterHelpWindow -from tailsgreeter.ui.region_settings import LocalizationSettingUI, LanguageSettingUI +from tailsgreeter.ui.region_settings import LocalizationSettingUI from tailsgreeter import TRANSLATION_DOMAIN from tailsgreeter.ui.persistent_storage import PersistentStorage @@ -131,7 +131,7 @@ class GreeterMainWindow(Gtk.Window, TranslatableWindow): self.listbox_settings.set_placeholder(self.label_settings_default) # Persistent storage - self.persistent_storage = PersistentStorage(self.persistence_setting, greeter, builder) + self.persistent_storage = PersistentStorage(self.persistence_setting, self.load_settings, builder) # Add children to ApplicationWindow self.add(self.box_main) @@ -176,6 +176,17 @@ class GreeterMainWindow(Gtk.Window, TranslatableWindow): # Actions + def load_settings(self): + # We have to load formats and keyboard before language, because + # changing the language also changes the other two, which causes + # the settings files to be overwritten. So we load the region + # settings in reversed order. + for setting in reversed(list(self.settings.region_settings)): + setting.load() + for setting in self.settings.additional_settings: + if setting.load(): + self.add_setting(setting.id) + def run_add_setting_dialog(self, id_=None): response = self.dialog_add_setting.run(id_) if response == Gtk.ResponseType.YES: diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py index 46258b4eb02187367e5159c14a170932074e4b02..62a08871f47d918d89508faa05678a4e315fdee8 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py @@ -1,7 +1,7 @@ import logging import gi import threading -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Callable from tailsgreeter.ui import _ @@ -14,9 +14,9 @@ if TYPE_CHECKING: class PersistentStorage(object): - def __init__(self, persistence_setting: "PersistenceSettings", greeter, builder): + def __init__(self, persistence_setting: "PersistenceSettings", load_settings_cb: Callable, builder): self.persistence_setting = persistence_setting - self.greeter = greeter + self.load_settings_cb = load_settings_cb self.box_storage = builder.get_object('box_storage') self.box_storage_unlock = builder.get_object('box_storage_unlock') @@ -109,7 +109,8 @@ class PersistentStorage(object): self.image_storage_state.set_visible(True) self.box_storage_unlocked.set_visible(True) self.button_start.set_sensitive(True) - self.greeter.load_settings() + + self.load_settings_cb() def cb_checkbutton_storage_show_passphrase_toggled(self, widget): self.entry_storage_passphrase.set_visibility(widget.get_active()) diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py index 05fda4be46f560d0477ae5efbbdd7a4eca113efd..042c72e06c1070762049241eace3da48ee250224 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py @@ -6,7 +6,7 @@ import tailsgreeter.config from tailsgreeter.ui import _ from tailsgreeter.ui.setting import GreeterSetting from tailsgreeter.ui.popover import Popover -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Callable gi.require_version('Gtk', '3.0') gi.require_version('Pango', '1.0') @@ -14,20 +14,24 @@ from gi.repository import Gtk, Pango if TYPE_CHECKING: from tailsgreeter.settings.localization import LocalizationSetting + from tailsgreeter.settings.language import LanguageSetting + from tailsgreeter.settings.formats import FormatsSetting + from tailsgreeter.settings.keyboard import KeyboardSetting + REGION_SETTINGS_UI_FILE = "region_settings.ui" class LocalizationSettingUI(GreeterSetting): def __init__(self, localization_setting: "LocalizationSetting"): - self._localization_setting = localization_setting + self._setting = localization_setting + self.value = self.default # type: {str, None} + self.value_changed_by_user = False super().__init__() - self.selected_code = "" # type: str - self.selected_name = "" # type: str - self._localization_setting.connect("notify::value", self.cb_value_changed) + self._setting.connect("notify::value", self.cb_value_changed) - self.treestore = self._localization_setting.get_tree() + self.treestore = self._setting.get_tree() self.builder = Gtk.Builder() self.builder.set_translation_domain(TRANSLATION_DOMAIN) @@ -53,9 +57,24 @@ class LocalizationSettingUI(GreeterSetting): self.treeview.set_model(self.treestore_filtered) def apply(self): - self._localization_setting.set_value(self.selected_code, chosen_by_user=True) + self._setting.save(self.value, is_default=False) super().apply() + def load(self): + value, is_default = self._setting.load() + if value is None: + return + self.value = value + self.value_changed_by_user = not is_default + self.apply() + + @property + def default(self) -> {str, None}: + return None + + def on_language_changed(self, locale: str): + pass + def cb_searchentry_activate(self, searchentry, user_data=None): """Selects the topmost item in the treeview when pressing Enter""" if searchentry.get_text(): @@ -76,12 +95,12 @@ class LocalizationSettingUI(GreeterSetting): def cb_treeview_row_activated(self, treeview, path, column, user_data=None): treemodel = treeview.get_model() - self.selected_code = treemodel.get_value(treemodel.get_iter(path), 0) - self.selected_name = treemodel.get_value(treemodel.get_iter(path), 1) + self.value = treemodel.get_value(treemodel.get_iter(path), 0) + self.value_changed_by_user = True self.popover.close(Gtk.ResponseType.YES) def cb_value_changed(self, obj, param): - logging.debug("refreshing {}".format(self._localization_setting.get_name())) + logging.debug("refreshing {}".format(self._setting.get_name(self.value))) def treeview_select_line(model, path, iter_, data): if model.get_value(iter_, 0) == data: @@ -94,7 +113,7 @@ class LocalizationSettingUI(GreeterSetting): self.treestore_filtered.foreach( treeview_select_line, - self._localization_setting.get_value()) + self._setting.value) def cb_liststore_filtered_visible_func(self, model, treeiter, searchentry): search_query = searchentry.get_text().lower() @@ -127,6 +146,8 @@ class LocalizationSettingUI(GreeterSetting): class LanguageSettingUI(LocalizationSettingUI): + _setting = None # type: LanguageSetting + @property def id(self) -> str: return "language" @@ -141,40 +162,102 @@ class LanguageSettingUI(LocalizationSettingUI): @property def value_for_display(self) -> str: - return self._localization_setting.get_name() + return self._setting.get_name(self.value) + @property + def default(self) -> str: + return 'en_US' + + def __init__(self, setting: "LanguageSetting", changed_cb: Callable): + self.changed_cb = changed_cb + super().__init__(setting) + + def apply(self): + super().apply() + self._setting.apply_language(self.value) + self.changed_cb(self.value) + + def load(self): + super().load() + self._setting.apply_language(self.value) + self.changed_cb(self.value) + + +class FormatsSettingUI(LocalizationSettingUI): + _setting = None # type: FormatsSetting -class KeyboardSettingUI(LocalizationSettingUI): @property def id(self) -> str: - return "keyboard" + return "formats" @property def title(self) -> str: - return _("_Keyboard Layout") + return _("_Formats") @property def icon_name(self): - return "tails-keyboard-layout" + return "tails-formats" @property def value_for_display(self) -> str: - return self._localization_setting.get_name() + return self._setting.get_name(self.value) + @property + def default(self) -> str: + return 'en_US' + + def on_language_changed(self, locale: str): + """Set the formats according to the new language""" + # Don't overwrite user chosen values + if self.value_changed_by_user: + return + + if self.value == locale: + return + + self.value = locale + self.update_value_label() + self._setting.save(locale, is_default=True) + + +class KeyboardSettingUI(LocalizationSettingUI): + _setting = None # type: KeyboardSetting -class FormatsSettingUI(LocalizationSettingUI): @property def id(self) -> str: - return "formats" + return "keyboard" @property def title(self) -> str: - return _("_Formats") + return _("_Keyboard Layout") @property def icon_name(self): - return "tails-formats" + return "tails-keyboard-layout" @property def value_for_display(self) -> str: - return self._localization_setting.get_name() + return self._setting.get_name(self.value) + + @property + def default(self) -> str: + return 'us' + + def apply(self): + super().apply() + self._setting.apply_layout_to_current_screen(self.value) + + def on_language_changed(self, locale: str): + """Set the keyboard layout according to the new language""" + + # Don't overwrite a user chosen value + if self.value_changed_by_user: + return + + layout = self._setting.get_layout_for_locale(locale) + if self.value == layout: + return + + self.value = layout + self.update_value_label() + self._setting.save(layout, is_default=True) diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py index cfbee7d9303668c29969cf49c2c650b7c73cf727..39d4dfb9d51685f3a15b84ebdb878e230a134eb2 100644 --- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py +++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py @@ -47,11 +47,13 @@ class GreeterSetting(object): self.title_label = self.builder.get_object("label_caption") self.value_label = self.builder.get_object("label_value") self.title_label.set_label(self.title) - self.update_value_label() def apply(self): self.update_value_label() + def load(self): + pass + def update_value_label(self): self.value_label.set_label(self.value_for_display)