chore: updates after iced rebase

This commit is contained in:
Ashley Wulber 2026-02-24 15:49:22 -05:00 committed by Jacob Kauffmann
parent 63cd93bddd
commit 89671a793f
10 changed files with 2367 additions and 2486 deletions

View file

@ -11,6 +11,7 @@ use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity
use cosmic::iced::event::listen_with;
use cosmic::iced::{Point, Size, window};
use cosmic::iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings;
use cosmic::iced_runtime::task::widget;
use cosmic::widget::text;
use cosmic::{
Element,
@ -39,9 +40,7 @@ use cosmic::{
use cosmic_greeter_config::Config as CosmicGreeterConfig;
use cosmic_greeter_daemon::{UserData, UserFilter};
use cosmic_randr_shell::{KdlParseWithError, List};
use cosmic_settings_subscriptions::cosmic_a11y_manager::{
AccessibilityEvent, AccessibilityRequest,
};
use cosmic_settings_a11y_manager_subscription::{AccessibilityEvent, AccessibilityRequest};
use greetd_ipc::Request;
use kdl::KdlDocument;
use std::process::Stdio;
@ -536,9 +535,11 @@ impl App {
.width(Length::Fixed(16.0))
.into()
} else {
widget::Space::with_width(Length::Fixed(17.0)).into()
widget::space::horizontal()
.width(Length::Fixed(17.0))
.into()
},
widget::Space::with_width(Length::Fixed(8.0)).into(),
widget::space::horizontal().width(Length::Fixed(8.0)).into(),
widget::text(label)
.align_x(iced::alignment::Horizontal::Left)
.into(),
@ -615,7 +616,7 @@ impl App {
}
let item_cnt = items.len();
let menu_button = widget::menu::menu_button(vec![
Element::from(widget::Space::with_width(Length::Fixed(10.0))),
Element::from(widget::space::horizontal().width(Length::Fixed(10.0))),
widget::text(fl!("enter-user"))
.align_x(iced::alignment::Horizontal::Left)
.into(),
@ -767,7 +768,7 @@ impl App {
// Add top spacing for better visual appearance
// Bottom of the password text input field should align with bottom of time widget
column = column.push(widget::Space::with_height(Length::Fixed(space_height)));
column = column.push(widget::space::vertical().height(Length::Fixed(space_height)));
match &self.socket_state {
SocketState::Pending => {
@ -799,10 +800,9 @@ impl App {
} else {
// Empty transparent box for users without icons
column = column.push(
widget::container(widget::Space::new(
Length::Fixed(78.0),
Length::Fixed(78.0),
))
widget::container(
widget::space::horizontal().width(Length::Fixed(78.0)),
)
.padding(0.0)
.width(Length::Fill)
.height(Length::Fixed(78.0))
@ -942,7 +942,9 @@ impl App {
.width(Length::Fill)
};
let menu = widget::container(widget::column::with_children(vec![
widget::Space::with_height(Length::FillPortion(1)).into(),
widget::space::vertical()
.height(Length::FillPortion(1))
.into(),
widget::layer_container(
iced::widget::row![left_element, right_element].align_y(Alignment::Start),
)
@ -962,7 +964,9 @@ impl App {
.class(cosmic::theme::Container::Background)
.width(Length::Fixed(800.0))
.into(),
widget::Space::with_height(Length::FillPortion(4)).into(),
widget::space::vertical()
.height(Length::FillPortion(4))
.into(),
]))
.width(Length::Fill)
.height(Length::Fill)
@ -1285,7 +1289,7 @@ impl cosmic::Application for App {
id: surface_id,
layer: Layer::Overlay,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
pointer_interactivity: true,
input_zone: None,
anchor: Anchor::TOP | Anchor::LEFT | Anchor::BOTTOM | Anchor::RIGHT,
output: IcedOutput::Output(output),
namespace: "cosmic-locker".into(),
@ -1484,19 +1488,21 @@ impl cosmic::Application for App {
// Start spinner animation if not already running
if self.spinner_handle.is_none() {
let (spinner_task, handle) = cosmic::task::stream(
cosmic::iced_futures::stream::channel(1, |mut msg_tx| async move {
let mut interval = time::interval(Duration::from_millis(16)); // ~60fps
loop {
msg_tx
.send(cosmic::Action::App(Message::SpinnerTick))
.await
.unwrap();
interval.tick().await;
}
}),
)
.abortable();
let (spinner_task, handle) =
cosmic::task::stream(cosmic::iced_futures::stream::channel(
1,
|mut msg_tx: iced::futures::channel::mpsc::Sender<_>| async move {
let mut interval = time::interval(Duration::from_millis(16)); // ~60fps
loop {
msg_tx
.send(cosmic::Action::App(Message::SpinnerTick))
.await
.unwrap();
interval.tick().await;
}
},
))
.abortable();
self.spinner_handle = Some(handle);
return spinner_task;
}
@ -1606,22 +1612,24 @@ impl cosmic::Application for App {
});
if self.heartbeat_handle.is_none() {
let (heartbeat, handle) = cosmic::task::stream(
cosmic::iced_futures::stream::channel(1, |mut msg_tx| async move {
let mut interval = time::interval(Duration::from_secs(1));
let (heartbeat, handle) =
cosmic::task::stream(cosmic::iced_futures::stream::channel(
1,
|mut msg_tx: iced::futures::channel::mpsc::Sender<_>| async move {
let mut interval = time::interval(Duration::from_secs(1));
loop {
// Send heartbeat once a second to update time
msg_tx
.send(cosmic::Action::App(Message::Heartbeat))
.await
.unwrap();
loop {
// Send heartbeat once a second to update time
msg_tx
.send(cosmic::Action::App(Message::Heartbeat))
.await
.unwrap();
interval.tick().await;
}
}),
)
.abortable();
interval.tick().await;
}
},
))
.abortable();
self.heartbeat_handle = Some(handle);
return heartbeat;

View file

@ -38,139 +38,145 @@ fn greetd_error_to_message(error_type: greetd_ipc::ErrorType, description: &str)
pub fn subscription() -> Subscription<Message> {
struct GreetdSubscription;
Subscription::run_with_id(
std::any::TypeId::of::<GreetdSubscription>(),
cosmic::iced_futures::stream::channel(1, |mut sender| async move {
let (tx, mut rx) = mpsc::channel::<greetd_ipc::Request>(1);
_ = sender.send(Message::GreetdChannel(tx)).await;
Subscription::run_with(std::any::TypeId::of::<GreetdSubscription>(), |_| {
cosmic::iced_futures::stream::channel(
1,
|mut sender: cosmic::iced::futures::channel::mpsc::Sender<_>| async move {
let (tx, mut rx) = mpsc::channel::<greetd_ipc::Request>(1);
_ = sender.send(Message::GreetdChannel(tx)).await;
let socket_path =
std::env::var_os("GREETD_SOCK").expect("GREETD_SOCK environment not set");
let socket_path =
std::env::var_os("GREETD_SOCK").expect("GREETD_SOCK environment not set");
let mut interval = tokio::time::interval(Duration::from_secs(1));
let mut interval = tokio::time::interval(Duration::from_secs(1));
loop {
_ = sender.send(Message::Reconnect).await;
loop {
_ = sender.send(Message::Reconnect).await;
let mut stream = match UnixStream::connect(&socket_path).await {
Ok(stream) => stream,
Err(why) => {
tracing::error!("greetd IPC socket connection failed: {why:?}");
_ = sender.send(Message::Socket(SocketState::Error(Arc::new(why))));
let mut stream = match UnixStream::connect(&socket_path).await {
Ok(stream) => stream,
Err(why) => {
tracing::error!("greetd IPC socket connection failed: {why:?}");
_ = sender.send(Message::Socket(SocketState::Error(Arc::new(why))));
break;
}
};
break;
}
};
_ = sender.send(Message::Socket(SocketState::Open)).await;
_ = sender.send(Message::Socket(SocketState::Open)).await;
while let Some(request) = rx.recv().await {
if let Err(why) = request.write_to(&mut stream).await {
tracing::error!("error writing to GREETD_SOCK stream: {why:?}");
break;
}
while let Some(request) = rx.recv().await {
if let Err(why) = request.write_to(&mut stream).await {
tracing::error!("error writing to GREETD_SOCK stream: {why:?}");
break;
}
match greetd_ipc::Response::read_from(&mut stream).await {
Ok(response) => {
match response {
greetd_ipc::Response::AuthMessage {
auth_message_type,
auth_message,
} => match auth_message_type {
greetd_ipc::AuthMessageType::Secret => {
_ = sender
.send(
common::Message::Prompt(
auth_message,
true,
Some(String::new()),
)
.into(),
)
.await;
}
greetd_ipc::AuthMessageType::Visible => {
_ = sender
.send(
common::Message::Prompt(
auth_message,
false,
Some(String::new()),
)
.into(),
)
.await;
}
greetd_ipc::AuthMessageType::Info => {
_ = sender
.send(
common::Message::Prompt(auth_message, false, None)
match greetd_ipc::Response::read_from(&mut stream).await {
Ok(response) => {
match response {
greetd_ipc::Response::AuthMessage {
auth_message_type,
auth_message,
} => match auth_message_type {
greetd_ipc::AuthMessageType::Secret => {
_ = sender
.send(
common::Message::Prompt(
auth_message,
true,
Some(String::new()),
)
.into(),
)
.await;
}
greetd_ipc::AuthMessageType::Error => {
_ = sender.send(Message::Error(auth_message)).await;
}
},
greetd_ipc::Response::Error {
error_type,
description,
} => {
match request {
greetd_ipc::Request::CancelSession => {
// Do not send errors for cancel session to gui
tracing::warn!(
"error while cancelling session: {}",
description
);
)
.await;
}
greetd_ipc::AuthMessageType::Visible => {
_ = sender
.send(
common::Message::Prompt(
auth_message,
false,
Some(String::new()),
)
.into(),
)
.await;
}
greetd_ipc::AuthMessageType::Info => {
_ = sender
.send(
common::Message::Prompt(
auth_message,
false,
None,
)
.into(),
)
.await;
}
greetd_ipc::AuthMessageType::Error => {
_ = sender.send(Message::Error(auth_message)).await;
}
},
greetd_ipc::Response::Error {
error_type,
description,
} => {
match request {
greetd_ipc::Request::CancelSession => {
// Do not send errors for cancel session to gui
tracing::warn!(
"error while cancelling session: {}",
description
);
// Reconnect to socket
break;
}
_ => {
_ = sender
.send(Message::Error(greetd_error_to_message(
error_type,
&description,
)))
.await;
}
}
}
greetd_ipc::Response::Success => match request {
greetd_ipc::Request::CreateSession { .. } => {
// User has no auth required, proceed to login
_ = sender.send(Message::Login).await;
}
greetd_ipc::Request::PostAuthMessageResponse { .. } => {
// All auth is completed, proceed to login
_ = sender.send(Message::Login).await;
}
greetd_ipc::Request::StartSession { .. } => {
// Session has been started, exit greeter
_ = sender.send(Message::Exit).await;
}
greetd_ipc::Request::CancelSession => {
tracing::info!("greetd IPC session canceled");
// Reconnect to socket
break;
}
_ => {
_ = sender
.send(Message::Error(greetd_error_to_message(
error_type,
&description,
)))
.await;
}
}
},
}
greetd_ipc::Response::Success => match request {
greetd_ipc::Request::CreateSession { .. } => {
// User has no auth required, proceed to login
_ = sender.send(Message::Login).await;
}
greetd_ipc::Request::PostAuthMessageResponse { .. } => {
// All auth is completed, proceed to login
_ = sender.send(Message::Login).await;
}
greetd_ipc::Request::StartSession { .. } => {
// Session has been started, exit greeter
_ = sender.send(Message::Exit).await;
}
greetd_ipc::Request::CancelSession => {
tracing::info!("greetd IPC session canceled");
// Reconnect to socket
break;
}
},
}
Err(err) => {
tracing::error!("failed to read socket: {:?}", err);
break;
}
}
Err(err) => {
tracing::error!("failed to read socket: {:?}", err);
break;
}
}
tracing::info!("reconnecting to greetd IPC socket");
interval.tick().await;
}
tracing::info!("reconnecting to greetd IPC socket");
interval.tick().await;
}
futures_util::future::pending().await
}),
)
futures_util::future::pending().await
},
)
})
}

View file

@ -211,9 +211,7 @@ impl Conversation {
futures::executor::block_on(async {
self.msg_tx
.send(cosmic::Action::App(
Message::Error(prompt.to_string()),
))
.send(cosmic::Action::App(Message::Error(prompt.to_string())))
.await
})
.map_err(|err| {
@ -367,9 +365,11 @@ impl App {
.width(Length::Fixed(16.0))
.into()
} else {
widget::Space::with_width(Length::Fixed(17.0)).into()
widget::space::horizontal()
.width(Length::Fixed(17.0))
.into()
},
widget::Space::with_width(Length::Fixed(8.0)).into(),
widget::space::horizontal().width(Length::Fixed(8.0)).into(),
widget::text(label)
.align_x(iced::alignment::Horizontal::Left)
.into(),
@ -477,7 +477,7 @@ impl App {
// Add top spacing for better visual appearance
// Bottom of the password text input field should align with bottom of time widget
column = column.push(widget::Space::with_height(Length::Fixed(space_height)));
column = column.push(widget::space::vertical().height(Length::Fixed(space_height)));
// Display user icon or empty transparent box
if let Some(icon_handle) = &self.flags.user_icon {
@ -496,7 +496,7 @@ impl App {
} else {
// Empty transparent box for users without icons
column = column.push(
widget::container(widget::Space::new(Length::Fixed(78.0), Length::Fixed(78.0)))
widget::container(widget::space::horizontal().width(Length::Fixed(78.0)))
.padding(0.0)
.width(Length::Fill)
.height(Length::Fixed(78.0))
@ -602,7 +602,9 @@ impl App {
};
widget::container(widget::column::with_children(vec![
widget::Space::with_height(Length::FillPortion(1)).into(),
widget::space::vertical()
.height(Length::FillPortion(1))
.into(),
widget::layer_container(
iced::widget::row![left_element, right_element].align_y(Alignment::Start),
)
@ -622,7 +624,9 @@ impl App {
.width(Length::Fill)
.height(Length::Shrink)
.into(),
widget::Space::with_height(Length::FillPortion(4)).into(),
widget::space::vertical()
.height(Length::FillPortion(4))
.into(),
]))
.width(Length::Fill)
.height(Length::Fill)
@ -865,72 +869,77 @@ impl cosmic::Application for App {
}
let username = self.flags.user_data.name.clone();
let (locked_task, locked_handle) = cosmic::task::stream(
cosmic::iced_futures::stream::channel(16, |mut msg_tx| async move {
// Send heartbeat once a second to update time.
let heartbeat_future = {
let mut output = msg_tx.clone();
async move {
let mut interval =
tokio::time::interval(Duration::from_secs(1));
let (locked_task, locked_handle) =
cosmic::task::stream(cosmic::iced_futures::stream::channel(
16,
|mut msg_tx: futures::channel::mpsc::Sender<_>| async move {
// Send heartbeat once a second to update time.
let heartbeat_future = {
let mut output = msg_tx.clone();
async move {
let mut interval =
tokio::time::interval(Duration::from_secs(1));
loop {
output
.send(cosmic::Action::App(Message::None))
.await
.unwrap();
interval.tick().await;
}
}
};
let pam_future = async {
loop {
output
.send(cosmic::Action::App(Message::None))
let (value_tx, value_rx) = mpsc::channel(16);
msg_tx
.send(cosmic::Action::App(Message::Channel(value_tx)))
.await
.unwrap();
interval.tick().await;
}
}
};
let pam_res = {
let username = username.clone();
let msg_tx = msg_tx.clone();
task::spawn_blocking(move || {
pam_thread(
username,
Conversation { msg_tx, value_rx },
)
})
.await
.unwrap()
};
let pam_future = async {
loop {
let (value_tx, value_rx) = mpsc::channel(16);
msg_tx
.send(cosmic::Action::App(Message::Channel(value_tx)))
.await
.unwrap();
let pam_res = {
let username = username.clone();
let msg_tx = msg_tx.clone();
task::spawn_blocking(move || {
pam_thread(username, Conversation { msg_tx, value_rx })
})
.await
.unwrap()
};
match pam_res {
Ok(()) => {
tracing::info!("successfully authenticated");
msg_tx
.send(cosmic::Action::App(Message::Unlock))
.await
.unwrap();
break;
}
Err(err) => {
tracing::warn!("authentication error: {}", err);
msg_tx
.send(cosmic::Action::App(Message::Error(
pam_error_to_message(&err),
)))
.await
.unwrap();
match pam_res {
Ok(()) => {
tracing::info!("successfully authenticated");
msg_tx
.send(cosmic::Action::App(Message::Unlock))
.await
.unwrap();
break;
}
Err(err) => {
tracing::warn!("authentication error: {}", err);
msg_tx
.send(cosmic::Action::App(Message::Error(
pam_error_to_message(&err),
)))
.await
.unwrap();
}
}
}
}
};
};
futures::pin_mut!(heartbeat_future);
futures::pin_mut!(pam_future);
futures::future::select(heartbeat_future, pam_future).await;
}),
)
.abortable();
futures::pin_mut!(heartbeat_future);
futures::pin_mut!(pam_future);
futures::future::select(heartbeat_future, pam_future).await;
},
))
.abortable();
let mut commands = Vec::with_capacity(self.common.surface_ids.len() + 1);
commands.push(locked_task);
@ -1046,20 +1055,22 @@ impl cosmic::Application for App {
Some(value_tx) => {
// Start spinner animation if not already running
if self.spinner_handle.is_none() {
let (spinner_task, handle) = cosmic::task::stream(
cosmic::iced_futures::stream::channel(1, |mut msg_tx| async move {
let mut interval =
tokio::time::interval(Duration::from_millis(16)); // ~60fps
loop {
msg_tx
.send(cosmic::Action::App(Message::SpinnerTick))
.await
.unwrap();
interval.tick().await;
}
}),
)
.abortable();
let (spinner_task, handle) =
cosmic::task::stream(cosmic::iced_futures::stream::channel(
1,
|mut msg_tx: futures::channel::mpsc::Sender<_>| async move {
let mut interval =
tokio::time::interval(Duration::from_millis(16)); // ~60fps
loop {
msg_tx
.send(cosmic::Action::App(Message::SpinnerTick))
.await
.unwrap();
interval.tick().await;
}
},
))
.abortable();
self.spinner_handle = Some(handle);
return Task::batch([

View file

@ -46,8 +46,7 @@ async fn inhibit(manager: &ManagerProxy<'_>) -> zbus::Result<OwnedFd> {
pub fn subscription() -> Subscription<Message> {
struct LogindSubscription;
Subscription::run_with_id(
TypeId::of::<LogindSubscription>(),
Subscription::run_with(TypeId::of::<LogindSubscription>(), |_| {
cosmic::iced_futures::stream::channel(16, |mut msg_tx| async move {
match handler(&mut msg_tx).await {
Ok(()) => {}
@ -58,8 +57,8 @@ pub fn subscription() -> Subscription<Message> {
}
std::process::exit(1);
}),
)
})
})
}
//TODO: use never type?

View file

@ -36,8 +36,7 @@ impl NetworkIcon {
pub fn subscription() -> Subscription<Option<&'static str>> {
struct NetworkSubscription;
Subscription::run_with_id(
TypeId::of::<NetworkSubscription>(),
Subscription::run_with(TypeId::of::<NetworkSubscription>(), |_| {
cosmic::iced_futures::stream::channel(16, |mut msg_tx| async move {
match handler(&mut msg_tx).await {
Ok(()) => {}
@ -52,8 +51,8 @@ pub fn subscription() -> Subscription<Option<&'static str>> {
//TODO: should we retry on error?
futures_util::future::pending().await
}),
)
})
})
}
//TODO: use never type?

View file

@ -9,8 +9,7 @@ use zbus::{Connection, Result};
pub fn subscription() -> Subscription<Option<(String, f64)>> {
struct PowerSubscription;
Subscription::run_with_id(
TypeId::of::<PowerSubscription>(),
Subscription::run_with(TypeId::of::<PowerSubscription>(), |_| {
cosmic::iced_futures::stream::channel(16, |mut msg_tx| async move {
match handler(&mut msg_tx).await {
Ok(()) => {}
@ -25,8 +24,8 @@ pub fn subscription() -> Subscription<Option<(String, f64)>> {
//TODO: should we retry on error?
futures_util::future::pending().await
}),
)
})
})
}
//TODO: use never type?

View file

@ -7,7 +7,7 @@ use cosmic::iced::{
futures::{self, SinkExt},
stream,
};
use cosmic_settings_subscriptions::cosmic_a11y_manager::{
use cosmic_settings_a11y_manager_subscription::{
self as thread, AccessibilityEvent, AccessibilityRequest,
};
use std::sync::LazyLock;
@ -24,16 +24,15 @@ pub enum WaylandUpdate {
}
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
Subscription::run_with_id(
std::any::TypeId::of::<WaylandUpdate>(),
Subscription::run_with(std::any::TypeId::of::<WaylandUpdate>(), |_| {
stream::channel(50, move |mut output| async move {
let mut state = State::Waiting;
loop {
state = start_listening(state, &mut output).await;
}
}),
)
})
})
}
async fn start_listening(
@ -42,7 +41,8 @@ async fn start_listening(
) -> State {
match state {
State::Waiting => {
let mut guard = WAYLAND_RX.lock().await;
let mut guard: tokio::sync::MutexGuard<'_, Option<tokio::sync::mpsc::Receiver<_>>> =
WAYLAND_RX.lock().await;
let rx = {
if guard.is_none() {
if let Ok(WaylandWatcher { rx, tx }) = WaylandWatcher::new() {