state: Become the source of layout choice
A redesign of popover was needed: it can no longer query the application state directly due to current state being its own actor, so instead the popover gets a dedicated copy of the relevant state. I'm not entirely happy with the extra complexity of having an extra actor just for 1 string, but at least the duplication between C and Rust and mutual calls have been reduced.
This commit is contained in:
		
							
								
								
									
										23
									
								
								src/actors/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/actors/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
/* Copyright (C) 2022 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! Actors are parts of Squeekboard containing state independent from the main application state.
 | 
			
		||||
 | 
			
		||||
Because main application state is meant to be immutable,
 | 
			
		||||
it cannot be referenced directly by pieces of logic
 | 
			
		||||
interacting with the environment.
 | 
			
		||||
 | 
			
		||||
Such impure logic is split away (actor's logic)
 | 
			
		||||
and combined with relevant pieces of state (actor state),
 | 
			
		||||
thus preserving the purity (and sometimes simplicity) of the main state.
 | 
			
		||||
 | 
			
		||||
Actors can communicate with the main state by sending it messages,
 | 
			
		||||
and by receiving updates from it.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// TODO: move crate::panel into crate::actors::panel.
 | 
			
		||||
// Panel contains state and logic to protect the main state from getting flooded
 | 
			
		||||
// with low-level wayland and gtk sizing events.
 | 
			
		||||
 | 
			
		||||
pub mod popover;
 | 
			
		||||
							
								
								
									
										40
									
								
								src/actors/popover.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/actors/popover.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
/* Copyright (C) 2022 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! The popover is opened directly by the GTK surface,
 | 
			
		||||
without bouncing click events off the main state.
 | 
			
		||||
Then it must accurately show which layout has been selected.
 | 
			
		||||
It can get the system layout directly from gsettings on open,
 | 
			
		||||
but it cannot get the user-selected overlay, because it's stored in state.
 | 
			
		||||
 | 
			
		||||
To solve this, overlay will be cached in the popover actor,
 | 
			
		||||
and updated by main state every time it changes.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::util::c::Wrapped;
 | 
			
		||||
    /// The mutable instance of state
 | 
			
		||||
    pub type Actor = Wrapped<State>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct State {
 | 
			
		||||
    pub overlay: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl State {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self { overlay: None }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn set_overlay(
 | 
			
		||||
    actor: &c::Actor,
 | 
			
		||||
    overlay: Option<String>,
 | 
			
		||||
) {
 | 
			
		||||
    let actor = actor.clone_ref();
 | 
			
		||||
    let mut actor = actor.borrow_mut();
 | 
			
		||||
    actor.overlay = overlay;
 | 
			
		||||
}
 | 
			
		||||
@ -7,69 +7,16 @@
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::convert::TryFrom;
 | 
			
		||||
 | 
			
		||||
use super::{ Error, LoadError };
 | 
			
		||||
use super::parsing;
 | 
			
		||||
 | 
			
		||||
use crate::layout;
 | 
			
		||||
use ::layout::ArrangementKind;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use ::util::c::as_str;
 | 
			
		||||
use ::xdg;
 | 
			
		||||
use ::imservice::ContentPurpose;
 | 
			
		||||
use crate::layout::ArrangementKind;
 | 
			
		||||
use crate::logging;
 | 
			
		||||
use crate::xdg;
 | 
			
		||||
use crate::imservice::ContentPurpose;
 | 
			
		||||
 | 
			
		||||
// traits, derives
 | 
			
		||||
use ::logging::Warn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_load_layout(
 | 
			
		||||
        name: *const c_char,    // name of the keyboard
 | 
			
		||||
        type_: u32,             // type like Wide
 | 
			
		||||
        variant: u32,          // purpose variant like numeric, terminal...
 | 
			
		||||
        // Overlay forces a variant other than specified
 | 
			
		||||
        // (typically "terminal", "emoji")
 | 
			
		||||
        overlay: *const c_char,
 | 
			
		||||
    ) -> *mut layout::Layout {
 | 
			
		||||
        let type_ = match type_ {
 | 
			
		||||
            0 => ArrangementKind::Base,
 | 
			
		||||
            1 => ArrangementKind::Wide,
 | 
			
		||||
            _ => panic!("Bad enum value"),
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        let name = as_str(&name)
 | 
			
		||||
            .expect("Bad layout name")
 | 
			
		||||
            .expect("Empty layout name");
 | 
			
		||||
 | 
			
		||||
        let variant = ContentPurpose::try_from(variant)
 | 
			
		||||
                    .or_print(
 | 
			
		||||
                        logging::Problem::Warning,
 | 
			
		||||
                        "Received invalid purpose value",
 | 
			
		||||
                    )
 | 
			
		||||
                    .unwrap_or(ContentPurpose::Normal);
 | 
			
		||||
 | 
			
		||||
        let overlay_str = as_str(&overlay)
 | 
			
		||||
                .expect("Bad overlay name")
 | 
			
		||||
                .expect("Empty overlay name");
 | 
			
		||||
        let overlay_str = match overlay_str {
 | 
			
		||||
            "" => None,
 | 
			
		||||
            other => Some(other),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        dbg!(&name, type_, variant, overlay_str);
 | 
			
		||||
        
 | 
			
		||||
        let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
 | 
			
		||||
        let layout = layout::Layout::new(layout, kind, variant);
 | 
			
		||||
        Box::into_raw(Box::new(layout))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FALLBACK_LAYOUT_NAME: &str = "us";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@
 | 
			
		||||
#include "eek/eek-renderer.h"
 | 
			
		||||
#include "eek/eek-types.h"
 | 
			
		||||
#include "src/main.h"
 | 
			
		||||
#include "src/popover.h"
 | 
			
		||||
#include "src/submission.h"
 | 
			
		||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
			
		||||
#include "text-input-unstable-v3-client-protocol.h"
 | 
			
		||||
@ -41,7 +42,7 @@ void squeek_layout_release(struct squeek_layout *layout,
 | 
			
		||||
                           struct submission *submission,
 | 
			
		||||
                           struct transformation widget_to_layout,
 | 
			
		||||
                           uint32_t timestamp,
 | 
			
		||||
                           EekboardContextService *manager,
 | 
			
		||||
                           struct squeek_popover *popover,
 | 
			
		||||
                           struct squeek_state_manager *state,
 | 
			
		||||
                           EekGtkKeyboard *ui_keyboard);
 | 
			
		||||
void squeek_layout_release_all_only(struct squeek_layout *layout,
 | 
			
		||||
@ -56,7 +57,7 @@ void squeek_layout_drag(struct squeek_layout *layout,
 | 
			
		||||
                        struct submission *submission,
 | 
			
		||||
                        double x_widget, double y_widget,
 | 
			
		||||
                        struct transformation widget_to_layout,
 | 
			
		||||
                        uint32_t timestamp, EekboardContextService *manager,
 | 
			
		||||
                        uint32_t timestamp, struct squeek_popover *popover,
 | 
			
		||||
                        struct squeek_state_manager *state,
 | 
			
		||||
                        EekGtkKeyboard *ui_keyboard);
 | 
			
		||||
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr, struct submission *submission);
 | 
			
		||||
 | 
			
		||||
@ -26,12 +26,11 @@ use std::rc::Rc;
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
use crate::action::Action;
 | 
			
		||||
use crate::actors;
 | 
			
		||||
use crate::drawing;
 | 
			
		||||
use crate::event_loop::driver::Threaded as AppState;
 | 
			
		||||
use crate::float_ord::FloatOrd;
 | 
			
		||||
use crate::keyboard::KeyState;
 | 
			
		||||
use crate::logging;
 | 
			
		||||
use crate::manager;
 | 
			
		||||
use crate::popover;
 | 
			
		||||
use crate::receiver;
 | 
			
		||||
use crate::submission::{ Submission, SubmitData, Timestamp };
 | 
			
		||||
@ -221,7 +220,7 @@ pub mod c {
 | 
			
		||||
            submission: CSubmission,
 | 
			
		||||
            widget_to_layout: Transformation,
 | 
			
		||||
            time: u32,
 | 
			
		||||
            manager: manager::c::Manager,
 | 
			
		||||
            popover: actors::popover::c::Actor,
 | 
			
		||||
            app_state: receiver::c::State,
 | 
			
		||||
            ui_keyboard: EekGtkKeyboard,
 | 
			
		||||
        ) {
 | 
			
		||||
@ -230,6 +229,7 @@ pub mod c {
 | 
			
		||||
            let submission = submission.clone_ref();
 | 
			
		||||
            let mut submission = submission.borrow_mut();
 | 
			
		||||
            let app_state = app_state.clone_owned();
 | 
			
		||||
            let popover_state = popover.clone_owned();
 | 
			
		||||
            
 | 
			
		||||
            let ui_backend = UIBackend {
 | 
			
		||||
                widget_to_layout,
 | 
			
		||||
@ -245,7 +245,7 @@ pub mod c {
 | 
			
		||||
                    &mut submission,
 | 
			
		||||
                    Some(&ui_backend),
 | 
			
		||||
                    time,
 | 
			
		||||
                    Some((manager, app_state.clone())),
 | 
			
		||||
                    Some((&popover_state, app_state.clone())),
 | 
			
		||||
                    key,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
@ -324,7 +324,7 @@ pub mod c {
 | 
			
		||||
            x_widget: f64, y_widget: f64,
 | 
			
		||||
            widget_to_layout: Transformation,
 | 
			
		||||
            time: u32,
 | 
			
		||||
            manager: manager::c::Manager,
 | 
			
		||||
            popover: actors::popover::c::Actor,
 | 
			
		||||
            app_state: receiver::c::State,
 | 
			
		||||
            ui_keyboard: EekGtkKeyboard,
 | 
			
		||||
        ) {
 | 
			
		||||
@ -332,6 +332,9 @@ pub mod c {
 | 
			
		||||
            let layout = unsafe { &mut *layout };
 | 
			
		||||
            let submission = submission.clone_ref();
 | 
			
		||||
            let mut submission = submission.borrow_mut();
 | 
			
		||||
            // We only need to query state here, not update.
 | 
			
		||||
            // A copy is enough.
 | 
			
		||||
            let popover_state = popover.clone_owned();
 | 
			
		||||
            let app_state = app_state.clone_owned();
 | 
			
		||||
            let ui_backend = UIBackend {
 | 
			
		||||
                widget_to_layout,
 | 
			
		||||
@ -363,7 +366,7 @@ pub mod c {
 | 
			
		||||
                            &mut submission,
 | 
			
		||||
                            Some(&ui_backend),
 | 
			
		||||
                            time,
 | 
			
		||||
                            Some((manager, app_state.clone())),
 | 
			
		||||
                            Some((&popover_state, app_state.clone())),
 | 
			
		||||
                            key,
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
@ -388,7 +391,7 @@ pub mod c {
 | 
			
		||||
                        &mut submission,
 | 
			
		||||
                        Some(&ui_backend),
 | 
			
		||||
                        time,
 | 
			
		||||
                        Some((manager, app_state.clone())),
 | 
			
		||||
                        Some((&popover_state, app_state.clone())),
 | 
			
		||||
                        key,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
@ -1050,7 +1053,7 @@ mod seat {
 | 
			
		||||
        // passing state conditionally because it's only used for popover.
 | 
			
		||||
        // Eventually, it should be used for sumitting button events,
 | 
			
		||||
        // and passed always.
 | 
			
		||||
        manager: Option<(manager::c::Manager, receiver::State)>,
 | 
			
		||||
        manager: Option<(&actors::popover::State, receiver::State)>,
 | 
			
		||||
        rckey: &Rc<RefCell<KeyState>>,
 | 
			
		||||
    ) {
 | 
			
		||||
        let key: KeyState = {
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ mod assert_matches;
 | 
			
		||||
mod logging;
 | 
			
		||||
 | 
			
		||||
mod action;
 | 
			
		||||
mod actors;
 | 
			
		||||
mod animation;
 | 
			
		||||
pub mod data;
 | 
			
		||||
mod debug;
 | 
			
		||||
@ -34,7 +35,6 @@ mod keyboard;
 | 
			
		||||
mod layout;
 | 
			
		||||
mod locale;
 | 
			
		||||
mod main;
 | 
			
		||||
mod manager;
 | 
			
		||||
mod outputs;
 | 
			
		||||
mod panel;
 | 
			
		||||
mod popover;
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
#include "eek/eek-types.h"
 | 
			
		||||
#include "dbus.h"
 | 
			
		||||
#include "panel.h"
 | 
			
		||||
#include "src/popover.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct receiver;
 | 
			
		||||
@ -23,9 +24,10 @@ struct rsobjects {
 | 
			
		||||
    struct squeek_state_manager *state_manager;
 | 
			
		||||
    struct submission *submission;
 | 
			
		||||
    struct squeek_wayland *wayland;
 | 
			
		||||
    struct squeek_popover *popover;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void register_ui_loop_handler(struct receiver *receiver, struct panel_manager *panel, EekboardContextService *hint_manager, DBusHandler *dbus_handler);
 | 
			
		||||
void register_ui_loop_handler(struct receiver *receiver, struct panel_manager *panel, struct squeek_popover *popover, EekboardContextService *hint_manager, DBusHandler *dbus_handler);
 | 
			
		||||
 | 
			
		||||
struct rsobjects squeek_init(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								src/main.rs
									
									
									
									
									
								
							@ -3,11 +3,11 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! Glue for the main loop. */
 | 
			
		||||
