Use cosmic::Application/cosmic::app::applet

This saves a bit of duplicated boilerplate.

Applets seem to work fairly well with this. Though we should see if any
other changes to initial window settings are needed in certain applets
for the exact behavior we want.
This commit is contained in:
Ian Douglas Scott 2023-08-03 13:22:17 -07:00
parent 3ad64df5f3
commit a23f181b7f
28 changed files with 2029 additions and 2597 deletions

View file

@ -3,34 +3,8 @@ mod graphics;
mod localize;
mod window;
use cosmic::{
iced::{wayland::InitialSurface, Application, Settings},
iced_runtime::core::layout::Limits,
};
use cosmic_applet::{cosmic_panel_config::PanelAnchor, CosmicAppletHelper};
use window::*;
pub fn main() -> cosmic::iced::Result {
let helper = CosmicAppletHelper::default();
let mut settings: Settings<()> = helper.window_settings();
match helper.anchor {
PanelAnchor::Top | PanelAnchor::Bottom => {
match &mut settings.initial_surface {
InitialSurface::LayerSurface(_) => todo!(),
InitialSurface::XdgWindow(w) => {
w.autosize = true;
w.resizable = None;
w.size_limits = Limits::NONE
.min_height(1.0)
.max_height(200.0)
.min_width(1.0)
.max_width(1000.0);
}
InitialSurface::None => unimplemented!(),
};
}
_ => {}
};
Window::run(settings)
cosmic::app::applet::run::<Window>(true, ())
}

View file

