From 362c0da53f7d42cc4121bd31a93c095d4c144dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20I=C3=B1iguez=20Goia?= Date: Wed, 12 Jun 2024 22:04:50 +0200 Subject: [PATCH] ui: allow to configure screen/themes scale factor Added new options to the Preferences dialog, to configure screens/themes scale factor. If the UI is using the System theme (default), configure Qt scale options (needs UI restart): QT_AUTO_SCREEN_SCALE_FACTOR (default True) QT_SCREEN_SCALE_FACTORS (If auto scale is False, use this value(s)) The user can configure different scale factors for multiple screens, by separating values with ; (1;1.5, etc...) https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt If the UI is using a qt-material theme, you can configure the "density" scale of the theme: https://github.com/UN-GCPDS/qt-material?tab=readme-ov-file#density-scale https://github.com/evilsocket/opensnitch/wiki/GUI-known-problems#gui-size-problems-on-4k-monitors (cherry-picked from bf9801f917e1a433150dc257453ce3cd719cd195) --- ui/bin/opensnitch-ui | 19 +- ui/opensnitch/config.py | 4 + ui/opensnitch/dialogs/preferences.py | 124 +++- ui/opensnitch/res/preferences.ui | 817 ++++++++++++++++----------- ui/opensnitch/service.py | 2 +- ui/opensnitch/utils/__init__.py | 30 +- 6 files changed, 613 insertions(+), 383 deletions(-) diff --git a/ui/bin/opensnitch-ui b/ui/bin/opensnitch-ui index f57f545079..336c5bf0be 100755 --- a/ui/bin/opensnitch-ui +++ b/ui/bin/opensnitch-ui @@ -65,6 +65,21 @@ def restrict_socket_perms(socket): except Exception as e: print("Unable to change unix socket permissions:", socket, e) +def configure_screen_scale_factor(cfg): + """configure qt screen scale: + https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt + """ + auto_screen_factor = cfg.getBool(Config.QT_AUTO_SCREEN_SCALE_FACTOR, default_value=True) + screen_factor = cfg.getSettings(Config.QT_SCREEN_SCALE_FACTOR) + if screen_factor is None or screen_factor == "": + screen_factor = "1" + + print("QT_AUTO_SCREEN_SCALE_FACTOR:", auto_screen_factor) + os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = str(int(auto_screen_factor)) + if auto_screen_factor is False: + print("QT_SCREEN_SCALE_FACTORS:", screen_factor) + os.environ["QT_SCREEN_SCALE_FACTORS"] = screen_factor + def check_environ(): if xdg_current_session == "": print(""" @@ -111,12 +126,13 @@ Examples: faulthandler.enable() logging.getLogger().disabled = not args.debug + cfg = Config.get() + configure_screen_scale_factor(cfg) if args.debug and args.debug_grpc: os.environ["GRPC_TRACE"] = "all" os.environ["GRPC_VERBOSITY"] = "debug" - os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" if supported_qt_version(5,6,0): try: # NOTE: maybe we also need Qt::AA_UseHighDpiPixmaps @@ -144,7 +160,6 @@ Examples: thm = Themes.instance() thm.load_theme(app) - cfg = Config.get() if args.socket == None: # default args.socket = "unix:///tmp/osui.sock" diff --git a/ui/opensnitch/config.py b/ui/opensnitch/config.py index c465530917..5b16c801eb 100644 --- a/ui/opensnitch/config.py +++ b/ui/opensnitch/config.py @@ -88,6 +88,7 @@ class Config: POPUP_BOTTOM_LEFT = 4 DEFAULT_THEME = "global/theme" + DEFAULT_THEME_DENSITY_SCALE = "global/theme_density_scale" DEFAULT_LANGUAGE = "global/language" DEFAULT_LANGNAME = "global/langname" DEFAULT_DISABLE_POPUPS = "global/disable_popups" @@ -138,6 +139,9 @@ class Config: STATS_VIEW_COL_STATE = "statsDialog/view_columns_state" STATS_VIEW_DETAILS_COL_STATE = "statsDialog/view_details_columns_state" + QT_AUTO_SCREEN_SCALE_FACTOR = "global/screen_scale_factor_auto" + QT_SCREEN_SCALE_FACTOR = "global/screen_scale_factor" + INFOWIN_GEOMETRY = "infoWindow/geometry" AUTH_TYPE = "auth/type" diff --git a/ui/opensnitch/dialogs/preferences.py b/ui/opensnitch/dialogs/preferences.py index 0e1b5a1eb1..f5e19b38ae 100644 --- a/ui/opensnitch/dialogs/preferences.py +++ b/ui/opensnitch/dialogs/preferences.py @@ -78,18 +78,21 @@ def __init__(self, parent=None, appicon=None): self.dbLabel.setVisible(False) self.dbType = None + intValidator = QtGui.QDoubleValidator(0, 20, 2, self) + self.lineUIScreenFactor.setValidator(intValidator) + self.acceptButton.clicked.connect(self._cb_accept_button_clicked) self.applyButton.clicked.connect(self._cb_apply_button_clicked) self.cancelButton.clicked.connect(self._cb_cancel_button_clicked) self.helpButton.clicked.connect(self._cb_help_button_clicked) self.popupsCheck.clicked.connect(self._cb_popups_check_toggled) self.dbFileButton.clicked.connect(self._cb_file_db_clicked) - self.checkUIRules.toggled.connect(self._cb_check_ui_rules_toggled) - self.comboUITheme.currentIndexChanged.connect(self._cb_combo_themes_changed) self.cmdTimeoutUp.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinUITimeout, self.SUM)) self.cmdTimeoutDown.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinUITimeout, self.REST)) self.cmdRefreshUIUp.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinUIRefresh, self.SUM)) self.cmdRefreshUIDown.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinUIRefresh, self.REST)) + self.cmdUIDensityUp.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinUIDensity, self.SUM)) + self.cmdUIDensityDown.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinUIDensity, self.REST)) self.cmdDBMaxDaysUp.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinDBMaxDays, self.SUM)) self.cmdDBMaxDaysDown.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinDBMaxDays, self.REST)) self.cmdDBPurgesUp.clicked.connect(lambda: self._cb_cmd_spin_clicked(self.spinDBPurgeInterval, self.SUM)) @@ -137,6 +140,8 @@ def __init__(self, parent=None, appicon=None): self.cmdTimeoutDown.setIcon(delIcon) self.cmdRefreshUIUp.setIcon(addIcon) self.cmdRefreshUIDown.setIcon(delIcon) + self.cmdUIDensityUp.setIcon(addIcon) + self.cmdUIDensityDown.setIcon(delIcon) self.cmdDBMaxDaysUp.setIcon(addIcon) self.cmdDBMaxDaysDown.setIcon(delIcon) self.cmdDBPurgesUp.setIcon(addIcon) @@ -206,6 +211,12 @@ def showEvent(self, event): self.lineNodeCertFile.textChanged.connect(self._cb_node_line_certs_changed) self.lineNodeCertKeyFile.textChanged.connect(self._cb_node_line_certs_changed) + self.lineUIScreenFactor.textChanged.connect(self._cb_ui_screen_factor_changed) + self.checkUIRules.toggled.connect(self._cb_ui_check_rules_toggled) + self.checkUIAutoScreen.toggled.connect(self._cb_ui_check_auto_scale_toggled) + self.comboUITheme.currentIndexChanged.connect(self._cb_combo_themes_changed) + self.spinUIDensity.valueChanged.connect(self._cb_spin_uidensity_changed) + self.comboDBType.currentIndexChanged.connect(self._cb_db_type_changed) self.checkDBMaxDays.toggled.connect(self._cb_db_max_days_toggled) self.checkDBJrnlWal.toggled.connect(self._cb_db_jrnl_wal_toggled) @@ -232,7 +243,7 @@ def _load_langs(self): def _load_themes(self): self.comboUITheme.blockSignals(True) - theme_idx, self._saved_theme = self._themes.get_saved_theme() + theme_idx, self._saved_theme, theme_density = self._themes.get_saved_theme() self.labelThemeError.setVisible(False) self.labelThemeError.setText("") @@ -248,6 +259,12 @@ def _load_themes(self): self.labelThemeError.setText(QC.translate("preferences", "Themes not available. Install qt-material: pip3 install qt-material")) self.comboUITheme.setCurrentIndex(theme_idx) + self._show_ui_density_widgets(theme_idx) + try: + self.spinUIDensity.setValue(int(theme_density)) + except Exception as e: + print("load_theme() invalid theme density scale:", theme_density, ":", e) + self.comboUITheme.blockSignals(False) def _load_settings(self): @@ -263,11 +280,16 @@ def _load_settings(self): self.comboUIDuration.setCurrentIndex(self._default_duration) self.comboUIDialogPos.setCurrentIndex(self._cfg.getInt(self._cfg.DEFAULT_POPUP_POSITION)) + self.comboUIAction.setCurrentIndex(self._default_action) + self.comboUITarget.setCurrentIndex(self._default_target) + self.spinUITimeout.setValue(self._default_timeout) + self.spinUITimeout.setEnabled(not self._disable_popups) + self.popupsCheck.setChecked(self._disable_popups) - self._ui_refresh_interval = self._cfg.getInt(self._cfg.STATS_REFRESH_INTERVAL, 0) - self.spinUIRefresh.setValue(self._ui_refresh_interval) - - self.checkAutostart.setChecked(self._autostart.isEnabled()) + self.showAdvancedCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED)) + self.dstIPCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED_DSTIP)) + self.dstPortCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED_DSTPORT)) + self.uidCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED_UID)) maxmsgsize = self._cfg.getSettings(Config.DEFAULT_SERVER_MAX_MESSAGE_LENGTH) if maxmsgsize: @@ -286,17 +308,11 @@ def _load_settings(self): self.lineCertKeyFile.setEnabled(False) self.comboAuthType.setCurrentIndex(authtype_idx) - saved_lang = self._cfg.getSettings(Config.DEFAULT_LANGUAGE) - if saved_lang: - saved_langname = self._cfg.getSettings(Config.DEFAULT_LANGNAME) - self.comboUILang.blockSignals(True) - self.comboUILang.setCurrentText(saved_langname) - self.comboUILang.blockSignals(False) - self.comboUIRules.blockSignals(True) self.comboUIRules.setCurrentIndex(self._cfg.getInt(self._cfg.DEFAULT_IGNORE_TEMPORARY_RULES)) self.checkUIRules.setChecked(self._cfg.getBool(self._cfg.DEFAULT_IGNORE_RULES)) self.comboUIRules.setEnabled(self._cfg.getBool(self._cfg.DEFAULT_IGNORE_RULES)) + #self._set_rules_duration_filter() self._cfg.setRulesDurationFilter( @@ -305,18 +321,7 @@ def _load_settings(self): ) self.comboUIRules.blockSignals(False) - self.comboUIAction.setCurrentIndex(self._default_action) - self.comboUITarget.setCurrentIndex(self._default_target) - self.spinUITimeout.setValue(self._default_timeout) - self.spinUITimeout.setEnabled(not self._disable_popups) - self.popupsCheck.setChecked(self._disable_popups) - - self.showAdvancedCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED)) - self.dstIPCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED_DSTIP)) - self.dstPortCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED_DSTPORT)) - self.uidCheck.setChecked(self._cfg.getBool(self._cfg.DEFAULT_POPUP_ADVANCED_UID)) - - # by default, if no configuration exists, enable notifications. + # by default, if no configuration exists, enable notifications. self.groupNotifs.setChecked(self._cfg.getBool(Config.NOTIFICATIONS_ENABLED, True)) self.radioSysNotifs.setChecked( True if self._cfg.getInt(Config.NOTIFICATIONS_TYPE) == Config.NOTIFICATION_TYPE_SYSTEM and self._desktop_notifications.is_available() == True else False @@ -325,6 +330,7 @@ def _load_settings(self): True if self._cfg.getInt(Config.NOTIFICATIONS_TYPE) == Config.NOTIFICATION_TYPE_QT or self._desktop_notifications.is_available() == False else False ) + ## db self.dbType = self._cfg.getInt(self._cfg.DEFAULT_DB_TYPE_KEY) self.comboDBType.setCurrentIndex(self.dbType) if self.comboDBType.currentIndex() != Database.DB_TYPE_MEMORY: @@ -341,6 +347,31 @@ def _load_settings(self): self._load_themes() self._load_node_settings() + self._load_ui_settings() + + def _load_ui_settings(self): + self._ui_refresh_interval = self._cfg.getInt(self._cfg.STATS_REFRESH_INTERVAL, 0) + self.spinUIRefresh.setValue(self._ui_refresh_interval) + + saved_lang = self._cfg.getSettings(Config.DEFAULT_LANGUAGE) + if saved_lang: + saved_langname = self._cfg.getSettings(Config.DEFAULT_LANGNAME) + self.comboUILang.blockSignals(True) + self.comboUILang.setCurrentText(saved_langname) + self.comboUILang.blockSignals(False) + + auto_scale = self._cfg.getBool(Config.QT_AUTO_SCREEN_SCALE_FACTOR, default_value=True) + screen_factor = self._cfg.getSettings(Config.QT_SCREEN_SCALE_FACTOR) + if screen_factor is None or screen_factor == "": + screen_factor = "1" + self.lineUIScreenFactor.setText(screen_factor) + self.checkUIAutoScreen.blockSignals(True) + self.checkUIAutoScreen.setChecked(auto_scale) + self.checkUIAutoScreen.blockSignals(False) + self._show_ui_scalefactor_widgets(auto_scale) + + self.checkAutostart.setChecked(self._autostart.isEnabled()) + self._load_ui_columns_config() def _load_node_settings(self): @@ -605,7 +636,10 @@ def _save_ui_config(self): self._cfg.setSettings(self._cfg.NOTIFICATIONS_TYPE, int(Config.NOTIFICATION_TYPE_SYSTEM if self.radioSysNotifs.isChecked() else Config.NOTIFICATION_TYPE_QT)) - self._themes.save_theme(self.comboUITheme.currentIndex(), self.comboUITheme.currentText()) + self._themes.save_theme(self.comboUITheme.currentIndex(), self.comboUITheme.currentText(), str(self.spinUIDensity.value())) + + self._cfg.setSettings(Config.QT_AUTO_SCREEN_SCALE_FACTOR, bool(self.checkUIAutoScreen.isChecked())) + self._cfg.setSettings(Config.QT_SCREEN_SCALE_FACTOR, self.lineUIScreenFactor.text()) if self._themes.available() and self._saved_theme != "" and self.comboUITheme.currentText() == QC.translate("preferences", "System"): self._changes_needs_restart = QC.translate("preferences", "UI theme changed") @@ -759,6 +793,21 @@ def _needs_restart(self): QtWidgets.QMessageBox.Warning) self._changes_needs_restart = None + + def _show_ui_density_widgets(self, idx): + """show ui density widget only for qt-material themes: + https://github.com/UN-GCPDS/qt-material?tab=readme-ov-file#density-scale + """ + hidden = idx == 0 + self.labelUIDensity.setHidden(hidden) + self.spinUIDensity.setHidden(hidden) + self.cmdUIDensityUp.setHidden(hidden) + self.cmdUIDensityDown.setHidden(hidden) + + def _show_ui_scalefactor_widgets(self, show=False): + self.labelUIScreenFactor.setHidden(show) + self.lineUIScreenFactor.setHidden(show) + def _hide_status_label(self): self.statusLabel.hide() @@ -800,6 +849,12 @@ def _enable_db_jrnl_wal(self, enable, db_jrnl_wal): self.checkDBJrnlWal.setChecked(db_jrnl_wal) self.checkDBJrnlWal.setEnabled(enable) + def _change_theme(self): + extra_opts = { + 'density_scale': str(self.spinUIDensity.value()) + } + self._themes.change_theme(self, self.comboUITheme.currentText(), extra_opts) + @QtCore.pyqtSlot(ui_pb2.NotificationReply) def _cb_notification_callback(self, reply): #print(self.LOG_TAG, "Config notification received: ", reply.id, reply.code) @@ -870,11 +925,22 @@ def _cb_node_combo_changed(self, index): def _cb_node_needs_update(self): self._node_needs_update = True - def _cb_check_ui_rules_toggled(self, state): + def _cb_ui_check_rules_toggled(self, state): self.comboUIRules.setEnabled(state) def _cb_combo_themes_changed(self, index): - self._themes.change_theme(self, self.comboUITheme.currentText()) + self._change_theme() + self._show_ui_density_widgets(index) + + def _cb_spin_uidensity_changed(self, value): + self._change_theme() + + def _cb_ui_check_auto_scale_toggled(self, checked): + self._changes_needs_restart = True + self._show_ui_scalefactor_widgets(checked) + + def _cb_ui_screen_factor_changed(self, text): + self._changes_needs_restart = True def _cb_combo_auth_type_changed(self, index): curtype = self.comboAuthType.itemData(self.comboAuthType.currentIndex()) diff --git a/ui/opensnitch/res/preferences.ui b/ui/opensnitch/res/preferences.ui index a305f06317..2c0cc51a6f 100644 --- a/ui/opensnitch/res/preferences.ui +++ b/ui/opensnitch/res/preferences.ui @@ -7,7 +7,7 @@ 0 0 626 - 494 + 534 @@ -210,338 +210,340 @@ - - - - Default options + + + + Disable pop-ups, only display a notification - - - - - - - - 0 - 0 - - - - If checked, this field will be selected when a pop-up is displayed + + true + + + + + + + + Default options + + + + + + + 0 + 0 + + + + + once + + - User ID + 30s - - - - - - - 0 - 0 - + + + + 5m - - If checked, this field will be selected when a pop-up is displayed + + + + 15m + + - Destination port + 30m - - - - - - - 0 - 0 - + + + + 1h - - If checked, this field will be selected when a pop-up is displayed + + + + until reboot + + - Destination IP + forever - - - - - - - - - 0 - 0 - - - - - deny + + + + + + + <html><head/><body><p>Pop-up default action.</p><p>When a new outgoing connection is about to be established, this action will be selected by default, so if the timeout fires, this is the option that will be applied.</p><p>While a pop-up is asking the user to allow or deny a connection:</p><p>1. the daemon's default action will be applied (see Nodes tab).</p><p>2. known connections are allowed or denied based on the rules defined by the user.</p></body></html> - - - ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup + + Action - - + + + + - allow + Default position on screen - - - ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup + + true - - - - reject - - - - .. - - - - - - - - <html><head/><body><p>Pop-up default action.</p><p>When a new outgoing connection is about to be established, this action will be selected by default, so if the timeout fires, this is the option that will be applied.</p><p>While a pop-up is asking the user to allow or deny a connection:</p><p>1. the daemon's default action will be applied (see Nodes tab).</p><p>2. known connections are allowed or denied based on the rules defined by the user.</p></body></html> - - - Action - - - - - - - true - - - - 0 - 0 - - - - - center + + + + + + Pop-up default duration - - - top right + Duration - - - - bottom right + + + + + + + 0 + 0 + - - - - top left + + + by executable + + + + + by command line + + + + + by destination port + + + + + by destination ip + + + + + by user id + + + + + by PID + + + + + + + + true - - - - bottom left - - - - - - - - - 0 - 0 - - - - - once + + + 0 + 0 + - - - - 30s + + + center + + + + + top right + + + + + bottom right + + + + + top left + + + + + bottom left + + + + + + + + + 0 + 0 + - - + + + deny + + + + ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup + + + + + allow + + + + ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup + + + + + reject + + + + .. + + + + + + - 5m + Default target - - - - 15m + + + + + + + More + + + + + + + + + 0 + 0 + + + + If checked, this field will be selected when a pop-up is displayed + + + User ID + + + + + + + + 0 + 0 + + + + If checked, this field will be selected when a pop-up is displayed + + + Destination port + + + + + + + + 0 + 0 + + + + If checked, this field will be selected when a pop-up is displayed + + + Destination IP + + + + + + + + + + 0 + 0 + - - - - 30m + + <html><head/><body><p>By default when a new pop-up appears, in its simplest form, you'll be able to filter connections or applications by one property of the connection (executable, port, IP, etc).</p><p>With these options, you can choose multiple fields to filter connections for.</p></body></html> - - - 1h + Filter connections also by: - - - - until reboot + + true - - - - forever - - - - - - - - - 0 - 0 - - - - <html><head/><body><p>By default when a new pop-up appears, in its simplest form, you'll be able to filter connections or applications by one property of the connection (executable, port, IP, etc).</p><p>With these options, you can choose multiple fields to filter connections for.</p></body></html> - - - Filter connections also by: - - - true - - - - - - - - 0 - 0 - - - - - by executable + + + + + + + 0 + 0 + - - - - by command line + + The advanced view allows you to easily select multiple fields to filter connections - - - by destination port + Show advanced view by default - - - - by destination ip + + true - - - - by user id + + + + + + + 0 + 0 + + + + <html><head/><body><p>If checked, the pop-ups will be displayed with the advanced view active.</p></body></html> - - - by PID - - - - - - - - Qt::Horizontal - - - - - - - Default target - - - - - - - Default position on screen - - - true - - - - - - - Pop-up default duration - - - Duration - - - - - - - - 0 - 0 - - - - The advanced view allows you to easily select multiple fields to filter connections - - - Show advanced view by default - - - true - - - - - - - - 0 - 0 - - - - <html><head/><body><p>If checked, the pop-ups will be displayed with the advanced view active.</p></body></html> - - - - - - - - - - - - - Disable pop-ups, only display a notification - - - true - + + + + + + @@ -551,7 +553,7 @@ UI - + 0 @@ -562,14 +564,86 @@ 0 0 586 - 252 + 301 General - - + + + + + 0 + + + + + + 0 + 0 + + + + + + + + ../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../.designer/backup + + + true + + + + + + + + 0 + 0 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + true + + + 100 + + + 1 + + + + + + + + 0 + 0 + + + + + + + + ../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../.designer/backup + + + true + + + + + + @@ -585,30 +659,43 @@ - - + + - + 0 0 - - Theme + + Use numbers to define a global scale factor for the whole application: +1, 1.2, 1.5, 2, etc ... + +Use ; to define multiple screens: 1;1.5 etc... + + + ex: 1, 1.25, 1.5, 2, ... - - - - - System - - + + + + + + + + 0 + 0 + + + + Language + - - + + 0 @@ -616,12 +703,12 @@ - + Theme density scale - + 0 @@ -629,33 +716,40 @@ - Language + Theme - - - - - - - By default the GUI is started when login - + + - Autostart the GUI upon login + Auto screen scale factor true - - + + + + + 0 + 0 + + + + <html><head/><body><p>Scale factor (use ; for multiple displays) <a href="https://github.com/evilsocket/opensnitch/wiki/GUI-known-problems#gui-size-problems-on-4k-monitors"><span style=" text-decoration: underline; color:#0000ff;">More information</span></a></p></body></html> + + + + + 0 - + 0 @@ -667,7 +761,7 @@ - ../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../.designer/backup + ../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../.designer/backup true @@ -675,7 +769,7 @@ - + 0 @@ -691,16 +785,19 @@ true + + -20 + - 100 + 20 - 1 + 0 - + 0 @@ -712,7 +809,7 @@ - ../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../.designer/backup + ../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../.designer/backup true @@ -721,6 +818,44 @@ + + + + + System + + + + + + + + + 0 + 0 + + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + By default the GUI is started when login + + + Autostart the GUI upon login + + + true + + + @@ -729,7 +864,7 @@ 0 0 586 - 240 + 301 @@ -836,7 +971,7 @@ 0 0 586 - 240 + 301 @@ -932,7 +1067,7 @@ 0 0 586 - 240 + 301 @@ -1275,7 +1410,7 @@ Temporary rules will still be valid, and you can use them when prompted to allow 0 0 586 - 211 + 260 @@ -1425,7 +1560,7 @@ Temporary rules will still be valid, and you can use them when prompted to allow 0 0 586 - 199 + 260 @@ -1560,8 +1695,8 @@ Temporary rules will still be valid, and you can use them when prompted to allow 0 0 - 572 - 211 + 586 + 260 diff --git a/ui/opensnitch/service.py b/ui/opensnitch/service.py index abca096d53..a5fd071755 100644 --- a/ui/opensnitch/service.py +++ b/ui/opensnitch/service.py @@ -415,7 +415,7 @@ def _on_settings_saved(self): elif self._cfg.getBool(Config.DEFAULT_DB_PURGE_OLDEST) == False and self._cleaner != None: self._stop_db_cleaner() - theme_idx, theme_name = self._themes.get_saved_theme() + theme_idx, theme_name, theme_density = self._themes.get_saved_theme() if theme_idx > 0: self._themes.load_theme(self._app) diff --git a/ui/opensnitch/utils/__init__.py b/ui/opensnitch/utils/__init__.py index 6a0469775b..4d81e48eac 100644 --- a/ui/opensnitch/utils/__init__.py +++ b/ui/opensnitch/utils/__init__.py @@ -125,19 +125,24 @@ def available(self): return Themes.AVAILABLE def get_saved_theme(self): + theme = self._cfg.getSettings(self._cfg.DEFAULT_THEME) + theme_density = self._cfg.getSettings(self._cfg.DEFAULT_THEME_DENSITY_SCALE) + if theme_density == "" or theme_density == None: + theme_density = '0' + if not Themes.AVAILABLE: - return 0, "" + return 0, "", theme_density - theme = self._cfg.getSettings(self._cfg.DEFAULT_THEME) if theme != "" and theme != None: # 0 == System - return self.list_themes().index(theme)+1, theme - return 0, "" + return self.list_themes().index(theme)+1, theme, theme_density + return 0, "", theme_density - def save_theme(self, theme_idx, theme): + def save_theme(self, theme_idx, theme, density_scale): if not Themes.AVAILABLE: return + self._cfg.setSettings(self._cfg.DEFAULT_THEME_DENSITY_SCALE, density_scale) if theme_idx == 0: self._cfg.setSettings(self._cfg.DEFAULT_THEME, "") else: @@ -148,20 +153,23 @@ def load_theme(self, app): return try: - theme_idx, theme_name = self.get_saved_theme() + theme_idx, theme_name, theme_density = self.get_saved_theme() if theme_name != "": invert = "light" in theme_name print("Using theme:", theme_idx, theme_name, "inverted:", invert) # TODO: load {theme}.xml.extra and .xml.css for further # customizations. - Themes.qtmaterial_apply_stylesheet(app, theme=theme_name, invert_secondary=invert) + extra_opts = { + 'density_scale': theme_density + } + Themes.qtmaterial_apply_stylesheet(app, theme=theme_name, invert_secondary=invert, extra=extra_opts) except Exception as e: print("Themes.load_theme() exception:", e) - def change_theme(self, window, theme_name): + def change_theme(self, window, theme_name, extra={}): try: invert = "light" in theme_name - Themes.qtmaterial_apply_stylesheet(window, theme=theme_name, invert_secondary=invert) + Themes.qtmaterial_apply_stylesheet(window, theme=theme_name, invert_secondary=invert, extra=extra) except Exception as e: print("Themes.change_theme() exception:", e, " - ", window, theme_name) @@ -470,7 +478,9 @@ class Icons(): 'system-search': "SP_FileDialogContentsView", 'accessories-text-editor': "SP_DialogOpenButton", 'edit-clear-all': "SP_DialogResetButton", - 'reload': "SP_DialogResetButton" + 'reload': "SP_DialogResetButton", + 'dialog-information': "SP_MessageBoxInformation", + 'dialog-warning': "SP_MessageBoxWarning" } @staticmethod