From 122b4e87a08452bc2a30c42c50d8435fafbb13aa Mon Sep 17 00:00:00 2001 From: Yaroslav Chvanov Date: Fri, 3 Mar 2023 22:20:47 +0300 Subject: [PATCH] resolutionrow: make the caller recreate the widget on profile switch --- piper/resolutionrow.py | 40 +++++++++------------------------------- piper/resolutionspage.py | 10 ++++++---- piper/util/gobject.py | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 35 deletions(-) create mode 100644 piper/util/gobject.py diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index ba474be..894146b 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later from .ratbagd import RatbagdResolution +from .util.gobject import disconnect_handlers import gi gi.require_version("Gtk", "3.0") @@ -24,38 +25,24 @@ class ResolutionRow(Gtk.ListBoxRow): CAP_SEPARATE_XY_RESOLUTION = False CAP_DISABLE = False - def __init__(self, device, resolution, *args, **kwargs): + def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: Gtk.ListBoxRow.__init__(self, *args, **kwargs) - self._resolution = None - self._resolution_handler = 0 - self._active_handler = 0 - self._disabled_handler = 0 + self._resolution = resolution + self.resolutions = resolution.resolutions self._scale_handler = self.scale.connect("value-changed", self._on_scale_value_changed) self._disabled_button_handler = self.disable_button.connect("toggled", self._on_disable_button_toggled) - device.connect("active-profile-changed", - self._on_active_profile_changed, resolution.index) - - self._init_values(resolution) - - def _init_values(self, resolution): - if self._resolution_handler > 0: - self._resolution.disconnect(self._resolution_handler) - if self._active_handler > 0: - self._resolution.disconnect(self._active_handler) - if self._disabled_handler > 0: - self._resolution.disconnect(self._disabled_handler) - self._resolution = resolution - self.resolutions = resolution.resolutions - self._resolution_handler = resolution.connect("notify::resolution", - self._on_resolution_changed) self._active_handler = resolution.connect("notify::is-active", self._on_status_changed) self._disabled_handler = resolution.connect("notify::is-disabled", self._on_status_changed) + # https://gitlab.gnome.org/GNOME/pygobject/-/issues/557 + self.weak_ref( + lambda: disconnect_handlers(resolution, (self._active_handler, self._disabled_handler)) + ) # Get resolution capabilities and update internal values. if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in resolution.capabilities: @@ -75,10 +62,6 @@ class ResolutionRow(Gtk.ListBoxRow): self.disable_button.set_active(True) self._on_status_changed(resolution, pspec=None) - def _on_active_profile_changed(self, device, profile, index): - resolution = profile.resolutions[index] - self._init_values(resolution) - @Gtk.Template.Callback("_on_change_value") def _on_change_value(self, scale, scroll, value): # Cursor-controlled slider may get out of the GtkAdjustment's range. @@ -129,10 +112,6 @@ class ResolutionRow(Gtk.ListBoxRow): res = int(scale.get_value()) self._on_dpi_values_changed(res=res) - def _on_resolution_changed(self, resolution, pspec): - # RatbagdResolution's resolution has changed, re-initialize. - self._init_values(resolution) - def _on_status_changed(self, resolution, pspec): # The resolution's status changed, update UI. self._on_dpi_values_changed() @@ -174,5 +153,4 @@ class ResolutionRow(Gtk.ListBoxRow): # Only update new resolution if changed if (new_res != self._resolution.resolution): - with self._resolution.handler_block(self._resolution_handler): - self._resolution.resolution = new_res + self._resolution.resolution = new_res diff --git a/piper/resolutionspage.py b/piper/resolutionspage.py index 25c1769..325162e 100644 --- a/piper/resolutionspage.py +++ b/piper/resolutionspage.py @@ -68,10 +68,6 @@ class ResolutionsPage(Gtk.Box): mousemap.add(label, "#button{}".format(button.index)) mousemap.show_all() - for resolution in profile.resolutions: - row = ResolutionRow(self._device, resolution) - self.listbox.insert(row, resolution.index) - are_report_rates_supported = profile.report_rate != 0 \ and len(profile.report_rates) != 0 self.rate_button_box.set_sensitive(are_report_rates_supported) @@ -84,6 +80,12 @@ class ResolutionsPage(Gtk.Box): self._on_active_profile_changed(self._device, profile) def _on_active_profile_changed(self, device, profile): + # TODO: don't delete the unused "add new resolution" button. + self.listbox.foreach(Gtk.Widget.destroy) + for resolution in profile.resolutions: + row = ResolutionRow(resolution) + self.listbox.insert(row, resolution.index) + # Updates report rate to reflect the new active profile's report rate. with self.rate_125.handler_block(self._handler_125): self.rate_125.set_active(profile.report_rate == 125) diff --git a/piper/util/gobject.py b/piper/util/gobject.py new file mode 100644 index 0000000..f0075f3 --- /dev/null +++ b/piper/util/gobject.py @@ -0,0 +1,15 @@ +from typing import Tuple + +from gi.repository import GObject + + +def disconnect_handlers(obj: GObject.GObject, handlers: Tuple[int, ...]) -> None: + """Disconnect supplied handlers from the supplied GObject.""" + + def disconnect_non_zero(handler_id: int) -> None: + if not handler_id > 0: + return + obj.disconnect(handler_id) + + for handler in handlers: + disconnect_non_zero(handler)