@ -1,23 +1,24 @@
use crate::dbus::{self, PowerDaemonProxy};
use crate::fl;
use crate::graphics::{get_current_graphics, set_graphics, Graphics};
use cosmic::app::{
applet::{applet_button_theme, cosmic_panel_config::PanelAnchor},
Command,
};
use cosmic::iced::wayland::popup::{destroy_popup, get_popup};
use cosmic::iced::Color;
use cosmic::iced_futures::Subscription;
use cosmic::iced_runtime::core::alignment::Horizontal;
use cosmic::iced_runtime::core::Alignment;
use cosmic::iced_style::application::{self, Appearance};
use cosmic::iced_style::application;
use cosmic::theme::Button;
use cosmic::widget::icon;
use cosmic::{
iced::widget::{column, container, row, text},
iced::{self, Application, Command, Length},
iced::{self, Length},
iced_runtime::core::window,
theme::{Svg, Theme},
widget::{button, divider},
Element,
};
use cosmic_applet::{applet_button_theme, cosmic_panel_config::PanelAnchor, CosmicAppletHelper};
use zbus::Connection;
const ID: &str = "com.system76.CosmicAppletGraphics";
@ -41,12 +42,11 @@ impl GraphicsMode {
#[derive(Default)]
pub struct Window {
core: cosmic::app::Core,
popup: Option<window::Id>,
graphics_mode: Option<GraphicsMode>,
id_ctr: u128,
theme: Theme,
dbus: Option<(Connection, PowerDaemonProxy<'static>)>,
applet_helper: CosmicAppletHelper,
}
#[allow(dead_code)]
@ -58,35 +58,37 @@ pub enum Message {
SelectGraphicsMode(Graphics),
TogglePopup,
PopupClosed(window::Id),
Theme(Theme),
}
impl Application for Window {
impl cosmic::Application for Window {
type Executor = cosmic::SingleThreadExecutor;
type Flags = ();
type Message = Message;
type Theme = Theme;
const APP_ID: &'static str = ID;
fn new(_flags: ()) -> (Self, Command<Self::Message>) {
let applet_helper = CosmicAppletHelper::default();
let theme = applet_helper.theme();
fn init(core: cosmic::app::Core, _flags: ()) -> (Self, Command<Message>) {
let window = Window {
theme,
applet_helper,
core,
..Default::default()
};
(window, Command::perform(dbus::init(), Message::DBusInit))
(
window,
iced::Command::perform(dbus::init(), |x| {
cosmic::app::message::app(Message::DBusInit(x))
}),
)
}
fn title(&self) -> String {
String::from("Cosmic Graphics Applet")
fn core(&self) -> &cosmic::app::Core {
&self.core
}
fn update(&mut self, message: Message) -> iced::Command<Self::Message> {
fn core_mut(&mut self) -> &mut cosmic::app::Core {
&mut self.core
}
fn update(&mut self, message: Message) -> Command<Self::Message> {
match message {
Message::Theme(t) => {
self.theme = t;
}
Message::SelectGraphicsMode(new) => {
if let Some((_, proxy)) = self.dbus.as_ref() {
let prev = self
@ -94,9 +96,14 @@ impl Application for Window {
.map(|m| m.inner())
.unwrap_or_else(|| Graphics::Integrated);
self.graphics_mode = Some(GraphicsMode::SelectedGraphicsMode { prev, new });
return Command::perform(set_graphics(proxy.clone(), new), move |success| {
Message::AppliedGraphics(success.ok().map(|_| new))
});
return iced::Command::perform(
set_graphics(proxy.clone(), new),
move |success| {
cosmic::app::message::app(Message::AppliedGraphics(
success.ok().map(|_| new),
))
},
);
}
}
Message::TogglePopup => {
@ -108,12 +115,12 @@ impl Application for Window {
self.popup.replace(new_id);
let mut commands = Vec::new();
if let Some((_, proxy)) = self.dbus.as_ref() {
commands.push(Command::perform(
commands.push(iced::Command::perform(
get_current_graphics(proxy.clone()),
|cur_graphics| Message::CurrentGraphics(cur_graphics.ok()),
));
}
let popup_settings = self.applet_helper.get_popup_settings(
let popup_settings = self.core.applet_helper.get_popup_settings(
window::Id(0),
new_id,
None,
@ -121,12 +128,12 @@ impl Application for Window {
None,
);
commands.push(get_popup(popup_settings));
return Command::batch(commands);
return iced::Command::batch(commands).map(cosmic::app::message::app);
}
}
Message::DBusInit(dbus) => {
self.dbus = dbus;
return Command::perform(
return iced::Command::perform(
get_current_graphics(self.dbus.as_ref().unwrap().1.clone()),
|cur_graphics| {
Message::CurrentGraphics(match cur_graphics {
@ -137,7 +144,8 @@ impl Application for Window {
}
})
},
);
)
.map(cosmic::app::message::app);
}
Message::CurrentGraphics(g) => {
if let Some(g) = g {
@ -166,16 +174,17 @@ impl Application for Window {
// Reset to prev after failing
// https://github.com/pop-os/system76-power/issues/387
if let Some((_, proxy)) = self.dbus.as_ref() {
return Command::perform(
return iced::Command::perform(
set_graphics(proxy.clone(), prev),
move |success| {
Message::AppliedGraphics(success.ok().map(|_| new))
},
);
)
.map(cosmic::app::message::app);
}
}
_ => {
return Command::perform(
return iced::Command::perform(
get_current_graphics(self.dbus.as_ref().unwrap().1.clone()),
|cur_graphics| {
Message::CurrentGraphics(match cur_graphics {
@ -187,6 +196,7 @@ impl Application for Window {
})
},
)
.map(cosmic::app::message::app)
}
};
}
@ -195,227 +205,207 @@ impl Application for Window {
Command::none()
}
fn view(&self, id: window::Id) -> Element<Message> {
if id == window::Id(0) {
match self.applet_helper.anchor {
PanelAnchor::Left | PanelAnchor::Right => self
.applet_helper
.icon_button(ID)
.on_press(Message::TogglePopup)
.style(Button::Text)
.into(),
PanelAnchor::Top | PanelAnchor::Bottom => button(Button::Text)
.custom(vec![row![
icon(ID, self.applet_helper.suggested_size().0,).style(Svg::Symbolic),
text(match self.graphics_mode.map(|g| g.inner()) {
Some(Graphics::Integrated) => fl!("integrated"),
Some(Graphics::Nvidia) => fl!("nvidia"),
Some(Graphics::Compute) => fl!("compute"),
Some(Graphics::Hybrid) => fl!("hybrid"),
None => "".into(),
})
.size(14)
fn view(&self) -> Element<Message> {
match self.core.applet_helper.anchor {
PanelAnchor::Left | PanelAnchor::Right => self
.core
.applet_helper
.icon_button(ID)
.on_press(Message::TogglePopup)
.style(Button::Text)
.into(),
PanelAnchor::Top | PanelAnchor::Bottom => button(Button::Text)
.custom(vec![row![
icon(ID, self.core.applet_helper.suggested_size().0,).style(Svg::Symbolic),
text(match self.graphics_mode.map(|g| g.inner()) {
Some(Graphics::Integrated) => fl!("integrated"),
Some(Graphics::Nvidia) => fl!("nvidia"),
Some(Graphics::Compute) => fl!("compute"),
Some(Graphics::Hybrid) => fl!("hybrid"),
None => "".into(),
})
.size(14)
]
.spacing(8)
.padding([0, self.core.applet_helper.suggested_size().0 / 2])
.align_items(Alignment::Center)
.into()])
.style(Button::Text)
.on_press(Message::TogglePopup)
.padding(8)
.width(Length::Shrink)
.height(Length::Shrink)
.into(),
}
}
fn view_window(&self, _id: window::Id) -> Element<Message> {
let content_list = vec![
button(applet_button_theme())
.custom(vec![row![
column![
text(format!("{} {}", fl!("integrated"), fl!("graphics"))).size(14),
text(fl!("integrated-desc")).size(12)
]
.spacing(8)
.padding([0, self.applet_helper.suggested_size().0 / 2])
.align_items(Alignment::Center)
.into()])
.style(Button::Text)
.on_press(Message::TogglePopup)
.padding(8)
.width(Length::Shrink)
.height(Length::Shrink)
.into(),
}
} else {
let content_list = vec![
button(applet_button_theme())
.custom(vec![row![
column![
text(format!("{} {}", fl!("integrated"), fl!("graphics"))).size(14),
text(fl!("integrated-desc")).size(12)
]
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Integrated,
..
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Integrated)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Integrated)) =>
Svg::SymbolicActive,
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Integrated,
..
}) => Svg::Symbolic,
_ => Svg::Default,
},),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Integrated))
.width(Length::Fill)
.into(),
button(applet_button_theme())
.custom(vec![row![
column![text(format!("{} {}", fl!("nvidia"), fl!("graphics"))).size(14),]
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Nvidia,
..
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Nvidia)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Nvidia)) =>
Svg::SymbolicActive,
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Integrated)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Integrated)) =>
Svg::SymbolicActive,
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Integrated,
..
}) => Svg::Symbolic,
_ => Svg::Default,
},),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Integrated))
.width(Length::Fill)
.into(),
button(applet_button_theme())
.custom(vec![row![
column![text(format!("{} {}", fl!("nvidia"), fl!("graphics"))).size(14),]
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Nvidia,
..
}) => Svg::Symbolic,
_ => Svg::Default,
}),
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Nvidia)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Nvidia)) =>
Svg::SymbolicActive,
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Nvidia,
..
}) => Svg::Symbolic,
_ => Svg::Default,
}),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Nvidia))
.width(Length::Fill)
.into(),
button(applet_button_theme())
.custom(vec![row![
column![
text(format!("{} {}", fl!("hybrid"), fl!("graphics"))).size(14),
text(fl!("hybrid-desc")).size(12)
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Nvidia))
.width(Length::Fill)
.into(),
button(applet_button_theme())
.custom(vec![row![
column![
text(format!("{} {}", fl!("hybrid"), fl!("graphics"))).size(14),
text(fl!("hybrid-desc")).size(12)
]
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Hybrid,
..
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Hybrid)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Hybrid)) =>
Svg::SymbolicActive,
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Hybrid,
..
}) => Svg::Symbolic,
_ => Svg::Default,
})
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Hybrid)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Hybrid)) =>
Svg::SymbolicActive,
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Hybrid,
..
}) => Svg::Symbolic,
_ => Svg::Default,
})
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Hybrid))
.width(Length::Fill)
.into(),
button(applet_button_theme())
.custom(vec![row![
column![
text(format!("{} {}", fl!("compute"), fl!("graphics"))).size(14),
text(fl!("compute-desc")).size(12)
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Hybrid))
.width(Length::Fill)
.into(),
button(applet_button_theme())
.custom(vec![row![
column![
text(format!("{} {}", fl!("compute"), fl!("graphics"))).size(14),
text(fl!("compute-desc")).size(12)
]
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Compute,
..
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Compute)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Compute)) =>
Svg::SymbolicActive,
.width(Length::Fill),
icon(
match self.graphics_mode {
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Compute,
..
}) => Svg::Symbolic,
_ => Svg::Default,
}),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Compute))
.width(Length::Fill)
.into(),
];
}) => "process-working-symbolic",
_ => "emblem-ok-symbolic",
},
12
)
.size(12)
.style(match self.graphics_mode {
Some(GraphicsMode::CurrentGraphicsMode(Graphics::Compute)) =>
Svg::SymbolicActive,
Some(GraphicsMode::AppliedGraphicsMode(Graphics::Compute)) =>
Svg::SymbolicActive,
Some(GraphicsMode::SelectedGraphicsMode {
new: Graphics::Compute,
..
}) => Svg::Symbolic,
_ => Svg::Default,
}),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectGraphicsMode(Graphics::Compute))
.width(Length::Fill)
.into(),
];
self.applet_helper
.popup_container(
column(vec![
text(fl!("graphics-mode"))
.width(Length::Fill)
.horizontal_alignment(Horizontal::Center)
.size(14)
.into(),
container(divider::horizontal::light())
.padding([0, 12])
.width(Length::Fill)
.into(),
column(content_list).into(),
])
.padding([8, 0])
.spacing(12),
)
.into()
}
}
fn subscription(&self) -> Subscription<Message> {
self.applet_helper.theme_subscription(0).map(Message::Theme)
self.core
.applet_helper
.popup_container(
column(vec![
text(fl!("graphics-mode"))
.width(Length::Fill)
.horizontal_alignment(Horizontal::Center)
.size(14)
.into(),
container(divider::horizontal::light())
.padding([0, 12])
.width(Length::Fill)
.into(),
column(content_list).into(),
])
.padding([8, 0])
.spacing(12),
)
.into()
}
fn close_requested(&self, id: window::Id) -> Self::Message {
if id != window::Id(0) {
Message::PopupClosed(id)
} else {
unimplemented!();
}
}
fn style(&self) -> <Self::Theme as application::StyleSheet>::Style {
<Self::Theme as application::StyleSheet>::Style::Custom(Box::new(|theme| Appearance {
background_color: Color::from_rgba(0.0, 0.0, 0.0, 0.0),
text_color: theme.cosmic().background.on.into(),
}))
}
fn should_exit(&self) -> bool {
false
}
fn theme(&self) -> Theme {
self.theme.clone()
fn style(&self) -> Option<<Theme as application::StyleSheet>::Style> {
Some(cosmic::app::applet::style())
}
}