From 0833f23d94b00b6a5df60793412d93a5e704c47d Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 10 Oct 2025 23:45:00 +0200 Subject: [PATCH 1/8] ChangeInformation: Modern code style --- src/Core/ChangeInformation.vala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Core/ChangeInformation.vala b/src/Core/ChangeInformation.vala index f4a00dc9f..d9a25551d 100644 --- a/src/Core/ChangeInformation.vala +++ b/src/Core/ChangeInformation.vala @@ -42,11 +42,11 @@ public class AppCenterCore.ChangeInformation : Object { public Gee.ArrayList updatable_packages { get; private set; } - public bool can_cancel { public get; private set; default=true; } - public double progress { public get; private set; default=0.0f; } - public Status status { public get; private set; default=Status.UNKNOWN; } - public string status_description { public get; private set; default=_("Waiting"); } - public uint64 size; + public bool can_cancel { get; private set; default = true; } + public double progress { get; private set; default = 0.0f; } + public Status status { get; private set; default = Status.UNKNOWN; } + public string status_description { get; private set; default = _("Waiting"); } + public uint64 size { get; set; } construct { updatable_packages = new Gee.ArrayList (); @@ -82,9 +82,9 @@ public class AppCenterCore.ChangeInformation : Object { } public void clear_update_info () { - updatable_packages.clear (); - size = 0; - } + updatable_packages.clear (); + size = 0; + } public void reset_progress () { status = Status.UNKNOWN; From 8ccebf2c413d74f1e9821cbb256e7c46544b90f9 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 11 Oct 2025 00:19:27 +0200 Subject: [PATCH 2/8] Split ChangeInfo and UpdateInfo Update info is only required for updates whereas change info is required for all package operations. Also update info only makes sense for runtime updates. Therefore split the update info from the change info. This will allow for easier rework of the update process later to reduce overhead by trying to fit runtime updates into a normal package and allows fixing some things with the change info without having to worry about it for now. --- src/Core/ChangeInformation.vala | 17 --------------- src/Core/FlatpakBackend.vala | 37 ++++++++++++++++++++------------- src/Core/Package.vala | 14 ++++++++++--- src/Core/UpdateInformation.vala | 16 ++++++++++++++ src/meson.build | 1 + 5 files changed, 51 insertions(+), 34 deletions(-) create mode 100644 src/Core/UpdateInformation.vala diff --git a/src/Core/ChangeInformation.vala b/src/Core/ChangeInformation.vala index d9a25551d..e5a29051a 100644 --- a/src/Core/ChangeInformation.vala +++ b/src/Core/ChangeInformation.vala @@ -40,22 +40,10 @@ public class AppCenterCore.ChangeInformation : Object { */ public signal void progress_changed (); - public Gee.ArrayList updatable_packages { get; private set; } - public bool can_cancel { get; private set; default = true; } public double progress { get; private set; default = 0.0f; } public Status status { get; private set; default = Status.UNKNOWN; } public string status_description { get; private set; default = _("Waiting"); } - public uint64 size { get; set; } - - construct { - updatable_packages = new Gee.ArrayList (); - size = 0; - } - - public bool has_changes () { - return updatable_packages.size > 0; - } public void start () { progress = 0.0f; @@ -81,11 +69,6 @@ public class AppCenterCore.ChangeInformation : Object { progress_changed (); } - public void clear_update_info () { - updatable_packages.clear (); - size = 0; - } - public void reset_progress () { status = Status.UNKNOWN; status_description = _("Starting"); diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index c82a4776f..0a6c5b25e 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -111,7 +111,7 @@ public class AppCenterCore.FlatpakBackend : Object { uint64 size = 0; for (uint i = 0; i < updatable_packages.get_n_items (); i++) { var package = (Package) updatable_packages.get_item (i); - size += package.change_information.size; + size += package.update_information.size; } return size; } @@ -1894,7 +1894,7 @@ public class AppCenterCore.FlatpakBackend : Object { string[] user_updates = {}; string[] system_updates = {}; - foreach (var updatable in package.change_information.updatable_packages) { + foreach (var updatable in package.update_information.updatable_packages) { bool system = false; string bundle_id = ""; @@ -2103,14 +2103,14 @@ public class AppCenterCore.FlatpakBackend : Object { return; } - private void fill_runtime_updates () { - if (!runtime_updates.update_available) { + private void fill_runtime_updates (UpdateInformation info) { + if (info.updatable_packages.is_empty) { return; } string runtime_desc = ""; - foreach (var update in runtime_updates.change_information.updatable_packages) { + foreach (var update in info.updatable_packages) { string bundle_id; if (!get_package_list_key_parts (update, null, null, out bundle_id)) { continue; @@ -2134,10 +2134,12 @@ public class AppCenterCore.FlatpakBackend : Object { var latest_version = ngettext ( "%u runtime with updates", "%u runtimes with updates", - runtime_updates.change_information.updatable_packages.size - ).printf (runtime_updates.change_information.updatable_packages.size); + info.updatable_packages.size + ).printf (info.updatable_packages.size); runtime_updates.latest_version = latest_version; runtime_updates.description = "%s\n%s\n".printf (GLib.Markup.printf_escaped (_("%s:"), latest_version), runtime_desc); + + runtime_updates.update_information = info; } public async void get_updates (Cancellable? cancellable = null) { @@ -2147,27 +2149,34 @@ public class AppCenterCore.FlatpakBackend : Object { // Clear any packages previously marked as updatable for (int i = (int) n_updatable_packages - 1; i >= 0; i--) { var package = (Package) updatable_packages.get_item (i); - package.change_information.clear_update_info (); - package.update_state (); + package.update_information = null; } var job = yield launch_job (Job.Type.GET_UPDATES, job_args); + var runtime_update_information = new UpdateInformation (); + foreach (var update in (Gee.ArrayList)job.result.get_object ()) { - var package = package_list[update] ?? runtime_updates; + if (!package_list.has_key (update)) { + runtime_update_information.updatable_packages.add (update); + continue; + } + + var package = package_list[update]; + var update_info = new UpdateInformation (); - package.change_information.updatable_packages.add (update); + update_info.updatable_packages.add (update); try { - package.change_information.size += yield get_download_size (package, cancellable, true); + update_info.size = yield get_download_size (package, cancellable, true); } catch (Error e) { warning ("Error getting download size for package %s: %s", update, e.message); } - package.update_state (); + package.update_information = update_info; } - fill_runtime_updates (); + fill_runtime_updates (runtime_update_information); } private void repair_internal (Job job) { diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 05cfbd84e..d2c6c00de 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -110,6 +110,15 @@ public class AppCenterCore.Package : Object { public GLib.Cancellable action_cancellable { public get; private set; } public State state { public get; private set; default = State.NOT_INSTALLED; } + private UpdateInformation? _update_information; + public UpdateInformation? update_information { + get { return _update_information; } + set { + _update_information = value; + update_state (); + } + } + public double progress { get { return change_information.progress; @@ -454,7 +463,7 @@ public class AppCenterCore.Package : Object { State new_state; if (installed) { - if (change_information.has_changes ()) { + if (update_information != null) { new_state = State.UPDATE_AVAILABLE; } else { new_state = State.INSTALLED; @@ -562,8 +571,7 @@ public class AppCenterCore.Package : Object { case State.UPDATING: var success = yield backend.update_package (this, change_information, action_cancellable); if (success) { - change_information.clear_update_info (); - update_state (); + update_information = null; } return success; diff --git a/src/Core/UpdateInformation.vala b/src/Core/UpdateInformation.vala new file mode 100644 index 000000000..e3d4b6808 --- /dev/null +++ b/src/Core/UpdateInformation.vala @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Authored by: Leonhard Kargl + */ + +public class AppCenterCore.UpdateInformation : Object { + public Gee.ArrayList updatable_packages { get; private set; } + public uint64 size { get; set; } + + construct { + updatable_packages = new Gee.ArrayList (); + size = 0; + } +} diff --git a/src/meson.build b/src/meson.build index 1008c3939..21bf7e7d4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,6 +18,7 @@ appcenter_files = files( 'Core/SearchEngine.vala', 'Core/SoupClient.vala', 'Core/Stripe.vala', + 'Core' / 'UpdateInformation.vala', 'Core/UpdateManager.vala', 'Dialogs/InstallFailDialog.vala', 'Dialogs' / 'ReleasesDialog.vala', From 3c6e9a8941b53bb75ded203a86b975fae9bc4e03 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 10 Oct 2025 23:46:19 +0200 Subject: [PATCH 3/8] ChangeInformation: Remove finished state We never actually show the finished state so remove it and instead immediately switch back to unknown state. --- src/Core/ChangeInformation.vala | 23 ++++++++--------------- src/Core/Package.vala | 10 ++-------- src/Widgets/ProgressButton.vala | 7 +------ 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/Core/ChangeInformation.vala b/src/Core/ChangeInformation.vala index e5a29051a..e2c77bbfb 100644 --- a/src/Core/ChangeInformation.vala +++ b/src/Core/ChangeInformation.vala @@ -24,8 +24,7 @@ public class AppCenterCore.ChangeInformation : Object { UNKNOWN, CANCELLED, WAITING, - RUNNING, - FINISHED + RUNNING } /** @@ -46,33 +45,27 @@ public class AppCenterCore.ChangeInformation : Object { public string status_description { get; private set; default = _("Waiting"); } public void start () { - progress = 0.0f; + can_cancel = true; status = Status.WAITING; status_description = _("Waiting"); status_changed (); progress_changed (); } - public void complete () { - status = Status.FINISHED; - status_description = _("Finished"); - status_changed (); - reset_progress (); - } - public void cancel () { - progress = 0.0f; status = Status.CANCELLED; status_description = _("Cancelling"); - reset_progress (); status_changed (); progress_changed (); } - public void reset_progress () { + public void complete () { + can_cancel = false; + progress = 0; status = Status.UNKNOWN; - status_description = _("Starting"); - progress = 0.0f; + status_description = _("Unknown"); + status_changed (); + progress_changed (); } public void callback (bool can_cancel, string status_description, double progress, Status status) { diff --git a/src/Core/Package.vala b/src/Core/Package.vala index d2c6c00de..2f8b17102 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -202,12 +202,6 @@ public class AppCenterCore.Package : Object { } } - public bool changes_finished { - get { - return change_information.status == ChangeInformation.Status.FINISHED; - } - } - public bool is_runtime_updates { get { return component.id == RUNTIME_UPDATES_ID; @@ -593,12 +587,12 @@ public class AppCenterCore.Package : Object { private void clean_up_package_operation (bool success, State success_state, State fail_state) { changing (false); + change_information.complete (); + if (success) { - change_information.complete (); state = success_state; } else { state = fail_state; - change_information.cancel (); } FlatpakBackend.get_default ().notify_package_changed (this); diff --git a/src/Widgets/ProgressButton.vala b/src/Widgets/ProgressButton.vala index a3036f0eb..391654927 100644 --- a/src/Widgets/ProgressButton.vala +++ b/src/Widgets/ProgressButton.vala @@ -45,12 +45,7 @@ public class AppCenter.ProgressButton : Gtk.Button { private void update_progress_status () { Idle.add (() => { tooltip_text = package.get_progress_description (); - sensitive = package.change_information.can_cancel && !package.changes_finished; - /* Ensure progress bar shows complete to match status (lp:1606902) */ - if (package.changes_finished) { - progressbar.fraction = 1.0f; - } - + sensitive = package.change_information.can_cancel; return GLib.Source.REMOVE; }); } From 101ecf851517ef736f1ada9376beacffa9dd2d88 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 10 Oct 2025 23:55:01 +0200 Subject: [PATCH 4/8] Move action cancellable to ChangeInfo Instead of manually passing the cancellable, include it in change info. This makes it easier to keep the change info status in sync with the cancelled state. Notably this allows to fix an issue where clicking cancel seemingly didn't do anything until the backend actually drops out of the transaction. --- src/Core/ChangeInformation.vala | 2 ++ src/Core/FlatpakBackend.vala | 21 +++++++++------------ src/Core/Job.vala | 9 +++------ src/Core/Package.vala | 10 +++------- src/Widgets/ActionStack.vala | 2 +- 5 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/Core/ChangeInformation.vala b/src/Core/ChangeInformation.vala index e2c77bbfb..436949f2a 100644 --- a/src/Core/ChangeInformation.vala +++ b/src/Core/ChangeInformation.vala @@ -39,12 +39,14 @@ public class AppCenterCore.ChangeInformation : Object { */ public signal void progress_changed (); + public Cancellable cancellable { get; private set; } public bool can_cancel { get; private set; default = true; } public double progress { get; private set; default = 0.0f; } public Status status { get; private set; default = Status.UNKNOWN; } public string status_description { get; private set; default = _("Waiting"); } public void start () { + cancellable = new Cancellable (); can_cancel = true; status = Status.WAITING; status_description = _("Waiting"); diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index 0a6c5b25e..89c3d72ca 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -1623,8 +1623,8 @@ public class AppCenterCore.FlatpakBackend : Object { unowned var args = (InstallPackageArgs)job.args; unowned var package = args.package; unowned var fp_package = package as FlatpakPackage; - unowned ChangeInformation? change_info = args.change_info; - unowned var cancellable = args.cancellable; + unowned var change_info = args.change_info; + unowned var cancellable = change_info.cancellable; var bundle = package.component.get_bundle (AppStream.BundleKind.FLATPAK); if (bundle == null) { @@ -1732,11 +1732,10 @@ public class AppCenterCore.FlatpakBackend : Object { job.results_ready (); } - public async bool install_package (Package package, ChangeInformation? change_info, Cancellable? cancellable) throws GLib.Error { + public async bool install_package (Package package, ChangeInformation change_info) throws GLib.Error { var job_args = new InstallPackageArgs (); job_args.package = package; job_args.change_info = change_info; - job_args.cancellable = cancellable; var job = yield launch_job (Job.Type.INSTALL_PACKAGE, job_args); if (job.error != null) { @@ -1750,8 +1749,8 @@ public class AppCenterCore.FlatpakBackend : Object { unowned var args = (RemovePackageArgs)job.args; unowned var package = args.package; unowned var fp_package = package as FlatpakPackage; - unowned ChangeInformation? change_info = args.change_info; - unowned var cancellable = args.cancellable; + unowned var change_info = args.change_info; + unowned var cancellable = change_info.cancellable; unowned var bundle = package.component.get_bundle (AppStream.BundleKind.FLATPAK); if (bundle == null) { @@ -1864,11 +1863,10 @@ public class AppCenterCore.FlatpakBackend : Object { job.results_ready (); } - public async bool remove_package (Package package, ChangeInformation? change_info, Cancellable? cancellable) throws GLib.Error { + public async bool remove_package (Package package, ChangeInformation change_info) throws GLib.Error { var job_args = new RemovePackageArgs (); job_args.package = package; job_args.change_info = change_info; - job_args.cancellable = cancellable; var job = yield launch_job (Job.Type.REMOVE_PACKAGE, job_args); if (job.error != null) { @@ -1881,8 +1879,8 @@ public class AppCenterCore.FlatpakBackend : Object { private void update_package_internal (Job job) { unowned var args = (UpdatePackageArgs)job.args; unowned var package = args.package; - unowned ChangeInformation change_info = args.change_info; - unowned var cancellable = args.cancellable; + unowned var change_info = args.change_info; + unowned var cancellable = change_info.cancellable; if (user_installation == null && system_installation == null) { critical ("Error getting flatpak installation"); @@ -2034,11 +2032,10 @@ public class AppCenterCore.FlatpakBackend : Object { return success; } - public async bool update_package (Package package, ChangeInformation? change_info, Cancellable? cancellable) throws GLib.Error { + public async bool update_package (Package package, ChangeInformation change_info) throws GLib.Error { var job_args = new UpdatePackageArgs (); job_args.package = package; job_args.change_info = change_info; - job_args.cancellable = cancellable; var job = yield launch_job (Job.Type.UPDATE_PACKAGE, job_args); if (job.error != null) { diff --git a/src/Core/Job.vala b/src/Core/Job.vala index 29a04d1d8..f4c2bd42f 100644 --- a/src/Core/Job.vala +++ b/src/Core/Job.vala @@ -88,20 +88,17 @@ public class AppCenterCore.GetInstalledPackagesArgs : JobArgs { public class AppCenterCore.InstallPackageArgs : JobArgs { public Package package; - public ChangeInformation? change_info; - public Cancellable? cancellable; + public ChangeInformation change_info; } public class AppCenterCore.UpdatePackageArgs : JobArgs { public Package package; - public ChangeInformation? change_info; - public Cancellable? cancellable; + public ChangeInformation change_info; } public class AppCenterCore.RemovePackageArgs : JobArgs { public Package package; - public ChangeInformation? change_info; - public Cancellable? cancellable; + public ChangeInformation change_info; } public class AppCenterCore.GetDownloadSizeArgs : JobArgs { diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 2f8b17102..774306c9f 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -107,7 +107,6 @@ public class AppCenterCore.Package : Object { public AppStream.Component component { get; protected set; } public ChangeInformation change_information { public get; private set; } - public GLib.Cancellable action_cancellable { public get; private set; } public State state { public get; private set; default = State.NOT_INSTALLED; } private UpdateInformation? _update_information; @@ -428,8 +427,6 @@ public class AppCenterCore.Package : Object { construct { change_information = new ChangeInformation (); change_information.status_changed.connect (() => info_changed (change_information.status)); - - action_cancellable = new GLib.Cancellable (); } public Package (string uid, AppStream.Component component) { @@ -551,7 +548,6 @@ public class AppCenterCore.Package : Object { private void prepare_package_operation (State initial_state) { changing (true); - action_cancellable.reset (); change_information.start (); state = initial_state; @@ -563,19 +559,19 @@ public class AppCenterCore.Package : Object { switch (state) { case State.UPDATING: - var success = yield backend.update_package (this, change_information, action_cancellable); + var success = yield backend.update_package (this, change_information); if (success) { update_information = null; } return success; case State.INSTALLING: - var success = yield backend.install_package (this, change_information, action_cancellable); + var success = yield backend.install_package (this, change_information); _installed = success; update_state (); return success; case State.REMOVING: - var success = yield backend.remove_package (this, change_information, action_cancellable); + var success = yield backend.remove_package (this, change_information); _installed = !success; update_state (); return success; diff --git a/src/Widgets/ActionStack.vala b/src/Widgets/ActionStack.vala index 703392cd8..eb0ea0dd3 100644 --- a/src/Widgets/ActionStack.vala +++ b/src/Widgets/ActionStack.vala @@ -180,7 +180,7 @@ public class AppCenter.ActionStack : Gtk.Box { private void action_cancelled () { update_action (); - package.action_cancellable.cancel (); + package.change_information.cancel (); } private void launch_package_app () { From a9b5db296c68bcc2221103c773fced149852f646 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 11 Oct 2025 00:29:55 +0200 Subject: [PATCH 5/8] ChangeInformation: Simplify callback and make it thread safe --- src/Core/ChangeInformation.vala | 22 ++++++++++++---------- src/Core/FlatpakBackend.vala | 12 +++--------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/Core/ChangeInformation.vala b/src/Core/ChangeInformation.vala index 436949f2a..201043a8e 100644 --- a/src/Core/ChangeInformation.vala +++ b/src/Core/ChangeInformation.vala @@ -70,17 +70,19 @@ public class AppCenterCore.ChangeInformation : Object { progress_changed (); } - public void callback (bool can_cancel, string status_description, double progress, Status status) { - if (this.can_cancel != can_cancel || this.status_description != status_description || this.status != status) { - this.can_cancel = can_cancel; - this.status_description = status_description; - this.status = status; - status_changed (); - } + public void callback (double progress, string status_description) { + Idle.add_once (() => idle_callback (progress, status_description)); + } - if (this.progress != progress) { - this.progress = progress; - progress_changed (); + private void idle_callback (double progress, string status_description) { + if (status != RUNNING) { + status = RUNNING; } + + this.progress = progress; + this.status_description = status_description; + + status_changed (); + progress_changed (); } } diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index 89c3d72ca..27c44c23a 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -1683,7 +1683,7 @@ public class AppCenterCore.FlatpakBackend : Object { // Calculate the progress contribution of the previous operations not including the current, hence -1 double existing_progress = (double)(current_operation - 1) / (double)total_operations; double this_op_progress = (double)progress.get_progress () / 100.0f / (double)total_operations; - change_info.callback (true, _("Installing"), existing_progress + this_op_progress, ChangeInformation.Status.RUNNING); + change_info.callback (existing_progress + this_op_progress, _("Installing")); }); }); @@ -1692,7 +1692,6 @@ public class AppCenterCore.FlatpakBackend : Object { transaction.operation_error.connect ((operation, e, detail) => { warning ("Flatpak installation failed: %s (detail: %d)", e.message, detail); if (e is GLib.IOError.CANCELLED) { - change_info.callback (false, _("Cancelling"), 1.0f, ChangeInformation.Status.CANCELLED); success = true; } @@ -1716,7 +1715,6 @@ public class AppCenterCore.FlatpakBackend : Object { success = transaction.run (cancellable); } catch (Error e) { if (e is GLib.IOError.CANCELLED) { - change_info.callback (false, _("Cancelling"), 1.0f, ChangeInformation.Status.CANCELLED); success = true; } else { success = false; @@ -1814,7 +1812,7 @@ public class AppCenterCore.FlatpakBackend : Object { // Calculate the progress contribution of the previous operations not including the current, hence -1 double existing_progress = (double)(current_operation - 1) / (double)total_operations; double this_op_progress = (double)progress.get_progress () / 100.0f / (double)total_operations; - change_info.callback (true, _("Uninstalling"), existing_progress + this_op_progress, ChangeInformation.Status.RUNNING); + change_info.callback (existing_progress + this_op_progress, _("Uninstalling")); }); }); @@ -1823,7 +1821,6 @@ public class AppCenterCore.FlatpakBackend : Object { transaction.operation_error.connect ((operation, e, detail) => { warning ("Flatpak removal failed: %s (detail: %d)", e.message, detail); if (e is GLib.IOError.CANCELLED) { - change_info.callback (false, _("Cancelling"), 1.0f, ChangeInformation.Status.CANCELLED); success = true; } @@ -1847,7 +1844,6 @@ public class AppCenterCore.FlatpakBackend : Object { success = transaction.run (cancellable); } catch (Error e) { if (e is GLib.IOError.CANCELLED) { - change_info.callback (false, _("Cancelling"), 1.0f, ChangeInformation.Status.CANCELLED); success = true; } else { success = false; @@ -1995,7 +1991,7 @@ public class AppCenterCore.FlatpakBackend : Object { // Calculate the progress contribution of the previous operations not including the current, hence -1 double existing_progress = (double)(current_operation - 1) / (double)total_operations; double this_op_progress = (double)progress.get_progress () / 100.0f / (double)total_operations; - change_info.callback (true, _("Updating"), existing_progress + this_op_progress, ChangeInformation.Status.RUNNING); + change_info.callback (existing_progress + this_op_progress, _("Updating")); }); }); @@ -2004,7 +2000,6 @@ public class AppCenterCore.FlatpakBackend : Object { transaction.operation_error.connect ((operation, e, detail) => { warning ("Flatpak installation failed: %s", e.message); if (e is GLib.IOError.CANCELLED) { - change_info.callback (false, _("Cancelling"), 1.0f, ChangeInformation.Status.CANCELLED); success = true; } @@ -2022,7 +2017,6 @@ public class AppCenterCore.FlatpakBackend : Object { success = transaction.run (cancellable); } catch (Error e) { if (e is GLib.IOError.CANCELLED) { - change_info.callback (false, _("Cancelling"), 1.0f, ChangeInformation.Status.CANCELLED); success = true; } else { throw e; From ec30f2325020db9d508f61d6cc6581ae7c090e8e Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 11 Oct 2025 00:34:04 +0200 Subject: [PATCH 6/8] ProgressButton: Use property bindings instead of signals --- src/Core/ChangeInformation.vala | 21 --------------------- src/Core/Package.vala | 6 ------ src/Widgets/ProgressButton.vala | 27 ++++----------------------- 3 files changed, 4 insertions(+), 50 deletions(-) diff --git a/src/Core/ChangeInformation.vala b/src/Core/ChangeInformation.vala index 201043a8e..c91b0e3d2 100644 --- a/src/Core/ChangeInformation.vala +++ b/src/Core/ChangeInformation.vala @@ -27,18 +27,6 @@ public class AppCenterCore.ChangeInformation : Object { RUNNING } - /** - * This signal is likely to be fired from a non-main thread. Ensure any UI - * logic driven from this runs on the GTK thread - */ - public signal void status_changed (); - - /** - * This signal is likely to be fired from a non-main thread. Ensure any UI - * logic driven from this runs on the GTK thread - */ - public signal void progress_changed (); - public Cancellable cancellable { get; private set; } public bool can_cancel { get; private set; default = true; } public double progress { get; private set; default = 0.0f; } @@ -50,15 +38,11 @@ public class AppCenterCore.ChangeInformation : Object { can_cancel = true; status = Status.WAITING; status_description = _("Waiting"); - status_changed (); - progress_changed (); } public void cancel () { status = Status.CANCELLED; status_description = _("Cancelling"); - status_changed (); - progress_changed (); } public void complete () { @@ -66,8 +50,6 @@ public class AppCenterCore.ChangeInformation : Object { progress = 0; status = Status.UNKNOWN; status_description = _("Unknown"); - status_changed (); - progress_changed (); } public void callback (double progress, string status_description) { @@ -81,8 +63,5 @@ public class AppCenterCore.ChangeInformation : Object { this.progress = progress; this.status_description = status_description; - - status_changed (); - progress_changed (); } } diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 774306c9f..3aab4a6bb 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -61,11 +61,6 @@ public class AppCenterCore.Package : Object { }; public signal void changing (bool is_changing); - /** - * This signal is likely to be fired from a non-main thread. Ensure any UI - * logic driven from this runs on the GTK thread - */ - public signal void info_changed (ChangeInformation.Status status); public enum State { NOT_INSTALLED, @@ -426,7 +421,6 @@ public class AppCenterCore.Package : Object { construct { change_information = new ChangeInformation (); - change_information.status_changed.connect (() => info_changed (change_information.status)); } public Package (string uid, AppStream.Component component) { diff --git a/src/Widgets/ProgressButton.vala b/src/Widgets/ProgressButton.vala index 391654927..dd6e9df1b 100644 --- a/src/Widgets/ProgressButton.vala +++ b/src/Widgets/ProgressButton.vala @@ -6,8 +6,6 @@ public class AppCenter.ProgressButton : Gtk.Button { public AppCenterCore.Package package { get; construct; } - private Gtk.ProgressBar progressbar; - public ProgressButton (AppCenterCore.Package package) { Object (package: package); } @@ -16,37 +14,20 @@ public class AppCenter.ProgressButton : Gtk.Button { add_css_class ("progress"); add_css_class ("text-button"); - package.change_information.progress_changed.connect (update_progress); - package.change_information.status_changed.connect (update_progress_status); - - update_progress_status (); - update_progress (); - var cancel_label = new Gtk.Label (_("Cancel")) { mnemonic_widget = this }; - progressbar = new Gtk.ProgressBar (); + var progressbar = new Gtk.ProgressBar (); + package.change_information.bind_property ("progress", progressbar, "fraction", SYNC_CREATE); var box = new Gtk.Box (VERTICAL, 0); box.append (cancel_label); box.append (progressbar); child = box; - } - - private void update_progress () { - Idle.add (() => { - progressbar.fraction = package.progress; - return GLib.Source.REMOVE; - }); - } - private void update_progress_status () { - Idle.add (() => { - tooltip_text = package.get_progress_description (); - sensitive = package.change_information.can_cancel; - return GLib.Source.REMOVE; - }); + package.change_information.bind_property ("can-cancel", this, "sensitive", SYNC_CREATE); + package.change_information.bind_property ("status-description", this, "tooltip-text", SYNC_CREATE); } } From 1b90291e43b516f1089ecac15fb177986ecf9fb3 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 11 Oct 2025 00:36:09 +0200 Subject: [PATCH 7/8] Package: Remove unused properties, signals and methods related to change info --- src/Core/Package.vala | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 3aab4a6bb..9c77ec6b2 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -60,8 +60,6 @@ public class AppCenterCore.Package : Object { "language-discrimination" }; - public signal void changing (bool is_changing); - public enum State { NOT_INSTALLED, INSTALLED, @@ -113,12 +111,6 @@ public class AppCenterCore.Package : Object { } } - public double progress { - get { - return change_information.progress; - } - } - private bool _installed = false; public bool installed { get { @@ -540,8 +532,6 @@ public class AppCenterCore.Package : Object { } private void prepare_package_operation (State initial_state) { - changing (true); - change_information.start (); state = initial_state; @@ -575,8 +565,6 @@ public class AppCenterCore.Package : Object { } private void clean_up_package_operation (bool success, State success_state, State fail_state) { - changing (false); - change_information.complete (); if (success) { @@ -657,10 +645,6 @@ public class AppCenterCore.Package : Object { summary = new_summary; } - public string get_progress_description () { - return change_information.status_description; - } - public GLib.Icon get_icon (uint size, uint scale_factor) { GLib.Icon? icon = null; uint current_size = 0; From 64cbe1b9b10ab1a29ed883121f964a743567b5b9 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 11 Oct 2025 00:38:35 +0200 Subject: [PATCH 8/8] Handle cancel in progress button --- src/Widgets/ActionStack.vala | 6 ------ src/Widgets/ProgressButton.vala | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Widgets/ActionStack.vala b/src/Widgets/ActionStack.vala index eb0ea0dd3..613bc4915 100644 --- a/src/Widgets/ActionStack.vala +++ b/src/Widgets/ActionStack.vala @@ -78,7 +78,6 @@ public class AppCenter.ActionStack : Gtk.Box { cancel_button = new ProgressButton (package) { valign = CENTER }; - cancel_button.clicked.connect (() => action_cancelled ()); var action_button_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.BOTH); action_button_group.add_widget (action_button); @@ -178,11 +177,6 @@ public class AppCenter.ActionStack : Gtk.Box { } } - private void action_cancelled () { - update_action (); - package.change_information.cancel (); - } - private void launch_package_app () { try { package.launch (); diff --git a/src/Widgets/ProgressButton.vala b/src/Widgets/ProgressButton.vala index dd6e9df1b..15a4138bf 100644 --- a/src/Widgets/ProgressButton.vala +++ b/src/Widgets/ProgressButton.vala @@ -29,5 +29,7 @@ public class AppCenter.ProgressButton : Gtk.Button { package.change_information.bind_property ("can-cancel", this, "sensitive", SYNC_CREATE); package.change_information.bind_property ("status-description", this, "tooltip-text", SYNC_CREATE); + + clicked.connect (package.change_information.cancel); } }