fractal/account_switcher/
account_switcher_button.rs1use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
2
3use super::AccountSwitcherPopover;
4use crate::{
5 Window,
6 components::Avatar,
7 session_list::SessionInfo,
8 utils::{BoundObjectWeakRef, TemplateCallbacks},
9};
10
11mod imp {
12 use glib::subclass::InitializingObject;
13
14 use super::*;
15
16 #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
17 #[template(resource = "/org/gnome/Fractal/ui/account_switcher/account_switcher_button.ui")]
18 #[properties(wrapper_type = super::AccountSwitcherButton)]
19 pub struct AccountSwitcherButton {
20 #[property(get, set = Self::set_popover, explicit_notify, nullable)]
22 popover: BoundObjectWeakRef<AccountSwitcherPopover>,
23 }
24
25 #[glib::object_subclass]
26 impl ObjectSubclass for AccountSwitcherButton {
27 const NAME: &'static str = "AccountSwitcherButton";
28 type Type = super::AccountSwitcherButton;
29 type ParentType = gtk::ToggleButton;
30
31 fn class_init(klass: &mut Self::Class) {
32 Avatar::ensure_type();
33 SessionInfo::ensure_type();
34
35 Self::bind_template(klass);
36 Self::bind_template_callbacks(klass);
37 TemplateCallbacks::bind_template_callbacks(klass);
38 }
39
40 fn instance_init(obj: &InitializingObject<Self>) {
41 obj.init_template();
42 }
43 }
44
45 #[glib::derived_properties]
46 impl ObjectImpl for AccountSwitcherButton {
47 fn dispose(&self) {
48 self.reset();
49 }
50 }
51
52 impl WidgetImpl for AccountSwitcherButton {}
53 impl ButtonImpl for AccountSwitcherButton {}
54 impl ToggleButtonImpl for AccountSwitcherButton {}
55
56 #[gtk::template_callbacks]
57 impl AccountSwitcherButton {
58 fn set_popover(&self, popover: Option<&AccountSwitcherPopover>) {
60 if self.popover.obj().as_ref() == popover {
61 return;
62 }
63
64 self.reset();
66 let obj = self.obj();
67
68 if let Some(popover) = popover {
69 if let Some(parent) = popover
71 .parent()
72 .and_downcast::<super::AccountSwitcherButton>()
73 {
74 parent.set_popover(None::<AccountSwitcherPopover>);
75 }
76
77 let closed_handler = popover.connect_closed(clone!(
78 #[weak]
79 obj,
80 move |_| {
81 obj.set_active(false);
82 }
83 ));
84
85 popover.set_parent(&*obj);
86 self.popover.set(popover, vec![closed_handler]);
87 }
88
89 obj.notify_popover();
90 }
91
92 #[template_callback]
94 fn toggle_popover(&self) {
95 let obj = self.obj();
96
97 if obj.is_active() {
98 let Some(window) = obj.root().and_downcast::<Window>() else {
99 return;
100 };
101
102 let popover = window.account_switcher();
103 self.set_popover(Some(popover));
104
105 popover.popup();
106 } else if let Some(popover) = self.popover.obj() {
107 popover.popdown();
108 }
109 }
110
111 fn reset(&self) {
113 if let Some(popover) = self.popover.obj() {
114 popover.unparent();
115 }
116 self.popover.disconnect_signals();
117 self.obj().set_active(false);
118 }
119 }
120}
121
122glib::wrapper! {
123 pub struct AccountSwitcherButton(ObjectSubclass<imp::AccountSwitcherButton>)
125 @extends gtk::Widget, gtk::Button, gtk::ToggleButton,
126 @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Actionable;
127}
128
129#[gtk::template_callbacks]
130impl AccountSwitcherButton {
131 pub fn new() -> Self {
132 glib::Object::new()
133 }
134}
135
136impl Default for AccountSwitcherButton {
137 fn default() -> Self {
138 Self::new()
139 }
140}