use crate::actors;
 | 
			
		||||
use crate::animation;
 | 
			
		||||
use crate::debug;
 | 
			
		||||
use crate::data::loading;
 | 
			
		||||
use crate::panel;
 | 
			
		||||
use crate::state;
 | 
			
		||||
use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ mod c {
 | 
			
		||||
        submission: Wrapped<Submission>,
 | 
			
		||||
        /// Not wrapped, because C needs to access this.
 | 
			
		||||
        wayland: *mut Wayland,
 | 
			
		||||
        popover: actors::popover::c::Actor,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Corresponds to wayland.h::squeek_wayland.
 | 
			
		||||
@ -81,7 +82,6 @@ mod c {
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        #[allow(improper_ctypes)]
 | 
			
		||||
        fn init_wayland(wayland: *mut Wayland);
 | 
			
		||||
        fn eekboard_context_service_set_hint_purpose(service: HintManager, hint: u32, purpose: u32);
 | 
			
		||||
        #[allow(improper_ctypes)]
 | 
			
		||||
        fn eekboard_context_service_set_layout(service: HintManager, layout: *const layout::Layout, timestamp: u32);
 | 
			
		||||
        // This should probably only get called from the gtk main loop,
 | 
			
		||||
@ -121,6 +121,7 @@ mod c {
 | 
			
		||||
            state_manager: Wrapped::new(state_manager),
 | 
			
		||||
            receiver: Wrapped::new(receiver),
 | 
			
		||||
            wayland: Box::into_raw(wayland),
 | 
			
		||||
            popover: Wrapped::new(actors::popover::State::new()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -130,6 +131,7 @@ mod c {
 | 
			
		||||
    fn register_ui_loop_handler(
 | 
			
		||||
        receiver: Wrapped<Receiver<Commands>>,
 | 
			
		||||
        panel_manager: panel::c::PanelManager,
 | 
			
		||||
        popover: actors::popover::c::Actor,
 | 
			
		||||
        hint_manager: HintManager,
 | 
			
		||||
        dbus_handler: *const DBusHandler,
 | 
			
		||||
    ) {
 | 
			
		||||
@ -142,7 +144,13 @@ mod c {
 | 
			
		||||
        receiver.attach(
 | 
			
		||||
            Some(&ctx),
 | 
			
		||||
            move |msg| {
 | 
			
		||||
                main_loop_handle_message(msg, panel_manager.clone(), hint_manager, dbus_handler);
 | 
			
		||||
                main_loop_handle_message(
 | 
			
		||||
                    msg,
 | 
			
		||||
                    panel_manager.clone(),
 | 
			
		||||
                    &popover,
 | 
			
		||||
                    hint_manager,
 | 
			
		||||
                    dbus_handler,
 | 
			
		||||
                );
 | 
			
		||||
                Continue(true)
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
@ -157,6 +165,7 @@ mod c {
 | 
			
		||||
    fn main_loop_handle_message(
 | 
			
		||||
        msg: Commands,
 | 
			
		||||
        panel_manager: Wrapped<panel::Manager>,
 | 
			
		||||
        popover: &actors::popover::c::Actor,
 | 
			
		||||
        hint_manager: HintManager,
 | 
			
		||||
        dbus_handler: *const DBusHandler,
 | 
			
		||||
    ) {
 | 
			
		||||
@ -169,29 +178,19 @@ mod c {
 | 
			
		||||
                unsafe { dbus_handler_set_visible(dbus_handler, visible as u8) };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(hints) = msg.layout_hint_set {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                eekboard_context_service_set_hint_purpose(
 | 
			
		||||
                    hint_manager,
 | 
			
		||||
                    hints.hint.bits(),
 | 
			
		||||
                    hints.purpose.clone() as u32,
 | 
			
		||||
                )
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if let Some(commands::SetLayout { description }) = msg.layout_selection {
 | 
			
		||||
            dbg!(&description);
 | 
			
		||||
            let animation::Contents {
 | 
			
		||||
                name,
 | 
			
		||||
                kind,
 | 
			
		||||
                overlay_name,
 | 
			
		||||
                purpose,
 | 
			
		||||
            } = description;
 | 
			
		||||
            actors::popover::set_overlay(popover, overlay_name.clone());
 | 
			
		||||
            let layout = loading::load_layout(name, kind, purpose, overlay_name);
 | 
			
		||||
            let layout = Box::into_raw(Box::new(layout));
 | 
			
		||||
            unsafe {
 | 
			
		||||
                //eekboard_context_service_set_layout(hint_manager, layout, 0);
 | 
			
		||||
                eekboard_context_service_set_layout(hint_manager, layout, 0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -210,7 +209,6 @@ pub mod commands {
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct Commands {
 | 
			
		||||
    pub panel_visibility: Option<panel::Command>,
 | 
			
		||||
    pub layout_hint_set: Option<state::InputMethodDetails>,
 | 
			
		||||
    pub dbus_visible_set: Option<bool>,
 | 
			
		||||
    pub layout_selection: Option<commands::SetLayout>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,33 +0,0 @@
 | 
			
		||||
/*! Procedures relating to the management of the switching of layouts */
 | 
			
		||||
use crate::util;
 | 
			
		||||
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use std::os::raw::{c_char, c_void};
 | 
			
		||||
 | 
			
		||||
    /// EekboardContextService*
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Clone, Copy)]
 | 
			
		||||
    pub struct Manager(*const c_void);
 | 
			
		||||
    
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        pub fn eekboard_context_service_set_overlay(
 | 
			
		||||
            manager: Manager,
 | 
			
		||||
            name: *const c_char,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        pub fn eekboard_context_service_get_overlay(
 | 
			
		||||
            manager: Manager,
 | 
			
		||||
        ) -> *const c_char;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns the overlay name.
 | 
			
		||||
/// The result lifetime is "as long as the C copy lives"
 | 
			
		||||
pub fn get_overlay(manager: c::Manager) -> Option<String> {
 | 
			
		||||
    let raw_str = unsafe {
 | 
			
		||||
        c::eekboard_context_service_get_overlay(manager)
 | 
			
		||||
    };
 | 
			
		||||
    // this string is generated from Rust, should never be invalid
 | 
			
		||||
    util::c::as_str(&raw_str).unwrap()
 | 
			
		||||
        .map(String::from)
 | 
			
		||||
}
 | 
			
		||||
@ -52,7 +52,7 @@ make_widget (struct panel_manager *self)
 | 
			
		||||
    if (self->widget) {
 | 
			
		||||
        g_error("Widget already present");
 | 
			
		||||
    }
 | 
			
		||||
    self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->layout, self->state_manager);
 | 
			
		||||
    self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->state_manager, self->popover);
 | 
			
		||||
 | 
			
		||||
    gtk_widget_set_has_tooltip (self->widget, TRUE);
 | 
			
		||||
    gtk_container_add (GTK_CONTAINER(self->window), self->widget);
 | 
			
		||||
@ -116,16 +116,16 @@ panel_manager_resize (struct panel_manager *self, uint32_t height)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager)
 | 
			
		||||
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_state_manager *state_manager, struct squeek_popover *popover)
 | 
			
		||||
{
 | 
			
		||||
    struct panel_manager mgr = {
 | 
			
		||||
        .state = state,
 | 
			
		||||
        .submission = submission,
 | 
			
		||||
        .layout = layout,
 | 
			
		||||
        .window = NULL,
 | 
			
		||||
        .widget = NULL,
 | 
			
		||||
        .current_output = NULL,
 | 
			
		||||
        .state_manager = state_manager,
 | 
			
		||||
        .popover = popover,
 | 
			
		||||
    };
 | 
			
		||||
    return mgr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,8 @@ struct panel_manager {
 | 
			
		||||
    EekboardContextService *state; // unowned
 | 
			
		||||
    /// Needed for instantiating the widget
 | 
			
		||||
    struct squeek_state_manager *state_manager; // shared reference
 | 
			
		||||
    struct squeek_popover *popover; // shared reference
 | 
			
		||||
    struct submission *submission; // unowned
 | 
			
		||||
    struct squeek_layout_state *layout;
 | 
			
		||||
 | 
			
		||||
    PhoshLayerSurface *window;
 | 
			
		||||
    GtkWidget *widget; // nullable
 | 
			
		||||
@ -20,4 +20,4 @@ struct panel_manager {
 | 
			
		||||
    struct wl_output *current_output;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager);
 | 
			
		||||
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_state_manager *state_manager, struct squeek_popover *popover);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								src/popover.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/popover.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
/// Popover state.
 | 
			
		||||
/// Wrapped<actors::popover::State>
 | 
			
		||||
struct squeek_popover;
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,10 @@ 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::logging;
 | 
			
		||||
use crate::manager;
 | 
			
		||||
use crate::receiver;
 | 
			
		||||
use crate::resources;
 | 
			
		||||
use crate::state;
 | 
			
		||||
@ -129,9 +129,11 @@ fn get_settings(schema_name: &str) -> Option<gio::Settings> {
 | 
			
		||||
        .map(|_sschema| gio::Settings::new(schema_name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn set_layout(kind: String, name: String) {
 | 
			
		||||
fn set_layout(kind: &str, name: &str) {
 | 
			
		||||
    let settings = get_settings("org.gnome.desktop.input-sources");
 | 
			
		||||
    if let Some(settings) = settings {
 | 
			
		||||
        let kind = String::from(kind);
 | 
			
		||||
        let name = String::from(name);
 | 
			
		||||
        #[cfg(feature = "glib_v0_14")]
 | 
			
		||||
        let inputs = settings.value("sources");
 | 
			
		||||
        #[cfg(not(feature = "glib_v0_14"))]
 | 
			
		||||
@ -172,40 +174,23 @@ impl LayoutId {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn set_visible_layout(
 | 
			
		||||
    manager: manager::c::Manager,
 | 
			
		||||
    layout_id: LayoutId,
 | 
			
		||||
    layout_id: &LayoutId,
 | 
			
		||||
) {
 | 
			
		||||
    match layout_id {
 | 
			
		||||
        LayoutId::System { kind, name } => {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                use std::ptr;
 | 
			
		||||
                manager::c::eekboard_context_service_set_overlay(
 | 
			
		||||
                    manager,
 | 
			
		||||
                    ptr::null(),
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            set_layout(kind, name);
 | 
			
		||||
        }
 | 
			
		||||
        LayoutId::Local(name) => {
 | 
			
		||||
            let name = CString::new(name.as_str()).unwrap();
 | 
			
		||||
            let name_ptr = name.as_ptr();
 | 
			
		||||
            unsafe {
 | 
			
		||||
                manager::c::eekboard_context_service_set_overlay(
 | 
			
		||||
                    manager,
 | 
			
		||||
                    name_ptr,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        _ => {},
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Takes into account first any overlays, then system layouts from the list
 | 
			
		||||
fn get_current_layout(
 | 
			
		||||
    manager: manager::c::Manager,
 | 
			
		||||
    popover: &actors::popover::State,
 | 
			
		||||
    system_layouts: &Vec<LayoutId>,
 | 
			
		||||
) -> Option<LayoutId> {
 | 
			
		||||
    match manager::get_overlay(manager) {
 | 
			
		||||
        Some(name) => Some(LayoutId::Local(name)),
 | 
			
		||||
    match &popover.overlay {
 | 
			
		||||
        Some(name) => Some(LayoutId::Local(name.into())),
 | 
			
		||||
        None => system_layouts.get(0).map(LayoutId::clone),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -249,7 +234,7 @@ fn translate_layout_names(layouts: &Vec<LayoutId>) -> Vec<OwnedTranslation> {
 | 
			
		||||
pub fn show(
 | 
			
		||||
    window: EekGtkKeyboard,
 | 
			
		||||
    position: Bounds,
 | 
			
		||||
    manager: manager::c::Manager,
 | 
			
		||||
    popover: &actors::popover::State,
 | 
			
		||||
    app_state: receiver::State,
 | 
			
		||||
) {
 | 
			
		||||
    unsafe { gtk::set_initialized() };
 | 
			
		||||
@ -330,7 +315,7 @@ pub fn show(
 | 
			
		||||
 | 
			
		||||
    let action_group = gio::SimpleActionGroup::new();
 | 
			
		||||
 | 
			
		||||
    if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
 | 
			
		||||
    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()
 | 
			
		||||
@ -365,10 +350,7 @@ pub fn show(
 | 
			
		||||
                                    logging::Problem::Bug,
 | 
			
		||||
                                    &format!("Can't send to state"),
 | 
			
		||||
                                );
 | 
			
		||||
                            set_visible_layout(
 | 
			
		||||
                                manager,
 | 
			
		||||
                                layout.clone(),
 | 
			
		||||
                            )
 | 
			
		||||
                            set_visible_layout(layout)
 | 
			
		||||
                        });
 | 
			
		||||
                },
 | 
			
		||||
                None => log_print!(
 | 
			
		||||
 | 
			
		||||
@ -56,8 +56,6 @@ struct squeekboard {
 | 
			
		||||
    /// Gsettings hook for visibility. TODO: this does not belong in gsettings.
 | 
			
		||||
    ServerContextService *settings_handler;
 | 
			
		||||
    struct panel_manager panel_manager; // Controls the shape of the panel.
 | 
			
		||||
    /// Currently wanted layout. TODO: merge into state::Application
 | 
			
		||||
    struct squeek_layout_state layout_choice;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -400,7 +398,7 @@ main (int argc, char **argv)
 | 
			
		||||
    // Also initializes wayland
 | 
			
		||||
    struct rsobjects rsobjects = squeek_init();
 | 
			
		||||
 | 
			
		||||
    instance.settings_context = eekboard_context_service_new(rsobjects.state_manager, &instance.layout_choice);
 | 
			
		||||
    instance.settings_context = eekboard_context_service_new(rsobjects.state_manager);
 | 
			
		||||
 | 
			
		||||
    // set up dbus
 | 
			
		||||
 | 
			
		||||
@ -450,10 +448,10 @@ main (int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
    instance.panel_manager = panel_manager_new(instance.settings_context,
 | 
			
		||||
        rsobjects.submission,
 | 
			
		||||
        &instance.layout_choice,
 | 
			
		||||
        rsobjects.state_manager);
 | 
			
		||||
        rsobjects.state_manager,
 | 
			
		||||
        rsobjects.popover);
 | 
			
		||||
 | 
			
		||||
    register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, instance.settings_context, instance.dbus_handler);
 | 
			
		||||
    register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, rsobjects.popover, instance.settings_context, instance.dbus_handler);
 | 
			
		||||
 | 
			
		||||
    session_register();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								src/state.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/state.rs
									
									
									
									
									
								
							@ -126,27 +126,6 @@ impl Outcome {
 | 
			
		||||
    /// The receivers of the commands bear the burden
 | 
			
		||||
    /// of checking if the commands end up being no-ops.
 | 
			
		||||
    pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
 | 
			
		||||
        let layout_hint_set = match new_state {
 | 
			
		||||
            Outcome {
 | 
			
		||||
                panel: animation::Outcome::Visible{..},
 | 
			
		||||
                im: InputMethod::Active(hints),
 | 
			
		||||
                ..
 | 
			
		||||
            } => Some(hints.clone()),
 | 
			
		||||
            
 | 
			
		||||
            Outcome {
 | 
			
		||||
                panel: animation::Outcome::Visible{..},
 | 
			
		||||
                im: InputMethod::InactiveSince(_),
 | 
			
		||||
                ..
 | 
			
		||||
            } => Some(InputMethodDetails {
 | 
			
		||||
                hint: ContentHint::NONE,
 | 
			
		||||
                purpose: ContentPurpose::Normal,
 | 
			
		||||
            }),
 | 
			
		||||
            
 | 
			
		||||
            Outcome {
 | 
			
		||||
                panel: animation::Outcome::Hidden,
 | 
			
		||||
                ..
 | 
			
		||||
            } => None,
 | 
			
		||||
        };
 | 
			
		||||
// FIXME: handle switching outputs
 | 
			
		||||
        let (dbus_visible_set, panel_visibility) = match new_state.panel {
 | 
			
		||||
            animation::Outcome::Visible{output, height, ..}
 | 
			
		||||
@ -179,7 +158,6 @@ impl Outcome {
 | 
			
		||||
 | 
			
		||||
        Commands {
 | 
			
		||||
            panel_visibility,
 | 
			
		||||
            layout_hint_set,
 | 
			
		||||
            dbus_visible_set,
 | 
			
		||||
            layout_selection,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user