Move layout and prompt handling to common code
This commit is contained in:
parent
8812240f50
commit
2fff220392
4 changed files with 308 additions and 215 deletions
138
src/common.rs
138
src/common.rs
|
|
@ -12,15 +12,26 @@ use cosmic::{
|
||||||
iced_runtime::core::window::Id as SurfaceId,
|
iced_runtime::core::window::Id as SurfaceId,
|
||||||
widget,
|
widget,
|
||||||
};
|
};
|
||||||
use cosmic_greeter_daemon::{BgSource, UserData};
|
use cosmic_config::{ConfigSet, CosmicConfigEntry};
|
||||||
use std::collections::HashMap;
|
use cosmic_greeter_daemon::{BgSource, CosmicCompConfig, UserData};
|
||||||
|
use std::{collections::HashMap, sync::Arc};
|
||||||
use wayland_client::protocol::wl_output::WlOutput;
|
use wayland_client::protocol::wl_output::WlOutput;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct ActiveLayout {
|
||||||
|
pub layout: String,
|
||||||
|
pub description: String,
|
||||||
|
pub variant: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Common<M> {
|
pub struct Common<M> {
|
||||||
|
pub active_layouts: Vec<ActiveLayout>,
|
||||||
pub active_surface_id_opt: Option<SurfaceId>,
|
pub active_surface_id_opt: Option<SurfaceId>,
|
||||||
|
pub comp_config_handler: Option<cosmic_config::Config>,
|
||||||
pub core: Core,
|
pub core: Core,
|
||||||
pub error_opt: Option<String>,
|
pub error_opt: Option<String>,
|
||||||
pub input: String,
|
pub fallback_background: widget::image::Handle,
|
||||||
|
pub layouts_opt: Option<Arc<xkb_data::KeyboardLayouts>>,
|
||||||
pub network_icon_opt: Option<&'static str>,
|
pub network_icon_opt: Option<&'static str>,
|
||||||
pub on_output_event: Option<Box<dyn Fn(OutputEvent, WlOutput) -> M>>,
|
pub on_output_event: Option<Box<dyn Fn(OutputEvent, WlOutput) -> M>>,
|
||||||
pub on_session_lock_event: Option<Box<dyn Fn(SessionLockEvent) -> M>>,
|
pub on_session_lock_event: Option<Box<dyn Fn(SessionLockEvent) -> M>>,
|
||||||
|
|
@ -39,11 +50,11 @@ pub struct Common<M> {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
Focus(SurfaceId),
|
Focus(SurfaceId),
|
||||||
Input(String),
|
|
||||||
Key(Modifiers, Key, Option<SmolStr>),
|
Key(Modifiers, Key, Option<SmolStr>),
|
||||||
NetworkIcon(Option<&'static str>),
|
NetworkIcon(Option<&'static str>),
|
||||||
OutputEvent(OutputEvent, WlOutput),
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
PowerInfo(Option<(String, f64)>),
|
PowerInfo(Option<(String, f64)>),
|
||||||
|
Prompt(String, bool, Option<String>),
|
||||||
SessionLockEvent(SessionLockEvent),
|
SessionLockEvent(SessionLockEvent),
|
||||||
Tick,
|
Tick,
|
||||||
Tz(chrono_tz::Tz),
|
Tz(chrono_tz::Tz),
|
||||||
|
|
@ -59,11 +70,35 @@ impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
core.window.show_minimize = false;
|
core.window.show_minimize = false;
|
||||||
core.window.use_template = false;
|
core.window.use_template = false;
|
||||||
|
|
||||||
|
let comp_config_handler = match cosmic_config::Config::new(
|
||||||
|
"com.system76.CosmicComp",
|
||||||
|
CosmicCompConfig::VERSION,
|
||||||
|
) {
|
||||||
|
Ok(config_handler) => Some(config_handler),
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("failed to create cosmic-comp config handler: {}", err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let layouts_opt = match xkb_data::all_keyboard_layouts() {
|
||||||
|
Ok(ok) => Some(Arc::new(ok)),
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("failed to load keyboard layouts: {}", err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let app = Self {
|
let app = Self {
|
||||||
|
active_layouts: Vec::new(),
|
||||||
active_surface_id_opt: None,
|
active_surface_id_opt: None,
|
||||||
|
comp_config_handler,
|
||||||
core,
|
core,
|
||||||
error_opt: None,
|
error_opt: None,
|
||||||
input: String::new(),
|
fallback_background: widget::image::Handle::from_bytes(
|
||||||
|
include_bytes!("../res/background.jpg").as_slice(),
|
||||||
|
),
|
||||||
|
layouts_opt,
|
||||||
network_icon_opt: None,
|
network_icon_opt: None,
|
||||||
on_output_event: None,
|
on_output_event: None,
|
||||||
on_session_lock_event: None,
|
on_session_lock_event: None,
|
||||||
|
|
@ -87,6 +122,27 @@ impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_xkb_config(&self, user_data: &UserData) {
|
||||||
|
if let Some(mut xkb_config) = user_data.xkb_config_opt.clone() {
|
||||||
|
xkb_config.layout = String::new();
|
||||||
|
xkb_config.variant = String::new();
|
||||||
|
for (i, layout) in self.active_layouts.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
xkb_config.layout.push(',');
|
||||||
|
xkb_config.variant.push(',');
|
||||||
|
}
|
||||||
|
xkb_config.layout.push_str(&layout.layout);
|
||||||
|
xkb_config.variant.push_str(&layout.variant);
|
||||||
|
}
|
||||||
|
if let Some(comp_config_handler) = &self.comp_config_handler {
|
||||||
|
match comp_config_handler.set("xkb_config", xkb_config) {
|
||||||
|
Ok(()) => log::info!("updated cosmic-comp xkb_config"),
|
||||||
|
Err(err) => log::error!("failed to update cosmic-comp xkb_config: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_wallpapers(&mut self, user_data: &UserData) {
|
pub fn update_wallpapers(&mut self, user_data: &UserData) {
|
||||||
for (_output, surface_id) in self.surface_ids.iter() {
|
for (_output, surface_id) in self.surface_ids.iter() {
|
||||||
if self.surface_images.contains_key(surface_id) {
|
if self.surface_images.contains_key(surface_id) {
|
||||||
|
|
@ -129,6 +185,55 @@ impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_user_data(&mut self, user_data: &UserData) {
|
||||||
|
self.update_wallpapers(user_data);
|
||||||
|
|
||||||
|
// From cosmic-applet-input-sources
|
||||||
|
if let Some(keyboard_layouts) = &self.layouts_opt {
|
||||||
|
if let Some(xkb_config) = &user_data.xkb_config_opt {
|
||||||
|
self.active_layouts.clear();
|
||||||
|
let config_layouts = xkb_config.layout.split_terminator(',');
|
||||||
|
let config_variants = xkb_config
|
||||||
|
.variant
|
||||||
|
.split_terminator(',')
|
||||||
|
.chain(std::iter::repeat(""));
|
||||||
|
'outer: for (config_layout, config_variant) in config_layouts.zip(config_variants) {
|
||||||
|
for xkb_layout in keyboard_layouts.layouts() {
|
||||||
|
if config_layout != xkb_layout.name() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if config_variant.is_empty() {
|
||||||
|
let active_layout = ActiveLayout {
|
||||||
|
description: xkb_layout.description().to_owned(),
|
||||||
|
layout: config_layout.to_owned(),
|
||||||
|
variant: config_variant.to_owned(),
|
||||||
|
};
|
||||||
|
self.active_layouts.push(active_layout);
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(xkb_variants) = xkb_layout.variants() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
for xkb_variant in xkb_variants {
|
||||||
|
if config_variant != xkb_variant.name() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let active_layout = ActiveLayout {
|
||||||
|
description: xkb_variant.description().to_owned(),
|
||||||
|
layout: config_layout.to_owned(),
|
||||||
|
variant: config_variant.to_owned(),
|
||||||
|
};
|
||||||
|
self.active_layouts.push(active_layout);
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log::info!("{:?}", self.active_layouts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, message: Message) -> Task<M> {
|
pub fn update(&mut self, message: Message) -> Task<M> {
|
||||||
match message {
|
match message {
|
||||||
Message::Focus(surface_id) => {
|
Message::Focus(surface_id) => {
|
||||||
|
|
@ -141,9 +246,6 @@ impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
return widget::text_input::focus(text_input_id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Input(input) => {
|
|
||||||
self.input = input;
|
|
||||||
}
|
|
||||||
Message::Key(modifiers, key, text) => {
|
Message::Key(modifiers, key, text) => {
|
||||||
// Uncaptured keys with only shift modifiers go to the password box
|
// Uncaptured keys with only shift modifiers go to the password box
|
||||||
if !modifiers.logo()
|
if !modifiers.logo()
|
||||||
|
|
@ -152,7 +254,9 @@ impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
&& matches!(key, Key::Character(_))
|
&& matches!(key, Key::Character(_))
|
||||||
{
|
{
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
self.input.push_str(&text);
|
if let Some((_, _, Some(value))) = &mut self.prompt_opt {
|
||||||
|
value.push_str(&text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(surface_id) = self.active_surface_id_opt {
|
if let Some(surface_id) = self.active_surface_id_opt {
|
||||||
|
|
@ -177,6 +281,22 @@ impl<M: From<Message> + Send + 'static> Common<M> {
|
||||||
Message::PowerInfo(power_info_opt) => {
|
Message::PowerInfo(power_info_opt) => {
|
||||||
self.power_info_opt = power_info_opt;
|
self.power_info_opt = power_info_opt;
|
||||||
}
|
}
|
||||||
|
Message::Prompt(prompt, secret, value_opt) => {
|
||||||
|
let prompt_was_none = self.prompt_opt.is_none();
|
||||||
|
self.prompt_opt = Some((prompt, secret, value_opt));
|
||||||
|
if prompt_was_none {
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
log::info!("focus surface found id {:?}", text_input_id);
|
||||||
|
return widget::text_input::focus(text_input_id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::SessionLockEvent(lock_event) => {
|
Message::SessionLockEvent(lock_event) => {
|
||||||
if let Some(on_session_lock_event) = &self.on_session_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)));
|
return Task::done(cosmic::Action::App(on_session_lock_event(lock_event)));
|
||||||
|
|
|
||||||
167
src/greeter.rs
167
src/greeter.rs
|
|
@ -11,7 +11,7 @@ use cosmic::surface;
|
||||||
use cosmic::widget::text;
|
use cosmic::widget::text;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Element,
|
Element,
|
||||||
cosmic_config::{self, ConfigSet, CosmicConfigEntry},
|
cosmic_config::{self, ConfigSet},
|
||||||
executor,
|
executor,
|
||||||
iced::{
|
iced::{
|
||||||
self, Background, Border, Length, Subscription, alignment,
|
self, Background, Border, Length, Subscription, alignment,
|
||||||
|
|
@ -27,7 +27,6 @@ use cosmic::{
|
||||||
iced_runtime::core::window::Id as SurfaceId,
|
iced_runtime::core::window::Id as SurfaceId,
|
||||||
theme, widget,
|
theme, widget,
|
||||||
};
|
};
|
||||||
use cosmic_comp_config::CosmicCompConfig;
|
|
||||||
use cosmic_greeter_config::Config as CosmicGreeterConfig;
|
use cosmic_greeter_config::Config as CosmicGreeterConfig;
|
||||||
use cosmic_greeter_daemon::UserData;
|
use cosmic_greeter_daemon::UserData;
|
||||||
use greetd_ipc::Request;
|
use greetd_ipc::Request;
|
||||||
|
|
@ -260,34 +259,11 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
||||||
sessions
|
sessions
|
||||||
};
|
};
|
||||||
|
|
||||||
let layouts_opt = match xkb_data::all_keyboard_layouts() {
|
|
||||||
Ok(ok) => Some(Arc::new(ok)),
|
|
||||||
Err(err) => {
|
|
||||||
log::warn!("failed to load keyboard layouts: {}", err);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let comp_config_handler =
|
|
||||||
match cosmic_config::Config::new("com.system76.CosmicComp", CosmicCompConfig::VERSION) {
|
|
||||||
Ok(config_handler) => Some(config_handler),
|
|
||||||
Err(err) => {
|
|
||||||
log::error!("failed to create cosmic-comp config handler: {}", err);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let fallback_background =
|
|
||||||
widget::image::Handle::from_bytes(include_bytes!("../res/background.jpg").as_slice());
|
|
||||||
|
|
||||||
let flags = Flags {
|
let flags = Flags {
|
||||||
user_datas,
|
user_datas,
|
||||||
sessions,
|
sessions,
|
||||||
layouts_opt,
|
|
||||||
comp_config_handler,
|
|
||||||
greeter_config,
|
greeter_config,
|
||||||
greeter_config_handler,
|
greeter_config_handler,
|
||||||
fallback_background,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let settings = Settings::default().no_main_window(true);
|
let settings = Settings::default().no_main_window(true);
|
||||||
|
|
@ -301,11 +277,8 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
||||||
pub struct Flags {
|
pub struct Flags {
|
||||||
user_datas: Vec<UserData>,
|
user_datas: Vec<UserData>,
|
||||||
sessions: HashMap<String, (Vec<String>, Vec<String>)>,
|
sessions: HashMap<String, (Vec<String>, Vec<String>)>,
|
||||||
layouts_opt: Option<Arc<xkb_data::KeyboardLayouts>>,
|
|
||||||
comp_config_handler: Option<cosmic_config::Config>,
|
|
||||||
greeter_config: CosmicGreeterConfig,
|
greeter_config: CosmicGreeterConfig,
|
||||||
greeter_config_handler: Option<cosmic_config::Config>,
|
greeter_config_handler: Option<cosmic_config::Config>,
|
||||||
fallback_background: widget::image::Handle,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -320,13 +293,6 @@ pub enum SocketState {
|
||||||
Error(Arc<io::Error>),
|
Error(Arc<io::Error>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct ActiveLayout {
|
|
||||||
layout: String,
|
|
||||||
description: String,
|
|
||||||
variant: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum DialogPage {
|
pub enum DialogPage {
|
||||||
Restart(Instant),
|
Restart(Instant),
|
||||||
|
|
@ -377,7 +343,6 @@ pub enum Message {
|
||||||
Heartbeat,
|
Heartbeat,
|
||||||
KeyboardLayout(usize),
|
KeyboardLayout(usize),
|
||||||
Login,
|
Login,
|
||||||
Prompt(String, bool, Option<String>),
|
|
||||||
Reconnect,
|
Reconnect,
|
||||||
Restart,
|
Restart,
|
||||||
Session(String),
|
Session(String),
|
||||||
|
|
@ -404,7 +369,6 @@ pub struct App {
|
||||||
selected_username: NameIndexPair,
|
selected_username: NameIndexPair,
|
||||||
session_names: Vec<String>,
|
session_names: Vec<String>,
|
||||||
selected_session: String,
|
selected_session: String,
|
||||||
active_layouts: Vec<ActiveLayout>,
|
|
||||||
dialog_page_opt: Option<DialogPage>,
|
dialog_page_opt: Option<DialogPage>,
|
||||||
dropdown_opt: Option<Dropdown>,
|
dropdown_opt: Option<Dropdown>,
|
||||||
heartbeat_handle: Option<cosmic::iced::task::Handle>,
|
heartbeat_handle: Option<cosmic::iced::task::Handle>,
|
||||||
|
|
@ -495,8 +459,8 @@ impl App {
|
||||||
)
|
)
|
||||||
.position(widget::popover::Position::Bottom);
|
.position(widget::popover::Position::Bottom);
|
||||||
if matches!(self.dropdown_opt, Some(Dropdown::Keyboard)) {
|
if matches!(self.dropdown_opt, Some(Dropdown::Keyboard)) {
|
||||||
let mut items = Vec::with_capacity(self.active_layouts.len());
|
let mut items = Vec::with_capacity(self.common.active_layouts.len());
|
||||||
for (i, layout) in self.active_layouts.iter().enumerate() {
|
for (i, layout) in self.common.active_layouts.iter().enumerate() {
|
||||||
items.push(menu_checklist(
|
items.push(menu_checklist(
|
||||||
&layout.description,
|
&layout.description,
|
||||||
i == 0,
|
i == 0,
|
||||||
|
|
@ -648,16 +612,22 @@ impl App {
|
||||||
.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,
|
value.as_str(),
|
||||||
Some(Message::Prompt(
|
Some(
|
||||||
prompt.clone(),
|
common::Message::Prompt(
|
||||||
!*secret,
|
prompt.clone(),
|
||||||
Some(value.clone()),
|
!*secret,
|
||||||
)),
|
Some(value.clone()),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
*secret,
|
*secret,
|
||||||
)
|
)
|
||||||
.id(text_input_id)
|
.id(text_input_id)
|
||||||
.on_input(|input| common::Message::Input(input).into())
|
.on_input(|input| {
|
||||||
|
common::Message::Prompt(prompt.clone(), *secret, Some(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
|
||||||
|
|
@ -773,6 +743,7 @@ impl App {
|
||||||
None => popover.into(),
|
None => popover.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a [`Request`] to the greetd IPC subscription.
|
/// Send a [`Request`] to the greetd IPC subscription.
|
||||||
fn send_request(&self, request: Request) {
|
fn send_request(&self, request: Request) {
|
||||||
if let Some(ref sender) = self.greetd_sender {
|
if let Some(ref sender) = self.greetd_sender {
|
||||||
|
|
@ -793,27 +764,10 @@ impl App {
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mut xkb_config) = user_data.xkb_config_opt.clone() {
|
self.common.set_xkb_config(&user_data);
|
||||||
xkb_config.layout = String::new();
|
|
||||||
xkb_config.variant = String::new();
|
|
||||||
for (i, layout) in self.active_layouts.iter().enumerate() {
|
|
||||||
if i > 0 {
|
|
||||||
xkb_config.layout.push(',');
|
|
||||||
xkb_config.variant.push(',');
|
|
||||||
}
|
|
||||||
xkb_config.layout.push_str(&layout.layout);
|
|
||||||
xkb_config.variant.push_str(&layout.variant);
|
|
||||||
}
|
|
||||||
if let Some(comp_config_handler) = &self.flags.comp_config_handler {
|
|
||||||
match comp_config_handler.set("xkb_config", xkb_config) {
|
|
||||||
Ok(()) => log::info!("updated cosmic-comp xkb_config"),
|
|
||||||
Err(err) => log::error!("failed to update cosmic-comp xkb_config: {}", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_user_config(&mut self) -> Task<Message> {
|
fn update_user_data(&mut self) -> Task<Message> {
|
||||||
let user_data = match self
|
let user_data = match self
|
||||||
.selected_username
|
.selected_username
|
||||||
.data_idx
|
.data_idx
|
||||||
|
|
@ -825,54 +779,10 @@ impl App {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.common.update_wallpapers(&user_data);
|
self.common.update_user_data(&user_data);
|
||||||
|
|
||||||
// From cosmic-applet-input-sources
|
// Ensure that user's xkb config is used
|
||||||
if let Some(keyboard_layouts) = &self.flags.layouts_opt {
|
self.common.set_xkb_config(&user_data);
|
||||||
if let Some(xkb_config) = &user_data.xkb_config_opt {
|
|
||||||
self.active_layouts.clear();
|
|
||||||
let config_layouts = xkb_config.layout.split_terminator(',');
|
|
||||||
let config_variants = xkb_config
|
|
||||||
.variant
|
|
||||||
.split_terminator(',')
|
|
||||||
.chain(std::iter::repeat(""));
|
|
||||||
for (config_layout, config_variant) in config_layouts.zip(config_variants) {
|
|
||||||
for xkb_layout in keyboard_layouts.layouts() {
|
|
||||||
if config_layout != xkb_layout.name() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if config_variant.is_empty() {
|
|
||||||
let active_layout = ActiveLayout {
|
|
||||||
description: xkb_layout.description().to_owned(),
|
|
||||||
layout: config_layout.to_owned(),
|
|
||||||
variant: config_variant.to_owned(),
|
|
||||||
};
|
|
||||||
self.active_layouts.push(active_layout);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(xkb_variants) = xkb_layout.variants() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
for xkb_variant in xkb_variants {
|
|
||||||
if config_variant != xkb_variant.name() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let active_layout = ActiveLayout {
|
|
||||||
description: xkb_variant.description().to_owned(),
|
|
||||||
layout: config_layout.to_owned(),
|
|
||||||
variant: config_variant.to_owned(),
|
|
||||||
};
|
|
||||||
self.active_layouts.push(active_layout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log::info!("{:?}", self.active_layouts);
|
|
||||||
|
|
||||||
// Ensure that user's xkb config is used
|
|
||||||
self.set_xkb_config();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match &user_data.theme_opt {
|
match &user_data.theme_opt {
|
||||||
Some(theme) => {
|
Some(theme) => {
|
||||||
|
|
@ -958,7 +868,6 @@ impl cosmic::Application for App {
|
||||||
selected_username,
|
selected_username,
|
||||||
session_names,
|
session_names,
|
||||||
selected_session,
|
selected_session,
|
||||||
active_layouts: Vec::new(),
|
|
||||||
dialog_page_opt: None,
|
dialog_page_opt: None,
|
||||||
dropdown_opt: None,
|
dropdown_opt: None,
|
||||||
heartbeat_handle: None,
|
heartbeat_handle: None,
|
||||||
|
|
@ -1059,7 +968,7 @@ impl cosmic::Application for App {
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
return Task::batch([
|
return Task::batch([
|
||||||
self.update_user_config(),
|
self.update_user_data(),
|
||||||
get_layer_surface(SctkLayerSurfaceSettings {
|
get_layer_surface(SctkLayerSurfaceSettings {
|
||||||
id: surface_id,
|
id: surface_id,
|
||||||
layer: Layer::Overlay,
|
layer: Layer::Overlay,
|
||||||
|
|
@ -1116,27 +1025,6 @@ impl cosmic::Application for App {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Prompt(prompt, secret, value_opt) => {
|
|
||||||
let value_was_some = self
|
|
||||||
.common
|
|
||||||
.prompt_opt
|
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |(_, _, x)| x.is_some());
|
|
||||||
let value_is_some = value_opt.is_some();
|
|
||||||
self.common.prompt_opt = Some((prompt, secret, value_opt));
|
|
||||||
if value_is_some && !value_was_some {
|
|
||||||
if let Some(surface_id) = self.common.active_surface_id_opt {
|
|
||||||
if let Some(text_input_id) = self
|
|
||||||
.common
|
|
||||||
.surface_names
|
|
||||||
.get(&surface_id)
|
|
||||||
.and_then(|id| self.common.text_input_ids.get(id))
|
|
||||||
{
|
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message::Session(selected_session) => {
|
Message::Session(selected_session) => {
|
||||||
self.selected_session = selected_session;
|
self.selected_session = selected_session;
|
||||||
if self.dropdown_opt == Some(Dropdown::Session) {
|
if self.dropdown_opt == Some(Dropdown::Session) {
|
||||||
|
|
@ -1241,7 +1129,6 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Auth(response) => {
|
Message::Auth(response) => {
|
||||||
self.common.input.clear();
|
|
||||||
self.common.prompt_opt = None;
|
self.common.prompt_opt = None;
|
||||||
self.common.error_opt = None;
|
self.common.error_opt = None;
|
||||||
self.send_request(Request::PostAuthMessageResponse { response });
|
self.send_request(Request::PostAuthMessageResponse { response });
|
||||||
|
|
@ -1262,7 +1149,7 @@ impl cosmic::Application for App {
|
||||||
self.send_request(Request::CancelSession);
|
self.send_request(Request::CancelSession);
|
||||||
}
|
}
|
||||||
Message::Reconnect => {
|
Message::Reconnect => {
|
||||||
return self.update_user_config();
|
return self.update_user_data();
|
||||||
}
|
}
|
||||||
Message::DialogCancel => {
|
Message::DialogCancel => {
|
||||||
self.dialog_page_opt = None;
|
self.dialog_page_opt = None;
|
||||||
|
|
@ -1305,8 +1192,8 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::KeyboardLayout(layout_i) => {
|
Message::KeyboardLayout(layout_i) => {
|
||||||
if layout_i < self.active_layouts.len() {
|
if layout_i < self.common.active_layouts.len() {
|
||||||
self.active_layouts.swap(0, layout_i);
|
self.common.active_layouts.swap(0, layout_i);
|
||||||
self.set_xkb_config();
|
self.set_xkb_config();
|
||||||
}
|
}
|
||||||
if self.dropdown_opt == Some(Dropdown::Keyboard) {
|
if self.dropdown_opt == Some(Dropdown::Keyboard) {
|
||||||
|
|
@ -1400,7 +1287,7 @@ impl cosmic::Application for App {
|
||||||
.common
|
.common
|
||||||
.surface_images
|
.surface_images
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.unwrap_or(&self.flags.fallback_background);
|
.unwrap_or(&self.common.fallback_background);
|
||||||
widget::image(img)
|
widget::image(img)
|
||||||
.content_fit(iced::ContentFit::Cover)
|
.content_fit(iced::ContentFit::Cover)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ use std::time::Duration;
|
||||||
use tokio::net::UnixStream;
|
use tokio::net::UnixStream;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
use crate::common;
|
||||||
|
|
||||||
pub fn subscription() -> Subscription<Message> {
|
pub fn subscription() -> Subscription<Message> {
|
||||||
struct GreetdSubscription;
|
struct GreetdSubscription;
|
||||||
Subscription::run_with_id(
|
Subscription::run_with_id(
|
||||||
|
|
@ -53,27 +55,36 @@ pub fn subscription() -> Subscription<Message> {
|
||||||
} => match auth_message_type {
|
} => match auth_message_type {
|
||||||
greetd_ipc::AuthMessageType::Secret => {
|
greetd_ipc::AuthMessageType::Secret => {
|
||||||
_ = sender
|
_ = sender
|
||||||
.send(Message::Prompt(
|
.send(
|
||||||
auth_message,
|
common::Message::Prompt(
|
||||||
true,
|
auth_message,
|
||||||
Some(String::new()),
|
true,
|
||||||
))
|
Some(String::new()),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
greetd_ipc::AuthMessageType::Visible => {
|
greetd_ipc::AuthMessageType::Visible => {
|
||||||
_ = sender
|
_ = sender
|
||||||
.send(Message::Prompt(
|
.send(
|
||||||
auth_message,
|
common::Message::Prompt(
|
||||||
false,
|
auth_message,
|
||||||
Some(String::new()),
|
false,
|
||||||
))
|
Some(String::new()),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
//TODO: treat error type differently?
|
//TODO: treat error type differently?
|
||||||
greetd_ipc::AuthMessageType::Info
|
greetd_ipc::AuthMessageType::Info
|
||||||
| greetd_ipc::AuthMessageType::Error => {
|
| greetd_ipc::AuthMessageType::Error => {
|
||||||
_ = sender
|
_ = sender
|
||||||
.send(Message::Prompt(auth_message, false, None))
|
.send(
|
||||||
|
common::Message::Prompt(auth_message, false, None)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
185
src/locker.rs
185
src/locker.rs
|
|
@ -9,7 +9,7 @@ use cosmic::surface;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Element, executor,
|
Element, executor,
|
||||||
iced::{
|
iced::{
|
||||||
self, Length, Subscription, alignment,
|
self, Background, Border, Length, Subscription, alignment,
|
||||||
event::wayland::{OutputEvent, SessionLockEvent},
|
event::wayland::{OutputEvent, SessionLockEvent},
|
||||||
futures::{self, SinkExt},
|
futures::{self, SinkExt},
|
||||||
platform_specific::shell::wayland::commands::session_lock::{
|
platform_specific::shell::wayland::commands::session_lock::{
|
||||||
|
|
@ -17,7 +17,7 @@ use cosmic::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
iced_runtime::core::window::Id as SurfaceId,
|
iced_runtime::core::window::Id as SurfaceId,
|
||||||
widget,
|
theme, widget,
|
||||||
};
|
};
|
||||||
use cosmic_config::CosmicConfigEntry;
|
use cosmic_config::CosmicConfigEntry;
|
||||||
use cosmic_greeter_daemon::{TimeAppletConfig, UserData};
|
use cosmic_greeter_daemon::{TimeAppletConfig, UserData};
|
||||||
|
|
@ -35,7 +35,10 @@ 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};
|
use crate::{
|
||||||
|
common::{self, Common},
|
||||||
|
fl,
|
||||||
|
};
|
||||||
|
|
||||||
fn lockfile_opt() -> Option<PathBuf> {
|
fn lockfile_opt() -> Option<PathBuf> {
|
||||||
let runtime_dir = dirs::runtime_dir()?;
|
let runtime_dir = dirs::runtime_dir()?;
|
||||||
|
|
@ -52,13 +55,9 @@ pub fn main(user: pwd::Passwd) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// We are already the user at this point
|
// We are already the user at this point
|
||||||
user_data.load_config_as_user();
|
user_data.load_config_as_user();
|
||||||
|
|
||||||
let fallback_background =
|
|
||||||
widget::image::Handle::from_bytes(include_bytes!("../res/background.jpg").as_slice());
|
|
||||||
|
|
||||||
let flags = Flags {
|
let flags = Flags {
|
||||||
user_data,
|
user_data,
|
||||||
lockfile_opt: lockfile_opt(),
|
lockfile_opt: lockfile_opt(),
|
||||||
fallback_background,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let settings = Settings::default().no_main_window(true);
|
let settings = Settings::default().no_main_window(true);
|
||||||
|
|
@ -103,11 +102,9 @@ impl Conversation {
|
||||||
|
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
self.msg_tx
|
self.msg_tx
|
||||||
.send(cosmic::Action::App(Message::Prompt(
|
.send(cosmic::Action::App(
|
||||||
prompt.to_string(),
|
common::Message::Prompt(prompt.to_string(), secret, Some(String::new())).into(),
|
||||||
secret,
|
))
|
||||||
Some(String::new()),
|
|
||||||
)))
|
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
|
@ -134,11 +131,9 @@ impl Conversation {
|
||||||
|
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
self.msg_tx
|
self.msg_tx
|
||||||
.send(cosmic::Action::App(Message::Prompt(
|
.send(cosmic::Action::App(
|
||||||
prompt.to_string(),
|
common::Message::Prompt(prompt.to_string(), false, None).into(),
|
||||||
false,
|
))
|
||||||
None,
|
|
||||||
)))
|
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
|
@ -182,7 +177,12 @@ impl pam_client::ConversationHandler for Conversation {
|
||||||
pub struct Flags {
|
pub struct Flags {
|
||||||
user_data: UserData,
|
user_data: UserData,
|
||||||
lockfile_opt: Option<PathBuf>,
|
lockfile_opt: Option<PathBuf>,
|
||||||
fallback_background: widget::image::Handle,
|
}
|
||||||
|
|
||||||
|
///TODO: this is custom code that should be better handled by libcosmic
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Dropdown {
|
||||||
|
Keyboard,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages that are used specifically by our [`App`].
|
/// Messages that are used specifically by our [`App`].
|
||||||
|
|
@ -194,12 +194,13 @@ pub enum Message {
|
||||||
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),
|
DropdownToggle(Dropdown),
|
||||||
|
KeyboardLayout(usize),
|
||||||
Inhibit(Arc<OwnedFd>),
|
Inhibit(Arc<OwnedFd>),
|
||||||
Prompt(String, bool, Option<String>),
|
|
||||||
Submit(String),
|
Submit(String),
|
||||||
Surface(surface::Action),
|
Surface(surface::Action),
|
||||||
Suspend,
|
Suspend,
|
||||||
|
TimeAppletConfig(TimeAppletConfig),
|
||||||
Error(String),
|
Error(String),
|
||||||
Lock,
|
Lock,
|
||||||
Unlock,
|
Unlock,
|
||||||
|
|
@ -236,6 +237,7 @@ pub struct App {
|
||||||
common: Common<Message>,
|
common: Common<Message>,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
state: State,
|
state: State,
|
||||||
|
dropdown_opt: Option<Dropdown>,
|
||||||
inhibit_opt: Option<Arc<OwnedFd>>,
|
inhibit_opt: Option<Arc<OwnedFd>>,
|
||||||
value_tx_opt: Option<mpsc::Sender<String>>,
|
value_tx_opt: Option<mpsc::Sender<String>>,
|
||||||
}
|
}
|
||||||
|
|
@ -270,22 +272,88 @@ impl App {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: move code for custom dropdowns to libcosmic
|
||||||
|
let menu_checklist = |label, value, message| {
|
||||||
|
Element::from(
|
||||||
|
widget::menu::menu_button(vec![
|
||||||
|
if value {
|
||||||
|
widget::icon::from_name("object-select-symbolic")
|
||||||
|
.size(16)
|
||||||
|
.icon()
|
||||||
|
.width(Length::Fixed(16.0))
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
widget::Space::with_width(Length::Fixed(17.0)).into()
|
||||||
|
},
|
||||||
|
widget::Space::with_width(Length::Fixed(8.0)).into(),
|
||||||
|
widget::text(label)
|
||||||
|
.align_x(iced::alignment::Horizontal::Left)
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.on_press(message),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let dropdown_menu = |items| {
|
||||||
|
widget::container(widget::column::with_children(items))
|
||||||
|
.padding(1)
|
||||||
|
//TODO: move style to libcosmic
|
||||||
|
.class(theme::Container::custom(|theme| {
|
||||||
|
let cosmic = theme.cosmic();
|
||||||
|
let component = &cosmic.background.component;
|
||||||
|
widget::container::Style {
|
||||||
|
icon_color: Some(component.on.into()),
|
||||||
|
text_color: Some(component.on.into()),
|
||||||
|
background: Some(Background::Color(component.base.into())),
|
||||||
|
border: Border {
|
||||||
|
radius: 8.0.into(),
|
||||||
|
width: 1.0,
|
||||||
|
color: component.divider.into(),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.width(Length::Fixed(240.0))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut input_button = widget::popover(
|
||||||
|
widget::button::custom(widget::icon::from_name("input-keyboard-symbolic"))
|
||||||
|
.padding(12.0)
|
||||||
|
.on_press(Message::DropdownToggle(Dropdown::Keyboard)),
|
||||||
|
)
|
||||||
|
.position(widget::popover::Position::Bottom);
|
||||||
|
if matches!(self.dropdown_opt, Some(Dropdown::Keyboard)) {
|
||||||
|
let mut items = Vec::with_capacity(self.common.active_layouts.len());
|
||||||
|
for (i, layout) in self.common.active_layouts.iter().enumerate() {
|
||||||
|
items.push(menu_checklist(
|
||||||
|
&layout.description,
|
||||||
|
i == 0,
|
||||||
|
Message::KeyboardLayout(i),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
input_button = input_button.popup(dropdown_menu(items));
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: implement these buttons
|
//TODO: implement these buttons
|
||||||
let button_row = iced::widget::row![
|
let button_row = iced::widget::row![
|
||||||
|
/*TODO: greeter accessibility options
|
||||||
widget::button::custom(widget::icon::from_name(
|
widget::button::custom(widget::icon::from_name(
|
||||||
"applications-accessibility-symbolic"
|
"applications-accessibility-symbolic"
|
||||||
))
|
))
|
||||||
.padding(12.0)
|
.padding(12.0)
|
||||||
.on_press(Message::None),
|
.on_press(Message::None),
|
||||||
widget::button::custom(widget::icon::from_name("input-keyboard-symbolic"))
|
*/
|
||||||
.padding(12.0)
|
widget::tooltip(
|
||||||
.on_press(Message::None),
|
input_button,
|
||||||
widget::button::custom(widget::icon::from_name("system-users-symbolic"))
|
widget::text(fl!("keyboard-layout")),
|
||||||
.padding(12.0)
|
widget::tooltip::Position::Top
|
||||||
.on_press(Message::None),
|
),
|
||||||
widget::button::custom(widget::icon::from_name("system-suspend-symbolic"))
|
widget::tooltip(
|
||||||
.padding(12.0)
|
widget::button::custom(widget::icon::from_name("system-suspend-symbolic"))
|
||||||
.on_press(Message::Suspend),
|
.padding(12.0)
|
||||||
|
.on_press(Message::Suspend),
|
||||||
|
widget::text(fl!("suspend")),
|
||||||
|
widget::tooltip::Position::Top
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.padding([16.0, 0.0, 0.0, 0.0])
|
.padding([16.0, 0.0, 0.0, 0.0])
|
||||||
.spacing(8.0);
|
.spacing(8.0);
|
||||||
|
|
@ -340,16 +408,21 @@ impl App {
|
||||||
|
|
||||||
let mut text_input = widget::secure_input(
|
let mut text_input = widget::secure_input(
|
||||||
prompt.clone(),
|
prompt.clone(),
|
||||||
&self.common.input,
|
value.as_str(),
|
||||||
Some(Message::Prompt(
|
Some(
|
||||||
prompt.clone(),
|
common::Message::Prompt(
|
||||||
!*secret,
|
prompt.clone(),
|
||||||
Some(value.clone()),
|
!*secret,
|
||||||
)),
|
Some(value.clone()),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
*secret,
|
*secret,
|
||||||
)
|
)
|
||||||
.id(text_input_id)
|
.id(text_input_id)
|
||||||
.on_input(|input| common::Message::Input(input).into())
|
.on_input(|input| {
|
||||||
|
common::Message::Prompt(prompt.clone(), *secret, Some(input)).into()
|
||||||
|
})
|
||||||
.on_submit(Message::Submit);
|
.on_submit(Message::Submit);
|
||||||
|
|
||||||
if *secret {
|
if *secret {
|
||||||
|
|
@ -434,6 +507,7 @@ impl cosmic::Application for App {
|
||||||
Message::OutputEvent(output_event, output)
|
Message::OutputEvent(output_event, output)
|
||||||
}));
|
}));
|
||||||
common.on_session_lock_event = Some(Box::new(|evt| Message::SessionLockEvent(evt)));
|
common.on_session_lock_event = Some(Box::new(|evt| Message::SessionLockEvent(evt)));
|
||||||
|
common.update_user_data(&flags.user_data);
|
||||||
|
|
||||||
let already_locked = match flags.lockfile_opt {
|
let already_locked = match flags.lockfile_opt {
|
||||||
Some(ref lockfile) => lockfile.exists(),
|
Some(ref lockfile) => lockfile.exists(),
|
||||||
|
|
@ -444,6 +518,7 @@ impl cosmic::Application for App {
|
||||||
common,
|
common,
|
||||||
flags,
|
flags,
|
||||||
state: State::Unlocked,
|
state: State::Unlocked,
|
||||||
|
dropdown_opt: None,
|
||||||
inhibit_opt: None,
|
inhibit_opt: None,
|
||||||
value_tx_opt: None,
|
value_tx_opt: None,
|
||||||
};
|
};
|
||||||
|
|
@ -783,31 +858,28 @@ impl cosmic::Application for App {
|
||||||
self.common.surface_images.clear();
|
self.common.surface_images.clear();
|
||||||
self.common.update_wallpapers(&self.flags.user_data);
|
self.common.update_wallpapers(&self.flags.user_data);
|
||||||
}
|
}
|
||||||
Message::TimeAppletConfig(config) => {
|
Message::DropdownToggle(dropdown) => {
|
||||||
self.flags.user_data.time_applet_config = config;
|
if self.dropdown_opt == Some(dropdown) {
|
||||||
|
self.dropdown_opt = None;
|
||||||
|
} else {
|
||||||
|
self.dropdown_opt = Some(dropdown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::Inhibit(inhibit) => {
|
Message::Inhibit(inhibit) => {
|
||||||
self.inhibit_opt = Some(inhibit);
|
self.inhibit_opt = Some(inhibit);
|
||||||
}
|
}
|
||||||
Message::Prompt(prompt, secret, value_opt) => {
|
Message::KeyboardLayout(layout_i) => {
|
||||||
let prompt_was_none = self.common.prompt_opt.is_none();
|
if layout_i < self.common.active_layouts.len() {
|
||||||
self.common.prompt_opt = Some((prompt, secret, value_opt));
|
self.common.active_layouts.swap(0, layout_i);
|
||||||
if prompt_was_none {
|
self.common.set_xkb_config(&self.flags.user_data);
|
||||||
if let Some(surface_id) = self.common.active_surface_id_opt {
|
}
|
||||||
if let Some(text_input_id) = self
|
if self.dropdown_opt == Some(Dropdown::Keyboard) {
|
||||||
.common
|
self.dropdown_opt = None
|
||||||
.surface_names
|
|
||||||
.get(&surface_id)
|
|
||||||
.and_then(|id| self.common.text_input_ids.get(id))
|
|
||||||
{
|
|
||||||
log::info!("focus surface found id {:?}", text_input_id);
|
|
||||||
return widget::text_input::focus(text_input_id.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Submit(value) => {
|
Message::Submit(value) => {
|
||||||
self.common.input.clear();
|
self.common.prompt_opt = None;
|
||||||
|
self.common.error_opt = None;
|
||||||
match self.value_tx_opt.take() {
|
match self.value_tx_opt.take() {
|
||||||
Some(value_tx) => {
|
Some(value_tx) => {
|
||||||
// Clear errors
|
// Clear errors
|
||||||
|
|
@ -828,6 +900,9 @@ impl cosmic::Application for App {
|
||||||
cosmic::task::message(cosmic::Action::App(Message::Error(err.to_string())))
|
cosmic::task::message(cosmic::Action::App(Message::Error(err.to_string())))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Message::TimeAppletConfig(config) => {
|
||||||
|
self.flags.user_data.time_applet_config = config;
|
||||||
|
}
|
||||||
Message::Error(error) => {
|
Message::Error(error) => {
|
||||||
self.common.error_opt = Some(error);
|
self.common.error_opt = Some(error);
|
||||||
}
|
}
|
||||||
|
|
@ -914,7 +989,7 @@ impl cosmic::Application for App {
|
||||||
.common
|
.common
|
||||||
.surface_images
|
.surface_images
|
||||||
.get(&surface_id)
|
.get(&surface_id)
|
||||||
.unwrap_or(&self.flags.fallback_background);
|
.unwrap_or(&self.common.fallback_background);
|
||||||
widget::image(img)
|
widget::image(img)
|
||||||
.content_fit(iced::ContentFit::Cover)
|
.content_fit(iced::ContentFit::Cover)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue