diff --git a/src/components/overlapping_box.rs b/src/components/overlapping_box.rs index 56891884..3a3126f7 100644 --- a/src/components/overlapping_box.rs +++ b/src/components/overlapping_box.rs @@ -28,7 +28,7 @@ mod imp { pub orientation: Cell, /// The list model that is bound, if any. - pub bound_model: RefCell>>, + pub bound_model: BoundObjectWeakRef, /// The method used to create widgets from the items of the list model, /// if any. @@ -102,9 +102,7 @@ mod imp { widget.unparent(); } - if let Some(bound_model) = self.bound_model.take() { - bound_model.disconnect_signals() - } + self.bound_model.disconnect_signals(); } } @@ -221,7 +219,7 @@ impl OverlappingBox { widget.unparent() } } else if max_children == 0 || (old_max_children != 0 && max_children > old_max_children) { - let Some(model) = imp.bound_model.borrow().as_ref().and_then(|s| s.obj()) else { + let Some(model) = imp.bound_model.obj() else { return; }; @@ -282,10 +280,8 @@ impl OverlappingBox { ) { let imp = self.imp(); - if let Some(bound_model) = imp.bound_model.take() { - bound_model.disconnect_signals() - } - for child in self.imp().widgets.take() { + imp.bound_model.disconnect_signals(); + for child in imp.widgets.take() { child.unparent(); } imp.create_widget_func.take(); @@ -300,10 +296,8 @@ impl OverlappingBox { }), ); - imp.bound_model.replace(Some(BoundObjectWeakRef::new( - model.upcast_ref(), - vec![signal_handler_id], - ))); + imp.bound_model + .set(model.upcast_ref(), vec![signal_handler_id]); imp.create_widget_func .replace(Some(Box::new(create_widget_func))); diff --git a/src/session/content/room_history/read_receipts_list.rs b/src/session/content/room_history/read_receipts_list.rs index 292107a8..3163496d 100644 --- a/src/session/content/room_history/read_receipts_list.rs +++ b/src/session/content/room_history/read_receipts_list.rs @@ -13,8 +13,6 @@ use crate::{ const MAX_RECEIPTS_SHOWN: u32 = 10; mod imp { - use std::cell::RefCell; - use glib::subclass::InitializingObject; use once_cell::sync::Lazy; @@ -29,7 +27,7 @@ mod imp { pub overlapping_box: TemplateChild, /// The read receipts that are bound, if any. - pub bound_receipts: RefCell>>, + pub bound_receipts: BoundObjectWeakRef, } #[glib::object_subclass] @@ -68,9 +66,7 @@ mod imp { } fn dispose(&self) { - if let Some(bound_receipts) = self.bound_receipts.take() { - bound_receipts.disconnect_signals() - } + self.bound_receipts.disconnect_signals(); } } @@ -91,20 +87,12 @@ impl ReadReceiptsList { } pub fn list(&self) -> Option { - self.imp() - .bound_receipts - .borrow() - .as_ref() - .and_then(|r| r.obj()) + self.imp().bound_receipts.obj() } pub fn set_list(&self, read_receipts: &ReadReceipts) { let imp = self.imp(); - if let Some(bound_receipts) = imp.bound_receipts.take() { - bound_receipts.disconnect_signals(); - } - imp.overlapping_box.bind_model(Some(read_receipts), |obj| { let avatar_item = obj.downcast_ref::().unwrap().avatar(); let avatar = Avatar::new(); @@ -119,10 +107,8 @@ impl ReadReceiptsList { }), ); - imp.bound_receipts.replace(Some(BoundObjectWeakRef::new( - read_receipts, - vec![items_changed_handler_id], - ))); + imp.bound_receipts + .set(read_receipts, vec![items_changed_handler_id]); self.update_label(read_receipts); self.notify("list"); } diff --git a/src/session/content/room_history/typing_row.rs b/src/session/content/room_history/typing_row.rs index f8d65035..fd9fcffd 100644 --- a/src/session/content/room_history/typing_row.rs +++ b/src/session/content/room_history/typing_row.rs @@ -10,8 +10,6 @@ use crate::{ }; mod imp { - use std::cell::RefCell; - use glib::subclass::InitializingObject; use once_cell::sync::Lazy; @@ -25,7 +23,7 @@ mod imp { #[template_child] pub label: TemplateChild, /// The list of members that are currently typing. - pub bound_list: RefCell>>, + pub bound_list: BoundObjectWeakRef, } #[glib::object_subclass] @@ -79,9 +77,7 @@ mod imp { } fn dispose(&self) { - if let Some(bound_list) = self.bound_list.take() { - bound_list.disconnect_signals(); - } + self.bound_list.disconnect_signals(); } } @@ -102,11 +98,7 @@ impl TypingRow { /// The list of members that are currently typing. pub fn list(&self) -> Option { - self.imp() - .bound_list - .borrow() - .as_ref() - .and_then(|bound_list| bound_list.obj()) + self.imp().bound_list.obj() } /// Set the list of members that are currently typing. @@ -118,9 +110,7 @@ impl TypingRow { let imp = self.imp(); let prev_is_empty = self.is_empty(); - if let Some(bound_list) = imp.bound_list.take() { - bound_list.disconnect_signals(); - } + imp.bound_list.disconnect_signals(); if let Some(list) = list { let items_changed_handler_id = list.connect_items_changed( @@ -143,10 +133,10 @@ impl TypingRow { avatar.upcast() }); - imp.bound_list.replace(Some(BoundObjectWeakRef::new( + imp.bound_list.set( list, vec![items_changed_handler_id, is_empty_notify_handler_id], - ))); + ); self.update_label(list); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index bba14edb..be0babeb 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -8,6 +8,7 @@ pub mod sourceview; pub mod template_callbacks; use std::{ + cell::RefCell, path::PathBuf, rc::{Rc, Weak}, }; @@ -157,19 +158,25 @@ pub static EMOJI_REGEX: Lazy = Lazy::new(|| { #[derive(Debug)] pub struct BoundObjectWeakRef { weak_obj: glib::WeakRef, - signal_handler_ids: Vec, + signal_handler_ids: RefCell>, } impl BoundObjectWeakRef { - /// Creates a new `BoundObjectWeakRef` with the given object and signal - /// handlers IDs. - pub fn new(obj: &T, signal_handler_ids: Vec) -> Self { - let weak_obj = glib::WeakRef::new(); - weak_obj.set(Some(obj)); - Self { - weak_obj, - signal_handler_ids, - } + /// Creates a new empty `BoundObjectWeakRef` with the given object and + /// signal handlers IDs. + pub fn new() -> Self { + Self::default() + } + + /// Set the given object and signal handlers IDs. + /// + /// Calls `disconnect_signals` first to remove the previous weak reference + /// and disconnect the previous signal handlers. + pub fn set(&self, obj: &T, signal_handler_ids: Vec) { + self.disconnect_signals(); + + self.weak_obj.set(Some(obj)); + self.signal_handler_ids.replace(signal_handler_ids); } /// Get a strong reference to the object. @@ -179,18 +186,31 @@ impl BoundObjectWeakRef { /// Add `SignalHandlerId`s to this `BoundObjectWeakRef`. pub fn add_signal_handler_ids(&mut self, signal_handler_ids: Vec) { - self.signal_handler_ids.extend(signal_handler_ids); + self.signal_handler_ids + .borrow_mut() + .extend(signal_handler_ids); } - /// Disconnect the signal handlers. - /// - /// This is a no-op if the weak reference to the object can't be upgraded. - pub fn disconnect_signals(self) { + /// Disconnect the signal handlers and drop the weak reference. + pub fn disconnect_signals(&self) { + let signal_handler_ids = self.signal_handler_ids.take(); + if let Some(obj) = self.weak_obj.upgrade() { - for signal_handler_id in self.signal_handler_ids { + for signal_handler_id in signal_handler_ids { obj.disconnect(signal_handler_id) } } + + self.weak_obj.set(None); + } +} + +impl Default for BoundObjectWeakRef { + fn default() -> Self { + Self { + weak_obj: Default::default(), + signal_handler_ids: Default::default(), + } } }