diff --git a/src/popover.rs b/src/popover.rs index 71cba64e..f8b99650 100644 --- a/src/popover.rs +++ b/src/popover.rs @@ -1,24 +1,24 @@ /*! The layout chooser popover */ -use gio; -use gtk; -use std::ffi::CString; -use std::cmp::Ordering; use crate::actors; -use crate::layout::c::{ Bounds, EekGtkKeyboard }; -use crate::locale::{ OwnedTranslation, compare_current_locale }; +use crate::layout::c::{Bounds, EekGtkKeyboard}; +use crate::locale::{compare_current_locale, OwnedTranslation}; use crate::logging; use crate::receiver; use crate::resources; use crate::state; +use gio; +use gtk; +use std::cmp::Ordering; +use std::ffi::CString; // Traits +use crate::logging::Warn; use gio::prelude::ActionMapExt; use gio::prelude::SettingsExt; use glib::translate::FromGlibPtrNone; use glib::variant::ToVariant; use gtk::prelude::*; -use crate::logging::Warn; mod c { use std::os::raw::c_char; @@ -34,22 +34,23 @@ mod variants { use glib_sys; use std::os::raw::c_char; - use glib::ToVariant; use glib::translate::FromGlibPtrFull; use glib::translate::FromGlibPtrNone; use glib::translate::ToGlibPtr; + use glib::ToVariant; /// Unpacks tuple & array variants fn get_items(items: glib::Variant) -> Vec { let variant_naked = items.to_glib_none().0; let count = unsafe { glib_sys::g_variant_n_children(variant_naked) }; - (0..count).map(|index| - unsafe { - glib::Variant::from_glib_full( - glib_sys::g_variant_get_child_value(variant_naked, index) - ) - } - ).collect() + (0..count) + .map(|index| unsafe { + glib::Variant::from_glib_full(glib_sys::g_variant_get_child_value( + variant_naked, + index, + )) + }) + .collect() } /// Unpacks "a(ss)" variants @@ -57,19 +58,14 @@ mod variants { get_items(items) .into_iter() .map(get_items) - .map(|v| { - ( - v[0].get::().unwrap(), - v[1].get::().unwrap(), - ) - }) + .map(|v| (v[0].get::().unwrap(), v[1].get::().unwrap())) .collect() } /// "a(ss)" variant /// Rust doesn't allow implementing existing traits for existing types pub struct ArrayPairString(pub Vec<(String, String)>); - + impl ToVariant for ArrayPairString { fn to_variant(&self) -> Variant { let tspec = "a(ss)".to_glib_none(); @@ -88,11 +84,7 @@ mod variants { let a: *const c_char = a.0; let b: *const c_char = b.0; unsafe { - glib_sys::g_variant_builder_add( - builder, - ispec.0, - a, b - ); + glib_sys::g_variant_builder_add(builder, ispec.0, a, b); } } } @@ -106,24 +98,23 @@ mod variants { } fn get_settings(schema_name: &str) -> Option { - let mut error_handler = logging::Print{}; + let mut error_handler = logging::Print {}; let ss = gio::SettingsSchemaSource::default(); - + ss.or_warn( + &mut error_handler, + logging::Problem::Surprise, + "No gsettings schemas installed.", + ) + .and_then(|sss| { + sss.lookup(schema_name, true).or_warn( &mut error_handler, logging::Problem::Surprise, - "No gsettings schemas installed.", + &format!("Gsettings schema {} not installed", schema_name), ) - .and_then(|sss| - sss.lookup(schema_name, true) - .or_warn( - &mut error_handler, - logging::Problem::Surprise, - &format!("Gsettings schema {} not installed", schema_name), - ) - ) - .map(|_sschema| gio::Settings::new(schema_name)) + }) + .map(|_sschema| gio::Settings::new(schema_name)) } fn set_layout(kind: &str, name: &str) { @@ -134,14 +125,11 @@ fn set_layout(kind: &str, name: &str) { let inputs = settings.value("sources"); let current = (kind.clone(), name.clone()); - let inputs = variants::get_tuples(inputs).into_iter() + let inputs = variants::get_tuples(inputs) + .into_iter() .filter(|t| t != ¤t); - let inputs = vec![(kind, name)].into_iter() - .chain(inputs).collect(); - let _ = settings.set_value( - "sources", - &variants::ArrayPairString(inputs).to_variant(), - ); + let inputs = vec![(kind, name)].into_iter().chain(inputs).collect(); + let _ = settings.set_value("sources", &variants::ArrayPairString(inputs).to_variant()); settings.apply(); } } @@ -150,10 +138,7 @@ fn set_layout(kind: &str, name: &str) { #[derive(PartialEq, Clone, Debug)] pub enum LayoutId { /// Affects the layout in system settings - System { - kind: String, - name: String, - }, + System { kind: String, name: String }, /// Only affects what this input method presents Local(String), } @@ -167,14 +152,12 @@ impl LayoutId { } } -fn set_visible_layout( - layout_id: &LayoutId, -) { +fn set_visible_layout(layout_id: &LayoutId) { match layout_id { LayoutId::System { kind, name } => { set_layout(kind, name); - }, - _ => {}, + } + _ => {} } } @@ -204,18 +187,17 @@ fn translate_layout_names(layouts: &Vec) -> Vec { // Attempt to take all xkb names from gnome-desktop's xkb info. let xkb_translator = crate::locale::XkbInfo::new(); - let translated_names = layouts.iter() - .map(|id| match id { - LayoutId::System { name, kind: _ } => { - xkb_translator.get_display_name(name) - .map(|s| Status::Translated(OwnedTranslation(s))) - .or_print( - logging::Problem::Surprise, - &format!("No display name for xkb layout {}", name), - ).unwrap_or_else(|| Status::Remaining(name.clone())) - }, - LayoutId::Local (_) => unreachable!(), - }); + let translated_names = layouts.iter().map(|id| match id { + LayoutId::System { name, kind: _ } => xkb_translator + .get_display_name(name) + .map(|s| Status::Translated(OwnedTranslation(s))) + .or_print( + logging::Problem::Surprise, + &format!("No display name for xkb layout {}", name), + ) + .unwrap_or_else(|| Status::Remaining(name.clone())), + LayoutId::Local(_) => unreachable!(), + }); translated_names .map(|status| match status { @@ -234,7 +216,8 @@ pub fn show( unsafe { gtk::set_initialized() }; let window = unsafe { gtk::Widget::from_glib_none(window.0) }; - let overlay_layouts = resources::get_overlays().into_iter() + let overlay_layouts = resources::get_overlays() + .into_iter() .map(|name| LayoutId::Local(name.to_string())); let settings = get_settings("org.gnome.desktop.input-sources"); @@ -245,14 +228,10 @@ pub fn show( variants::get_tuples(inputs) }) .unwrap_or_else(|| Vec::new()); - - let system_layouts: Vec = inputs.into_iter() - .map(|(kind, name)| LayoutId::System { kind, name }) - .collect(); - let all_layouts: Vec = system_layouts.clone() + let system_layouts: Vec = inputs .into_iter() - .chain(overlay_layouts) + .map(|(kind, name)| LayoutId::System { kind, name }) .collect(); let translated_names = translate_layout_names(&system_layouts); @@ -268,96 +247,35 @@ pub fn show( match (layout_a, layout_b) { (LayoutId::Local(_), LayoutId::System { .. }) => Ordering::Greater, (LayoutId::System { .. }, LayoutId::Local(_)) => Ordering::Less, - _ => compare_current_locale(&tr_a.0, &tr_b.0) + _ => compare_current_locale(&tr_a.0, &tr_b.0), } }); - let model: gio::Menu = { - { - let builder = gtk::Builder::from_resource("/sm/puri/squeekboard/popover.ui"); - builder.object("app-menu").unwrap() - } - }; + let current_layout = get_current_layout(popover, &system_layouts); + let mut found_current = false; + let mut target_layout = None; - for (tr, l) in human_names.iter().rev() { - let detailed_action = format!("layout::{}", l.get_name()); - let item = gio::MenuItem::new(Some(&tr.0), Some(detailed_action.as_str())); - model.prepend_item (&item); + for (_, l) in human_names.iter() { + if found_current { + target_layout = Some(l.clone()); + break; + } + if let Some(current) = ¤t_layout { + if current == l { + println!("Found current: {:?} vs {:?}", current, l); + found_current = true; + } + } + } + if target_layout.is_none() { + target_layout = human_names.first().map(|item| item.1.clone()); } - let menu = gtk::Popover::from_model(Some(&window), &model); - - menu.set_pointing_to(>k::Rectangle::new ( - position.x.ceil() as i32, - position.y.ceil() as i32, - position.width.floor() as i32, - position.width.floor() as i32, - )); - menu.set_constrain_to(gtk::PopoverConstraint::None); - - let action_group = gio::SimpleActionGroup::new(); - - if let Some(current_layout) = get_current_layout(popover, &system_layouts) { - let current_layout_name = all_layouts.iter() - .find( - |l| l.get_name() == current_layout.get_name() - ).unwrap() - .get_name(); - log_print!(logging::Level::Debug, "Current Layout {}", current_layout_name); - - let layout_action = gio::SimpleAction::new_stateful( - "layout", - Some(current_layout_name.to_variant().type_()), - ¤t_layout_name.to_variant() - ); - - let menu_inner = menu.clone(); - layout_action.connect_change_state(move |_action, state| { - match state { - Some(v) => { - log_print!(logging::Level::Debug, "Selected layout {}", v); - v.get::() - .or_print( - logging::Problem::Bug, - &format!("Variant is not string: {:?}", v) - ) - .map(|state| { - let layout = all_layouts.iter() - .find( - |choices| state == choices.get_name() - ).unwrap(); - app_state - .send(state::Event::OverlayChanged(layout.clone())) - .or_print( - logging::Problem::Bug, - &format!("Can't send to state"), - ); - set_visible_layout(layout) - }); - }, - None => log_print!( - logging::Level::Debug, - "No variant selected", - ), - }; - menu_inner.popdown(); - }); - action_group.add_action(&layout_action); - }; - - let settings_action = gio::SimpleAction::new("settings", None); - settings_action.set_enabled(popover.settings_active); - settings_action.connect_activate(move |_, _| { - let s = CString::new("keyboard").unwrap(); - unsafe { c::popover_open_settings_panel(s.as_ptr()) }; - }); - action_group.add_action(&settings_action); - - menu.insert_action_group("popup", Some(&action_group)); - - menu.bind_model(Some(&model), Some("popup")); - glib::idle_add_local(move || { - menu.popup(); - glib::ControlFlow::Break - }); + if let Some(target) = target_layout { + println!("Target layout: {:?}", target); + app_state + .send(state::Event::OverlayChanged(target.clone())) + .or_print(logging::Problem::Bug, &format!("Can't send to state")); + set_visible_layout(&target); + } }