diff --git a/Cargo.lock b/Cargo.lock index 616744f..1dc0fb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,6 +1336,7 @@ dependencies = [ "cosmic-dbus-networkmanager", "cosmic-greeter-config", "cosmic-greeter-daemon", + "cosmic-osk-config", "cosmic-protocols", "cosmic-randr-shell", "cosmic-settings-a11y-manager-subscription", @@ -1409,6 +1410,15 @@ dependencies = [ "zbus_systemd", ] +[[package]] +name = "cosmic-osk-config" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-osk#d7b66a24890d03e38dd8962d956bc802d4a41067" +dependencies = [ + "cosmic-config", + "serde", +] + [[package]] name = "cosmic-protocols" version = "0.2.0" @@ -1891,7 +1901,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2086,7 +2096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4166,7 +4176,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4807,7 +4817,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6156,7 +6166,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6745,7 +6755,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -7831,7 +7841,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3f172ea..83bf4d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ cosmic-comp-config.workspace = true cosmic-config = { workspace = true, features = ["calloop", "macro"] } cosmic-greeter-config.workspace = true cosmic-greeter-daemon = { path = "daemon" } +cosmic-osk-config = { git = "https://github.com/pop-os/cosmic-osk" } dirs = "6" libcosmic = { workspace = true, features = [ "autosize", diff --git a/i18n/en/cosmic_greeter.ftl b/i18n/en/cosmic_greeter.ftl index 2625d59..fa77b09 100644 --- a/i18n/en/cosmic_greeter.ftl +++ b/i18n/en/cosmic_greeter.ftl @@ -9,6 +9,7 @@ caps-lock = Caps Lock is active. enter-user = Enter name manually... type-username = Username: keyboard-layout = Keyboard layout +on-screen-keyboard = On-screen keyboard restart = Restart restart-now = Restart now? restart-timeout = The system will restart automatically diff --git a/src/common.rs b/src/common.rs index 51db69b..442a5a1 100644 --- a/src/common.rs +++ b/src/common.rs @@ -10,6 +10,7 @@ use cosmic::iced::{self, Rectangle, Size, Subscription}; use cosmic::surface::corner_radius::rounded_rect_strips; use cosmic::widget::rectangle_tracker::{RectangleUpdate, rectangle_tracker_subscription}; use cosmic::widget::{self, RectangleTracker}; +use cosmic_config::CosmicConfigEntry; use cosmic_greeter_daemon::{BgSource, UserData}; use cosmic_protocols::keyboard_layout::v1::client::zcosmic_keyboard_layout_v1::ZcosmicKeyboardLayoutV1; use std::collections::{HashMap, HashSet}; @@ -19,6 +20,7 @@ use wayland_client::{Connection, Proxy}; use crate::keyboard_layout_wayland; +pub const MAX_WIDTH: f32 = 866.; pub const DEFAULT_MENU_ITEM_HEIGHT: f32 = 36.; #[derive(Debug, Clone, Eq, PartialEq)] @@ -28,6 +30,18 @@ pub struct ActiveLayout { pub variant: String, } +impl ActiveLayout { + pub fn name(&self) -> String { + let mut name = self.layout.clone(); + if !self.variant.is_empty() { + name.push_str(" ("); + name.push_str(&self.variant); + name.push_str(")"); + } + name + } +} + pub struct Common { pub wayland_connection: Option, pub keyboard_layout: Option, @@ -67,6 +81,7 @@ pub enum Message { Focus(SurfaceId), Key(Modifiers, Key, Option), NetworkIcon(Option<&'static str>), + OnScreenKeyboard, SubsurfaceOpened(SurfaceId), OutputEvent(OutputEvent, WlOutput), PowerInfo(Option<(f64, bool, bool)>), @@ -276,6 +291,26 @@ impl + Send + 'static> Common { self.network_icon_opt = network_icon_opt.map(|name| widget::icon::from_name(name).into()); } + Message::OnScreenKeyboard => { + use cosmic_osk_config::Config; + match Config::handler() { + Ok(handler) => { + let mut config = match Config::get_entry(&handler) { + Ok(config) => config, + Err((errs, config)) => { + tracing::warn!("failed to parse OSK config: {:?}", errs); + config + } + }; + if let Err(err) = config.set_always_shown(&handler, !config.always_shown) { + tracing::error!("failed to set OSK always_shown config: {}", err); + } + } + Err(err) => { + tracing::error!("failed to create OSK config handler: {}", err); + } + } + } Message::OutputEvent(output_event, output) => { if self.wayland_connection.is_none() { if let Some(backend) = output.backend().upgrade() { diff --git a/src/greeter.rs b/src/greeter.rs index bb1b78e..16986b4 100644 --- a/src/greeter.rs +++ b/src/greeter.rs @@ -11,6 +11,7 @@ use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity use cosmic::cosmic_config::{self, ConfigSet}; use cosmic::cosmic_theme::{self, CosmicPalette}; use cosmic::desktop::fde::{DesktopEntry, get_languages_from_env}; +use cosmic::iced::core::text::{Ellipsize, EllipsizeHeightLimit}; use cosmic::iced::event::listen_with; use cosmic::iced::event::wayland::OutputEvent; use cosmic::iced::futures::SinkExt; @@ -41,7 +42,7 @@ use std::num::NonZeroU32; use std::process::Stdio; use std::sync::{Arc, LazyLock}; use std::time::{Duration, Instant}; -use std::{fs, io, process}; +use std::{fs, io, process, thread}; use tokio::process::Child; use tokio::time; use tracing::metadata::LevelFilter; @@ -52,7 +53,7 @@ use wayland_client::Proxy; use wayland_client::protocol::wl_output::WlOutput; use zbus::{Connection, proxy}; -use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT}; +use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT, MAX_WIDTH}; use crate::fl; static USERNAME_ID: LazyLock = LazyLock::new(|| iced::id::Id::new("username-id")); @@ -280,6 +281,15 @@ pub fn main() -> Result<(), Box> { sessions }; + match process::Command::new("cosmic-osk").spawn() { + Ok(mut child) => { + thread::spawn(move || child.wait().unwrap()); + } + Err(err) => { + tracing::warn!("failed to spawn cosmic-osk: {}", err); + } + } + let flags = Flags { user_icons: user_datas .iter_mut() @@ -482,9 +492,9 @@ impl App { .window_size .get(&id) .map(|s| s.width) - .unwrap_or(800.); - let menu_width = if window_width > 800. { - 800. + .unwrap_or(MAX_WIDTH); + let menu_width = if window_width > MAX_WIDTH { + MAX_WIDTH } else { window_width }; @@ -584,9 +594,19 @@ impl App { }; let mut input_button = widget::popover( - widget::button::custom(widget::icon::from_name("input-keyboard-symbolic")) + widget::container( + widget::button::custom( + widget::text( + self.common.active_layouts[self.common.current_keyboard_layout].name(), + ) + .ellipsize(Ellipsize::End(EllipsizeHeightLimit::Lines(1))) + .height(16) + .center(), + ) .padding(12.0) .on_press(Message::DropdownToggle(Dropdown::Keyboard)), + ) + .max_width(92), ) .position(widget::popover::Position::Bottom); if matches!(self.dropdown_opt, Some(Dropdown::Keyboard)) { @@ -702,6 +722,13 @@ impl App { text(fl!("accessibility")), widget::tooltip::Position::Top ), + widget::tooltip( + widget::button::custom(widget::icon::from_name("input-keyboard-symbolic")) + .padding(12.0) + .on_press(Message::Common(common::Message::OnScreenKeyboard)), + text(fl!("on-screen-keyboard")), + widget::tooltip::Position::Top, + ), widget::tooltip( input_button, text(fl!("keyboard-layout")), @@ -965,7 +992,7 @@ impl App { appearance }, ))) - .width(Length::Fixed(800.0)); + .width(Length::Fixed(MAX_WIDTH)); let menu = if let Some(t) = self.common.rectangle_tracker.as_ref() { Element::from(t.container((id, false), menu)) } else { @@ -1253,10 +1280,10 @@ impl cosmic::Application for App { let unwrapped_size = size .map(|s| (s.0.unwrap_or(1920), s.1.unwrap_or(1080))) .unwrap_or((1920, 1080)); - let (loc, sub_size) = if unwrapped_size.0 > 800 { + let (loc, sub_size) = if unwrapped_size.0 as f32 > MAX_WIDTH { ( - Point::new(unwrapped_size.0 as f32 / 2. - 400., 32.), - Size::new(800., unwrapped_size.1 as f32 - 32.), + Point::new((unwrapped_size.0 as f32 - MAX_WIDTH) / 2., 32.), + Size::new(MAX_WIDTH, unwrapped_size.1 as f32 - 32.), ) } else { ( @@ -1872,8 +1899,8 @@ impl cosmic::Application for App { tracing::error!("Failed to find subsurface menu id"); return Task::none(); }; - let loc = if size.width > 800. { - Point::new(size.width / 2. - 400., 32.) + let loc = if size.width > MAX_WIDTH { + Point::new((size.width - MAX_WIDTH) / 2., 32.) } else { Point::new(0., 32.) }; diff --git a/src/locker.rs b/src/locker.rs index e358f0c..af2f357 100644 --- a/src/locker.rs +++ b/src/locker.rs @@ -4,6 +4,7 @@ use color_eyre::eyre::WrapErr; use cosmic::app::{Core, Settings, Task}; use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity; +use cosmic::iced::core::text::{Ellipsize, EllipsizeHeightLimit}; use cosmic::iced::event::wayland::{OutputEvent, SessionLockEvent}; use cosmic::iced::futures::{self, SinkExt}; use cosmic::iced::platform_specific::shell::wayland::commands::session_lock::{ @@ -34,7 +35,7 @@ use tracing_subscriber::{EnvFilter, fmt}; use wayland_client::Proxy; use wayland_client::protocol::wl_output::WlOutput; -use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT}; +use crate::common::{self, Common, DEFAULT_MENU_ITEM_HEIGHT, MAX_WIDTH}; use crate::fl; fn lockfile_opt() -> Option { @@ -326,9 +327,9 @@ impl App { .window_size .get(&surface_id) .map(|s| s.width) - .unwrap_or(800.); - let menu_width = if window_width > 800. { - 800. + .unwrap_or(MAX_WIDTH); + let menu_width = if window_width > MAX_WIDTH { + MAX_WIDTH } else { window_width }; @@ -417,9 +418,19 @@ impl App { }; let mut input_button = widget::popover( - widget::button::custom(widget::icon::from_name("input-keyboard-symbolic")) + widget::container( + widget::button::custom( + widget::text( + self.common.active_layouts[self.common.current_keyboard_layout].name(), + ) + .ellipsize(Ellipsize::End(EllipsizeHeightLimit::Lines(1))) + .height(16) + .center(), + ) .padding(12.0) .on_press(Message::DropdownToggle(Dropdown::Keyboard)), + ) + .max_width(92), ) .position(widget::popover::Position::Bottom); if matches!(self.dropdown_opt, Some(Dropdown::Keyboard)) { @@ -443,6 +454,13 @@ impl App { .padding(12.0) .on_press(Message::None), */ + widget::tooltip( + widget::button::custom(widget::icon::from_name("input-keyboard-symbolic")) + .padding(12.0) + .on_press(Message::Common(common::Message::OnScreenKeyboard)), + widget::text(fl!("on-screen-keyboard")), + widget::tooltip::Position::Top, + ), widget::tooltip( input_button, widget::text(fl!("keyboard-layout")), @@ -783,10 +801,10 @@ impl cosmic::Application for App { let unwrapped_size = size .map(|s| (s.0.unwrap_or(1920), s.1.unwrap_or(1080))) .unwrap_or((1920, 1080)); - let (loc, sub_size) = if unwrapped_size.0 > 800 { + let (loc, sub_size) = if unwrapped_size.0 as f32 > MAX_WIDTH { ( Point::new(unwrapped_size.0 as f32 / 2. - 400., 32.), - Size::new(800., unwrapped_size.1 as f32 - 32.), + Size::new(MAX_WIDTH, unwrapped_size.1 as f32 - 32.), ) } else { ( @@ -864,10 +882,10 @@ impl cosmic::Application for App { let unwrapped_size = size .map(|s| (s.0.unwrap_or(1920), s.1.unwrap_or(1080))) .unwrap_or((1920, 1080)); - let (loc, sub_size) = if unwrapped_size.0 > 800 { + let (loc, sub_size) = if unwrapped_size.0 as f32 > MAX_WIDTH { ( Point::new(unwrapped_size.0 as f32 / 2. - 400., 32.), - Size::new(800., unwrapped_size.1 as f32 - 32.), + Size::new(MAX_WIDTH, unwrapped_size.1 as f32 - 32.), ) } else { (Point::ORIGIN, Size::new(1920., 1080.))