Combine some logic between greeter and locker
This commit is contained in:
parent
c9913834f2
commit
8812240f50
4 changed files with 418 additions and 384 deletions
235
src/common.rs
Normal file
235
src/common.rs
Normal file
|
|
@ -0,0 +1,235 @@
|
||||||
|
use cosmic::{
|
||||||
|
app::{Core, Task},
|
||||||
|
iced::{
|
||||||
|
self, Rectangle, Size, Subscription,
|
||||||
|
core::SmolStr,
|
||||||
|
event::{
|
||||||
|
self,
|
||||||
|
wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent},
|
||||||
|
},
|
||||||
|
keyboard::{Event as KeyEvent, Key, Modifiers},
|
||||||
|
},
|
||||||
|
iced_runtime::core::window::Id as SurfaceId,
|
||||||
|
widget,
|
||||||
|
};
|
||||||
|
use cosmic_greeter_daemon::{BgSource, UserData};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use wayland_client::protocol::wl_output::WlOutput;
|
||||||
|
|
||||||
|
pub struct Common<M> {
|
||||||
|
pub active_surface_id_opt: Option<SurfaceId>,
|
||||||
|
pub core: Core,
|
||||||
|
pub error_opt: Option<String>,
|
||||||
|
pub input: String,
|
||||||
|
pub network_icon_opt: Option<&'static str>,
|
||||||
|
pub on_output_event: Option<Box<dyn Fn(OutputEvent, WlOutput) -> M>>,
|
||||||
|
pub on_session_lock_event: Option<Box<dyn Fn(SessionLockEvent) -> M>>,
|
||||||
|
pub output_names: HashMap<WlOutput, String>,
|
||||||
|
pub power_info_opt: Option<(String, f64)>,
|
||||||
|
pub prompt_opt: Option<(String, bool, Option<String>)>,
|
||||||
|
pub subsurface_rects: HashMap<WlOutput, Rectangle>,
|
||||||
|
pub surface_ids: HashMap<WlOutput, SurfaceId>,
|
||||||
|
pub surface_images: HashMap<SurfaceId, widget::image::Handle>,
|
||||||
|
pub surface_names: HashMap<SurfaceId, String>,
|
||||||
|
pub text_input_ids: HashMap<String, widget::Id>,
|
||||||
|
pub time: crate::time::Time,
|
||||||
|
pub window_size: HashMap<SurfaceId, Size>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Message {
|
||||||
|
Focus(SurfaceId),
|
||||||
|
Input(String),
|
||||||
|
Key(Modifiers, Key, Option<SmolStr>),
|
||||||
|
NetworkIcon(Option<&'static str>),
|
||||||
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
|
PowerInfo(Option<(String, f64)>),
|
||||||
|
SessionLockEvent(SessionLockEvent),
|
||||||
|
Tick,
|
||||||
|
Tz(chrono_tz::Tz),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
|
pub fn init(mut core: Core) -> (Self, Task<M>) {
|
||||||
|
core.window.show_window_menu = false;
|
||||||
|
core.window.show_headerbar = false;
|
||||||
|
// XXX must be false or define custom style to have transparent bg
|
||||||
|
core.window.sharp_corners = false;
|
||||||
|
core.window.show_maximize = false;
|
||||||
|
core.window.show_minimize = false;
|
||||||
|
core.window.use_template = false;
|
||||||
|
|
||||||
|
let app = Self {
|
||||||
|
active_surface_id_opt: None,
|
||||||
|
core,
|
||||||
|
error_opt: None,
|
||||||
|
input: String::new(),
|
||||||
|
network_icon_opt: None,
|
||||||
|
on_output_event: None,
|
||||||
|
on_session_lock_event: None,
|
||||||
|
output_names: HashMap::new(),
|
||||||
|
power_info_opt: None,
|
||||||
|
prompt_opt: None,
|
||||||
|
subsurface_rects: HashMap::new(),
|
||||||
|
surface_ids: HashMap::new(),
|
||||||
|
surface_images: HashMap::new(),
|
||||||
|
surface_names: HashMap::new(),
|
||||||
|
text_input_ids: HashMap::new(),
|
||||||
|
time: crate::time::Time::new(),
|
||||||
|
window_size: HashMap::new(),
|
||||||
|
};
|
||||||
|
(
|
||||||
|
app,
|
||||||
|
Task::batch(vec![
|
||||||
|
crate::time::tick().map(|_| cosmic::Action::App(Message::Tick.into())),
|
||||||
|
crate::time::tz_updates().map(|tz| cosmic::Action::App(Message::Tz(tz).into())),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_wallpapers(&mut self, user_data: &UserData) {
|
||||||
|
for (_output, surface_id) in self.surface_ids.iter() {
|
||||||
|
if self.surface_images.contains_key(surface_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(output_name) = self.surface_names.get(surface_id) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
log::info!("updating wallpaper for {:?}", output_name);
|
||||||
|
|
||||||
|
for (wallpaper_output_name, wallpaper_source) in user_data.bg_state.wallpapers.iter() {
|
||||||
|
if wallpaper_output_name == output_name {
|
||||||
|
match wallpaper_source {
|
||||||
|
BgSource::Path(path) => {
|
||||||
|
match user_data.bg_path_data.get(path) {
|
||||||
|
Some(bytes) => {
|
||||||
|
let image = widget::image::Handle::from_bytes(bytes.clone());
|
||||||
|
self.surface_images.insert(*surface_id, image);
|
||||||
|
//TODO: what to do about duplicates?
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::warn!(
|
||||||
|
"output {}: failed to find wallpaper data for source {:?}",
|
||||||
|
output_name,
|
||||||
|
path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BgSource::Color(color) => {
|
||||||
|
//TODO: support color sources
|
||||||
|
log::warn!("output {}: unsupported source {:?}", output_name, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, message: Message) -> Task<M> {
|
||||||
|
match message {
|
||||||
|
Message::Focus(surface_id) => {
|
||||||
|
self.active_surface_id_opt = Some(surface_id);
|
||||||
|
if let Some(text_input_id) = self
|
||||||
|
.surface_names
|
||||||
|
.get(&surface_id)
|
||||||
|
.and_then(|id| self.text_input_ids.get(id))
|
||||||
|
{
|
||||||
|
return widget::text_input::focus(text_input_id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Input(input) => {
|
||||||
|
self.input = input;
|
||||||
|
}
|
||||||
|
Message::Key(modifiers, key, text) => {
|
||||||
|
// Uncaptured keys with only shift modifiers go to the password box
|
||||||
|
if !modifiers.logo()
|
||||||
|
&& !modifiers.control()
|
||||||
|
&& !modifiers.alt()
|
||||||
|
&& matches!(key, Key::Character(_))
|
||||||
|
{
|
||||||
|
if let Some(text) = text {
|
||||||
|
self.input.push_str(&text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(surface_id) = self.active_surface_id_opt {
|
||||||
|
if let Some(text_input_id) = self
|
||||||
|
.surface_names
|
||||||
|
.get(&surface_id)
|
||||||
|
.and_then(|id| self.text_input_ids.get(id))
|
||||||
|
{
|
||||||
|
return widget::text_input::focus(text_input_id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::NetworkIcon(network_icon_opt) => {
|
||||||
|
self.network_icon_opt = network_icon_opt;
|
||||||
|
}
|
||||||
|
Message::OutputEvent(output_event, output) => {
|
||||||
|
if let Some(on_output_event) = &self.on_output_event {
|
||||||
|
return Task::done(cosmic::Action::App(on_output_event(output_event, output)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::PowerInfo(power_info_opt) => {
|
||||||
|
self.power_info_opt = power_info_opt;
|
||||||
|
}
|
||||||
|
Message::SessionLockEvent(lock_event) => {
|
||||||
|
if let Some(on_session_lock_event) = &self.on_session_lock_event {
|
||||||
|
return Task::done(cosmic::Action::App(on_session_lock_event(lock_event)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Tick => {
|
||||||
|
self.time.tick();
|
||||||
|
}
|
||||||
|
Message::Tz(tz) => {
|
||||||
|
self.time.set_tz(tz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscription(&self) -> Subscription<Message> {
|
||||||
|
let mut subscriptions = Vec::with_capacity(3);
|
||||||
|
|
||||||
|
subscriptions.push(event::listen_with(|event, status, id| match event {
|
||||||
|
iced::Event::Keyboard(KeyEvent::KeyPressed {
|
||||||
|
key,
|
||||||
|
modifiers,
|
||||||
|
text,
|
||||||
|
..
|
||||||
|
}) => match status {
|
||||||
|
event::Status::Ignored => Some(Message::Key(modifiers, key, text)),
|
||||||
|
event::Status::Captured => None,
|
||||||
|
},
|
||||||
|
iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(
|
||||||
|
wayland_event,
|
||||||
|
)) => match wayland_event {
|
||||||
|
WaylandEvent::Output(output_event, output) => {
|
||||||
|
Some(Message::OutputEvent(output_event, output))
|
||||||
|
}
|
||||||
|
WaylandEvent::SessionLock(lock_event) => {
|
||||||
|
Some(Message::SessionLockEvent(lock_event))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
iced::Event::Window(iced::window::Event::Focused) => Some(Message::Focus(id)),
|
||||||
|
_ => None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
#[cfg(feature = "networkmanager")]
|
||||||
|
{
|
||||||
|
subscriptions.push(crate::networkmanager::subscription().map(Message::NetworkIcon));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "upower")]
|
||||||
|
{
|
||||||
|
subscriptions.push(crate::upower::subscription().map(Message::PowerInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
Subscription::batch(subscriptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
260
src/greeter.rs
260
src/greeter.rs
|
|
@ -6,7 +6,6 @@ mod ipc;
|
||||||
use cosmic::app::{Core, Settings, Task};
|
use cosmic::app::{Core, Settings, Task};
|
||||||
use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity;
|
use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity;
|
||||||
use cosmic::iced::{Point, Size};
|
use cosmic::iced::{Point, Size};
|
||||||
use cosmic::iced_core::image;
|
|
||||||
use cosmic::iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings;
|
use cosmic::iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings;
|
||||||
use cosmic::surface;
|
use cosmic::surface;
|
||||||
use cosmic::widget::text;
|
use cosmic::widget::text;
|
||||||
|
|
@ -16,10 +15,7 @@ use cosmic::{
|
||||||
executor,
|
executor,
|
||||||
iced::{
|
iced::{
|
||||||
self, Background, Border, Length, Subscription, alignment,
|
self, Background, Border, Length, Subscription, alignment,
|
||||||
event::{
|
event::wayland::OutputEvent,
|
||||||
self,
|
|
||||||
wayland::{Event as WaylandEvent, OutputEvent},
|
|
||||||
},
|
|
||||||
futures::SinkExt,
|
futures::SinkExt,
|
||||||
platform_specific::{
|
platform_specific::{
|
||||||
runtime::wayland::layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings},
|
runtime::wayland::layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings},
|
||||||
|
|
@ -33,7 +29,7 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use cosmic_comp_config::CosmicCompConfig;
|
use cosmic_comp_config::CosmicCompConfig;
|
||||||
use cosmic_greeter_config::Config as CosmicGreeterConfig;
|
use cosmic_greeter_config::Config as CosmicGreeterConfig;
|
||||||
use cosmic_greeter_daemon::{BgSource, UserData};
|
use cosmic_greeter_daemon::UserData;
|
||||||
use greetd_ipc::Request;
|
use greetd_ipc::Request;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, hash_map},
|
collections::{HashMap, hash_map},
|
||||||
|
|
@ -49,7 +45,10 @@ use tokio::time;
|
||||||
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
||||||
use zbus::{Connection, proxy};
|
use zbus::{Connection, proxy};
|
||||||
|
|
||||||
use crate::fl;
|
use crate::{
|
||||||
|
common::{self, Common},
|
||||||
|
fl,
|
||||||
|
};
|
||||||
|
|
||||||
#[proxy(
|
#[proxy(
|
||||||
interface = "com.system76.CosmicGreeter",
|
interface = "com.system76.CosmicGreeter",
|
||||||
|
|
@ -364,6 +363,8 @@ struct NameIndexPair {
|
||||||
/// Messages that are used specifically by our [`App`].
|
/// Messages that are used specifically by our [`App`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
|
Common(common::Message),
|
||||||
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
Auth(Option<String>),
|
Auth(Option<String>),
|
||||||
ConfigUpdateUser,
|
ConfigUpdateUser,
|
||||||
DialogCancel,
|
DialogCancel,
|
||||||
|
|
@ -371,15 +372,11 @@ pub enum Message {
|
||||||
DropdownToggle(Dropdown),
|
DropdownToggle(Dropdown),
|
||||||
Error(String),
|
Error(String),
|
||||||
Exit,
|
Exit,
|
||||||
Focus(SurfaceId),
|
|
||||||
// Sets channel used to communicate with the greetd IPC subscription.
|
// Sets channel used to communicate with the greetd IPC subscription.
|
||||||
GreetdChannel(tokio::sync::mpsc::Sender<Request>),
|
GreetdChannel(tokio::sync::mpsc::Sender<Request>),
|
||||||
Heartbeat,
|
Heartbeat,
|
||||||
KeyboardLayout(usize),
|
KeyboardLayout(usize),
|
||||||
Login,
|
Login,
|
||||||
NetworkIcon(Option<&'static str>),
|
|
||||||
OutputEvent(OutputEvent, WlOutput),
|
|
||||||
PowerInfo(Option<(String, f64)>),
|
|
||||||
Prompt(String, bool, Option<String>),
|
Prompt(String, bool, Option<String>),
|
||||||
Reconnect,
|
Reconnect,
|
||||||
Restart,
|
Restart,
|
||||||
|
|
@ -388,41 +385,39 @@ pub enum Message {
|
||||||
Socket(SocketState),
|
Socket(SocketState),
|
||||||
Surface(surface::Action),
|
Surface(surface::Action),
|
||||||
Suspend,
|
Suspend,
|
||||||
Tick,
|
|
||||||
Tz(chrono_tz::Tz),
|
|
||||||
Username(String),
|
Username(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<common::Message> for Message {
|
||||||
|
fn from(message: common::Message) -> Self {
|
||||||
|
Self::Common(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The [`App`] stores application-specific state.
|
/// The [`App`] stores application-specific state.
|
||||||
pub struct App {
|
pub struct App {
|
||||||
core: Core,
|
common: Common<Message>,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
greetd_sender: Option<tokio::sync::mpsc::Sender<greetd_ipc::Request>>,
|
greetd_sender: Option<tokio::sync::mpsc::Sender<greetd_ipc::Request>>,
|
||||||
surface_ids: HashMap<WlOutput, SurfaceId>,
|
|
||||||
active_surface_id_opt: Option<SurfaceId>,
|
|
||||||
surface_images: HashMap<SurfaceId, image::Handle>,
|
|
||||||
surface_names: HashMap<SurfaceId, String>,
|
|
||||||
text_input_ids: HashMap<String, widget::Id>,
|
|
||||||
network_icon_opt: Option<&'static str>,
|
|
||||||
power_info_opt: Option<(String, f64)>,
|
|
||||||
socket_state: SocketState,
|
socket_state: SocketState,
|
||||||
usernames: Vec<(String, String)>,
|
usernames: Vec<(String, String)>,
|
||||||
selected_username: NameIndexPair,
|
selected_username: NameIndexPair,
|
||||||
prompt_opt: Option<(String, bool, Option<String>)>,
|
|
||||||
session_names: Vec<String>,
|
session_names: Vec<String>,
|
||||||
selected_session: String,
|
selected_session: String,
|
||||||
active_layouts: Vec<ActiveLayout>,
|
active_layouts: Vec<ActiveLayout>,
|
||||||
error_opt: Option<String>,
|
|
||||||
dialog_page_opt: Option<DialogPage>,
|
dialog_page_opt: Option<DialogPage>,
|
||||||
dropdown_opt: Option<Dropdown>,
|
dropdown_opt: Option<Dropdown>,
|
||||||
window_size: HashMap<SurfaceId, Size>,
|
|
||||||
heartbeat_handle: Option<cosmic::iced::task::Handle>,
|
heartbeat_handle: Option<cosmic::iced::task::Handle>,
|
||||||
time: crate::time::Time,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn menu(&self, id: SurfaceId) -> Element<Message> {
|
fn menu(&self, id: SurfaceId) -> Element<Message> {
|
||||||
let window_width = self.window_size.get(&id).map(|s| s.width).unwrap_or(800.);
|
let window_width = self
|
||||||
|
.common
|
||||||
|
.window_size
|
||||||
|
.get(&id)
|
||||||
|
.map(|s| s.width)
|
||||||
|
.unwrap_or(800.);
|
||||||
let menu_width = if window_width > 800. {
|
let menu_width = if window_width > 800. {
|
||||||
800.
|
800.
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -435,15 +430,15 @@ impl App {
|
||||||
.and_then(|i| self.flags.user_datas.get(i))
|
.and_then(|i| self.flags.user_datas.get(i))
|
||||||
.map(|user_data| user_data.time_applet_config.military_time)
|
.map(|user_data| user_data.time_applet_config.military_time)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let date_time_column = self.time.date_time_widget(military_time);
|
let date_time_column = self.common.time.date_time_widget(military_time);
|
||||||
|
|
||||||
let mut status_row = widget::row::with_capacity(2).padding(16.0).spacing(12.0);
|
let mut status_row = widget::row::with_capacity(2).padding(16.0).spacing(12.0);
|
||||||
|
|
||||||
if let Some(network_icon) = self.network_icon_opt {
|
if let Some(network_icon) = self.common.network_icon_opt {
|
||||||
status_row = status_row.push(widget::icon::from_name(network_icon));
|
status_row = status_row.push(widget::icon::from_name(network_icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((power_icon, power_percent)) = &self.power_info_opt {
|
if let Some((power_icon, power_percent)) = &self.common.power_info_opt {
|
||||||
status_row = status_row.push(iced::widget::row![
|
status_row = status_row.push(iced::widget::row![
|
||||||
widget::icon::from_name(power_icon.clone()),
|
widget::icon::from_name(power_icon.clone()),
|
||||||
widget::text(format!("{:.0}%", power_percent)),
|
widget::text(format!("{:.0}%", power_percent)),
|
||||||
|
|
@ -641,18 +636,19 @@ impl App {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match &self.prompt_opt {
|
match &self.common.prompt_opt {
|
||||||
Some((prompt, secret, value_opt)) => match value_opt {
|
Some((prompt, secret, value_opt)) => match value_opt {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let text_input_id = self
|
let text_input_id = self
|
||||||
|
.common
|
||||||
.surface_names
|
.surface_names
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
.and_then(|id| self.common.text_input_ids.get(id))
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| cosmic::widget::Id::new("text_input"));
|
.unwrap_or_else(|| cosmic::widget::Id::new("text_input"));
|
||||||
let mut text_input = widget::secure_input(
|
let mut text_input = widget::secure_input(
|
||||||
prompt.clone(),
|
prompt.clone(),
|
||||||
"",
|
&self.common.input,
|
||||||
Some(Message::Prompt(
|
Some(Message::Prompt(
|
||||||
prompt.clone(),
|
prompt.clone(),
|
||||||
!*secret,
|
!*secret,
|
||||||
|
|
@ -661,13 +657,14 @@ impl App {
|
||||||
*secret,
|
*secret,
|
||||||
)
|
)
|
||||||
.id(text_input_id)
|
.id(text_input_id)
|
||||||
.manage_value(true)
|
.on_input(|input| common::Message::Input(input).into())
|
||||||
.on_submit(|v| Message::Auth(Some(v)));
|
.on_submit(|v| Message::Auth(Some(v)));
|
||||||
|
|
||||||
if let Some(text_input_id) = self
|
if let Some(text_input_id) = self
|
||||||
|
.common
|
||||||
.surface_names
|
.surface_names
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
.and_then(|id| self.common.text_input_ids.get(id))
|
||||||
{
|
{
|
||||||
text_input = text_input.id(text_input_id.clone());
|
text_input = text_input.id(text_input_id.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -698,7 +695,7 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(error) = &self.error_opt {
|
if let Some(error) = &self.common.error_opt {
|
||||||
column = column.push(widget::text(error));
|
column = column.push(widget::text(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -828,45 +825,7 @@ impl App {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (_output, surface_id) in self.surface_ids.iter() {
|
self.common.update_wallpapers(&user_data);
|
||||||
if self.surface_images.contains_key(surface_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(output_name) = self.surface_names.get(surface_id) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
log::info!("updating wallpaper for {:?}", output_name);
|
|
||||||
|
|
||||||
for (wallpaper_output_name, wallpaper_source) in user_data.bg_state.wallpapers.iter() {
|
|
||||||
if wallpaper_output_name == output_name {
|
|
||||||
match wallpaper_source {
|
|
||||||
BgSource::Path(path) => {
|
|
||||||
match user_data.bg_path_data.get(path) {
|
|
||||||
Some(bytes) => {
|
|
||||||
let image = widget::image::Handle::from_bytes(bytes.clone());
|
|
||||||
self.surface_images.insert(*surface_id, image);
|
|
||||||
//TODO: what to do about duplicates?
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::warn!(
|
|
||||||
"output {}: failed to find wallpaper data for source {:?}",
|
|
||||||
output_name,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
BgSource::Color(color) => {
|
|
||||||
//TODO: support color sources
|
|
||||||
log::warn!("output {}: unsupported source {:?}", output_name, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// From cosmic-applet-input-sources
|
// From cosmic-applet-input-sources
|
||||||
if let Some(keyboard_layouts) = &self.flags.layouts_opt {
|
if let Some(keyboard_layouts) = &self.flags.layouts_opt {
|
||||||
|
|
@ -945,22 +904,19 @@ impl cosmic::Application for App {
|
||||||
const APP_ID: &'static str = "com.system76.CosmicGreeter";
|
const APP_ID: &'static str = "com.system76.CosmicGreeter";
|
||||||
|
|
||||||
fn core(&self) -> &Core {
|
fn core(&self) -> &Core {
|
||||||
&self.core
|
&self.common.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core_mut(&mut self) -> &mut Core {
|
fn core_mut(&mut self) -> &mut Core {
|
||||||
&mut self.core
|
&mut self.common.core
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the application, and optionally emits command on initialize.
|
/// Creates the application, and optionally emits command on initialize.
|
||||||
fn init(mut core: Core, flags: Self::Flags) -> (Self, Task<Message>) {
|
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Message>) {
|
||||||
core.window.show_window_menu = false;
|
let (mut common, common_task) = Common::init(core);
|
||||||
core.window.show_headerbar = false;
|
common.on_output_event = Some(Box::new(|output_event, output| {
|
||||||
// XXX must be false or define custom style to have transparent bg
|
Message::OutputEvent(output_event, output)
|
||||||
core.window.sharp_corners = false;
|
}));
|
||||||
core.window.show_maximize = false;
|
|
||||||
core.window.show_minimize = false;
|
|
||||||
core.window.use_template = false;
|
|
||||||
|
|
||||||
//TODO: use full_name?
|
//TODO: use full_name?
|
||||||
let mut usernames: Vec<_> = flags
|
let mut usernames: Vec<_> = flags
|
||||||
|
|
@ -994,42 +950,28 @@ impl cosmic::Application for App {
|
||||||
let selected_username = NameIndexPair { username, data_idx };
|
let selected_username = NameIndexPair { username, data_idx };
|
||||||
|
|
||||||
let app = App {
|
let app = App {
|
||||||
core,
|
common,
|
||||||
flags,
|
flags,
|
||||||
greetd_sender: None,
|
greetd_sender: None,
|
||||||
surface_ids: HashMap::new(),
|
|
||||||
active_surface_id_opt: None,
|
|
||||||
surface_images: HashMap::new(),
|
|
||||||
surface_names: HashMap::new(),
|
|
||||||
text_input_ids: HashMap::new(),
|
|
||||||
network_icon_opt: None,
|
|
||||||
power_info_opt: None,
|
|
||||||
socket_state: SocketState::Pending,
|
socket_state: SocketState::Pending,
|
||||||
usernames,
|
usernames,
|
||||||
selected_username,
|
selected_username,
|
||||||
prompt_opt: None,
|
|
||||||
session_names,
|
session_names,
|
||||||
selected_session,
|
selected_session,
|
||||||
active_layouts: Vec::new(),
|
active_layouts: Vec::new(),
|
||||||
error_opt: None,
|
|
||||||
dialog_page_opt: None,
|
dialog_page_opt: None,
|
||||||
dropdown_opt: None,
|
dropdown_opt: None,
|
||||||
window_size: HashMap::new(),
|
|
||||||
heartbeat_handle: None,
|
heartbeat_handle: None,
|
||||||
time: crate::time::Time::new(),
|
|
||||||
};
|
};
|
||||||
(
|
(app, common_task)
|
||||||
app,
|
|
||||||
Task::batch(vec![
|
|
||||||
crate::time::tick().map(|_| cosmic::Action::App(Message::Tick)),
|
|
||||||
crate::time::tz_updates().map(|tz| cosmic::Action::App(Message::Tz(tz))),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Self::Message) -> Task<Message> {
|
fn update(&mut self, message: Self::Message) -> Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
|
Message::Common(common_message) => {
|
||||||
|
return self.common.update(common_message);
|
||||||
|
}
|
||||||
Message::OutputEvent(output_event, output) => {
|
Message::OutputEvent(output_event, output) => {
|
||||||
match output_event {
|
match output_event {
|
||||||
OutputEvent::Created(output_info_opt) => {
|
OutputEvent::Created(output_info_opt) => {
|
||||||
|
|
@ -1038,7 +980,7 @@ impl cosmic::Application for App {
|
||||||
let surface_id = SurfaceId::unique();
|
let surface_id = SurfaceId::unique();
|
||||||
let subsurface_id = SurfaceId::unique();
|
let subsurface_id = SurfaceId::unique();
|
||||||
|
|
||||||
match self.surface_ids.insert(output.clone(), surface_id) {
|
match self.common.surface_ids.insert(output.clone(), surface_id) {
|
||||||
Some(old_surface_id) => {
|
Some(old_surface_id) => {
|
||||||
//TODO: remove old surface?
|
//TODO: remove old surface?
|
||||||
log::warn!(
|
log::warn!(
|
||||||
|
|
@ -1059,13 +1001,17 @@ impl cosmic::Application for App {
|
||||||
match output_info_opt {
|
match output_info_opt {
|
||||||
Some(output_info) => match output_info.name {
|
Some(output_info) => match output_info.name {
|
||||||
Some(output_name) => {
|
Some(output_name) => {
|
||||||
self.surface_names.insert(surface_id, output_name.clone());
|
self.common
|
||||||
self.surface_names
|
.surface_names
|
||||||
|
.insert(surface_id, output_name.clone());
|
||||||
|
self.common
|
||||||
|
.surface_names
|
||||||
.insert(subsurface_id, output_name.clone());
|
.insert(subsurface_id, output_name.clone());
|
||||||
self.surface_images.remove(&surface_id);
|
self.common.surface_images.remove(&surface_id);
|
||||||
let text_input_id =
|
let text_input_id =
|
||||||
widget::Id::new(format!("input-{output_name}",));
|
widget::Id::new(format!("input-{output_name}",));
|
||||||
self.text_input_ids
|
self.common
|
||||||
|
.text_input_ids
|
||||||
.insert(output_name.clone(), text_input_id.clone());
|
.insert(output_name.clone(), text_input_id.clone());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -1091,7 +1037,7 @@ impl cosmic::Application for App {
|
||||||
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32 - 32.),
|
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32 - 32.),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.window_size.insert(
|
self.common.window_size.insert(
|
||||||
surface_id,
|
surface_id,
|
||||||
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32),
|
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32),
|
||||||
);
|
);
|
||||||
|
|
@ -1139,12 +1085,12 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
OutputEvent::Removed => {
|
OutputEvent::Removed => {
|
||||||
log::info!("output {}: removed", output.id());
|
log::info!("output {}: removed", output.id());
|
||||||
match self.surface_ids.remove(&output) {
|
match self.common.surface_ids.remove(&output) {
|
||||||
Some(surface_id) => {
|
Some(surface_id) => {
|
||||||
self.surface_images.remove(&surface_id);
|
self.common.surface_images.remove(&surface_id);
|
||||||
self.window_size.remove(&surface_id);
|
self.common.window_size.remove(&surface_id);
|
||||||
if let Some(n) = self.surface_names.remove(&surface_id) {
|
if let Some(n) = self.common.surface_names.remove(&surface_id) {
|
||||||
self.text_input_ids.remove(&n);
|
self.common.text_input_ids.remove(&n);
|
||||||
}
|
}
|
||||||
return destroy_layer_surface(surface_id);
|
return destroy_layer_surface(surface_id);
|
||||||
}
|
}
|
||||||
|
|
@ -1170,25 +1116,21 @@ impl cosmic::Application for App {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::NetworkIcon(network_icon_opt) => {
|
|
||||||
self.network_icon_opt = network_icon_opt;
|
|
||||||
}
|
|
||||||
Message::PowerInfo(power_info_opt) => {
|
|
||||||
self.power_info_opt = power_info_opt;
|
|
||||||
}
|
|
||||||
Message::Prompt(prompt, secret, value_opt) => {
|
Message::Prompt(prompt, secret, value_opt) => {
|
||||||
let value_was_some = self
|
let value_was_some = self
|
||||||
|
.common
|
||||||
.prompt_opt
|
.prompt_opt
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(false, |(_, _, x)| x.is_some());
|
.map_or(false, |(_, _, x)| x.is_some());
|
||||||
let value_is_some = value_opt.is_some();
|
let value_is_some = value_opt.is_some();
|
||||||
self.prompt_opt = Some((prompt, secret, value_opt));
|
self.common.prompt_opt = Some((prompt, secret, value_opt));
|
||||||
if value_is_some && !value_was_some {
|
if value_is_some && !value_was_some {
|
||||||
if let Some(surface_id) = self.active_surface_id_opt {
|
if let Some(surface_id) = self.common.active_surface_id_opt {
|
||||||
if let Some(text_input_id) = self
|
if let Some(text_input_id) = self
|
||||||
|
.common
|
||||||
.surface_names
|
.surface_names
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
.and_then(|id| self.common.text_input_ids.get(id))
|
||||||
{
|
{
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
return widget::text_input::focus(text_input_id.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -1208,7 +1150,7 @@ impl cosmic::Application for App {
|
||||||
if username != self.selected_username.username {
|
if username != self.selected_username.username {
|
||||||
let data_idx = Self::user_data_index(&self.flags.user_datas, &username);
|
let data_idx = Self::user_data_index(&self.flags.user_datas, &username);
|
||||||
self.selected_username = NameIndexPair { username, data_idx };
|
self.selected_username = NameIndexPair { username, data_idx };
|
||||||
self.surface_images.clear();
|
self.common.surface_images.clear();
|
||||||
if let Some(session) = data_idx.and_then(|i| {
|
if let Some(session) = data_idx.and_then(|i| {
|
||||||
self.flags
|
self.flags
|
||||||
.user_datas
|
.user_datas
|
||||||
|
|
@ -1227,7 +1169,7 @@ impl cosmic::Application for App {
|
||||||
};
|
};
|
||||||
match &self.socket_state {
|
match &self.socket_state {
|
||||||
SocketState::Open => {
|
SocketState::Open => {
|
||||||
self.prompt_opt = None;
|
self.common.prompt_opt = None;
|
||||||
self.send_request(Request::CancelSession);
|
self.send_request(Request::CancelSession);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -1299,13 +1241,14 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Auth(response) => {
|
Message::Auth(response) => {
|
||||||
self.prompt_opt = None;
|
self.common.input.clear();
|
||||||
self.error_opt = None;
|
self.common.prompt_opt = None;
|
||||||
|
self.common.error_opt = None;
|
||||||
self.send_request(Request::PostAuthMessageResponse { response });
|
self.send_request(Request::PostAuthMessageResponse { response });
|
||||||
}
|
}
|
||||||
Message::Login => {
|
Message::Login => {
|
||||||
self.prompt_opt = None;
|
self.common.prompt_opt = None;
|
||||||
self.error_opt = None;
|
self.common.error_opt = None;
|
||||||
match self.flags.sessions.get(&self.selected_session).cloned() {
|
match self.flags.sessions.get(&self.selected_session).cloned() {
|
||||||
Some((cmd, env)) => {
|
Some((cmd, env)) => {
|
||||||
self.send_request(Request::StartSession { cmd, env });
|
self.send_request(Request::StartSession { cmd, env });
|
||||||
|
|
@ -1315,7 +1258,7 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Error(error) => {
|
Message::Error(error) => {
|
||||||
self.error_opt = Some(error);
|
self.common.error_opt = Some(error);
|
||||||
self.send_request(Request::CancelSession);
|
self.send_request(Request::CancelSession);
|
||||||
}
|
}
|
||||||
Message::Reconnect => {
|
Message::Reconnect => {
|
||||||
|
|
@ -1423,11 +1366,11 @@ impl cosmic::Application for App {
|
||||||
},
|
},
|
||||||
Message::Exit => {
|
Message::Exit => {
|
||||||
let mut commands = Vec::new();
|
let mut commands = Vec::new();
|
||||||
for (_output, surface_id) in self.surface_ids.drain() {
|
for (_output, surface_id) in self.common.surface_ids.drain() {
|
||||||
self.surface_images.remove(&surface_id);
|
self.common.surface_images.remove(&surface_id);
|
||||||
self.surface_names.remove(&surface_id);
|
self.common.surface_names.remove(&surface_id);
|
||||||
if let Some(n) = self.surface_names.remove(&surface_id) {
|
if let Some(n) = self.common.surface_names.remove(&surface_id) {
|
||||||
self.text_input_ids.remove(&n);
|
self.common.text_input_ids.remove(&n);
|
||||||
}
|
}
|
||||||
commands.push(destroy_layer_surface(surface_id));
|
commands.push(destroy_layer_surface(surface_id));
|
||||||
}
|
}
|
||||||
|
|
@ -1442,22 +1385,6 @@ impl cosmic::Application for App {
|
||||||
cosmic::app::Action::Surface(a),
|
cosmic::app::Action::Surface(a),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Message::Focus(surface_id) => {
|
|
||||||
self.active_surface_id_opt = Some(surface_id);
|
|
||||||
if let Some(text_input_id) = self
|
|
||||||
.surface_names
|
|
||||||
.get(&surface_id)
|
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
|
||||||
{
|
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message::Tick => {
|
|
||||||
self.time.tick();
|
|
||||||
}
|
|
||||||
Message::Tz(tz) => {
|
|
||||||
self.time.set_tz(tz);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -1470,6 +1397,7 @@ impl cosmic::Application for App {
|
||||||
/// Creates a view after each update.
|
/// Creates a view after each update.
|
||||||
fn view_window(&self, surface_id: SurfaceId) -> Element<Self::Message> {
|
fn view_window(&self, surface_id: SurfaceId) -> Element<Self::Message> {
|
||||||
let img = self
|
let img = self
|
||||||
|
.common
|
||||||
.surface_images
|
.surface_images
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.unwrap_or(&self.flags.fallback_background);
|
.unwrap_or(&self.flags.fallback_background);
|
||||||
|
|
@ -1481,33 +1409,9 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Self::Message> {
|
fn subscription(&self) -> Subscription<Self::Message> {
|
||||||
let mut subscriptions = vec![
|
Subscription::batch([
|
||||||
event::listen_with(|event, _, id| match event {
|
self.common.subscription().map(Message::from),
|
||||||
iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(
|
|
||||||
wayland_event,
|
|
||||||
)) => match wayland_event {
|
|
||||||
WaylandEvent::Output(output_event, output) => {
|
|
||||||
Some(Message::OutputEvent(output_event, output))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
iced::Event::Window(iced::window::Event::Focused) => Some(Message::Focus(id)),
|
|
||||||
_ => None,
|
|
||||||
}),
|
|
||||||
ipc::subscription(),
|
ipc::subscription(),
|
||||||
];
|
])
|
||||||
|
|
||||||
#[cfg(feature = "networkmanager")]
|
|
||||||
{
|
|
||||||
subscriptions.push(crate::networkmanager::subscription().map(Message::NetworkIcon));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "upower")]
|
|
||||||
{
|
|
||||||
subscriptions.push(crate::upower::subscription().map(Message::PowerInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
Subscription::batch(subscriptions)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
pub mod greeter;
|
pub mod greeter;
|
||||||
pub mod locker;
|
pub mod locker;
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
mod localize;
|
mod localize;
|
||||||
|
|
||||||
#[cfg(feature = "logind")]
|
#[cfg(feature = "logind")]
|
||||||
|
|
|
||||||
305
src/locker.rs
305
src/locker.rs
|
|
@ -10,10 +10,7 @@ use cosmic::{
|
||||||
Element, executor,
|
Element, executor,
|
||||||
iced::{
|
iced::{
|
||||||
self, Length, Subscription, alignment,
|
self, Length, Subscription, alignment,
|
||||||
event::{
|
event::wayland::{OutputEvent, SessionLockEvent},
|
||||||
self,
|
|
||||||
wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent},
|
|
||||||
},
|
|
||||||
futures::{self, SinkExt},
|
futures::{self, SinkExt},
|
||||||
platform_specific::shell::wayland::commands::session_lock::{
|
platform_specific::shell::wayland::commands::session_lock::{
|
||||||
destroy_lock_surface, get_lock_surface, lock, unlock,
|
destroy_lock_surface, get_lock_surface, lock, unlock,
|
||||||
|
|
@ -23,11 +20,10 @@ use cosmic::{
|
||||||
widget,
|
widget,
|
||||||
};
|
};
|
||||||
use cosmic_config::CosmicConfigEntry;
|
use cosmic_config::CosmicConfigEntry;
|
||||||
use cosmic_greeter_daemon::{BgSource, TimeAppletConfig, UserData};
|
use cosmic_greeter_daemon::{TimeAppletConfig, UserData};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
collections::HashMap,
|
|
||||||
env,
|
env,
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
fs,
|
fs,
|
||||||
|
|
@ -39,6 +35,8 @@ use std::{
|
||||||
use tokio::{sync::mpsc, task};
|
use tokio::{sync::mpsc, task};
|
||||||
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
||||||
|
|
||||||
|
use crate::common::{self, Common};
|
||||||
|
|
||||||
fn lockfile_opt() -> Option<PathBuf> {
|
fn lockfile_opt() -> Option<PathBuf> {
|
||||||
let runtime_dir = dirs::runtime_dir()?;
|
let runtime_dir = dirs::runtime_dir()?;
|
||||||
let session_id = env::var("XDG_SESSION_ID").ok()?;
|
let session_id = env::var("XDG_SESSION_ID").ok()?;
|
||||||
|
|
@ -191,26 +189,28 @@ pub struct Flags {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
None,
|
None,
|
||||||
|
Common(common::Message),
|
||||||
OutputEvent(OutputEvent, WlOutput),
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
SessionLockEvent(SessionLockEvent),
|
SessionLockEvent(SessionLockEvent),
|
||||||
Channel(mpsc::Sender<String>),
|
Channel(mpsc::Sender<String>),
|
||||||
BackgroundState(cosmic_bg_config::state::State),
|
BackgroundState(cosmic_bg_config::state::State),
|
||||||
TimeAppletConfig(TimeAppletConfig),
|
TimeAppletConfig(TimeAppletConfig),
|
||||||
Focus(SurfaceId),
|
|
||||||
Inhibit(Arc<OwnedFd>),
|
Inhibit(Arc<OwnedFd>),
|
||||||
NetworkIcon(Option<&'static str>),
|
|
||||||
PowerInfo(Option<(String, f64)>),
|
|
||||||
Prompt(String, bool, Option<String>),
|
Prompt(String, bool, Option<String>),
|
||||||
Submit(String),
|
Submit(String),
|
||||||
Surface(surface::Action),
|
Surface(surface::Action),
|
||||||
Suspend,
|
Suspend,
|
||||||
Error(String),
|
Error(String),
|
||||||
Lock,
|
Lock,
|
||||||
Tick,
|
|
||||||
Tz(chrono_tz::Tz),
|
|
||||||
Unlock,
|
Unlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<common::Message> for Message {
|
||||||
|
fn from(message: common::Message) -> Self {
|
||||||
|
Self::Common(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum State {
|
enum State {
|
||||||
Locking,
|
Locking,
|
||||||
|
|
@ -233,29 +233,17 @@ impl Drop for State {
|
||||||
|
|
||||||
/// The [`App`] stores application-specific state.
|
/// The [`App`] stores application-specific state.
|
||||||
pub struct App {
|
pub struct App {
|
||||||
core: Core,
|
common: Common<Message>,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
state: State,
|
state: State,
|
||||||
output_names: HashMap<WlOutput, String>,
|
|
||||||
surface_ids: HashMap<WlOutput, SurfaceId>,
|
|
||||||
subsurface_rects: HashMap<WlOutput, Rectangle>,
|
|
||||||
active_surface_id_opt: Option<SurfaceId>,
|
|
||||||
surface_images: HashMap<SurfaceId, widget::image::Handle>,
|
|
||||||
surface_names: HashMap<SurfaceId, String>,
|
|
||||||
text_input_ids: HashMap<String, widget::Id>,
|
|
||||||
inhibit_opt: Option<Arc<OwnedFd>>,
|
inhibit_opt: Option<Arc<OwnedFd>>,
|
||||||
network_icon_opt: Option<&'static str>,
|
|
||||||
power_info_opt: Option<(String, f64)>,
|
|
||||||
value_tx_opt: Option<mpsc::Sender<String>>,
|
value_tx_opt: Option<mpsc::Sender<String>>,
|
||||||
prompt_opt: Option<(String, bool, Option<String>)>,
|
|
||||||
error_opt: Option<String>,
|
|
||||||
time: crate::time::Time,
|
|
||||||
window_size: HashMap<SurfaceId, Size>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn menu(&self, surface_id: SurfaceId) -> Element<Message> {
|
fn menu(&self, surface_id: SurfaceId) -> Element<Message> {
|
||||||
let window_width = self
|
let window_width = self
|
||||||
|
.common
|
||||||
.window_size
|
.window_size
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.map(|s| s.width)
|
.map(|s| s.width)
|
||||||
|
|
@ -267,15 +255,15 @@ impl App {
|
||||||
};
|
};
|
||||||
let left_element = {
|
let left_element = {
|
||||||
let military_time = self.flags.user_data.time_applet_config.military_time;
|
let military_time = self.flags.user_data.time_applet_config.military_time;
|
||||||
let date_time_column = self.time.date_time_widget(military_time);
|
let date_time_column = self.common.time.date_time_widget(military_time);
|
||||||
|
|
||||||
let mut status_row = widget::row::with_capacity(2).padding(16.0).spacing(12.0);
|
let mut status_row = widget::row::with_capacity(2).padding(16.0).spacing(12.0);
|
||||||
|
|
||||||
if let Some(network_icon) = self.network_icon_opt {
|
if let Some(network_icon) = self.common.network_icon_opt {
|
||||||
status_row = status_row.push(widget::icon::from_name(network_icon));
|
status_row = status_row.push(widget::icon::from_name(network_icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((power_icon, power_percent)) = &self.power_info_opt {
|
if let Some((power_icon, power_percent)) = &self.common.power_info_opt {
|
||||||
status_row = status_row.push(iced::widget::row![
|
status_row = status_row.push(iced::widget::row![
|
||||||
widget::icon::from_name(power_icon.clone()),
|
widget::icon::from_name(power_icon.clone()),
|
||||||
widget::text(format!("{:.0}%", power_percent)),
|
widget::text(format!("{:.0}%", power_percent)),
|
||||||
|
|
@ -339,19 +327,20 @@ impl App {
|
||||||
.align_x(alignment::Horizontal::Center),
|
.align_x(alignment::Horizontal::Center),
|
||||||
);
|
);
|
||||||
|
|
||||||
match &self.prompt_opt {
|
match &self.common.prompt_opt {
|
||||||
Some((prompt, secret, value_opt)) => match value_opt {
|
Some((prompt, secret, value_opt)) => match value_opt {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let text_input_id = self
|
let text_input_id = self
|
||||||
|
.common
|
||||||
.surface_names
|
.surface_names
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
.and_then(|id| self.common.text_input_ids.get(id))
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| cosmic::widget::Id::new("text_input"));
|
.unwrap_or_else(|| cosmic::widget::Id::new("text_input"));
|
||||||
|
|
||||||
let mut text_input = widget::secure_input(
|
let mut text_input = widget::secure_input(
|
||||||
prompt.clone(),
|
prompt.clone(),
|
||||||
"",
|
&self.common.input,
|
||||||
Some(Message::Prompt(
|
Some(Message::Prompt(
|
||||||
prompt.clone(),
|
prompt.clone(),
|
||||||
!*secret,
|
!*secret,
|
||||||
|
|
@ -360,7 +349,7 @@ impl App {
|
||||||
*secret,
|
*secret,
|
||||||
)
|
)
|
||||||
.id(text_input_id)
|
.id(text_input_id)
|
||||||
.manage_value(true)
|
.on_input(|input| common::Message::Input(input).into())
|
||||||
.on_submit(Message::Submit);
|
.on_submit(Message::Submit);
|
||||||
|
|
||||||
if *secret {
|
if *secret {
|
||||||
|
|
@ -376,7 +365,7 @@ impl App {
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(error) = &self.error_opt {
|
if let Some(error) = &self.common.error_opt {
|
||||||
column = column.push(widget::text(error));
|
column = column.push(widget::text(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -414,51 +403,6 @@ impl App {
|
||||||
.class(cosmic::theme::Container::Transparent)
|
.class(cosmic::theme::Container::Transparent)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: cache wallpapers by source?
|
|
||||||
fn update_wallpapers(&mut self) {
|
|
||||||
let user_data = &self.flags.user_data;
|
|
||||||
|
|
||||||
for (_output, surface_id) in self.surface_ids.iter() {
|
|
||||||
if self.surface_images.contains_key(surface_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(output_name) = self.surface_names.get(surface_id) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
log::info!("updating wallpaper for {:?}", output_name);
|
|
||||||
|
|
||||||
for (wallpaper_output_name, wallpaper_source) in user_data.bg_state.wallpapers.iter() {
|
|
||||||
if wallpaper_output_name == output_name {
|
|
||||||
match wallpaper_source {
|
|
||||||
BgSource::Path(path) => {
|
|
||||||
match user_data.bg_path_data.get(path) {
|
|
||||||
Some(bytes) => {
|
|
||||||
let image = widget::image::Handle::from_bytes(bytes.clone());
|
|
||||||
self.surface_images.insert(*surface_id, image);
|
|
||||||
//TODO: what to do about duplicates?
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::warn!(
|
|
||||||
"output {}: failed to find wallpaper data for source {:?}",
|
|
||||||
output_name,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
BgSource::Color(color) => {
|
|
||||||
//TODO: support color sources
|
|
||||||
log::warn!("output {}: unsupported source {:?}", output_name, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement [`cosmic::Application`] to integrate with COSMIC.
|
/// Implement [`cosmic::Application`] to integrate with COSMIC.
|
||||||
|
|
@ -476,22 +420,20 @@ impl cosmic::Application for App {
|
||||||
const APP_ID: &'static str = "com.system76.CosmicGreeter";
|
const APP_ID: &'static str = "com.system76.CosmicGreeter";
|
||||||
|
|
||||||
fn core(&self) -> &Core {
|
fn core(&self) -> &Core {
|
||||||
&self.core
|
&self.common.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core_mut(&mut self) -> &mut Core {
|
fn core_mut(&mut self) -> &mut Core {
|
||||||
&mut self.core
|
&mut self.common.core
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the application, and optionally emits command on initialize.
|
/// Creates the application, and optionally emits command on initialize.
|
||||||
fn init(mut core: Core, flags: Self::Flags) -> (Self, Task<Self::Message>) {
|
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Self::Message>) {
|
||||||
core.window.show_window_menu = false;
|
let (mut common, common_task) = Common::init(core);
|
||||||
core.window.show_headerbar = false;
|
common.on_output_event = Some(Box::new(|output_event, output| {
|
||||||
// XXX must be false or define custom style to have transparent bg
|
Message::OutputEvent(output_event, output)
|
||||||
core.window.sharp_corners = false;
|
}));
|
||||||
core.window.show_maximize = false;
|
common.on_session_lock_event = Some(Box::new(|evt| Message::SessionLockEvent(evt)));
|
||||||
core.window.show_minimize = false;
|
|
||||||
core.window.use_template = false;
|
|
||||||
|
|
||||||
let already_locked = match flags.lockfile_opt {
|
let already_locked = match flags.lockfile_opt {
|
||||||
Some(ref lockfile) => lockfile.exists(),
|
Some(ref lockfile) => lockfile.exists(),
|
||||||
|
|
@ -499,24 +441,11 @@ impl cosmic::Application for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
core,
|
common,
|
||||||
flags,
|
flags,
|
||||||
state: State::Unlocked,
|
state: State::Unlocked,
|
||||||
surface_ids: HashMap::new(),
|
|
||||||
active_surface_id_opt: None,
|
|
||||||
output_names: HashMap::new(),
|
|
||||||
surface_images: HashMap::new(),
|
|
||||||
surface_names: HashMap::new(),
|
|
||||||
text_input_ids: HashMap::new(),
|
|
||||||
subsurface_rects: HashMap::new(),
|
|
||||||
inhibit_opt: None,
|
inhibit_opt: None,
|
||||||
network_icon_opt: None,
|
|
||||||
power_info_opt: None,
|
|
||||||
value_tx_opt: None,
|
value_tx_opt: None,
|
||||||
prompt_opt: None,
|
|
||||||
error_opt: None,
|
|
||||||
time: crate::time::Time::new(),
|
|
||||||
window_size: HashMap::new(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let task = if cfg!(feature = "logind") {
|
let task = if cfg!(feature = "logind") {
|
||||||
|
|
@ -536,20 +465,16 @@ impl cosmic::Application for App {
|
||||||
lock()
|
lock()
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(app, Task::batch([task, common_task]))
|
||||||
app,
|
|
||||||
Task::batch(vec![
|
|
||||||
task,
|
|
||||||
crate::time::tick().map(|_| cosmic::Action::App(Message::Tick)),
|
|
||||||
crate::time::tz_updates().map(|tz| cosmic::Action::App(Message::Tz(tz))),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::None => {}
|
Message::None => {}
|
||||||
|
Message::Common(common_message) => {
|
||||||
|
return self.common.update(common_message);
|
||||||
|
}
|
||||||
Message::OutputEvent(output_event, output) => {
|
Message::OutputEvent(output_event, output) => {
|
||||||
match output_event {
|
match output_event {
|
||||||
OutputEvent::Created(output_info_opt) => {
|
OutputEvent::Created(output_info_opt) => {
|
||||||
|
|
@ -559,7 +484,7 @@ impl cosmic::Application for App {
|
||||||
let subsurface_id = SurfaceId::unique();
|
let subsurface_id = SurfaceId::unique();
|
||||||
|
|
||||||
if let Some(old_surface_id) =
|
if let Some(old_surface_id) =
|
||||||
self.surface_ids.insert(output.clone(), surface_id)
|
self.common.surface_ids.insert(output.clone(), surface_id)
|
||||||
{
|
{
|
||||||
//TODO: remove old surface?
|
//TODO: remove old surface?
|
||||||
log::warn!(
|
log::warn!(
|
||||||
|
|
@ -580,16 +505,21 @@ impl cosmic::Application for App {
|
||||||
match output_info_opt {
|
match output_info_opt {
|
||||||
Some(output_info) => match output_info.name {
|
Some(output_info) => match output_info.name {
|
||||||
Some(output_name) => {
|
Some(output_name) => {
|
||||||
self.output_names
|
self.common
|
||||||
|
.output_names
|
||||||
.insert(output.clone(), output_name.clone());
|
.insert(output.clone(), output_name.clone());
|
||||||
self.surface_names.insert(surface_id, output_name.clone());
|
self.common
|
||||||
self.surface_names
|
.surface_names
|
||||||
|
.insert(surface_id, output_name.clone());
|
||||||
|
self.common
|
||||||
|
.surface_names
|
||||||
.insert(subsurface_id, output_name.clone());
|
.insert(subsurface_id, output_name.clone());
|
||||||
self.surface_images.remove(&surface_id);
|
self.common.surface_images.remove(&surface_id);
|
||||||
self.update_wallpapers();
|
self.common.update_wallpapers(&self.flags.user_data);
|
||||||
let text_input_id =
|
let text_input_id =
|
||||||
widget::Id::new(format!("input-{output_name}",));
|
widget::Id::new(format!("input-{output_name}",));
|
||||||
self.text_input_ids
|
self.common
|
||||||
|
.text_input_ids
|
||||||
.insert(output_name.clone(), text_input_id.clone());
|
.insert(output_name.clone(), text_input_id.clone());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -615,12 +545,13 @@ impl cosmic::Application for App {
|
||||||
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32 - 32.),
|
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32 - 32.),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.window_size.insert(
|
self.common.window_size.insert(
|
||||||
surface_id,
|
surface_id,
|
||||||
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32),
|
Size::new(unwrapped_size.0 as f32, unwrapped_size.1 as f32),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.subsurface_rects
|
self.common
|
||||||
|
.subsurface_rects
|
||||||
.insert(output.clone(), Rectangle::new(loc, sub_size));
|
.insert(output.clone(), Rectangle::new(loc, sub_size));
|
||||||
|
|
||||||
let msg = cosmic::surface::action::subsurface(
|
let msg = cosmic::surface::action::subsurface(
|
||||||
|
|
@ -651,13 +582,13 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
OutputEvent::Removed => {
|
OutputEvent::Removed => {
|
||||||
log::info!("output {}: removed", output.id());
|
log::info!("output {}: removed", output.id());
|
||||||
match self.surface_ids.remove(&output) {
|
match self.common.surface_ids.remove(&output) {
|
||||||
Some(surface_id) => {
|
Some(surface_id) => {
|
||||||
self.surface_images.remove(&surface_id);
|
self.common.surface_images.remove(&surface_id);
|
||||||
self.surface_names.remove(&surface_id);
|
self.common.surface_names.remove(&surface_id);
|
||||||
self.window_size.remove(&surface_id);
|
self.common.window_size.remove(&surface_id);
|
||||||
if let Some(n) = self.surface_names.remove(&surface_id) {
|
if let Some(n) = self.common.surface_names.remove(&surface_id) {
|
||||||
self.text_input_ids.remove(&n);
|
self.common.text_input_ids.remove(&n);
|
||||||
}
|
}
|
||||||
if matches!(self.state, State::Locked { .. }) {
|
if matches!(self.state, State::Locked { .. }) {
|
||||||
return destroy_lock_surface(surface_id);
|
return destroy_lock_surface(surface_id);
|
||||||
|
|
@ -685,7 +616,8 @@ impl cosmic::Application for App {
|
||||||
} else {
|
} else {
|
||||||
(Point::ORIGIN, Size::new(1920., 1080.))
|
(Point::ORIGIN, Size::new(1920., 1080.))
|
||||||
};
|
};
|
||||||
self.subsurface_rects
|
self.common
|
||||||
|
.subsurface_rects
|
||||||
.insert(output.clone(), Rectangle::new(loc, sub_size));
|
.insert(output.clone(), Rectangle::new(loc, sub_size));
|
||||||
|
|
||||||
log::info!("output {}: info update", output.id());
|
log::info!("output {}: info update", output.id());
|
||||||
|
|
@ -768,7 +700,7 @@ impl cosmic::Application for App {
|
||||||
)
|
)
|
||||||
.abortable();
|
.abortable();
|
||||||
|
|
||||||
let mut commands = Vec::with_capacity(self.surface_ids.len() + 1);
|
let mut commands = Vec::with_capacity(self.common.surface_ids.len() + 1);
|
||||||
commands.push(locked_task);
|
commands.push(locked_task);
|
||||||
|
|
||||||
self.state = State::Locked {
|
self.state = State::Locked {
|
||||||
|
|
@ -779,19 +711,22 @@ impl cosmic::Application for App {
|
||||||
self.inhibit_opt = None;
|
self.inhibit_opt = None;
|
||||||
// Create lock surfaces
|
// Create lock surfaces
|
||||||
|
|
||||||
for (output, surface_id) in self.surface_ids.iter() {
|
for (output, surface_id) in self.common.surface_ids.iter() {
|
||||||
commands.push(get_lock_surface(*surface_id, output.clone()));
|
commands.push(get_lock_surface(*surface_id, output.clone()));
|
||||||
|
|
||||||
if let Some((rect, name)) = self
|
if let Some((rect, name)) = self
|
||||||
|
.common
|
||||||
.subsurface_rects
|
.subsurface_rects
|
||||||
.get(output)
|
.get(output)
|
||||||
.copied()
|
.copied()
|
||||||
.zip(self.output_names.get(output))
|
.zip(self.common.output_names.get(output))
|
||||||
{
|
{
|
||||||
let subsurface_id = SurfaceId::unique();
|
let subsurface_id = SurfaceId::unique();
|
||||||
let surface_id = *surface_id;
|
let surface_id = *surface_id;
|
||||||
self.surface_names.insert(surface_id, name.clone());
|
self.common.surface_names.insert(surface_id, name.clone());
|
||||||
self.surface_names.insert(subsurface_id, name.clone());
|
self.common
|
||||||
|
.surface_names
|
||||||
|
.insert(subsurface_id, name.clone());
|
||||||
let msg = cosmic::surface::action::subsurface(
|
let msg = cosmic::surface::action::subsurface(
|
||||||
move |_: &mut App| SctkSubsurfaceSettings {
|
move |_: &mut App| SctkSubsurfaceSettings {
|
||||||
parent: surface_id,
|
parent: surface_id,
|
||||||
|
|
@ -822,9 +757,9 @@ impl cosmic::Application for App {
|
||||||
self.state = State::Unlocked;
|
self.state = State::Unlocked;
|
||||||
|
|
||||||
let mut commands = Vec::new();
|
let mut commands = Vec::new();
|
||||||
for (_output, surface_id) in self.surface_ids.iter() {
|
for (_output, surface_id) in self.common.surface_ids.iter() {
|
||||||
self.surface_names.remove(surface_id);
|
self.common.surface_names.remove(surface_id);
|
||||||
self.window_size.remove(surface_id);
|
self.common.window_size.remove(surface_id);
|
||||||
commands.push(destroy_lock_surface(*surface_id));
|
commands.push(destroy_lock_surface(*surface_id));
|
||||||
}
|
}
|
||||||
if cfg!(feature = "logind") {
|
if cfg!(feature = "logind") {
|
||||||
|
|
@ -843,11 +778,10 @@ impl cosmic::Application for App {
|
||||||
self.value_tx_opt = Some(value_tx);
|
self.value_tx_opt = Some(value_tx);
|
||||||
}
|
}
|
||||||
Message::BackgroundState(bg_state) => {
|
Message::BackgroundState(bg_state) => {
|
||||||
eprintln!("{:#?}", bg_state);
|
|
||||||
self.flags.user_data.bg_state = bg_state;
|
self.flags.user_data.bg_state = bg_state;
|
||||||
self.flags.user_data.load_wallpapers_as_user();
|
self.flags.user_data.load_wallpapers_as_user();
|
||||||
self.surface_images.clear();
|
self.common.surface_images.clear();
|
||||||
self.update_wallpapers();
|
self.common.update_wallpapers(&self.flags.user_data);
|
||||||
}
|
}
|
||||||
Message::TimeAppletConfig(config) => {
|
Message::TimeAppletConfig(config) => {
|
||||||
self.flags.user_data.time_applet_config = config;
|
self.flags.user_data.time_applet_config = config;
|
||||||
|
|
@ -855,51 +789,37 @@ impl cosmic::Application for App {
|
||||||
Message::Inhibit(inhibit) => {
|
Message::Inhibit(inhibit) => {
|
||||||
self.inhibit_opt = Some(inhibit);
|
self.inhibit_opt = Some(inhibit);
|
||||||
}
|
}
|
||||||
Message::NetworkIcon(network_icon_opt) => {
|
|
||||||
self.network_icon_opt = network_icon_opt;
|
|
||||||
}
|
|
||||||
Message::PowerInfo(power_info_opt) => {
|
|
||||||
self.power_info_opt = power_info_opt;
|
|
||||||
}
|
|
||||||
Message::Focus(surface_id) => {
|
|
||||||
self.active_surface_id_opt = Some(surface_id);
|
|
||||||
self.active_surface_id_opt = Some(surface_id);
|
|
||||||
if let Some(text_input_id) = self
|
|
||||||
.surface_names
|
|
||||||
.get(&surface_id)
|
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
|
||||||
{
|
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message::Prompt(prompt, secret, value_opt) => {
|
Message::Prompt(prompt, secret, value_opt) => {
|
||||||
let prompt_was_none = self.prompt_opt.is_none();
|
let prompt_was_none = self.common.prompt_opt.is_none();
|
||||||
self.prompt_opt = Some((prompt, secret, value_opt));
|
self.common.prompt_opt = Some((prompt, secret, value_opt));
|
||||||
if prompt_was_none {
|
if prompt_was_none {
|
||||||
if let Some(surface_id) = self.active_surface_id_opt {
|
if let Some(surface_id) = self.common.active_surface_id_opt {
|
||||||
if let Some(text_input_id) = self
|
if let Some(text_input_id) = self
|
||||||
|
.common
|
||||||
.surface_names
|
.surface_names
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.and_then(|id| self.text_input_ids.get(id))
|
.and_then(|id| self.common.text_input_ids.get(id))
|
||||||
{
|
{
|
||||||
log::error!("focus surface found id {:?}", text_input_id);
|
log::info!("focus surface found id {:?}", text_input_id);
|
||||||
|
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
return widget::text_input::focus(text_input_id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Submit(value) => match self.value_tx_opt.take() {
|
Message::Submit(value) => {
|
||||||
Some(value_tx) => {
|
self.common.input.clear();
|
||||||
// Clear errors
|
match self.value_tx_opt.take() {
|
||||||
self.error_opt = None;
|
Some(value_tx) => {
|
||||||
return cosmic::task::future(async move {
|
// Clear errors
|
||||||
value_tx.send(value).await.unwrap();
|
self.common.error_opt = None;
|
||||||
Message::Channel(value_tx)
|
return cosmic::task::future(async move {
|
||||||
});
|
value_tx.send(value).await.unwrap();
|
||||||
|
Message::Channel(value_tx)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => log::warn!("tried to submit when value_tx_opt not set"),
|
||||||
}
|
}
|
||||||
None => log::warn!("tried to submit when value_tx_opt not set"),
|
}
|
||||||
},
|
|
||||||
Message::Suspend => {
|
Message::Suspend => {
|
||||||
#[cfg(feature = "logind")]
|
#[cfg(feature = "logind")]
|
||||||
return cosmic::Task::future(async move { crate::logind::suspend().await.err() })
|
return cosmic::Task::future(async move { crate::logind::suspend().await.err() })
|
||||||
|
|
@ -909,14 +829,14 @@ impl cosmic::Application for App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Message::Error(error) => {
|
Message::Error(error) => {
|
||||||
self.error_opt = Some(error);
|
self.common.error_opt = Some(error);
|
||||||
}
|
}
|
||||||
Message::Lock => match self.state {
|
Message::Lock => match self.state {
|
||||||
State::Unlocked => {
|
State::Unlocked => {
|
||||||
log::info!("session locking");
|
log::info!("session locking");
|
||||||
self.state = State::Locking;
|
self.state = State::Locking;
|
||||||
// Clear errors
|
// Clear errors
|
||||||
self.error_opt = None;
|
self.common.error_opt = None;
|
||||||
// Clear value_tx
|
// Clear value_tx
|
||||||
self.value_tx_opt = None;
|
self.value_tx_opt = None;
|
||||||
// Try to create lockfile when locking
|
// Try to create lockfile when locking
|
||||||
|
|
@ -941,7 +861,7 @@ impl cosmic::Application for App {
|
||||||
log::info!("sessing unlocking");
|
log::info!("sessing unlocking");
|
||||||
self.state = State::Unlocking;
|
self.state = State::Unlocking;
|
||||||
// Clear errors
|
// Clear errors
|
||||||
self.error_opt = None;
|
self.common.error_opt = None;
|
||||||
// Clear value_tx
|
// Clear value_tx
|
||||||
self.value_tx_opt = None;
|
self.value_tx_opt = None;
|
||||||
// Try to delete lockfile when unlocking
|
// Try to delete lockfile when unlocking
|
||||||
|
|
@ -952,11 +872,11 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy lock surfaces
|
// Destroy lock surfaces
|
||||||
let mut commands = Vec::with_capacity(self.surface_ids.len() + 1);
|
let mut commands = Vec::with_capacity(self.common.surface_ids.len() + 1);
|
||||||
|
|
||||||
for (_output, surface_id) in self.surface_ids.iter() {
|
for (_output, surface_id) in self.common.surface_ids.iter() {
|
||||||
self.surface_names.remove(surface_id);
|
self.common.surface_names.remove(surface_id);
|
||||||
self.window_size.remove(&surface_id);
|
self.common.window_size.remove(&surface_id);
|
||||||
commands.push(destroy_lock_surface(*surface_id));
|
commands.push(destroy_lock_surface(*surface_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -979,12 +899,6 @@ impl cosmic::Application for App {
|
||||||
cosmic::app::Action::Surface(a),
|
cosmic::app::Action::Surface(a),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Message::Tick => {
|
|
||||||
self.time.tick();
|
|
||||||
}
|
|
||||||
Message::Tz(tz) => {
|
|
||||||
self.time.set_tz(tz);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -997,6 +911,7 @@ impl cosmic::Application for App {
|
||||||
/// Creates a view after each update.
|
/// Creates a view after each update.
|
||||||
fn view_window(&self, surface_id: SurfaceId) -> Element<Self::Message> {
|
fn view_window(&self, surface_id: SurfaceId) -> Element<Self::Message> {
|
||||||
let img = self
|
let img = self
|
||||||
|
.common
|
||||||
.surface_images
|
.surface_images
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.unwrap_or(&self.flags.fallback_background);
|
.unwrap_or(&self.flags.fallback_background);
|
||||||
|
|
@ -1010,19 +925,7 @@ impl cosmic::Application for App {
|
||||||
fn subscription(&self) -> Subscription<Self::Message> {
|
fn subscription(&self) -> Subscription<Self::Message> {
|
||||||
let mut subscriptions = Vec::with_capacity(7);
|
let mut subscriptions = Vec::with_capacity(7);
|
||||||
|
|
||||||
subscriptions.push(event::listen_with(|event, _, id| match event {
|
subscriptions.push(self.common.subscription().map(Message::from));
|
||||||
iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(
|
|
||||||
wayland_event,
|
|
||||||
)) => match wayland_event {
|
|
||||||
WaylandEvent::Output(output_event, output) => {
|
|
||||||
Some(Message::OutputEvent(output_event, output))
|
|
||||||
}
|
|
||||||
WaylandEvent::SessionLock(evt) => Some(Message::SessionLockEvent(evt)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
iced::Event::Window(iced::window::Event::Focused) => Some(Message::Focus(id)),
|
|
||||||
_ => None,
|
|
||||||
}));
|
|
||||||
|
|
||||||
struct BackgroundSubscription;
|
struct BackgroundSubscription;
|
||||||
subscriptions.push(
|
subscriptions.push(
|
||||||
|
|
@ -1059,16 +962,6 @@ impl cosmic::Application for App {
|
||||||
subscriptions.push(crate::logind::subscription());
|
subscriptions.push(crate::logind::subscription());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "networkmanager")]
|
|
||||||
{
|
|
||||||
subscriptions.push(crate::networkmanager::subscription().map(Message::NetworkIcon));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "upower")]
|
|
||||||
{
|
|
||||||
subscriptions.push(crate::upower::subscription().map(Message::PowerInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
Subscription::batch(subscriptions)
|
Subscription::batch(subscriptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue