chore: latest iced
All checks were successful
build / test-debian (push) Successful in 2m29s
build / test-alpine (push) Successful in 5m35s

This commit is contained in:
user0-07161 2026-02-11 20:27:41 +01:00
parent 25c89a270e
commit 99028d0605
3 changed files with 1545 additions and 1008 deletions

2400
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,14 @@ edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.98" anyhow = "1.0.98"
async-trait = "0.1.88" async-trait = "0.1.89"
freedesktop-icons = "0.4.0" freedesktop-icons = "0.4.0"
futures = "0.3.31" futures = "0.3.31"
iced = { version = "0.13.1", features = [ "image", "tokio", "svg", "async-std" ] } iced = { version = "0.14.0", features = [ "image", "tokio", "svg" ] }
iced_layershell = "0.13.7" iced_layershell = "0.14.2"
once_cell = "1.21.3" once_cell = "1.21.3"
tokio = { version = "1.47.1", features = ["full"] } tokio = { version = "1.47.1", features = ["full"] }
tracing-subscriber = "0.3.22"
wayrs-client = { version = "1.3.1", features = [ "tokio" ] } wayrs-client = { version = "1.3.1", features = [ "tokio" ] }
wayrs-protocols = { version = "0.14.11", features = [ "wlr-foreign-toplevel-management-unstable-v1" ] } wayrs-protocols = { version = "0.14.11", features = [ "wlr-foreign-toplevel-management-unstable-v1" ] }
wayrs-utils = { version = "0.17.2", features = [ "seats" ] } wayrs-utils = { version = "0.17.2", features = [ "seats" ] }

View file

