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:
Dorota Czaplejewicz
2022-06-04 13:40:30 +00:00
parent 30141db28d
commit c1ceec3673
19 changed files with 137 additions and 277 deletions

View File

@ -35,6 +35,7 @@
#include "eekboard/eekboard-context-service.h"
#include "src/layout.h"
#include "src/popover.h"
#include "src/submission.h"
#define LIBFEEDBACK_USE_UNSTABLE_API
@ -48,6 +49,7 @@ typedef struct _EekGtkKeyboardPrivate
struct render_geometry render_geometry; // mutable
EekboardContextService *eekboard_context; // unowned reference
struct squeek_popover *popover; // shared reference
struct squeek_state_manager *state_manager; // shared reference
struct submission *submission; // unowned reference
@ -119,15 +121,6 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
return FALSE;
}
// Units of virtual pixels size
static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) {
(void)height;
if (width < 540) {
return ARRANGEMENT_KIND_BASE;
}
return ARRANGEMENT_KIND_WIDE;
}
static void
eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
GtkAllocation *allocation)
@ -135,15 +128,6 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (keyboard);
// check if the change would switch types
enum squeek_arrangement_kind new_type = get_type(
(uint32_t)(allocation->width - allocation->x),
(uint32_t)(allocation->height - allocation->y));
if (priv->layout->arrangement != new_type) {
priv->layout->arrangement = new_type;
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(priv->eekboard_context, priv->layout, time);
}
if (priv->renderer) {
set_allocation_size (keyboard, priv->keyboard->layout,
@ -190,7 +174,7 @@ static void drag(EekGtkKeyboard *self,
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission,
x, y, priv->render_geometry.widget_to_layout, time,
priv->eekboard_context, priv->state_manager, self);
priv->popover, priv->state_manager, self);
}
static void release(EekGtkKeyboard *self, guint32 time)
@ -201,7 +185,7 @@ static void release(EekGtkKeyboard *self, guint32 time)
}
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission, priv->render_geometry.widget_to_layout, time,
priv->eekboard_context, priv->state_manager, self);
priv->popover, priv->state_manager, self);
}
static gboolean
@ -408,13 +392,14 @@ on_notify_keyboard (GObject *object,
GtkWidget *
eek_gtk_keyboard_new (EekboardContextService *eekservice,
struct submission *submission,
struct squeek_layout_state *layout, struct squeek_state_manager *state_manager)
struct squeek_state_manager *state_manager,
struct squeek_popover *popover)
{
EekGtkKeyboard *ret = EEK_GTK_KEYBOARD(g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL));
EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret);
priv->popover = popover;
priv->eekboard_context = eekservice;
priv->submission = submission;
priv->layout = layout;
priv->state_manager = state_manager;
priv->renderer = NULL;
// This should really be done on initialization.

View File

@ -31,6 +31,7 @@
#include "eek/eek-renderer.h"
#include "eek/eek-types.h"
#include "src/main.h"
#include "src/popover.h"
struct submission;
struct squeek_layout_state;
@ -49,7 +50,7 @@ struct _EekGtkKeyboardClass
gpointer pdummy[24];
};
GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager);
GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_state_manager *state_manager, struct squeek_popover *popover);
void eek_gtk_keyboard_emit_feedback (EekGtkKeyboard *self);
G_END_DECLS

View File

