Merge remote-tracking branch 'upstream/master' into latch
This commit is contained in:
@ -17,6 +17,7 @@ pub enum Modifier {
|
||||
/// so it's simple to implement as levels are deprecated in squeekboard.
|
||||
Control,
|
||||
Alt,
|
||||
Mod4,
|
||||
}
|
||||
|
||||
/// Action to perform on the keypress and, in reverse, on keyrelease
|
||||
|
||||
145
src/data.rs
145
src/data.rs
@ -97,6 +97,8 @@ impl fmt::Display for DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
type LayoutSource = (ArrangementKind, DataSource);
|
||||
|
||||
/// Lists possible sources, with 0 as the most preferred one
|
||||
/// Trying order: native lang of the right kind, native base,
|
||||
/// fallback lang of the right kind, fallback base
|
||||
@ -104,55 +106,76 @@ fn list_layout_sources(
|
||||
name: &str,
|
||||
kind: ArrangementKind,
|
||||
keyboards_path: Option<PathBuf>,
|
||||
) -> Vec<(ArrangementKind, DataSource)> {
|
||||
let mut ret = Vec::new();
|
||||
{
|
||||
fn name_with_arrangement(name: String, kind: &ArrangementKind)
|
||||
-> String
|
||||
{
|
||||
match kind {
|
||||
ArrangementKind::Base => name,
|
||||
ArrangementKind::Wide => name + "_wide",
|
||||
}
|
||||
}
|
||||
|
||||
let mut add_by_name = |name: &str, kind: &ArrangementKind| {
|
||||
if let Some(path) = keyboards_path.clone() {
|
||||
ret.push((
|
||||
kind.clone(),
|
||||
DataSource::File(
|
||||
path.join(name.to_owned()).with_extension("yaml")
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
) -> Vec<LayoutSource> {
|
||||
// Just a simplification of often called code.
|
||||
let add_by_name = |
|
||||
mut ret: Vec<LayoutSource>,
|
||||
name: &str,
|
||||
kind: &ArrangementKind,
|
||||
| -> Vec<LayoutSource> {
|
||||
if let Some(path) = keyboards_path.clone() {
|
||||
ret.push((
|
||||
kind.clone(),
|
||||
DataSource::Resource(name.into())
|
||||
));
|
||||
};
|
||||
DataSource::File(
|
||||
path.join(name.to_owned()).with_extension("yaml")
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
match &kind {
|
||||
ArrangementKind::Base => {},
|
||||
ret.push((
|
||||
kind.clone(),
|
||||
DataSource::Resource(name.into())
|
||||
));
|
||||
ret
|
||||
};
|
||||
|
||||
// Another grouping.
|
||||
let add_by_kind = |ret, name: &str, kind| {
|
||||
let ret = match kind {
|
||||
&ArrangementKind::Base => ret,
|
||||
kind => add_by_name(
|
||||
&name_with_arrangement(name.into(), &kind),
|
||||
&kind,
|
||||
ret,
|
||||
&name_with_arrangement(name.into(), kind),
|
||||
kind,
|
||||
),
|
||||
};
|
||||
|
||||
add_by_name(name, &ArrangementKind::Base);
|
||||
add_by_name(ret, name, &ArrangementKind::Base)
|
||||
};
|
||||
|
||||
match &kind {
|
||||
ArrangementKind::Base => {},
|
||||
kind => add_by_name(
|
||||
&name_with_arrangement(FALLBACK_LAYOUT_NAME.into(), &kind),
|
||||
&kind,
|
||||
),
|
||||
};
|
||||
|
||||
add_by_name(FALLBACK_LAYOUT_NAME, &ArrangementKind::Base);
|
||||
fn name_with_arrangement(name: String, kind: &ArrangementKind) -> String {
|
||||
match kind {
|
||||
ArrangementKind::Base => name,
|
||||
ArrangementKind::Wide => name + "_wide",
|
||||
}
|
||||
}
|
||||
ret
|
||||
|
||||
let ret = Vec::new();
|
||||
|
||||
// Name as given takes priority.
|
||||
let ret = add_by_kind(ret, name, &kind);
|
||||
|
||||
// Then try non-alternative name if applicable (`us` for `us+colemak`).
|
||||
let ret = {
|
||||
let mut parts = name.splitn(2, '+');
|
||||
match parts.next() {
|
||||
Some(base) => {
|
||||
// The name is already equal to base, so it was already added.
|
||||
if base == name { ret }
|
||||
else {
|
||||
add_by_kind(ret, base, &kind)
|
||||
}
|
||||
},
|
||||
// The layout's base name starts with a "+". Weird but OK.
|
||||
None => {
|
||||
log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
|
||||
ret
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// No other choices left, so give anything.
|
||||
add_by_kind(ret, FALLBACK_LAYOUT_NAME.into(), &kind)
|
||||
}
|
||||
|
||||
fn load_layout_data(source: DataSource)
|
||||
@ -645,6 +668,9 @@ fn create_action<H: logging::Handler>(
|
||||
Modifier::Alt => action::Action::ApplyModifier(
|
||||
action::Modifier::Alt,
|
||||
),
|
||||
Modifier::Mod4 => action::Action::ApplyModifier(
|
||||
action::Modifier::Mod4,
|
||||
),
|
||||
unsupported_modifier => {
|
||||
warning_handler.handle(
|
||||
logging::Level::Bug,
|
||||
@ -756,13 +782,21 @@ mod tests {
|
||||
|
||||
use ::logging::ProblemPanic;
|
||||
|
||||
const THIS_FILE: &str = file!();
|
||||
|
||||
fn path_from_root(file: &'static str) -> PathBuf {
|
||||
PathBuf::from(THIS_FILE)
|
||||
.parent().unwrap()
|
||||
.parent().unwrap()
|
||||
.join(file)
|
||||
let source_dir = env::var("SOURCE_DIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|e| {
|
||||
if let env::VarError::NotPresent = e {
|
||||
let this_file = file!();
|
||||
PathBuf::from(this_file)
|
||||
.parent().unwrap()
|
||||
.parent().unwrap()
|
||||
.into()
|
||||
} else {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
});
|
||||
source_dir.join(file)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -919,7 +953,26 @@ mod tests {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// If layout contains a "+", it should reach for what's in front of it too.
|
||||
#[test]
|
||||
fn fallbacks_order_base() {
|
||||
let sources = list_layout_sources("nb+aliens", ArrangementKind::Base, None);
|
||||
|
||||
assert_eq!(
|
||||
sources,
|
||||
vec!(
|
||||
(ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
|
||||
(ArrangementKind::Base, DataSource::Resource("nb".into())),
|
||||
(
|
||||
ArrangementKind::Base,
|
||||
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn unicode_keysym() {
|
||||
let keysym = xkb::keysym_from_name(
|
||||
|
||||
@ -59,7 +59,7 @@ handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation,
|
||||
|
||||
if (service->context) {
|
||||
if (arg_visible) {
|
||||
server_context_service_show_keyboard (service->context);
|
||||
server_context_service_force_show_keyboard (service->context);
|
||||
} else {
|
||||
server_context_service_hide_keyboard (service->context);
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@ mod c {
|
||||
pub struct GtkStyleContext(*const c_void);
|
||||
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn eek_renderer_get_scale_factor(
|
||||
|
||||
@ -25,6 +25,7 @@ static const struct zwp_input_method_v2_listener input_method_listener = {
|
||||
|
||||
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
|
||||
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
|
||||
struct vis_manager *vis_manager,
|
||||
struct wl_seat *seat,
|
||||
EekboardContextService *state) {
|
||||
struct zwp_input_method_v2 *im = NULL;
|
||||
@ -35,7 +36,7 @@ struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
|
||||
if (vkmanager) {
|
||||
vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmanager, seat);
|
||||
}
|
||||
return submission_new(im, vk, state);
|
||||
return submission_new(im, vk, state, vis_manager);
|
||||
}
|
||||
|
||||
/// Un-inlined
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
use std::boxed::Box;
|
||||
use std::ffi::CString;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::num::Wrapping;
|
||||
use std::string::String;
|
||||
|
||||
@ -24,7 +23,7 @@ pub mod c {
|
||||
|
||||
use std::os::raw::{c_char, c_void};
|
||||
|
||||
pub use ::submission::c::UIManager;
|
||||
pub use ::ui_manager::c::UIManager;
|
||||
pub use ::submission::c::StateManager;
|
||||
|
||||
// The following defined in C
|
||||
@ -33,17 +32,15 @@ pub mod c {
|
||||
#[repr(transparent)]
|
||||
pub struct InputMethod(*const c_void);
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
fn imservice_destroy_im(im: *mut c::InputMethod);
|
||||
|
||||
#[allow(improper_ctypes)] // IMService will never be dereferenced in C
|
||||
pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
|
||||
pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char);
|
||||
pub fn eek_input_method_delete_surrounding_text(im: *mut InputMethod, before: u32, after: u32);
|
||||
pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32);
|
||||
fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32);
|
||||
pub fn server_context_service_set_im_active(imservice: *const UIManager, active: u32);
|
||||
pub fn server_context_service_keyboard_release_visibility(imservice: *const UIManager);
|
||||
}
|
||||
|
||||
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||
@ -152,8 +149,10 @@ pub mod c {
|
||||
..IMProtocolState::default()
|
||||
};
|
||||
|
||||
imservice.serial += Wrapping(1u32);
|
||||
|
||||
if active_changed {
|
||||
imservice.apply_active_to_ui();
|
||||
(imservice.active_callback)(imservice.current.active);
|
||||
if imservice.current.active {
|
||||
unsafe {
|
||||
eekboard_context_service_set_hint_purpose(
|
||||
@ -179,9 +178,7 @@ pub mod c {
|
||||
// the keyboard is already decommissioned
|
||||
imservice.current.active = false;
|
||||
|
||||
if let Some(ui) = imservice.ui_manager {
|
||||
unsafe { server_context_service_keyboard_release_visibility(ui); }
|
||||
}
|
||||
(imservice.active_callback)(imservice.current.active);
|
||||
}
|
||||
|
||||
// FIXME: destroy and deallocate
|
||||
@ -334,8 +331,7 @@ pub struct IMService {
|
||||
pub im: *mut c::InputMethod,
|
||||
/// Unowned reference. Be careful, it's shared with C at large
|
||||
state_manager: *const c::StateManager,
|
||||
/// Unowned reference. Be careful, it's shared with C at large
|
||||
ui_manager: Option<*const c::UIManager>,
|
||||
active_callback: Box<dyn Fn(bool)>,
|
||||
|
||||
pending: IMProtocolState,
|
||||
current: IMProtocolState, // turn current into an idiomatic representation?
|
||||
@ -352,12 +348,13 @@ impl IMService {
|
||||
pub fn new(
|
||||
im: *mut c::InputMethod,
|
||||
state_manager: *const c::StateManager,
|
||||
active_callback: Box<dyn Fn(bool)>,
|
||||
) -> Box<IMService> {
|
||||
// IMService will be referenced to by C,
|
||||
// so it needs to stay in the same place in memory via Box
|
||||
let imservice = Box::new(IMService {
|
||||
im,
|
||||
ui_manager: None,
|
||||
active_callback,
|
||||
state_manager,
|
||||
pending: IMProtocolState::default(),
|
||||
current: IMProtocolState::default(),
|
||||
@ -373,26 +370,6 @@ impl IMService {
|
||||
imservice
|
||||
}
|
||||
|
||||
pub fn set_ui_manager(&mut self, mut ui_manager: Option<*const c::UIManager>) {
|
||||
mem::swap(&mut self.ui_manager, &mut ui_manager);
|
||||
// Now ui_manager is what was previously self.ui_manager.
|
||||
// If there wasn't any, we need to consider if UI was requested.
|
||||
if let None = ui_manager {
|
||||
self.apply_active_to_ui();
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_active_to_ui(&self) {
|
||||
if let Some(ui) = self.ui_manager {
|
||||
unsafe {
|
||||
c::server_context_service_set_im_active(
|
||||
ui,
|
||||
self.is_active() as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit_string(&self, text: &CString) -> Result<(), SubmitError> {
|
||||
match self.current.active {
|
||||
true => {
|
||||
@ -429,7 +406,6 @@ impl IMService {
|
||||
unsafe {
|
||||
c::eek_input_method_commit(self.im, self.serial.0)
|
||||
}
|
||||
self.serial += Wrapping(1u32);
|
||||
Ok(())
|
||||
},
|
||||
false => Err(SubmitError::NotActive),
|
||||
|
||||
@ -50,7 +50,6 @@ pub mod c {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget);
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn eek_gtk_keyboard_emit_feedback(
|
||||
|
||||
@ -24,7 +24,6 @@ mod c {
|
||||
#[repr(C)]
|
||||
pub struct GnomeXkbInfo(*const c_void);
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
// from libc
|
||||
pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
|
||||
|
||||
@ -9,7 +9,6 @@ pub mod c {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Manager(*const c_void);
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
pub fn eekboard_context_service_set_overlay(
|
||||
manager: Manager,
|
||||
|
||||
@ -80,6 +80,7 @@ test(
|
||||
'rstest',
|
||||
cargo_script,
|
||||
args: ['test'] + cargo_build_flags,
|
||||
env: ['SOURCE_DIR=' + meson.source_root()],
|
||||
# this is a whole Carg-based test suite, let it run for a while
|
||||
timeout: 900,
|
||||
depends: [build_rstests, cargo_toml],
|
||||
|
||||
@ -29,7 +29,6 @@ use ::logging::Warn;
|
||||
mod c {
|
||||
use std::os::raw::c_char;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
pub fn popover_open_settings_panel(panel: *const c_char);
|
||||
}
|
||||
@ -437,7 +436,8 @@ pub fn show(
|
||||
|
||||
let settings_action = gio::SimpleAction::new("settings", None);
|
||||
settings_action.connect_activate(move |_, _| {
|
||||
unsafe { c::popover_open_settings_panel(CString::new("region").unwrap().as_ptr()) };
|
||||
let s = CString::new("region").unwrap();
|
||||
unsafe { c::popover_open_settings_panel(s.as_ptr()) };
|
||||
});
|
||||
|
||||
let action_group = gio::SimpleActionGroup::new();
|
||||
|
||||
@ -10,34 +10,78 @@ use std::iter::FromIterator;
|
||||
// TODO: keep a list of what is a language layout,
|
||||
// and what a convenience layout. "_wide" is not a layout,
|
||||
// neither is "number"
|
||||
/// List of builtin layouts
|
||||
const KEYBOARDS: &[(*const str, *const str)] = &[
|
||||
// layouts: us must be left as first, as it is the,
|
||||
// fallback layout. The others should be alphabetical.
|
||||
// fallback layout.
|
||||
("us", include_str!("../data/keyboards/us.yaml")),
|
||||
("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
|
||||
("br", include_str!("../data/keyboards/br.yaml")),
|
||||
("de", include_str!("../data/keyboards/de.yaml")),
|
||||
|
||||
// Language layouts: keep alphabetical.
|
||||
("be", include_str!("../data/keyboards/be.yaml")),
|
||||
("be_wide", include_str!("../data/keyboards/be_wide.yaml")),
|
||||
|
||||
("bg", include_str!("../data/keyboards/bg.yaml")),
|
||||
|
||||
("br", include_str!("../data/keyboards/br.yaml")),
|
||||
|
||||
("de", include_str!("../data/keyboards/de.yaml")),
|
||||
("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
|
||||
|
||||
("cz", include_str!("../data/keyboards/cz.yaml")),
|
||||
("cz_wide", include_str!("../data/keyboards/cz_wide.yaml")),
|
||||
|
||||
("cz+qwerty", include_str!("../data/keyboards/cz+qwerty.yaml")),
|
||||
("cz+qwerty_wide", include_str!("../data/keyboards/cz+qwerty_wide.yaml")),
|
||||
|
||||
("dk", include_str!("../data/keyboards/dk.yaml")),
|
||||
|
||||
("epo", include_str!("../data/keyboards/epo.yaml")),
|
||||
|
||||
("es", include_str!("../data/keyboards/es.yaml")),
|
||||
("es+cat", include_str!("../data/keyboards/es+cat.yaml")),
|
||||
|
||||
("fi", include_str!("../data/keyboards/fi.yaml")),
|
||||
|
||||
("fr", include_str!("../data/keyboards/fr.yaml")),
|
||||
("fr_wide", include_str!("../data/keyboards/fr_wide.yaml")),
|
||||
("it+fur", include_str!("../data/keyboards/it+fur.yaml")),
|
||||
|
||||
("gr", include_str!("../data/keyboards/gr.yaml")),
|
||||
|
||||
("il", include_str!("../data/keyboards/il.yaml")),
|
||||
|
||||
("ir", include_str!("../data/keyboards/ir.yaml")),
|
||||
("ir_wide", include_str!("../data/keyboards/ir_wide.yaml")),
|
||||
|
||||
("it", include_str!("../data/keyboards/it.yaml")),
|
||||
("it+fur", include_str!("../data/keyboards/it+fur.yaml")),
|
||||
|
||||
("jp+kana", include_str!("../data/keyboards/jp+kana.yaml")),
|
||||
("jp+kana_wide", include_str!("../data/keyboards/jp+kana_wide.yaml")),
|
||||
|
||||
("no", include_str!("../data/keyboards/no.yaml")),
|
||||
("number", include_str!("../data/keyboards/number.yaml")),
|
||||
|
||||
("pl", include_str!("../data/keyboards/pl.yaml")),
|
||||
("pl_wide", include_str!("../data/keyboards/pl_wide.yaml")),
|
||||
|
||||
("ru", include_str!("../data/keyboards/ru.yaml")),
|
||||
|
||||
("se", include_str!("../data/keyboards/se.yaml")),
|
||||
|
||||
("th", include_str!("../data/keyboards/th.yaml")),
|
||||
("th_wide", include_str!("../data/keyboards/th_wide.yaml")),
|
||||
|
||||
("ua", include_str!("../data/keyboards/ua.yaml")),
|
||||
|
||||
("us+colemak", include_str!("../data/keyboards/us+colemak.yaml")),
|
||||
("us+colemak_wide", include_str!("../data/keyboards/us+colemak_wide.yaml")),
|
||||
|
||||
("us+dvorak", include_str!("../data/keyboards/us+dvorak.yaml")),
|
||||
("us+dvorak_wide", include_str!("../data/keyboards/us+dvorak_wide.yaml")),
|
||||
|
||||
// Others
|
||||
("number", include_str!("../data/keyboards/number.yaml")),
|
||||
|
||||
// layout+overlay
|
||||
("terminal", include_str!("../data/keyboards/terminal.yaml")),
|
||||
("terminal_wide", include_str!("../data/keyboards/terminal_wide.yaml")),
|
||||
@ -78,6 +122,7 @@ const LAYOUT_NAMES: &[(*const str, *const str)] = &[
|
||||
("en-US", include_str!("../data/langs/en-US.txt")),
|
||||
("es-ES", include_str!("../data/langs/es-ES.txt")),
|
||||
("fur-IT", include_str!("../data/langs/fur-IT.txt")),
|
||||
("he-IL", include_str!("../data/langs/he_IL.txt")),
|
||||
("ja-JP", include_str!("../data/langs/ja-JP.txt")),
|
||||
("pl-PL", include_str!("../data/langs/pl-PL.txt")),
|
||||
("ru-RU", include_str!("../data/langs/ru-RU.txt")),
|
||||
|
||||
@ -43,10 +43,9 @@ struct _ServerContextService {
|
||||
struct submission *submission; // unowned
|
||||
struct squeek_layout_state *layout;
|
||||
struct ui_manager *manager; // unowned
|
||||
struct vis_manager *vis_manager; // owned
|
||||
|
||||
gboolean visible;
|
||||
gboolean enabled;
|
||||
gboolean im_active;
|
||||
PhoshLayerSurface *window;
|
||||
GtkWidget *widget; // nullable
|
||||
guint hiding;
|
||||
@ -240,6 +239,13 @@ server_context_service_real_show_keyboard (ServerContextService *self)
|
||||
gtk_widget_show (GTK_WIDGET(self->window));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
show_keyboard_source_func(ServerContextService *context)
|
||||
{
|
||||
server_context_service_real_show_keyboard(context);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
server_context_service_real_hide_keyboard (ServerContextService *self)
|
||||
{
|
||||
@ -247,6 +253,13 @@ server_context_service_real_hide_keyboard (ServerContextService *self)
|
||||
self->visible = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
hide_keyboard_source_func(ServerContextService *context)
|
||||
{
|
||||
server_context_service_real_hide_keyboard(context);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_hide (ServerContextService *self)
|
||||
{
|
||||
@ -256,7 +269,7 @@ on_hide (ServerContextService *self)
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
server_context_service_show_keyboard (ServerContextService *self)
|
||||
{
|
||||
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
|
||||
@ -267,17 +280,30 @@ server_context_service_show_keyboard (ServerContextService *self)
|
||||
}
|
||||
|
||||
if (!self->visible) {
|
||||
server_context_service_real_show_keyboard (self);
|
||||
g_idle_add((GSourceFunc)show_keyboard_source_func, self);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
server_context_service_force_show_keyboard (ServerContextService *self)
|
||||
{
|
||||
if (!submission_hint_available(self->submission)) {
|
||||
eekboard_context_service_set_hint_purpose(
|
||||
self->state,
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
|
||||
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL
|
||||
);
|
||||
}
|
||||
server_context_service_show_keyboard(self);
|
||||
}
|
||||
|
||||
void
|
||||
server_context_service_hide_keyboard (ServerContextService *self)
|
||||
{
|
||||
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
|
||||
|
||||
if (self->visible) {
|
||||
server_context_service_real_hide_keyboard (self);
|
||||
g_idle_add((GSourceFunc)hide_keyboard_source_func, self);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +314,7 @@ server_context_service_hide_keyboard (ServerContextService *self)
|
||||
/// In this case, the user doesn't really need the keyboard surface
|
||||
/// to disappear completely.
|
||||
void
|
||||
server_context_service_keyboard_release_visibility (ServerContextService *self)
|
||||
server_context_service_release_visibility (ServerContextService *self)
|
||||
{
|
||||
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
|
||||
|
||||
@ -297,6 +323,13 @@ server_context_service_keyboard_release_visibility (ServerContextService *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
server_context_service_set_physical_keyboard_present (ServerContextService *self, gboolean physical_keyboard_present)
|
||||
{
|
||||
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
|
||||
squeek_visman_set_keyboard_present(self->vis_manager, physical_keyboard_present);
|
||||
}
|
||||
|
||||
static void
|
||||
server_context_service_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -310,7 +343,7 @@ server_context_service_set_property (GObject *object,
|
||||
self->visible = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_ENABLED:
|
||||
server_context_service_set_enabled (self, g_value_get_boolean (value));
|
||||
server_context_service_set_physical_keyboard_present (self, !g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@ -385,12 +418,14 @@ server_context_service_class_init (ServerContextServiceClass *klass)
|
||||
}
|
||||
|
||||
static void
|
||||
server_context_service_init (ServerContextService *self) {
|
||||
server_context_service_init (ServerContextService *self) {}
|
||||
|
||||
static void
|
||||
init (ServerContextService *self) {
|
||||
const char *schema_name = "org.gnome.desktop.a11y.applications";
|
||||
GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
|
||||
g_autoptr(GSettingsSchema) schema = NULL;
|
||||
|
||||
self->enabled = TRUE;
|
||||
if (!ssrc) {
|
||||
g_warning("No gsettings schemas installed.");
|
||||
return;
|
||||
@ -407,37 +442,24 @@ server_context_service_init (ServerContextService *self) {
|
||||
}
|
||||
|
||||
ServerContextService *
|
||||
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman)
|
||||
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman)
|
||||
{
|
||||
ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
|
||||
ui->submission = submission;
|
||||
ui->state = self;
|
||||
ui->layout = layout;
|
||||
ui->manager = uiman;
|
||||
ui->vis_manager = visman;
|
||||
init(ui);
|
||||
return ui;
|
||||
}
|
||||
|
||||
void
|
||||
server_context_service_update_visible (ServerContextService *self, gboolean delay) {
|
||||
if (self->enabled && self->im_active) {
|
||||
server_context_service_update_visible (ServerContextService *self, gboolean visible) {
|
||||
if (visible) {
|
||||
server_context_service_show_keyboard(self);
|
||||
} else if (delay) {
|
||||
server_context_service_keyboard_release_visibility(self);
|
||||
} else {
|
||||
server_context_service_hide_keyboard(self);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
server_context_service_set_enabled (ServerContextService *self, gboolean enabled)
|
||||
{
|
||||
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
|
||||
self->enabled = enabled;
|
||||
server_context_service_update_visible(self, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
server_context_service_set_im_active(ServerContextService *self, uint32_t active) {
|
||||
self->im_active = active;
|
||||
server_context_service_update_visible(self, TRUE);
|
||||
}
|
||||
|
||||
@ -29,11 +29,10 @@ G_BEGIN_DECLS
|
||||
/** Manages the lifecycle of the window displaying layouts. */
|
||||
G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONTEXT_SERVICE, GObject)
|
||||
|
||||
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman);
|
||||
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman);
|
||||
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
|
||||
void server_context_service_show_keyboard (ServerContextService *self);
|
||||
void server_context_service_force_show_keyboard (ServerContextService *self);
|
||||
void server_context_service_hide_keyboard (ServerContextService *self);
|
||||
void server_context_service_set_enabled (ServerContextService *self, gboolean enabled);
|
||||
G_END_DECLS
|
||||
#endif /* SERVER_CONTEXT_SERVICE_H */
|
||||
|
||||
|
||||
@ -50,9 +50,16 @@ struct squeekboard {
|
||||
};
|
||||
|
||||
|
||||
GMainLoop *loop;
|
||||
static gboolean opt_system = FALSE;
|
||||
static gchar *opt_address = NULL;
|
||||
|
||||
static void
|
||||
quit (void)
|
||||
{
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
// D-Bus
|
||||
|
||||
static void
|
||||
@ -131,6 +138,67 @@ static const struct wl_registry_listener registry_listener = {
|
||||
#define SESSION_NAME "sm.puri.OSK0"
|
||||
|
||||
GDBusProxy *_proxy = NULL;
|
||||
GDBusProxy *_client_proxy = NULL;
|
||||
gchar *_client_path = NULL;
|
||||
|
||||
|
||||
static void
|
||||
send_quit_response (GDBusProxy *proxy)
|
||||
{
|
||||
g_debug ("Calling EndSessionResponse");
|
||||
g_dbus_proxy_call (proxy, "EndSessionResponse",
|
||||
g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE,
|
||||
G_MAXINT, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
unregister_client (void)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_PROXY (_proxy));
|
||||
g_return_if_fail (_client_path != NULL);
|
||||
|
||||
g_debug ("Unregistering client");
|
||||
|
||||
g_dbus_proxy_call_sync (_proxy,
|
||||
"UnregisterClient",
|
||||
g_variant_new ("(o)", _client_path),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
G_MAXINT,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (error) {
|
||||
g_warning ("Failed to unregister client: %s", error->message);
|
||||
}
|
||||
|
||||
g_clear_object (&_client_proxy);
|
||||
g_clear_pointer (&_client_path, g_free);
|
||||
}
|
||||
|
||||
static void client_proxy_signal (GDBusProxy *proxy,
|
||||
const gchar *sender_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (g_str_equal (signal_name, "QueryEndSession")) {
|
||||
g_debug ("Received QueryEndSession");
|
||||
send_quit_response (proxy);
|
||||
} else if (g_str_equal (signal_name, "CancelEndSession")) {
|
||||
g_debug ("Received CancelEndSession");
|
||||
} else if (g_str_equal (signal_name, "EndSession")) {
|
||||
g_debug ("Received EndSession");
|
||||
send_quit_response (proxy);
|
||||
unregister_client ();
|
||||
quit ();
|
||||
} else if (g_str_equal (signal_name, "Stop")) {
|
||||
g_debug ("Received Stop");
|
||||
unregister_client ();
|
||||
quit ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
session_register(void) {
|
||||
@ -151,7 +219,8 @@ session_register(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_dbus_proxy_call_sync(_proxy, "RegisterClient",
|
||||
g_autoptr (GVariant) res = NULL;
|
||||
res = g_dbus_proxy_call_sync(_proxy, "RegisterClient",
|
||||
g_variant_new("(ss)", SESSION_NAME, autostart_id),
|
||||
G_DBUS_CALL_FLAGS_NONE, 1000, NULL, &error);
|
||||
if (error) {
|
||||
@ -160,6 +229,22 @@ session_register(void) {
|
||||
g_clear_error(&error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (res, "(o)", &_client_path);
|
||||
g_debug ("Registered client at '%s'", _client_path);
|
||||
|
||||
_client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
0, NULL, "org.gnome.SessionManager", _client_path,
|
||||
"org.gnome.SessionManager.ClientPrivate", NULL, &error);
|
||||
if (error) {
|
||||
g_warning ("Failed to get client proxy: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
g_free (_client_path);
|
||||
_client_path = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
g_signal_connect (_client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), NULL);
|
||||
}
|
||||
|
||||
int
|
||||
@ -277,8 +362,11 @@ main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
struct vis_manager *vis_manager = squeek_visman_new();
|
||||
|
||||
instance.submission = get_submission(instance.wayland.input_method_manager,
|
||||
instance.wayland.virtual_keyboard_manager,
|
||||
vis_manager,
|
||||
instance.wayland.seat,
|
||||
instance.settings_context);
|
||||
|
||||
@ -288,15 +376,15 @@ main (int argc, char **argv)
|
||||
instance.settings_context,
|
||||
instance.submission,
|
||||
&instance.layout_choice,
|
||||
instance.ui_manager);
|
||||
instance.ui_manager,
|
||||
vis_manager);
|
||||
if (!ui_context) {
|
||||
g_error("Could not initialize GUI");
|
||||
exit(1);
|
||||
}
|
||||
instance.ui_context = ui_context;
|
||||
if (instance.submission) {
|
||||
submission_set_ui(instance.submission, instance.ui_context);
|
||||
}
|
||||
squeek_visman_set_ui(vis_manager, instance.ui_context);
|
||||
|
||||
if (instance.dbus_handler) {
|
||||
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
|
||||
}
|
||||
@ -304,8 +392,7 @@ main (int argc, char **argv)
|
||||
|
||||
session_register();
|
||||
|
||||
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
if (connection) {
|
||||
|
||||
@ -4,17 +4,20 @@
|
||||
#include "input-method-unstable-v2-client-protocol.h"
|
||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||
#include "eek/eek-types.h"
|
||||
#include "src/ui_manager.h"
|
||||
|
||||
struct submission;
|
||||
struct squeek_layout;
|
||||
|
||||
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
|
||||
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
|
||||
struct vis_manager *vis_manager,
|
||||
struct wl_seat *seat,
|
||||
EekboardContextService *state);
|
||||
|
||||
// Defined in Rust
|
||||
struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state);
|
||||
struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state, struct vis_manager *vis_manager);
|
||||
uint8_t submission_hint_available(struct submission *self);
|
||||
void submission_set_ui(struct submission *self, ServerContextService *ui_context);
|
||||
void submission_use_layout(struct submission *self, struct squeek_layout *layout, uint32_t time);
|
||||
#endif
|
||||
|
||||
@ -24,6 +24,7 @@ use ::imservice;
|
||||
use ::imservice::IMService;
|
||||
use ::keyboard::{ KeyCode, KeyStateId, Modifiers, PressType };
|
||||
use ::layout;
|
||||
use ::ui_manager::VisibilityManager;
|
||||
use ::util::vec_remove;
|
||||
use ::vkeyboard;
|
||||
use ::vkeyboard::VirtualKeyboard;
|
||||
@ -38,14 +39,11 @@ pub mod c {
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use ::imservice::c::InputMethod;
|
||||
use ::util::c::Wrapped;
|
||||
use ::vkeyboard::c::ZwpVirtualKeyboardV1;
|
||||
|
||||
// The following defined in C
|
||||
|
||||
/// ServerContextService*
|
||||
#[repr(transparent)]
|
||||
pub struct UIManager(*const c_void);
|
||||
|
||||
/// EekboardContextService*
|
||||
#[repr(transparent)]
|
||||
pub struct StateManager(*const c_void);
|
||||
@ -55,12 +53,18 @@ pub mod c {
|
||||
fn submission_new(
|
||||
im: *mut InputMethod,
|
||||
vk: ZwpVirtualKeyboardV1,
|
||||
state_manager: *const StateManager
|
||||
state_manager: *const StateManager,
|
||||
visibility_manager: Wrapped<VisibilityManager>,
|
||||
) -> *mut Submission {
|
||||
let imservice = if im.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(IMService::new(im, state_manager))
|
||||
let visibility_manager = visibility_manager.clone_ref();
|
||||
Some(IMService::new(
|
||||
im,
|
||||
state_manager,
|
||||
Box::new(move |active| visibility_manager.borrow_mut().set_im_active(active)),
|
||||
))
|
||||
};
|
||||
// TODO: add vkeyboard too
|
||||
Box::<Submission>::into_raw(Box::new(
|
||||
@ -75,23 +79,6 @@ pub mod c {
|
||||
))
|
||||
}
|
||||
|
||||
/// Use to initialize the UI reference
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn submission_set_ui(submission: *mut Submission, ui_manager: *const UIManager) {
|
||||
if submission.is_null() {
|
||||
panic!("Null submission pointer");
|
||||
}
|
||||
let submission: &mut Submission = unsafe { &mut *submission };
|
||||
if let Some(ref mut imservice) = &mut submission.imservice {
|
||||
imservice.set_ui_manager(if ui_manager.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(ui_manager)
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn submission_use_layout(
|
||||
@ -106,6 +93,18 @@ pub mod c {
|
||||
let layout = unsafe { &*layout };
|
||||
submission.use_layout(layout, Timestamp(time));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn submission_hint_available(submission: *mut Submission) -> u8 {
|
||||
if submission.is_null() {
|
||||
panic!("Null submission pointer");
|
||||
}
|
||||
let submission: &mut Submission = unsafe { &mut *submission };
|
||||
let active = submission.imservice.as_ref()
|
||||
.map(|imservice| imservice.is_active());
|
||||
(Some(true) == active) as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -271,6 +270,7 @@ impl Submission {
|
||||
.map(|(_id, m)| match m {
|
||||
Modifier::Control => Modifiers::CONTROL,
|
||||
Modifier::Alt => Modifiers::MOD1,
|
||||
Modifier::Mod4 => Modifiers::MOD4,
|
||||
})
|
||||
.fold(Modifiers::empty(), |m, n| m | n);
|
||||
self.virtual_keyboard.set_modifiers_state(raw_modifiers);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "eek/eek-types.h"
|
||||
#include "outputs.h"
|
||||
|
||||
struct ui_manager;
|
||||
@ -11,4 +12,9 @@ struct ui_manager *squeek_uiman_new(void);
|
||||
void squeek_uiman_set_output(struct ui_manager *uiman, struct squeek_output_handle output);
|
||||
uint32_t squeek_uiman_get_perceptual_height(struct ui_manager *uiman);
|
||||
|
||||
struct vis_manager;
|
||||
|
||||
struct vis_manager *squeek_visman_new(void);
|
||||
void squeek_visman_set_ui(struct vis_manager *visman, ServerContextService *ui_context);
|
||||
void squeek_visman_set_keyboard_present(struct vis_manager *visman, uint32_t keyboard_present);
|
||||
#endif
|
||||
|
||||
@ -10,9 +10,48 @@
|
||||
use std::cmp::min;
|
||||
use ::outputs::c::OutputHandle;
|
||||
|
||||
mod c {
|
||||
pub mod c {
|
||||
use super::*;
|
||||
use std::os::raw::c_void;
|
||||
use ::util::c::Wrapped;
|
||||
|
||||
/// ServerContextService*
|
||||
#[repr(transparent)]
|
||||
pub struct UIManager(*const c_void);
|
||||
|
||||
extern "C" {
|
||||
pub fn server_context_service_update_visible(imservice: *const UIManager, active: u32);
|
||||
pub fn server_context_service_release_visibility(imservice: *const UIManager);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_visman_new() -> Wrapped<VisibilityManager> {
|
||||
Wrapped::new(VisibilityManager {
|
||||
ui_manager: None,
|
||||
visibility_state: VisibilityFactors {
|
||||
im_active: false,
|
||||
physical_keyboard_present: false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Use to initialize the UI reference
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_visman_set_ui(visman: Wrapped<VisibilityManager>, ui_manager: *const UIManager) {
|
||||
let visman = visman.clone_ref();
|
||||
let mut visman = visman.borrow_mut();
|
||||
visman.set_ui_manager(Some(ui_manager))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_visman_set_keyboard_present(visman: Wrapped<VisibilityManager>, present: u32) {
|
||||
let visman = visman.clone_ref();
|
||||
let mut visman = visman.borrow_mut();
|
||||
visman.set_keyboard_present(present != 0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
@ -79,3 +118,131 @@ impl Manager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum Visibility {
|
||||
Hidden,
|
||||
Visible,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum VisibilityTransition {
|
||||
/// Hide immediately
|
||||
Hide,
|
||||
/// Hide if no show request comes soon
|
||||
Release,
|
||||
/// Show instantly
|
||||
Show,
|
||||
/// Don't do anything
|
||||
NoTransition,
|
||||
}
|
||||
|
||||
/// Contains visibility policy
|
||||
#[derive(Clone, Debug)]
|
||||
struct VisibilityFactors {
|
||||
im_active: bool,
|
||||
physical_keyboard_present: bool,
|
||||
}
|
||||
|
||||
impl VisibilityFactors {
|
||||
/// Static policy.
|
||||
/// Use when transitioning from an undefined state (e.g. no UI before).
|
||||
fn desired(&self) -> Visibility {
|
||||
match self {
|
||||
VisibilityFactors {
|
||||
im_active: true,
|
||||
physical_keyboard_present: false,
|
||||
} => Visibility::Visible,
|
||||
_ => Visibility::Hidden,
|
||||
}
|
||||
}
|
||||
/// Stateful policy
|
||||
fn transition_to(&self, next: &Self) -> VisibilityTransition {
|
||||
use self::Visibility::*;
|
||||
let im_deactivation = self.im_active && !next.im_active;
|
||||
match (self.desired(), next.desired(), im_deactivation) {
|
||||
(Visible, Hidden, true) => VisibilityTransition::Release,
|
||||
(Visible, Hidden, _) => VisibilityTransition::Hide,
|
||||
(Hidden, Visible, _) => VisibilityTransition::Show,
|
||||
_ => VisibilityTransition::NoTransition,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary struct for migration. Should be integrated with Manager eventually.
|
||||
pub struct VisibilityManager {
|
||||
/// Owned reference. Be careful, it's shared with C at large
|
||||
ui_manager: Option<*const c::UIManager>,
|
||||
visibility_state: VisibilityFactors,
|
||||
}
|
||||
|
||||
impl VisibilityManager {
|
||||
fn set_ui_manager(&mut self, ui_manager: Option<*const c::UIManager>) {
|
||||
let new = VisibilityManager {
|
||||
ui_manager,
|
||||
..unsafe { self.clone() }
|
||||
};
|
||||
self.apply_changes(new);
|
||||
}
|
||||
|
||||
fn apply_changes(&mut self, new: Self) {
|
||||
if let Some(ui) = &new.ui_manager {
|
||||
if self.ui_manager.is_none() {
|
||||
// Previous state was never applied, so effectively undefined.
|
||||
// Just apply the new one.
|
||||
let new_state = new.visibility_state.desired();
|
||||
unsafe {
|
||||
c::server_context_service_update_visible(
|
||||
*ui,
|
||||
(new_state == Visibility::Visible) as u32,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
match self.visibility_state.transition_to(&new.visibility_state) {
|
||||
VisibilityTransition::Hide => unsafe {
|
||||
c::server_context_service_update_visible(*ui, 0);
|
||||
},
|
||||
VisibilityTransition::Show => unsafe {
|
||||
c::server_context_service_update_visible(*ui, 1);
|
||||
},
|
||||
VisibilityTransition::Release => unsafe {
|
||||
c::server_context_service_release_visibility(*ui);
|
||||
},
|
||||
VisibilityTransition::NoTransition => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
*self = new;
|
||||
}
|
||||
|
||||
pub fn set_im_active(&mut self, im_active: bool) {
|
||||
let new = VisibilityManager {
|
||||
visibility_state: VisibilityFactors {
|
||||
im_active,
|
||||
..self.visibility_state.clone()
|
||||
},
|
||||
..unsafe { self.clone() }
|
||||
};
|
||||
self.apply_changes(new);
|
||||
}
|
||||
|
||||
pub fn set_keyboard_present(&mut self, keyboard_present: bool) {
|
||||
let new = VisibilityManager {
|
||||
visibility_state: VisibilityFactors {
|
||||
physical_keyboard_present: keyboard_present,
|
||||
..self.visibility_state.clone()
|
||||
},
|
||||
..unsafe { self.clone() }
|
||||
};
|
||||
self.apply_changes(new);
|
||||
}
|
||||
|
||||
/// The struct is not really safe to clone due to the ui_manager reference.
|
||||
/// This is only a helper for getting desired visibility.
|
||||
unsafe fn clone(&self) -> Self {
|
||||
VisibilityManager {
|
||||
ui_manager: self.ui_manager.clone(),
|
||||
visibility_state: self.visibility_state.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,6 @@ pub mod c {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
// From libc, to let KeyMap get deallocated.
|
||||
fn close(fd: u32);
|
||||
|
||||
Reference in New Issue
Block a user