@ -1,37 +1,60 @@
mod toplevels;
use iced::border::Radius;
use iced::widget::image::Handle;
use iced::widget::scrollable::Scroller;
use iced::widget::{Column, Image, button, column, container, row, scrollable, stack, svg, text};
use iced::{
Alignment, Background, Border, Color, Element, Event, Font, Shadow, Task, Theme, event, exit,
};
use iced_layershell::Application;
use iced_layershell::reexport::{Anchor, Layer};
use iced_layershell::settings::{LayerShellSettings, Settings, StartMode};
use iced_layershell::to_layer_message;
use freedesktop_icons::lookup; use freedesktop_icons::lookup;
use iced::{
Alignment, Background, Border, Color, Element, Font, Shadow, Task, Theme,
border::Radius,
exit,
theme::Style,
widget::{
self, Column, Image, button, column, container,
image::Handle,
row,
scrollable::{self, Scroller},
stack, svg, text,
},
};
use iced_layershell::{
application,
reexport::{Anchor, Layer},
settings::{LayerShellSettings, Settings, StartMode},
to_layer_message,
};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
use tracing_subscriber;
use std::collections::HashMap; use std::{collections::HashMap, ffi::OsStr, sync::Mutex};
use std::ffi::OsStr;
use std::sync::Mutex;
use anyhow::Result; use anyhow::Result;
use crate::toplevels::{Backend, Toplevel, WlrToplevelManagement, ZwlrForeignToplevelHandleV1}; use crate::toplevels::{Backend, Toplevel, WlrToplevelManagement, ZwlrForeignToplevelHandleV1};
mod toplevels;
static MANAGER: Lazy<Mutex<Option<WlrToplevelManagement>>> = Lazy::new(|| Mutex::new(None)); static MANAGER: Lazy<Mutex<Option<WlrToplevelManagement>>> = Lazy::new(|| Mutex::new(None));
pub fn main() -> Result<(), iced_layershell::Error> { pub fn main() -> Result<(), anyhow::Error> {
tracing_subscriber::fmt::init();
let bound_output_name = std::env::args().nth(1); let bound_output_name = std::env::args().nth(1);
let start_mode = match bound_output_name { let start_mode = match bound_output_name {
Some(output) => StartMode::TargetScreen(output), Some(output) => StartMode::TargetScreen(output),
None => StartMode::Active, None => StartMode::Active,
}; };
Recents::run(Settings { application(
|| {
let mut honeycomb_recents = HoneycombRecents::default();
let tokio_rt = Runtime::new().unwrap();
honeycomb_recents.toplevels = tokio_rt.block_on(list_toplevels()).unwrap();
honeycomb_recents
},
HoneycombRecents::namespace,
HoneycombRecents::update,
HoneycombRecents::view,
)
.settings(Settings {
layer_settings: LayerShellSettings { layer_settings: LayerShellSettings {
size: Some((0, 0)), size: Some((0, 0)),
exclusive_zone: 0, exclusive_zone: 0,
@ -42,53 +65,48 @@ pub fn main() -> Result<(), iced_layershell::Error> {
}, },
..Default::default() ..Default::default()
}) })
.style(HoneycombRecents::style)
.run()?;
Ok(())
} }
struct Recents { struct HoneycombRecents {
toplevels: HashMap<ZwlrForeignToplevelHandleV1, Toplevel>, toplevels: HashMap<ZwlrForeignToplevelHandleV1, Toplevel>,
selected_toplevel: Option<ZwlrForeignToplevelHandleV1>, selected_toplevel: Option<ZwlrForeignToplevelHandleV1>,
recents_default: Handle,
recents_pressed: Handle,
} }
#[to_layer_message] #[to_layer_message]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[allow(dead_code)] #[allow(dead_code)]
enum Message { enum Message {
IcedEvent(Event),
ToplevelsListed(Option<HashMap<ZwlrForeignToplevelHandleV1, Toplevel>>),
ToplevelSelected(ZwlrForeignToplevelHandleV1), ToplevelSelected(ZwlrForeignToplevelHandleV1),
} }
impl Application for Recents { impl HoneycombRecents {
type Message = Message; fn default() -> Self {
type Flags = (); Self {
type Theme = Theme; toplevels: HashMap::new(),
type Executor = iced::executor::Default; selected_toplevel: None,
fn new(_flags: ()) -> (Self, Task<Message>) { recents_default: Handle::from_bytes(
( include_bytes!("res/recents_thumbnail_bg.png") as &[u8]
Self { ),
toplevels: HashMap::new(), recents_pressed: Handle::from_bytes(
selected_toplevel: None, include_bytes!("res/recents_thumbnail_bg_press.png") as &[u8],
}, ),
Task::perform(list_toplevels(), Message::ToplevelsListed), }
)
} }
fn namespace(&self) -> String { fn namespace() -> String {
String::from("project honeycomb - recents") String::from("honeycomb recents")
}
fn subscription(&self) -> iced::Subscription<Self::Message> {
iced::Subscription::batch(vec![event::listen().map(Message::IcedEvent)])
} }
fn update(&mut self, message: Message) -> Task<Message> { fn update(&mut self, message: Message) -> Task<Message> {
match message { match message {
Message::ToplevelsListed(Some(toplevels)) => {
self.toplevels = toplevels;
Task::none()
}
Message::ToplevelSelected(toplevel) => { Message::ToplevelSelected(toplevel) => {
self.selected_toplevel = Some(toplevel); self.selected_toplevel = Some(toplevel);
let mut mgr = MANAGER.lock().unwrap(); let mut mgr = MANAGER.lock().unwrap();
@ -98,17 +116,13 @@ impl Application for Recents {
exit() exit()
} }
Message::IcedEvent(e) => {
println!("{e:#?}");
Task::none()
}
_ => Task::none(), _ => Task::none(),
} }
} }
fn view(&self) -> Element<'_, Message> { fn view(&self) -> Element<'_, Message> {
let mut column = Column::new(); let mut column = Column::new();
for (toplevel, info) in self.toplevels.clone() { for (toplevel, info) in self.toplevels.clone() {
let title = info let title = info
.title .title
@ -123,16 +137,14 @@ impl Application for Recents {
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
let mut img = if Some(toplevel) != self.selected_toplevel { let image = if Some(toplevel) != self.selected_toplevel {
stack!(Image::new(Handle::from_bytes( &self.recents_default
include_bytes!("res/recents_thumbnail_bg.png") as &[u8]
)))
} else { } else {
stack!(Image::new(Handle::from_bytes(include_bytes!( &self.recents_pressed
"res/recents_thumbnail_bg_press.png"
) as &[u8])))
}; };
let mut img = stack!(Image::new(image.clone()).width(245).height(144));
if let Some(id) = info.app_id { if let Some(id) = info.app_id {
if let Some(icon) = lookup(&id).find() { if let Some(icon) = lookup(&id).find() {
if icon.extension() == Some(OsStr::new("svg")) { if icon.extension() == Some(OsStr::new("svg")) {
@ -157,14 +169,13 @@ impl Application for Recents {
)); ));
} }
scrollable(column.spacing(50)) widget::scrollable(column.spacing(50))
.style(transparent_scrollbar) .style(transparent_scrollbar)
.into() .into()
} }
fn style(&self, _: &Self::Theme) -> iced_layershell::Appearance { fn style(&self, _: &Theme) -> Style {
use iced_layershell::Appearance; Style {
Appearance {
background_color: Color { background_color: Color {
r: 0.0, r: 0.0,
g: 0.0, g: 0.0,
@ -178,8 +189,8 @@ impl Application for Recents {
async fn list_toplevels() -> Option<HashMap<ZwlrForeignToplevelHandleV1, Toplevel>> { async fn list_toplevels() -> Option<HashMap<ZwlrForeignToplevelHandleV1, Toplevel>> {
let mut mgr = MANAGER.lock().unwrap(); let mut mgr = MANAGER.lock().unwrap();
*mgr = futures::executor::block_on(WlrToplevelManagement::new()).ok(); *mgr = WlrToplevelManagement::new().await.ok();
match futures::executor::block_on(mgr.as_mut()?.get_info()).ok() { match mgr.as_mut()?.get_info().await.ok() {
Some(info) => return Some(info.toplevels), Some(info) => return Some(info.toplevels),
None => return None, None => return None,
} }
@ -195,8 +206,8 @@ fn transparent_scrollbar(_: &Theme, _: scrollable::Status) -> scrollable::Style
background: Some(Background::Color(Color::TRANSPARENT)), background: Some(Background::Color(Color::TRANSPARENT)),
border: empty_border.clone(), border: empty_border.clone(),
scroller: Scroller { scroller: Scroller {
color: Color::TRANSPARENT,
border: empty_border.clone(), border: empty_border.clone(),
background: Background::Color(Color::TRANSPARENT),
}, },
}; };
@ -205,6 +216,12 @@ fn transparent_scrollbar(_: &Theme, _: scrollable::Status) -> scrollable::Style
vertical_rail: rail.clone(), vertical_rail: rail.clone(),
horizontal_rail: rail.clone(), horizontal_rail: rail.clone(),
gap: Some(Background::Color(Color::TRANSPARENT)), gap: Some(Background::Color(Color::TRANSPARENT)),
auto_scroll: scrollable::AutoScroll {
background: Background::Color(Color::TRANSPARENT),
border: empty_border.clone(),
shadow: Shadow::default(),
icon: Color::TRANSPARENT,
},
} }
} }
@ -214,5 +231,6 @@ pub fn transparent_button(_: &Theme, _: button::Status) -> button::Style {
text_color: Color::WHITE, text_color: Color::WHITE,
border: Border::default(), border: Border::default(),
shadow: Shadow::default(), shadow: Shadow::default(),
snap: false,
} }
} }