@ -55,8 +55,6 @@ static guint signals[LAST_SIGNAL] = { 0, };
*/
struct _EekboardContextService {
GObject parent;
struct squeek_layout_state *layout; // Unowned
// FIXME: replaces layout
struct squeek_state_manager *state_manager; // shared reference
LevelKeyboard *keyboard; // currently used keyboard
@ -128,29 +126,6 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
g_variant_unref(inputs);
}
void eekboard_context_service_set_layout(EekboardContextService *context, struct squeek_layout *layout, uint32_t timestamp);
void
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *state, uint32_t timestamp) {
gchar *layout_name = state->layout_name;
gchar *overlay_name = state->overlay_name;
// try to get the best keyboard layout
if (layout_name == NULL) {
layout_name = "us";
}
// overlay is "Normal" for most layouts, we will only look for "terminal" in rust code.
// for now just avoid passing a null pointer
if (overlay_name == NULL) {
overlay_name = ""; // fallback to Normal
}
// generic part follows
struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement, state->purpose, overlay_name);
eekboard_context_service_set_layout(context, layout, timestamp);
}
void eekboard_context_service_set_layout(EekboardContextService *context, struct squeek_layout *layout, uint32_t timestamp) {
LevelKeyboard *keyboard = level_keyboard_new(layout);
// set as current
@ -178,18 +153,6 @@ static void eekboard_context_service_update_settings_layout(EekboardContextServi
&keyboard_type, &keyboard_layout);
squeek_state_send_layout_set(context->state_manager, keyboard_layout, keyboard_type, gdk_event_get_time(NULL));
if (g_strcmp0(context->layout->layout_name, keyboard_layout) != 0 || context->layout->overlay_name) {
g_free(context->layout->overlay_name);
context->layout->overlay_name = NULL;
if (keyboard_layout) {
g_free(context->layout->layout_name);
context->layout->layout_name = g_strdup(keyboard_layout);
}
// This must actually update the UI.
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
static gboolean
@ -307,48 +270,17 @@ eekboard_context_service_get_keyboard (EekboardContextService *context)
return context->keyboard;
}
// Used from Rust.
// TODO: move hint management to Rust entirely
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
uint32_t hint, uint32_t purpose)
{
if (context->layout->hint != hint || context->layout->purpose != purpose) {
context->layout->hint = hint;
context->layout->purpose = purpose;
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
void
eekboard_context_service_set_overlay(EekboardContextService *context, const char* name) {
if (g_strcmp0(context->layout->overlay_name, name)) {
g_free(context->layout->overlay_name);
context->layout->overlay_name = g_strdup(name);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
const char*
eekboard_context_service_get_overlay(EekboardContextService *context) {
return context->layout->overlay_name;
}
EekboardContextService *eekboard_context_service_new(struct squeek_state_manager *state_manager, struct squeek_layout_state *state)
EekboardContextService *eekboard_context_service_new(struct squeek_state_manager *state_manager)
{
EekboardContextService *context = g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL);
context->layout = state;
context->state_manager = state_manager;
eekboard_context_service_update_settings_layout(context);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
return context;
}
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission) {
context->submission = submission;
if (context->submission) {
if (context->submission && context->keyboard) {
uint32_t time = gdk_event_get_time(NULL);
submission_use_layout(context->submission, context->keyboard->layout, time);
}

View File

@ -38,7 +38,7 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(EekboardContextService, eekboard_context_service, EEKBOARD, CONTEXT_SERVICE, GObject)
EekboardContextService *eekboard_context_service_new(struct squeek_state_manager *state_manager, struct squeek_layout_state *state);
EekboardContextService *eekboard_context_service_new(struct squeek_state_manager *state_manager);
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission);
void eekboard_context_service_destroy (EekboardContextService *context);
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
@ -46,7 +46,5 @@ LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *con
void eekboard_context_service_set_keymap(EekboardContextService *context,
const LevelKeyboard *keyboard);
void
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout, uint32_t timestamp);
G_END_DECLS
#endif /* EEKBOARD_CONTEXT_SERVICE_H */

23
src/actors/mod.rs Normal file
View 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
View 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;
}

View File

@ -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";

View File

@ -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);

View File

@ -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 = {

View File

@ -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;

View File

@ -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);

View File

@ -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>,
}

View File

@ -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)
}

View File

@ -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;
}

View File

@ -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
View File

@ -0,0 +1,5 @@
#pragma once
/// Popover state.
/// Wrapped<actors::popover::State>
struct squeek_popover;

View File

@ -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!(

View File

@ -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();

View File

@ -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,
}