Merge branch 'central_visible' into 'master'
Central visibility policy See merge request Librem5/squeekboard!409
This commit is contained in:
		@ -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
 | 
			
		||||
@ -42,8 +41,6 @@ pub mod c {
 | 
			
		||||
        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
 | 
			
		||||
@ -153,7 +150,7 @@ pub mod c {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        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 +176,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 +329,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 +346,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 +368,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 => {
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -288,7 +287,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 +296,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 +316,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 +391,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 +415,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_hide_keyboard (ServerContextService *self);
 | 
			
		||||
void server_context_service_set_enabled (ServerContextService *self, gboolean enabled);
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* SERVER_CONTEXT_SERVICE_H */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -277,8 +277,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 +291,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -4,17 +4,19 @@
 | 
			
		||||
#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);
 | 
			
		||||
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(
 | 
			
		||||
 | 
			
		||||
@ -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,10 +10,50 @@
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    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"
 | 
			
		||||
    fn squeek_uiman_new() -> Wrapped<Manager> {
 | 
			
		||||
@ -79,3 +119,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(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user