|
|
|
|
@ -1,9 +1,4 @@
|
|
|
|
|
use gtk::{ |
|
|
|
|
glib::{self, clone, closure}, |
|
|
|
|
prelude::*, |
|
|
|
|
subclass::prelude::*, |
|
|
|
|
CompositeTemplate, |
|
|
|
|
}; |
|
|
|
|
use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate}; |
|
|
|
|
|
|
|
|
|
use super::AccountSwitcherPopover; |
|
|
|
|
use crate::{ |
|
|
|
|
@ -14,17 +9,17 @@ use crate::{
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
mod imp { |
|
|
|
|
use std::cell::RefCell; |
|
|
|
|
|
|
|
|
|
use glib::subclass::InitializingObject; |
|
|
|
|
|
|
|
|
|
use super::*; |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default, CompositeTemplate)] |
|
|
|
|
#[derive(Debug, Default, CompositeTemplate, glib::Properties)] |
|
|
|
|
#[template(resource = "/org/gnome/Fractal/ui/account_switcher/account_switcher_button.ui")] |
|
|
|
|
#[properties(wrapper_type = super::AccountSwitcherButton)] |
|
|
|
|
pub struct AccountSwitcherButton { |
|
|
|
|
pub popover: BoundObjectWeakRef<AccountSwitcherPopover>, |
|
|
|
|
pub watch: RefCell<Option<gtk::ExpressionWatch>>, |
|
|
|
|
/// The popover of this button.
|
|
|
|
|
#[property(get, set = Self::set_popover, explicit_notify, nullable)] |
|
|
|
|
popover: BoundObjectWeakRef<AccountSwitcherPopover>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[glib::object_subclass] |
|
|
|
|
@ -38,6 +33,7 @@ mod imp {
|
|
|
|
|
SessionInfo::ensure_type(); |
|
|
|
|
|
|
|
|
|
Self::bind_template(klass); |
|
|
|
|
Self::bind_template_callbacks(klass); |
|
|
|
|
TemplateCallbacks::bind_template_callbacks(klass); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -46,102 +42,86 @@ mod imp {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl ObjectImpl for AccountSwitcherButton { |
|
|
|
|
fn constructed(&self) { |
|
|
|
|
self.parent_constructed(); |
|
|
|
|
let obj = self.obj(); |
|
|
|
|
|
|
|
|
|
obj.connect_toggled(|obj| { |
|
|
|
|
obj.handle_toggled(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
let watch = obj |
|
|
|
|
.property_expression("root") |
|
|
|
|
.chain_property::<Window>("session-selection") |
|
|
|
|
.chain_property::<gtk::SingleSelection>("n-items") |
|
|
|
|
.chain_closure::<bool>(closure!(|_: Option<glib::Object>, n_items: u32| { |
|
|
|
|
n_items > 0 |
|
|
|
|
})) |
|
|
|
|
.bind(&*obj, "visible", glib::Object::NONE); |
|
|
|
|
self.watch.replace(Some(watch)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn dispose(&self) { |
|
|
|
|
if let Some(watch) = self.watch.take() { |
|
|
|
|
watch.unwatch(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#[glib::derived_properties] |
|
|
|
|
impl ObjectImpl for AccountSwitcherButton {} |
|
|
|
|
|
|
|
|
|
impl WidgetImpl for AccountSwitcherButton {} |
|
|
|
|
impl ButtonImpl for AccountSwitcherButton {} |
|
|
|
|
impl ToggleButtonImpl for AccountSwitcherButton {} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
glib::wrapper! { |
|
|
|
|
/// A button showing the currently selected account and opening the account switcher popover.
|
|
|
|
|
pub struct AccountSwitcherButton(ObjectSubclass<imp::AccountSwitcherButton>) |
|
|
|
|
@extends gtk::Widget, gtk::Button, gtk::ToggleButton, @implements gtk::Accessible; |
|
|
|
|
} |
|
|
|
|
#[gtk::template_callbacks] |
|
|
|
|
impl AccountSwitcherButton { |
|
|
|
|
/// Set the popover of this button.
|
|
|
|
|
fn set_popover(&self, popover: Option<&AccountSwitcherPopover>) { |
|
|
|
|
let old_popover = self.popover.obj(); |
|
|
|
|
|
|
|
|
|
#[gtk::template_callbacks] |
|
|
|
|
impl AccountSwitcherButton { |
|
|
|
|
pub fn new() -> Self { |
|
|
|
|
glib::Object::new() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn popover(&self) -> Option<AccountSwitcherPopover> { |
|
|
|
|
self.imp().popover.obj() |
|
|
|
|
} |
|
|
|
|
if old_popover.as_ref() == popover { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
let obj = self.obj(); |
|
|
|
|
|
|
|
|
|
pub fn set_popover(&self, popover: Option<&AccountSwitcherPopover>) { |
|
|
|
|
let old_popover = self.popover(); |
|
|
|
|
// Reset the state.
|
|
|
|
|
if let Some(popover) = old_popover { |
|
|
|
|
popover.unparent(); |
|
|
|
|
} |
|
|
|
|
self.popover.disconnect_signals(); |
|
|
|
|
obj.set_active(false); |
|
|
|
|
|
|
|
|
|
if let Some(popover) = popover { |
|
|
|
|
// We need to remove the popover from the previous button, if any.
|
|
|
|
|
if let Some(parent) = popover |
|
|
|
|
.parent() |
|
|
|
|
.and_downcast::<super::AccountSwitcherButton>() |
|
|
|
|
{ |
|
|
|
|
parent.set_popover(None::<AccountSwitcherPopover>); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if old_popover.as_ref() == popover { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
let closed_handler = popover.connect_closed(clone!( |
|
|
|
|
#[weak] |
|
|
|
|
obj, |
|
|
|
|
move |_| { |
|
|
|
|
obj.set_active(false); |
|
|
|
|
} |
|
|
|
|
)); |
|
|
|
|
|
|
|
|
|
let imp = self.imp(); |
|
|
|
|
popover.set_parent(&*obj); |
|
|
|
|
self.popover.set(popover, vec![closed_handler]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Reset the state.
|
|
|
|
|
if let Some(popover) = old_popover { |
|
|
|
|
popover.unparent(); |
|
|
|
|
obj.notify_popover(); |
|
|
|
|
} |
|
|
|
|
imp.popover.disconnect_signals(); |
|
|
|
|
self.set_active(false); |
|
|
|
|
|
|
|
|
|
if let Some(popover) = popover { |
|
|
|
|
// We need to remove the popover from the previous button, if any.
|
|
|
|
|
if let Some(parent) = popover.parent().and_downcast::<AccountSwitcherButton>() { |
|
|
|
|
parent.set_popover(None); |
|
|
|
|
} |
|
|
|
|
/// Toggle the popover of this button.
|
|
|
|
|
#[template_callback] |
|
|
|
|
fn toggle_popover(&self) { |
|
|
|
|
let obj = self.obj(); |
|
|
|
|
|
|
|
|
|
let closed_handler = popover.connect_closed(clone!( |
|
|
|
|
#[weak(rename_to = obj)] |
|
|
|
|
self, |
|
|
|
|
move |_| { |
|
|
|
|
obj.set_active(false); |
|
|
|
|
} |
|
|
|
|
)); |
|
|
|
|
if obj.is_active() { |
|
|
|
|
let Some(window) = obj.root().and_downcast::<Window>() else { |
|
|
|
|
return; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let popover = window.account_switcher(); |
|
|
|
|
self.set_popover(Some(popover)); |
|
|
|
|
|
|
|
|
|
popover.set_parent(self); |
|
|
|
|
imp.popover.set(popover, vec![closed_handler]); |
|
|
|
|
popover.popup(); |
|
|
|
|
} else if let Some(popover) = self.popover.obj() { |
|
|
|
|
popover.popdown(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn handle_toggled(&self) { |
|
|
|
|
if self.is_active() { |
|
|
|
|
let Some(window) = self.root().and_downcast::<Window>() else { |
|
|
|
|
return; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let popover = window.account_switcher(); |
|
|
|
|
self.set_popover(Some(popover)); |
|
|
|
|
glib::wrapper! { |
|
|
|
|
/// A button showing the currently selected session and opening the account switcher popover.
|
|
|
|
|
pub struct AccountSwitcherButton(ObjectSubclass<imp::AccountSwitcherButton>) |
|
|
|
|
@extends gtk::Widget, gtk::Button, gtk::ToggleButton, @implements gtk::Accessible; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
popover.popup(); |
|
|
|
|
} else if let Some(popover) = self.popover() { |
|
|
|
|
popover.popdown(); |
|
|
|
|
} |
|
|
|
|
#[gtk::template_callbacks] |
|
|
|
|
impl AccountSwitcherButton { |
|
|
|
|
pub fn new() -> Self { |
|
|
|
|
glib::Object::new() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|