From be14f7b300c6ad5b83af1aa28c45e9900ba6b9e6 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Fri, 23 Oct 2020 23:39:36 +0300 Subject: [PATCH] Proton: List uninstalled Proton versions from Steam in Add menu Proton: Fixed Virtual Desktop option InstallDialog: Download button for installers (#304) Former-commit-id: 602ca4740a5043a9a978b300beb5fe45199524b8 --- src/data/compat/tools/proton/Proton.vala | 18 +++++--- src/data/compat/tools/wine/Wine.vala | 2 +- .../runnables/tasks/install/InstallTask.vala | 9 ++++ .../runnables/tasks/install/Installer.vala | 13 ++++-- .../dialogs/InstallDialog/InstallDialog.vala | 2 + .../InstallDialog/steps/InstallerStep.vala | 15 +++++++ .../pages/general/Collection.vala | 28 +++++++++--- src/ui/widgets/compat/CompatToolsList.vala | 4 +- src/ui/widgets/compat/tabs/Proton.vala | 44 ++++++++++++++++++- src/ui/widgets/compat/tabs/Wine.vala | 2 +- src/utils/ExecTask.vala | 2 +- 11 files changed, 117 insertions(+), 22 deletions(-) diff --git a/src/data/compat/tools/proton/Proton.vala b/src/data/compat/tools/proton/Proton.vala index d64e1a80..54c3f240 100644 --- a/src/data/compat/tools/proton/Proton.vala +++ b/src/data/compat/tools/proton/Proton.vala @@ -69,7 +69,7 @@ namespace GameHub.Data.Compat.Tools.Proton string? _version = null; if(FileUtils.get_contents(executable.get_parent().get_child("version").get_path(), out _version)) { - version = _version; + version = _version.strip(); if(" " in version) { version = Utils.replace_prefix(version.split(" ", 2)[1], "proton-", "").strip(); @@ -147,12 +147,14 @@ namespace GameHub.Data.Compat.Tools.Proton } private static ArrayList? proton_versions = null; + private static HashMap? proton_appids = null; public static new ArrayList detect() { if(proton_versions != null) return proton_versions; proton_versions = new ArrayList(); + proton_appids = new HashMap(); var db_versions = (ArrayList) DB.Tables.CompatTools.get_all("proton"); if(db_versions != null) @@ -201,6 +203,11 @@ namespace GameHub.Data.Compat.Tools.Proton return proton_versions; } + public static HashMap? get_appids() + { + return proton_appids; + } + public static bool is_proton_version_added(File proton) { foreach(var existing_version in proton_versions) @@ -235,10 +242,11 @@ namespace GameHub.Data.Compat.Tools.Proton File? proton_dir = null; if(Steam.find_app_install_dir(appid, out proton_dir)) { - if(proton_dir != null) - { - add_proton_version_from_file(proton_dir.get_child("proton"), name); - } + add_proton_version_from_file(proton_dir.get_child("proton"), name); + } + else + { + proton_appids.set(appid, name ?? @"Proton (app $(appid))"); } } } diff --git a/src/data/compat/tools/wine/Wine.vala b/src/data/compat/tools/wine/Wine.vala index ffb1b55f..735ce739 100644 --- a/src/data/compat/tools/wine/Wine.vala +++ b/src/data/compat/tools/wine/Wine.vala @@ -162,7 +162,7 @@ namespace GameHub.Data.Compat.Tools.Wine string[] cmd = get_exec_cmdline_base(); if(wine_options.desktop.enabled) { - cmd += "explorer"; + cmd += "c:\\windows\\system32\\explorer.exe"; cmd += @"/desktop=$(runnable.name_escaped),$(wine_options.desktop.width)x$(wine_options.desktop.height)"; } if(file.get_path().down().has_suffix(".msi")) diff --git a/src/data/runnables/tasks/install/InstallTask.vala b/src/data/runnables/tasks/install/InstallTask.vala index 87c73bbf..6a08555c 100644 --- a/src/data/runnables/tasks/install/InstallTask.vala +++ b/src/data/runnables/tasks/install/InstallTask.vala @@ -43,6 +43,8 @@ namespace GameHub.Data.Runnables.Tasks.Install public bool can_import_install_dir { get; construct set; default = false; } private bool install_dir_imported = false; + public bool cancelled { get; private set; default = false; } + public InstallTask(Runnable? runnable, ArrayList? installers, ArrayList? install_dirs, InstallTask.Mode install_mode=InstallTask.Mode.INTERACTIVE, bool allow_install_dir_import=true) { Object(runnable: runnable, installers: installers, install_dirs: install_dirs, install_mode: install_mode, can_import_install_dir: allow_install_dir_import); @@ -113,6 +115,7 @@ namespace GameHub.Data.Runnables.Tasks.Install public async void start() { + if(cancelled) return; init(); if(install_mode == InstallTask.Mode.INTERACTIVE) { @@ -134,6 +137,7 @@ namespace GameHub.Data.Runnables.Tasks.Install public async void install() { + if(cancelled) return; if(install_dir_imported) { warning("[InstallTask.install] Installation directory was imported, skipping installation"); @@ -225,6 +229,11 @@ namespace GameHub.Data.Runnables.Tasks.Install } } + public void cancel() + { + cancelled = true; + } + private void update() { notify_property("config-step"); diff --git a/src/data/runnables/tasks/install/Installer.vala b/src/data/runnables/tasks/install/Installer.vala index e42957b1..04d635c6 100644 --- a/src/data/runnables/tasks/install/Installer.vala +++ b/src/data/runnables/tasks/install/Installer.vala @@ -162,10 +162,7 @@ namespace GameHub.Data.Runnables.Tasks.Install construct { - if(installers_dir != null && installers_dir.get_child(@".installer_$(id)").query_exists()) - { - download_state = new DownloadState(DownloadState.State.DOWNLOADED); - } + update_download_state(); } public File? installers_dir { get; protected set; } @@ -174,6 +171,14 @@ namespace GameHub.Data.Runnables.Tasks.Install public virtual async void fetch_parts(){} + public void update_download_state() + { + if(installers_dir != null && installers_dir.get_child(@".installer_$(id)").query_exists()) + { + download_state = new DownloadState(DownloadState.State.DOWNLOADED); + } + } + public override async bool install(InstallTask task) { try diff --git a/src/ui/dialogs/InstallDialog/InstallDialog.vala b/src/ui/dialogs/InstallDialog/InstallDialog.vala index ed8ced4a..a86ab20d 100644 --- a/src/ui/dialogs/InstallDialog/InstallDialog.vala +++ b/src/ui/dialogs/InstallDialog/InstallDialog.vala @@ -130,6 +130,8 @@ namespace GameHub.UI.Dialogs.InstallDialog back_button.clicked.connect(() => task.step_prev()); next_button.clicked.connect(() => task.step_next()); + task.notify["cancelled"].connect(() => destroy()); + task.load_installers.begin(); } diff --git a/src/ui/dialogs/InstallDialog/steps/InstallerStep.vala b/src/ui/dialogs/InstallDialog/steps/InstallerStep.vala index b2a51ab5..82b8608f 100644 --- a/src/ui/dialogs/InstallDialog/steps/InstallerStep.vala +++ b/src/ui/dialogs/InstallDialog/steps/InstallerStep.vala @@ -122,6 +122,14 @@ namespace GameHub.UI.Dialogs.InstallDialog.Steps download_button.get_style_context().add_class(Gtk.STYLE_CLASS_FLAT); download_button.valign = Align.CENTER; download_button.tooltip_text = _("Download"); + download_button.sensitive = false; + + download_button.clicked.connect(() => { + installer.cast(dl => { + dl.download.begin(task); + task.cancel(); + }); + }); notify["installer"].connect(() => update()); update(); @@ -136,11 +144,18 @@ namespace GameHub.UI.Dialogs.InstallDialog.Steps string[] detail_info_parts = {}; + download_button.sensitive = false; + installer.cast(dl => { + dl.update_download_state(); if(dl.download_state != null && dl.download_state.state == DownloadableInstaller.DownloadState.State.DOWNLOADED) { detail_info_parts += _("Downloaded"); } + else + { + download_button.sensitive = true; + } }); if(!installer.is_installable) diff --git a/src/ui/dialogs/SettingsDialog/pages/general/Collection.vala b/src/ui/dialogs/SettingsDialog/pages/general/Collection.vala index 2257a3e5..c8640be8 100644 --- a/src/ui/dialogs/SettingsDialog/pages/general/Collection.vala +++ b/src/ui/dialogs/SettingsDialog/pages/general/Collection.vala @@ -73,21 +73,35 @@ namespace GameHub.UI.Dialogs.SettingsDialog.Pages.General ); add_widget(sgrp_collection); + var vars_common = new ArrayList(); + vars_common.add(new VariableEntry.Variable("${root}", _("Collection directory"))); + vars_common.add(new VariableEntry.Variable("${game}", _("Game name"))); + + var vars_platform = new ArrayList(); + vars_platform.add(new VariableEntry.Variable("${platform}", _("Platform identifier"))); + vars_platform.add(new VariableEntry.Variable("${platform_name}", _("Platform name"))); + + var vars_subdir_game_dir = new ArrayList(); + vars_subdir_game_dir.add(new VariableEntry.Variable("${game_dir}", _("Game directory"))); + var vars_game_dir = new ArrayList(); - vars_game_dir.add(new VariableEntry.Variable("${root}", _("Collection directory"))); - vars_game_dir.add(new VariableEntry.Variable("${game}", _("Game name"))); - vars_game_dir.add(new VariableEntry.Variable("${platform}", _("Platform identifier"))); - vars_game_dir.add(new VariableEntry.Variable("${platform_name}", _("Platform name"))); + vars_game_dir.add_all(vars_common); + vars_game_dir.add_all(vars_platform); var vars_subdir = new ArrayList(); - vars_subdir.add(new VariableEntry.Variable("${game_dir}", _("Game directory"))); - vars_subdir.add_all(vars_game_dir); + vars_subdir.add_all(vars_subdir_game_dir); + vars_subdir.add_all(vars_common); + vars_subdir.add_all(vars_platform); + + var vars_subdir_gog_bonus = new ArrayList(); + vars_subdir_gog_bonus.add_all(vars_subdir_game_dir); + vars_subdir_gog_bonus.add_all(vars_common); var sgrp_gog = new SettingsGroup("GOG"); gog_game_dir = sgrp_gog.add_setting(new EntrySetting.bind(_("Game directory") + """ • ${game_dir}""", null, InlineWidgets.variable_entry(vars_game_dir, "source-gog-symbolic"), gog, "game-dir")); gog_installers = sgrp_gog.add_setting(new EntrySetting.bind(_("Installers directory"), null, InlineWidgets.variable_entry(vars_subdir, "source-gog-symbolic"), gog, "installers")); gog_dlc = sgrp_gog.add_setting(new EntrySetting.bind(_("DLC directory"), null, InlineWidgets.variable_entry(vars_subdir, "folder-download-symbolic"), gog, "dlc")); - gog_bonus = sgrp_gog.add_setting(new EntrySetting.bind(_("Bonus content directory"), null, InlineWidgets.variable_entry(vars_subdir, "folder-music-symbolic"), gog, "bonus")); + gog_bonus = sgrp_gog.add_setting(new EntrySetting.bind(_("Bonus content directory"), null, InlineWidgets.variable_entry(vars_subdir_gog_bonus, "folder-music-symbolic"), gog, "bonus")); add_widget(sgrp_gog); var sgrp_humble = new SettingsGroup("Humble Bundle"); diff --git a/src/ui/widgets/compat/CompatToolsList.vala b/src/ui/widgets/compat/CompatToolsList.vala index 4621c959..2917654b 100644 --- a/src/ui/widgets/compat/CompatToolsList.vala +++ b/src/ui/widgets/compat/CompatToolsList.vala @@ -68,7 +68,7 @@ namespace GameHub.UI.Widgets.Compat var tab = get_nth_page(page) as CompatToolsGroupTab; if(tab != null) { - tab.add_new_tool(); + tab.add_new_tool(add_tool_button); } } @@ -161,7 +161,7 @@ namespace GameHub.UI.Widgets.Compat protected virtual void create_options_widget(CompatToolRow row, Box container){} - public virtual void add_new_tool(){} + public virtual void add_new_tool(Button button){} } public class CompatToolRow: BaseSetting diff --git a/src/ui/widgets/compat/tabs/Proton.vala b/src/ui/widgets/compat/tabs/Proton.vala index d49f603d..1af86fdf 100644 --- a/src/ui/widgets/compat/tabs/Proton.vala +++ b/src/ui/widgets/compat/tabs/Proton.vala @@ -28,6 +28,9 @@ using GameHub.Data.Compat; using GameHub.Data.Compat.Tools; using GameHub.Data.Compat.Tools.Wine; using GameHub.Data.Compat.Tools.Proton; + +using GameHub.Data.Sources.Steam; + using GameHub.Data.Runnables; using GameHub.Utils; @@ -106,7 +109,46 @@ namespace GameHub.UI.Widgets.Compat.Tabs compat_tool_selected(proton); } - public override void add_new_tool() + public override void add_new_tool(Button button) + { + var appids = Tools.Proton.Proton.get_appids(); + if(appids != null && appids.size > 0) + { + var menu = new Gtk.Menu(); + menu.halign = Align.END; + + var steam_menu = new Gtk.Menu(); + foreach(var app in appids.entries) + { + var menu_item = new Gtk.MenuItem.with_label(app.value); + menu_item.activate.connect(() => { + Steam.install_app(app.key); + }); + steam_menu.add(menu_item); + } + + var steam_menu_item = new Gtk.MenuItem.with_label(_("Install Proton from Steam")); + steam_menu_item.submenu = steam_menu; + menu.add(steam_menu_item); + + var custom_menu_item = new Gtk.MenuItem.with_label(_("Add custom Proton version")); + custom_menu_item.activate.connect(add_custom_proton_version); + menu.add(custom_menu_item); + + menu.show_all(); + #if GTK_3_22 + menu.popup_at_widget(button, Gravity.SOUTH_EAST, Gravity.NORTH_EAST, null); + #else + menu.popup(null, null, null, 0, Gdk.CURRENT_TIME); + #endif + } + else + { + add_custom_proton_version(); + } + } + + private void add_custom_proton_version() { #if GTK_3_22 var chooser = new FileChooserNative(_("Select Proton executable"), GameHub.UI.Windows.MainWindow.instance, FileChooserAction.OPEN, _("Select"), _("Cancel")); diff --git a/src/ui/widgets/compat/tabs/Wine.vala b/src/ui/widgets/compat/tabs/Wine.vala index 8756f68d..33a4c7fd 100644 --- a/src/ui/widgets/compat/tabs/Wine.vala +++ b/src/ui/widgets/compat/tabs/Wine.vala @@ -209,7 +209,7 @@ namespace GameHub.UI.Widgets.Compat.Tabs wine_options.desktop.bind_property("height", vdesktop_resolution_height_spinbutton, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); } - public override void add_new_tool() + public override void add_new_tool(Button button) { #if GTK_3_22 var chooser = new FileChooserNative(_("Select Wine executable"), GameHub.UI.Windows.MainWindow.instance, FileChooserAction.OPEN, _("Select"), _("Cancel")); diff --git a/src/utils/ExecTask.vala b/src/utils/ExecTask.vala index f95df681..c77382fe 100644 --- a/src/utils/ExecTask.vala +++ b/src/utils/ExecTask.vala @@ -196,7 +196,7 @@ namespace GameHub.Utils } else { - Process.spawn_sync(_dir, _cmd, _env, SpawnFlags.SEARCH_PATH | SpawnFlags.CHILD_INHERITS_STDIN | SpawnFlags.STDERR_TO_DEV_NULL, null, null, null, out status); + Process.spawn_sync(_dir, _cmd, _env, SpawnFlags.SEARCH_PATH | SpawnFlags.CHILD_INHERITS_STDIN, null, null, null, out status); return new Result(status); } }