diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 19b0837d..2c2c953e 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -48,6 +48,7 @@ typedef struct _EekGtkKeyboardPrivate struct render_geometry render_geometry; // mutable EekboardContextService *eekboard_context; // unowned reference + struct squeek_state_manager *state_manager; // shared reference struct submission *submission; // unowned reference struct squeek_layout_state *layout; // unowned @@ -158,6 +159,7 @@ on_event_triggered (LfbEvent *event, GAsyncResult *res, gpointer unused) { + (void)unused; g_autoptr (GError) err = NULL; if (!lfb_event_trigger_feedback_finish (event, res, &err)) { @@ -188,7 +190,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, self); + priv->eekboard_context, priv->state_manager, self); } static void release(EekGtkKeyboard *self, guint32 time) @@ -199,7 +201,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, self); + priv->eekboard_context, priv->state_manager, self); } static gboolean @@ -406,13 +408,14 @@ on_notify_keyboard (GObject *object, GtkWidget * eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, - struct squeek_layout_state *layout) + struct squeek_layout_state *layout, struct squeek_state_manager *state_manager) { EekGtkKeyboard *ret = EEK_GTK_KEYBOARD(g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL)); EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret); 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. // Before the widget is allocated, diff --git a/eek/eek-gtk-keyboard.h b/eek/eek-gtk-keyboard.h index faccd1fa..57fc9477 100644 --- a/eek/eek-gtk-keyboard.h +++ b/eek/eek-gtk-keyboard.h @@ -30,6 +30,7 @@ #include "eek/eek-renderer.h" #include "eek/eek-types.h" +#include "src/main.h" struct submission; struct squeek_layout_state; @@ -48,7 +49,7 @@ struct _EekGtkKeyboardClass gpointer pdummy[24]; }; -GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_layout_state *layout); +GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager); void eek_gtk_keyboard_emit_feedback (EekGtkKeyboard *self); G_END_DECLS diff --git a/src/layout.h b/src/layout.h index e50eac8f..b238a612 100644 --- a/src/layout.h +++ b/src/layout.h @@ -7,6 +7,7 @@ #include "eek/eek-gtk-keyboard.h" #include "eek/eek-renderer.h" #include "eek/eek-types.h" +#include "src/main.h" #include "src/submission.h" #include "virtual-keyboard-unstable-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" @@ -41,6 +42,7 @@ void squeek_layout_release(struct squeek_layout *layout, struct transformation widget_to_layout, uint32_t timestamp, EekboardContextService *manager, + struct squeek_state_manager *state, EekGtkKeyboard *ui_keyboard); void squeek_layout_release_all_only(struct squeek_layout *layout, struct submission *submission, @@ -55,6 +57,7 @@ void squeek_layout_drag(struct squeek_layout *layout, double x_widget, double y_widget, struct transformation widget_to_layout, uint32_t timestamp, EekboardContextService *manager, + 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); void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr); diff --git a/src/layout.rs b/src/layout.rs index bb94d4dc..6d0cfa88 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -25,31 +25,37 @@ use std::fmt; use std::rc::Rc; use std::vec::Vec; -use ::action::Action; -use ::drawing; -use ::float_ord::FloatOrd; -use ::keyboard::KeyState; -use ::logging; -use ::manager; -use ::submission::{ Submission, SubmitData, Timestamp }; -use ::util::find_max_double; +use crate::action::Action; +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 }; +use crate::util::find_max_double; -use ::imservice::ContentPurpose; +use crate::imservice::ContentPurpose; // Traits use std::borrow::Borrow; -use ::logging::Warn; +use crate::logging::Warn; /// Gathers stuff defined in C or called by C pub mod c { use super::*; - - use gtk_sys; - use std::os::raw::c_void; + + use crate::receiver; use crate::submission::c::Submission as CSubmission; + use gtk_sys; use std::ops::{ Add, Sub }; - + use std::os::raw::c_void; + + use crate::util::CloneOwned; + // The following defined in C #[repr(transparent)] #[derive(Copy, Clone)] @@ -216,12 +222,15 @@ pub mod c { widget_to_layout: Transformation, time: u32, manager: manager::c::Manager, + app_state: receiver::c::State, ui_keyboard: EekGtkKeyboard, ) { let time = Timestamp(time); let layout = unsafe { &mut *layout }; let submission = submission.clone_ref(); let mut submission = submission.borrow_mut(); + let app_state = app_state.clone_owned(); + let ui_backend = UIBackend { widget_to_layout, keyboard: ui_keyboard, @@ -236,7 +245,7 @@ pub mod c { &mut submission, Some(&ui_backend), time, - Some(manager), + Some((manager, app_state.clone())), key, ); } @@ -316,12 +325,14 @@ pub mod c { widget_to_layout: Transformation, time: u32, manager: manager::c::Manager, + app_state: receiver::c::State, ui_keyboard: EekGtkKeyboard, ) { let time = Timestamp(time); let layout = unsafe { &mut *layout }; let submission = submission.clone_ref(); let mut submission = submission.borrow_mut(); + let app_state = app_state.clone_owned(); let ui_backend = UIBackend { widget_to_layout, keyboard: ui_keyboard, @@ -352,7 +363,7 @@ pub mod c { &mut submission, Some(&ui_backend), time, - Some(manager), + Some((manager, app_state.clone())), key, ); } @@ -377,7 +388,7 @@ pub mod c { &mut submission, Some(&ui_backend), time, - Some(manager), + Some((manager, app_state.clone())), key, ); } @@ -1035,7 +1046,11 @@ mod seat { submission: &mut Submission, ui: Option<&UIBackend>, time: Timestamp, - manager: Option, + // TODO: intermediate measure: + // 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)>, rckey: &Rc>, ) { let key: KeyState = { @@ -1070,7 +1085,7 @@ mod seat { // only show when UI is present Action::ShowPreferences => if let Some(ui) = &ui { // only show when layout manager is available - if let Some(manager) = manager { + if let Some((manager, app_state)) = manager { let view = layout.get_current_view(); let places = ::layout::procedures::find_key_places( view, &rckey, @@ -1085,10 +1100,11 @@ mod seat { width: button.size.width, height: button.size.height, }; - ::popover::show( + popover::show( ui.keyboard, ui.widget_to_layout.reverse_bounds(bounds), manager, + app_state, ); } } diff --git a/src/lib.rs b/src/lib.rs index 38b7944c..65701e17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ mod manager; mod outputs; mod panel; mod popover; +mod receiver; mod resources; mod state; mod style; diff --git a/src/panel.c b/src/panel.c index 6dfb69c9..bf49f7b2 100644 --- a/src/panel.c +++ b/src/panel.c @@ -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->widget = eek_gtk_keyboard_new (self->state, self->submission, self->layout, self->state_manager); gtk_widget_set_has_tooltip (self->widget, TRUE); gtk_container_add (GTK_CONTAINER(self->window), self->widget); @@ -116,7 +116,7 @@ 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 panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager) { struct panel_manager mgr = { .state = state, @@ -125,6 +125,7 @@ struct panel_manager panel_manager_new(EekboardContextService *state, struct sub .window = NULL, .widget = NULL, .current_output = NULL, + .state_manager = state_manager, }; return mgr; } diff --git a/src/panel.h b/src/panel.h index 5d0ae615..711eda8b 100644 --- a/src/panel.h +++ b/src/panel.h @@ -2,12 +2,14 @@ #include "eek/layersurface.h" #include "src/layout.h" +#include "src/main.h" #include "src/submission.h" // Stores the objects that the panel and its widget will refer to struct panel_manager { EekboardContextService *state; // unowned /// Needed for instantiating the widget + struct squeek_state_manager *state_manager; // shared reference struct submission *submission; // unowned struct squeek_layout_state *layout; @@ -18,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 panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager); diff --git a/src/popover.rs b/src/popover.rs index 1e9ad259..0344272a 100644 --- a/src/popover.rs +++ b/src/popover.rs @@ -4,11 +4,13 @@ use gio; use gtk; use std::ffi::CString; use std::cmp::Ordering; -use ::layout::c::{ Bounds, EekGtkKeyboard }; -use ::locale::{ OwnedTranslation, compare_current_locale }; -use ::logging; -use ::manager; -use ::resources; +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; // Traits use gio::prelude::ActionMapExt; @@ -16,7 +18,7 @@ use gio::prelude::SettingsExt; use glib::translate::FromGlibPtrNone; use glib::variant::ToVariant; use gtk::prelude::*; -use ::logging::Warn; +use crate::logging::Warn; mod c { use std::os::raw::c_char; @@ -150,7 +152,7 @@ fn set_layout(kind: String, name: String) { /// A reference to what the user wants to see #[derive(PartialEq, Clone, Debug)] -enum LayoutId { +pub enum LayoutId { /// Affects the layout in system settings System { kind: String, @@ -248,6 +250,7 @@ pub fn show( window: EekGtkKeyboard, position: Bounds, manager: manager::c::Manager, + app_state: receiver::State, ) { unsafe { gtk::set_initialized() }; let window = unsafe { gtk::Widget::from_glib_none(window.0) }; @@ -356,6 +359,12 @@ pub fn show( .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( manager, layout.clone(), diff --git a/src/receiver.rs b/src/receiver.rs new file mode 100644 index 00000000..de0e95d9 --- /dev/null +++ b/src/receiver.rs @@ -0,0 +1,15 @@ +/*! Defines the application-wide message bus for updating state.*/ + +use crate::event_loop::driver::Threaded; + +pub mod c { + use super::*; + use crate::util::c::Wrapped; + pub type State = Wrapped; +} + +// The state receiver is an endpoint of a channel, so it's safely cloneable. +// There's no need to keep it in a Rc. +// The C version uses Wrapped with an underlying Rc, +// because Wrapped is well-tested already. +pub type State = Threaded; \ No newline at end of file diff --git a/src/server-main.c b/src/server-main.c index db4f677f..09c2febe 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -450,7 +450,8 @@ main (int argc, char **argv) instance.panel_manager = panel_manager_new(instance.settings_context, rsobjects.submission, - &instance.layout_choice); + &instance.layout_choice, + rsobjects.state_manager); register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, instance.settings_context, instance.dbus_handler); diff --git a/src/state.rs b/src/state.rs index ed031891..8d20c337 100644 --- a/src/state.rs +++ b/src/state.rs @@ -13,6 +13,7 @@ use crate::outputs; use crate::outputs::{Millimeter, OutputId, OutputState}; use crate::panel; use crate::panel::PixelSize; +use crate::popover; use crate::util::Rational; use std::cmp; use std::collections::HashMap; @@ -53,7 +54,7 @@ impl From for LayoutSource { } } -/// The user's preferred layout +/// The user's preferred system layout #[derive(Clone, Debug)] pub struct LayoutChoice { pub name: String, @@ -69,6 +70,7 @@ pub enum Event { PhysicalKeyboard(Presence), Output(outputs::Event), LayoutChoice(LayoutChoice), + OverlayChanged(popover::LayoutId), Debug(debug::Event), /// Event triggered because a moment in time passed. /// Use to animate state transitions. @@ -188,6 +190,8 @@ pub struct Application { /// and we might not receive one at all (gsettings missing). /// Then a default is used. pub layout_choice: LayoutChoice, + /// Manual override of the system layout + pub overlay_layout: Option, } impl Application { @@ -209,6 +213,7 @@ impl Application { name: String::from("us"), source: LayoutSource::Xkb, }, + overlay_layout: None, } } @@ -295,8 +300,14 @@ impl Application { }, }, - Event::LayoutChoice(choice) => Self { - layout_choice: choice, + Event::LayoutChoice(layout_choice) => Self { + layout_choice, + overlay_layout: None, + ..self + }, + + Event::OverlayChanged(overlay_layout) => Self { + overlay_layout: Some(overlay_layout), ..self }, };