feat, chore: cleanup, make the back button work, latest iced
All checks were successful
build / test-alpine (push) Successful in 2m20s
build / test-debian (push) Successful in 2m59s

This commit is contained in:
user0-07161 2026-02-11 19:24:40 +01:00
parent 0e09558b1e
commit 0cd6c9e52f
4 changed files with 1520 additions and 1099 deletions

2416
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,10 +5,10 @@ edition = "2024"
[dependencies]
anyhow = "1.0.98"
iced = { version = "0.13.1", features = [ "image", "async-std" ] }
iced_layershell = "0.13.7"
iced = { version = "0.14.0", default-features = false, features = ["tokio", "image", "wayland"] }
iced_layershell = "0.14.2"
interprocess = "2.3.1"
tempfile = "3.20.0"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
tempfile = "3.25.0"
tracing = "0.1.44"
tracing-subscriber = "0.3.22"
xkbcommon = "0.9.0"

View file

@ -1,22 +1,25 @@
use std::time::Duration;
use anyhow::anyhow;
use iced::theme::Palette;
use iced::widget::image::{self, Handle};
use iced::widget::{Button, Text, button, horizontal_space, row, stack};
use iced::{
Background, Border, Color, Element, Event, Font, Shadow, Task as Command, Task, Theme, color,
event, font, time,
Background, Border, Color, Element, Font, Shadow, Task as Command, Theme, color, font,
theme::Palette,
time,
widget::{
Button, Text, button,
image::{self, Handle},
row,
space::horizontal as horizontal_space,
stack,
},
};
use iced_layershell::{
actions::{LayershellCustomAction, LayershellCustomActionWithId},
application,
reexport::{Anchor, KeyboardInteractivity, wl_keyboard::KeymapFormat},
settings::{LayerShellSettings, Settings, StartMode, VirtualKeyboardSettings},
};
use iced_layershell::Application;
use iced_layershell::actions::{LayershellCustomActions, LayershellCustomActionsWithId};
use iced_layershell::reexport::Anchor;
use iced_layershell::reexport::wl_keyboard::KeymapFormat;
use iced_layershell::settings::{LayerShellSettings, Settings, StartMode, VirtualKeyboardSettings};
use iced_layershell::to_layer_message;
use crate::ipc::Ipc;
use crate::xkb::get_keymap_as_file;
use crate::{ipc::Ipc, xkb::get_keymap_as_file};
mod ipc;
mod xkb;
@ -27,6 +30,7 @@ pub fn transparent_button(_: &Theme, _: button::Status) -> button::Style {
text_color: Color::WHITE,
border: Border::default(),
shadow: Shadow::default(),
snap: true,
}
}
@ -40,12 +44,19 @@ pub fn main() -> Result<(), iced_layershell::Error> {
tracing_subscriber::fmt::init();
Bar::run(Settings {
application(
|| HoneycombBar::default(),
HoneycombBar::namespace,
HoneycombBar::update,
HoneycombBar::view,
)
.settings(Settings {
layer_settings: LayerShellSettings {
size: Some((0, 40)),
exclusive_zone: 40,
anchor: Anchor::Bottom | Anchor::Left | Anchor::Right,
start_mode,
keyboard_interactivity: KeyboardInteractivity::None,
..Default::default()
},
virtual_keyboard_support: Some(VirtualKeyboardSettings {
@ -55,12 +66,28 @@ pub fn main() -> Result<(), iced_layershell::Error> {
}),
..Default::default()
})
.font(include_bytes!("res/fonts/HoneycombClock.ttf").as_slice())
.font(include_bytes!("res/fonts/HoneycombClock2.ttf").as_slice())
.subscription(HoneycombBar::subscription)
.theme(HoneycombBar::theme)
.run()?;
Ok(())
}
struct Bar {
struct HoneycombBar {
back_clicked: bool,
home_clicked: bool,
recent_clicked: bool,
recent_default: Handle,
recent_pressed: Handle,
back_default: Handle,
back_pressed: Handle,
home_default: Handle,
home_pressed: Handle,
}
#[derive(Debug, Clone)]
@ -70,11 +97,9 @@ enum NavButton {
Recent,
}
#[to_layer_message]
#[derive(Debug, Clone)]
#[allow(dead_code)]
enum Message {
IcedEvent(Event),
ButtonClicked(NavButton),
Poll,
FontLoaded(Result<(), font::Error>),
@ -82,69 +107,67 @@ enum Message {
OpenRecents,
}
impl TryInto<LayershellCustomActionsWithId> for Message {
type Error = anyhow::Error;
fn try_into(self) -> Result<LayershellCustomActionsWithId, Self::Error> {
// from github.com/waycrate/exwlshelleventloop/blob/master/iced_examples/iced_virtualkeyboard/src/main.rs
impl TryInto<LayershellCustomActionWithId> for Message {
type Error = Self;
fn try_into(self) -> Result<LayershellCustomActionWithId, Self::Error> {
match self {
Message::PressEsc => Ok(LayershellCustomActionsWithId(
Message::PressEsc => Ok(LayershellCustomActionWithId(
None,
LayershellCustomActions::VirtualKeyboardPressed { time: 100, key: 27 },
LayershellCustomAction::VirtualKeyboardPressed {
time: 100,
key: xkb::get_esc_keycode(),
},
)),
_ => Err(anyhow!("unknown message")),
_ => Err(self),
}
}
}
impl Application for Bar {
type Message = Message;
type Flags = ();
type Theme = Theme;
type Executor = iced::executor::Default;
fn new(_flags: ()) -> (Self, Command<Message>) {
(
Self {
back_clicked: false,
home_clicked: false,
recent_clicked: false,
},
Command::batch([
font::load(include_bytes!("res/fonts/HoneycombClock.ttf").as_slice())
.map(Message::FontLoaded),
font::load(include_bytes!("res/fonts/HoneycombClock2.ttf").as_slice())
.map(Message::FontLoaded),
]),
)
impl HoneycombBar {
fn namespace() -> String {
String::from("honeycomb navigation")
}
fn namespace(&self) -> String {
String::from("project honeycomb")
fn default() -> Self {
Self {
recent_default: Handle::from_bytes(include_bytes!("res/recent_default.png") as &[u8]),
recent_pressed: Handle::from_bytes(include_bytes!("res/recent_pressed.png") as &[u8]),
back_default: Handle::from_bytes(include_bytes!("res/back_default.png") as &[u8]),
back_pressed: Handle::from_bytes(include_bytes!("res/back_pressed.png") as &[u8]),
home_default: Handle::from_bytes(include_bytes!("res/home_default.png") as &[u8]),
home_pressed: Handle::from_bytes(include_bytes!("res/home_pressed.png") as &[u8]),
recent_clicked: false,
back_clicked: false,
home_clicked: false,
}
}
fn subscription(&self) -> iced::Subscription<Self::Message> {
fn subscription(&self) -> iced::Subscription<Message> {
iced::Subscription::batch(vec![
event::listen().map(Message::IcedEvent),
time::every(Duration::from_millis(300)).map(|_| Message::Poll),
time::every(Duration::from_millis(250)).map(|_| Message::Poll),
])
}
fn update(&mut self, message: Message) -> Task<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::ButtonClicked(button) => match button {
NavButton::Back => {
self.back_clicked = true;
Task::done(Message::PressEsc)
Command::done(Message::PressEsc)
}
NavButton::Home => {
self.home_clicked = true;
Task::none()
Command::none()
}
NavButton::Recent => {
self.recent_clicked = true;
Task::done(Message::OpenRecents)
Command::done(Message::OpenRecents)
}
},
@ -152,7 +175,7 @@ impl Application for Bar {
self.back_clicked = false;
self.home_clicked = false;
self.recent_clicked = false;
Task::none()
Command::none()
}
Message::FontLoaded(result) => {
@ -165,43 +188,46 @@ impl Application for Bar {
println!("error while loading font");
}
}
Task::none()
Command::none()
}
Message::OpenRecents => {
Ipc::open_recents().unwrap();
Task::none()
Command::none()
}
_ => Task::none(),
Message::PressEsc => Command::done(message),
}
}
fn view(&self) -> Element<'_, Message> {
let back = if !self.back_clicked {
include_bytes!("res/back_default.png") as &[u8]
&self.back_default
} else {
include_bytes!("res/back_pressed.png") as &[u8]
&self.back_pressed
};
let back_button = Button::new(image::Image::new(Handle::from_bytes(back)))
let home = if !self.home_clicked {
&self.home_default
} else {
&self.home_pressed
};
let recent = if !self.recent_clicked {
&self.recent_default
} else {
&self.recent_pressed
};
let back_button = Button::new(image::Image::new(back.clone()))
.on_press(Message::ButtonClicked(NavButton::Back))
.style(transparent_button);
let home = if !self.home_clicked {
include_bytes!("res/home_default.png") as &[u8]
} else {
include_bytes!("res/home_pressed.png") as &[u8]
};
let home_button = Button::new(image::Image::new(Handle::from_bytes(home)))
let home_button = Button::new(image::Image::new(home.clone()))
.on_press(Message::ButtonClicked(NavButton::Home))
.style(transparent_button);
let recent = if !self.recent_clicked {
include_bytes!("res/recent_default.png") as &[u8]
} else {
include_bytes!("res/recent_pressed.png") as &[u8]
};
let recent_button = Button::new(image::Image::new(Handle::from_bytes(recent)))
let recent_button = Button::new(image::Image::new(recent.clone()))
.on_press(Message::ButtonClicked(NavButton::Recent))
.style(transparent_button);
@ -225,13 +251,14 @@ impl Application for Bar {
.into()
}
fn theme(&self) -> Self::Theme {
fn theme(&self) -> Theme {
let custom_palette = Palette {
background: Color::BLACK,
primary: Color::BLACK,
text: Color::WHITE,
success: Color::WHITE,
danger: Color::WHITE,
warning: Color::WHITE,
};
Theme::custom("honeycomb-default".to_owned(), custom_palette)

View file

@ -2,8 +2,7 @@ use std::{ffi::CString, fs::File, io::Write, path::PathBuf};
use xkbcommon::xkb;
// from https://github.com/ptazithos/wkeys/blob/main/wkeys/src/native/session.rs
pub fn get_keymap_as_file() -> (File, u32) {
fn get_keymap() -> xkb::Keymap {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap = xkb::Keymap::new_from_names(
@ -17,9 +16,14 @@ pub fn get_keymap_as_file() -> (File, u32) {
)
.expect("xkbcommon keymap panicked!");
let xkb_state = xkb::State::new(&keymap);
let keymap = xkb_state
.get_keymap()
.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1);
xkb_state.get_keymap()
}
// from https://github.com/ptazithos/wkeys/blob/main/wkeys/src/native/session.rs
pub fn get_keymap_as_file() -> (File, u32) {
let keymap = get_keymap().get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1);
println!("{keymap}");
let keymap = CString::new(keymap).expect("Keymap should not contain interior nul bytes");
let keymap = keymap.as_bytes_with_nul();
let dir = std::env::var_os("XDG_RUNTIME_DIR")
@ -30,3 +34,7 @@ pub fn get_keymap_as_file() -> (File, u32) {
file.flush().unwrap();
(file, keymap.len() as u32)
}
pub fn get_esc_keycode() -> u32 {
Into::<u32>::into(get_keymap().key_by_name("ESC").unwrap()) - 8 as u32
}