From 48eaee524125db30bc58dd455b161e0224bf9648 Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Thu, 14 May 2026 16:12:35 +0500 Subject: [PATCH 1/4] feat: added disable runtime download settings Signed-off-by: Boris Yumankulov --- .../share/portproton/scripts/functions_helper | 15 ++++++++++--- build-aux/share/portproton/scripts/start.sh | 5 +++++ portprotonqt/app.py | 1 + portprotonqt/config/ui.py | 12 +++++++++++ portprotonqt/main_window.py | 21 +++++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/build-aux/share/portproton/scripts/functions_helper b/build-aux/share/portproton/scripts/functions_helper index ce46489d..cb2ba0c4 100755 --- a/build-aux/share/portproton/scripts/functions_helper +++ b/build-aux/share/portproton/scripts/functions_helper @@ -1282,7 +1282,11 @@ init_wine_ver () { } pw_init_runtime () { - check_flatpak && export PW_USE_RUNTIME="0" + if [[ ! -f "${PW_WINELIB}/runtime/files/bin/vkcube" ]] \ + || [[ ! -f "${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-wrap" ]] + then + export PW_USE_RUNTIME="0" + fi if [[ "$PW_USE_RUNTIME" != "1" ]] \ || [[ "$PW_WINE_USE" == "USE_SYSTEM_WINE" ]] then @@ -2515,7 +2519,7 @@ pw_enable_gamemode_basic () { start_portproton () { pw_check_and_download_plugins - if check_flatpak ; then + if [[ "${PW_DISABLE_RUNTIME_DOWNLOAD}" == "1" ]] ; then try_remove_dir "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}" else pw_check_and_download_runtime @@ -4110,7 +4114,12 @@ gui_edit_db () { if [[ $PW_WINE_USE =~ (PROTON_LG|WINE_LG) ]] || [[ $PW_VULKAN_USE == "0" ]] ; then DISABLE_EDIT_DB_LIST+=" PW_USE_SUPPLIED_DXVK_VKD3D" fi - check_flatpak && DISABLE_EDIT_DB_LIST+=" PW_USE_RUNTIME" + + if [[ ! -f "${PW_WINELIB}/runtime/files/bin/vkcube" ]] \ + || [[ ! -f "${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-wrap" ]] + then + DISABLE_EDIT_DB_LIST+=" PW_USE_RUNTIME" + fi # GALLIUM NINE [[ ! -f "${PW_TMPFS_PATH}/gallium_nine.tmp" ]] && DISABLE_EDIT_DB_LIST+=" PW_USE_GALLIUM_NINE" diff --git a/build-aux/share/portproton/scripts/start.sh b/build-aux/share/portproton/scripts/start.sh index cb1e09ce..f37154bf 100755 --- a/build-aux/share/portproton/scripts/start.sh +++ b/build-aux/share/portproton/scripts/start.sh @@ -37,6 +37,11 @@ if [[ -z "$PORT_DATA_PATH" ]] ; then fi fi +if [[ -f "$HOME/.config/PortProtonQt.conf" ]] \ +&& grep "disable_runtime_download = True" "$HOME/.config/PortProtonQt.conf" ; then + export PW_DISABLE_RUNTIME_DOWNLOAD=1 +fi + export PORT_SCRIPTS_PATH PORT_IMG_PATH PORT_DATA_PATH PORT_CONF_PATH export PW_LOG_FILE="${PORT_DATA_PATH}/PortProton.log" diff --git a/portprotonqt/app.py b/portprotonqt/app.py index 2695a888..02f82e73 100644 --- a/portprotonqt/app.py +++ b/portprotonqt/app.py @@ -179,6 +179,7 @@ def main(): portproton_location = get_portproton_location() if portproton_location: os.environ["PORT_DATA_PATH"] = portproton_location + ui_config.get_disable_runtime_download() # Check if running as Steam compatibility tool (STEAM_COMPAT=1). is_steam_compat = os.environ.get("STEAM_COMPAT") == "1" diff --git a/portprotonqt/config/ui.py b/portprotonqt/config/ui.py index b63d0f19..ee7e5337 100644 --- a/portprotonqt/config/ui.py +++ b/portprotonqt/config/ui.py @@ -294,6 +294,18 @@ class UIConfig(BaseConfig): validate_bool(enabled, "download_wine_to_steam") self._save_value("download_wine_to_steam", enabled, "bool") + def get_disable_runtime_download(self) -> bool: + """Get PortProton runtime download setting.""" + default = bool(os.getenv("FLATPAK_ID")) + return self._get_bool("disable_runtime_download", default) + + def set_disable_runtime_download(self, enabled: bool) -> None: + """Set PortProton runtime download setting.""" + if os.getenv("FLATPAK_ID"): + enabled = True + validate_bool(enabled, "disable_runtime_download") + self._save_value("disable_runtime_download", enabled, "bool") + def load_theme_metainfo(theme_name: str) -> dict: """Load theme metadata from metainfo.ini.""" diff --git a/portprotonqt/main_window.py b/portprotonqt/main_window.py index 88f5aecc..f398e631 100644 --- a/portprotonqt/main_window.py +++ b/portprotonqt/main_window.py @@ -2411,6 +2411,22 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind hide_autoinstall_layout.addStretch() uiForm.addRow(hide_autoinstall_layout) + if not os.getenv("FLATPAK_ID"): + self.disableRuntimeDownloadCheckBox = QCheckBox() + self.disableRuntimeDownloadCheckBox.setStyleSheet(self.theme.CHECKBOX_STYLE) + self.disableRuntimeDownloadCheckBox.setFocusPolicy(Qt.FocusPolicy.StrongFocus) + self.disableRuntimeDownloadTitle = QLabel(_("Disable PortProton runtime download")) + self.disableRuntimeDownloadTitle.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) + self.disableRuntimeDownloadTitle.setStyleSheet(self.theme.SETTINGS_TITLE_CHECKBOX_STYLE) + self.disableRuntimeDownloadTitle.setFocusPolicy(Qt.FocusPolicy.NoFocus) + self.disableRuntimeDownloadCheckBox.setChecked(ui_config.get_disable_runtime_download()) + disable_runtime_download_layout = QHBoxLayout() + disable_runtime_download_layout.setContentsMargins(0, 0, 0, 0) + disable_runtime_download_layout.addWidget(self.disableRuntimeDownloadCheckBox) + disable_runtime_download_layout.addWidget(self.disableRuntimeDownloadTitle) + disable_runtime_download_layout.addStretch() + uiForm.addRow(disable_runtime_download_layout) + self.steamCompatCheckBox = QCheckBox() self.steamCompatCheckBox.setStyleSheet(self.theme.CHECKBOX_STYLE) self.steamCompatCheckBox.setFocusPolicy(Qt.FocusPolicy.StrongFocus) @@ -2732,6 +2748,11 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind if hasattr(self, 'downloadWineToSteamCheckBox'): ui_config.set_download_wine_to_steam(self.downloadWineToSteamCheckBox.isChecked()) + if hasattr(self, 'disableRuntimeDownloadCheckBox'): + ui_config.set_disable_runtime_download(self.disableRuntimeDownloadCheckBox.isChecked()) + else: + ui_config.get_disable_runtime_download() + # Save GPU selection to user.conf (only if the combo box exists) if hasattr(self, 'gpuCombo') and self.gpuCombo.count() > 1: selected_gpu = self.gpuCombo.currentText() -- 2.54.0 From 0d9f08524008c83e9a84eee93db9ef6ac1e9ce4a Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Thu, 14 May 2026 20:40:38 +0500 Subject: [PATCH 2/4] chore(settings): move download options from appearance Signed-off-by: Boris Yumankulov --- portprotonqt/config/ui.py | 44 ++++++++++++++++++++++++++++++++----- portprotonqt/main_window.py | 26 ++++++++++++++++------ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/portprotonqt/config/ui.py b/portprotonqt/config/ui.py index ee7e5337..bcfb6201 100644 --- a/portprotonqt/config/ui.py +++ b/portprotonqt/config/ui.py @@ -15,6 +15,7 @@ from portprotonqt.logger import get_logger logger = get_logger(__name__) THEME_VARIANTS = ("dark", "light", "auto") +DOWNLOADS_SECTION = "Downloads" def _read_theme_variants(theme_name: str) -> dict[str, str]: @@ -278,33 +279,64 @@ class UIConfig(BaseConfig): def get_economy_mode(self) -> bool: """Get economy mode setting.""" - return self._get_bool("economy_mode", False) + return self._get_download_bool("economy_mode", False) def set_economy_mode(self, enabled: bool): """Set economy mode setting.""" validate_bool(enabled, "economy_mode") - self._save_value("economy_mode", enabled, "bool") + self._save_download_value("economy_mode", enabled) + + def _get_download_bool(self, option: str, default: bool) -> bool: + cp = self._read_config() + if cp is None: + return self._save_download_value(option, default) + + try: + if cp.has_option(DOWNLOADS_SECTION, option): + return cp.getboolean(DOWNLOADS_SECTION, option, fallback=default) + if cp.has_option(self._section, option): + return cp.getboolean(self._section, option, fallback=default) + except ValueError as e: + logger.warning("Error reading %s: %s", option, e) + return self._save_download_value(option, default) + except configparser.Error as e: + logger.warning("Error reading %s: %s", option, e) + return self._save_download_value(option, default) + + return self._save_download_value(option, default) + + def _save_download_value(self, option: str, value: bool) -> bool: + validate_bool(value, option) + cp = self._read_config() or configparser.ConfigParser() + if DOWNLOADS_SECTION not in cp: + cp[DOWNLOADS_SECTION] = {} + + cp[DOWNLOADS_SECTION][option] = str(value) + if cp.has_section(self._section): + cp.remove_option(self._section, option) + self._save_config(cp) + return value def get_download_wine_to_steam(self) -> bool: """Get Steam compatibility tools download setting.""" - return self._get_bool("download_wine_to_steam", False) + return self._get_download_bool("download_wine_to_steam", False) def set_download_wine_to_steam(self, enabled: bool) -> None: """Set Steam compatibility tools download setting.""" validate_bool(enabled, "download_wine_to_steam") - self._save_value("download_wine_to_steam", enabled, "bool") + self._save_download_value("download_wine_to_steam", enabled) def get_disable_runtime_download(self) -> bool: """Get PortProton runtime download setting.""" default = bool(os.getenv("FLATPAK_ID")) - return self._get_bool("disable_runtime_download", default) + return self._get_download_bool("disable_runtime_download", default) def set_disable_runtime_download(self, enabled: bool) -> None: """Set PortProton runtime download setting.""" if os.getenv("FLATPAK_ID"): enabled = True validate_bool(enabled, "disable_runtime_download") - self._save_value("disable_runtime_download", enabled, "bool") + self._save_download_value("disable_runtime_download", enabled) def load_theme_metainfo(theme_name: str) -> dict: diff --git a/portprotonqt/main_window.py b/portprotonqt/main_window.py index f398e631..28ee2592 100644 --- a/portprotonqt/main_window.py +++ b/portprotonqt/main_window.py @@ -2411,11 +2411,12 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind hide_autoinstall_layout.addStretch() uiForm.addRow(hide_autoinstall_layout) + disable_runtime_download_layout = None if not os.getenv("FLATPAK_ID"): self.disableRuntimeDownloadCheckBox = QCheckBox() self.disableRuntimeDownloadCheckBox.setStyleSheet(self.theme.CHECKBOX_STYLE) self.disableRuntimeDownloadCheckBox.setFocusPolicy(Qt.FocusPolicy.StrongFocus) - self.disableRuntimeDownloadTitle = QLabel(_("Disable PortProton runtime download")) + self.disableRuntimeDownloadTitle = QLabel(_("Disable runtime download")) self.disableRuntimeDownloadTitle.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.disableRuntimeDownloadTitle.setStyleSheet(self.theme.SETTINGS_TITLE_CHECKBOX_STYLE) self.disableRuntimeDownloadTitle.setFocusPolicy(Qt.FocusPolicy.NoFocus) @@ -2425,8 +2426,8 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind disable_runtime_download_layout.addWidget(self.disableRuntimeDownloadCheckBox) disable_runtime_download_layout.addWidget(self.disableRuntimeDownloadTitle) disable_runtime_download_layout.addStretch() - uiForm.addRow(disable_runtime_download_layout) + download_wine_to_steam_layout = None self.steamCompatCheckBox = QCheckBox() self.steamCompatCheckBox.setStyleSheet(self.theme.CHECKBOX_STYLE) self.steamCompatCheckBox.setFocusPolicy(Qt.FocusPolicy.StrongFocus) @@ -2457,7 +2458,6 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind download_wine_to_steam_layout.addWidget(self.downloadWineToSteamCheckBox) download_wine_to_steam_layout.addWidget(self.downloadWineToSteamTitle) download_wine_to_steam_layout.addStretch() - uiForm.addRow(download_wine_to_steam_layout) self.economyModeCheckBox = QCheckBox() self.economyModeCheckBox.setStyleSheet(self.theme.CHECKBOX_STYLE) @@ -2481,7 +2481,6 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind economy_mode_layout.addWidget(self.economyModeCheckBox) economy_mode_layout.addWidget(self.economyModeTitle) economy_mode_layout.addStretch() - uiForm.addRow(economy_mode_layout) self.forceSystemDpiCheckBox = QCheckBox() self.forceSystemDpiCheckBox.setStyleSheet(self.theme.CHECKBOX_STYLE) @@ -2499,7 +2498,20 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind force_system_dpi_layout.addStretch() uiForm.addRow(force_system_dpi_layout) - # 3. Gamepad Settings Section + # 3. Download Settings Section + downloadFrame, downloadForm = create_section(_("Download Settings"), self.theme) + downloadForm.setRowWrapPolicy(QFormLayout.RowWrapPolicy.DontWrapRows) + scrollLayout.addWidget(downloadFrame) + + if disable_runtime_download_layout is not None: + downloadForm.addRow(disable_runtime_download_layout) + + if download_wine_to_steam_layout is not None: + downloadForm.addRow(download_wine_to_steam_layout) + + downloadForm.addRow(economy_mode_layout) + + # 4. Gamepad Settings Section padFrame, padForm = create_section(_("Gamepad Settings"), self.theme) padForm.setRowWrapPolicy(QFormLayout.RowWrapPolicy.DontWrapRows) scrollLayout.addWidget(padFrame) @@ -2520,7 +2532,7 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind auto_fullscreen_layout.addStretch() padForm.addRow(auto_fullscreen_layout) - # 4. Hardware Settings Section + # 5. Hardware Settings Section hwFrame, hwForm = create_section(_("Hardware Settings"), self.theme) hwForm.setRowWrapPolicy(QFormLayout.RowWrapPolicy.DontWrapRows) scrollLayout.addWidget(hwFrame) @@ -2556,7 +2568,7 @@ class MainWindow(MainWindowControlHintsMixin, MainWindowSystemTabMixin, MainWind elif not filtered_gpu_list: hwForm.addRow(QLabel(_("No GPUs found")), QLabel("")) - # 5. Proxy Settings Section + # 6. Proxy Settings Section proxyFrame, proxyForm = create_section(_("Proxy Settings"), self.theme) proxyForm.setRowWrapPolicy(QFormLayout.RowWrapPolicy.DontWrapRows) scrollLayout.addWidget(proxyFrame) -- 2.54.0 From a8d043cea1e7c11899ceef03da3681bce39a216c Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Tue, 19 May 2026 00:10:24 +0500 Subject: [PATCH 3/4] chore: use xterm from plugins Signed-off-by: Boris Yumankulov --- build-aux/share/portproton/scripts/start.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build-aux/share/portproton/scripts/start.sh b/build-aux/share/portproton/scripts/start.sh index f37154bf..d156119e 100755 --- a/build-aux/share/portproton/scripts/start.sh +++ b/build-aux/share/portproton/scripts/start.sh @@ -200,8 +200,8 @@ if [[ -z "$DOWNLOAD_STEAM_GRID" ]] ; then fi if check_gamescope_session -then PW_TERM="env LANG=C xterm -fullscreen -bg black -fg white -e" -else PW_TERM="env LANG=C xterm -bg black -fg white -e" +then PW_TERM="env LANG=C $PW_PLUGINS_PATH/portable/bin/xterm -fullscreen -bg black -fg white -e" +else PW_TERM="env LANG=C $PW_PLUGINS_PATH/portable/bin/xterm -bg black -fg white -e" fi pw_cleanup () { @@ -433,7 +433,7 @@ Usage examples: get_wine_and_pfx "$2" "$3" start_portproton cd "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c" || fatal - if check_flatpak ; then + if [[ $PW_DISABLE_RUNTIME_DOWNLOAD == "1" ]]; then $PW_TERM "pw_run cmd" else export PW_USE_TERMINAL=1 -- 2.54.0 From 8cefe93b7079c07b145717347ae3664cf63a405b Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Wed, 20 May 2026 21:12:25 +0500 Subject: [PATCH 4/4] chore: use squashfs-tools from plugins Signed-off-by: Boris Yumankulov --- build-aux/share/portproton/scripts/functions_helper | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/share/portproton/scripts/functions_helper b/build-aux/share/portproton/scripts/functions_helper index cb2ba0c4..d1839f3d 100755 --- a/build-aux/share/portproton/scripts/functions_helper +++ b/build-aux/share/portproton/scripts/functions_helper @@ -4708,7 +4708,7 @@ pw_create_prefix_backup_cli () { chmod -R u+w "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}" echo "#!/usr/bin/env bash - ${TMP_ALL_PATH} mksquashfs \"${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}\" \ + ${TMP_ALL_PATH} \"${PW_PLUGINS_PATH}/portable/bin/mksquashfs\" \"${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}\" \ \"${PW_PREFIX_TO_BACKUP}/${PW_PREFIX_NAME}.ppack.part\" -comp zstd \ || rm -f \"${PW_PREFIX_TO_BACKUP}/${PW_PREFIX_NAME}.ppack.part\" " > "${PORT_WINE_TMP_PATH}/pp_pfx_backup.sh" @@ -4749,7 +4749,7 @@ pw_unpack_prefix () { PW_PREFIX_NAME=$(basename "${PW_BACKUP_FILE^^}" .PPACK) echo "#!/usr/bin/env bash - ${TMP_ALL_PATH} unsquashfs $NO_XATTRS_NEED -f -d \ + ${TMP_ALL_PATH} \"${PW_PLUGINS_PATH}/portable/bin/unsquashfs\" $NO_XATTRS_NEED -f -d \ \"${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}\" \"$PW_BACKUP_FILE\" \ || echo \"ERROR\" > \"${PORT_WINE_TMP_PATH}/pp_pfx_unpack_error\" " > "${PORT_WINE_TMP_PATH}/pp_pfx_unpack.sh" -- 2.54.0