panel: Split away panel handling
This reduces ServerContextService to a mere handler of "docked mode" gsetting.
This commit is contained in:
		@ -55,6 +55,8 @@ typedef struct _EekGtkKeyboardPrivate
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GdkEventSequence *sequence; // unowned reference
 | 
					    GdkEventSequence *sequence; // unowned reference
 | 
				
			||||||
    LfbEvent *event;
 | 
					    LfbEvent *event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gulong kb_signal;
 | 
				
			||||||
} EekGtkKeyboardPrivate;
 | 
					} EekGtkKeyboardPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
 | 
					G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
 | 
				
			||||||
@ -307,12 +309,19 @@ eek_gtk_keyboard_set_property (GObject      *object,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This may actually get called multiple times in a row
 | 
				
			||||||
 | 
					// if both a parent object and its parent get destroyed
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eek_gtk_keyboard_dispose (GObject *object)
 | 
					eek_gtk_keyboard_dispose (GObject *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (object);
 | 
					    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (object);
 | 
				
			||||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
					    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (priv->kb_signal != 0) {
 | 
				
			||||||
 | 
					        g_signal_handler_disconnect(priv->eekboard_context, priv->kb_signal);
 | 
				
			||||||
 | 
					        priv->kb_signal = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (priv->renderer) {
 | 
					    if (priv->renderer) {
 | 
				
			||||||
        eek_renderer_free(priv->renderer);
 | 
					        eek_renderer_free(priv->renderer);
 | 
				
			||||||
        priv->renderer = NULL;
 | 
					        priv->renderer = NULL;
 | 
				
			||||||
@ -424,7 +433,7 @@ eek_gtk_keyboard_new (EekboardContextService *eekservice,
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    priv->render_geometry = initial_geometry;
 | 
					    priv->render_geometry = initial_geometry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_signal_connect (eekservice,
 | 
					    priv->kb_signal = g_signal_connect (eekservice,
 | 
				
			||||||
                      "notify::keyboard",
 | 
					                      "notify::keyboard",
 | 
				
			||||||
                      G_CALLBACK(on_notify_keyboard),
 | 
					                      G_CALLBACK(on_notify_keyboard),
 | 
				
			||||||
                      ret);
 | 
					                      ret);
 | 
				
			||||||
 | 
				
			|||||||
@ -60,10 +60,10 @@ struct _EekboardContextService {
 | 
				
			|||||||
    LevelKeyboard *keyboard; // currently used keyboard
 | 
					    LevelKeyboard *keyboard; // currently used keyboard
 | 
				
			||||||
    GSettings *settings; // Owned reference
 | 
					    GSettings *settings; // Owned reference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Maybe TODO: it's used only for fetching layout type.
 | 
					    /// Needed for keymap changes after keyboard updates.
 | 
				
			||||||
    // Maybe let UI push the type to this structure?
 | 
					    // TODO: can the main loop access submission to change the key maps instead?
 | 
				
			||||||
    ServerContextService *ui; // unowned reference
 | 
					    // This should probably land together with passing buttons through state,
 | 
				
			||||||
    /// Needed for keymap changes after keyboard updates
 | 
					    // to avoid race conditions between setting buttons and key maps.
 | 
				
			||||||
    struct submission *submission; // unowned
 | 
					    struct submission *submission; // unowned
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -297,6 +297,8 @@ eekboard_context_service_get_keyboard (EekboardContextService *context)
 | 
				
			|||||||
    return context->keyboard;
 | 
					    return context->keyboard;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used from Rust.
 | 
				
			||||||
 | 
					// TODO: move hint management to Rust entirely
 | 
				
			||||||
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
					void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
				
			||||||
                                               uint32_t hint, uint32_t purpose)
 | 
					                                               uint32_t hint, uint32_t purpose)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -340,7 +342,3 @@ void eekboard_context_service_set_submission(EekboardContextService *context, st
 | 
				
			|||||||
        submission_use_layout(context->submission, context->keyboard->layout, time);
 | 
					        submission_use_layout(context->submission, context->keyboard->layout, time);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui) {
 | 
					 | 
				
			||||||
    context->ui = ui;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -39,16 +39,12 @@ G_DECLARE_FINAL_TYPE(EekboardContextService, eekboard_context_service, EEKBOARD,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state);
 | 
					EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state);
 | 
				
			||||||
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission);
 | 
					void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission);
 | 
				
			||||||
void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui);
 | 
					 | 
				
			||||||
void          eekboard_context_service_destroy (EekboardContextService *context);
 | 
					void          eekboard_context_service_destroy (EekboardContextService *context);
 | 
				
			||||||
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
 | 
					LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void eekboard_context_service_set_keymap(EekboardContextService *context,
 | 
					void eekboard_context_service_set_keymap(EekboardContextService *context,
 | 
				
			||||||
                                         const LevelKeyboard *keyboard);
 | 
					                                         const LevelKeyboard *keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
					 | 
				
			||||||
                                               uint32_t hint,
 | 
					 | 
				
			||||||
                                               uint32_t purpose);
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout, uint32_t timestamp);
 | 
					eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout, uint32_t timestamp);
 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
				
			|||||||
@ -6,8 +6,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::main::PixelSize;
 | 
					 | 
				
			||||||
use crate::outputs::OutputId;
 | 
					use crate::outputs::OutputId;
 | 
				
			||||||
 | 
					use crate::panel::PixelSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The keyboard should hide after this has elapsed to prevent flickering.
 | 
					/// The keyboard should hide after this has elapsed to prevent flickering.
 | 
				
			||||||
pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
 | 
					pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
 | 
				
			||||||
 | 
				
			|||||||
@ -151,7 +151,7 @@ mod test {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::animation;
 | 
					    use crate::animation;
 | 
				
			||||||
    use crate::imservice::{ ContentHint, ContentPurpose };
 | 
					    use crate::imservice::{ ContentHint, ContentPurpose };
 | 
				
			||||||
    use crate::main::PanelCommand;
 | 
					    use crate::panel;
 | 
				
			||||||
    use crate::state::{ Application, InputMethod, InputMethodDetails, Presence, visibility };
 | 
					    use crate::state::{ Application, InputMethod, InputMethodDetails, Presence, visibility };
 | 
				
			||||||
    use crate::state::test::application_with_fake_output;
 | 
					    use crate::state::test::application_with_fake_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -176,13 +176,13 @@ mod test {
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        let l = State::new(state, now);
 | 
					        let l = State::new(state, now);
 | 
				
			||||||
        let (l, commands) = handle_event(l, InputMethod::InactiveSince(now).into(), now);
 | 
					        let (l, commands) = handle_event(l, InputMethod::InactiveSince(now).into(), now);
 | 
				
			||||||
        assert_matches!(commands.panel_visibility, Some(PanelCommand::Show{..}));
 | 
					        assert_matches!(commands.panel_visibility, Some(panel::Command::Show{..}));
 | 
				
			||||||
        assert_eq!(l.scheduled_wakeup, Some(now + animation::HIDING_TIMEOUT));
 | 
					        assert_eq!(l.scheduled_wakeup, Some(now + animation::HIDING_TIMEOUT));
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        now += animation::HIDING_TIMEOUT;
 | 
					        now += animation::HIDING_TIMEOUT;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        let (l, commands) = handle_event(l, Event::TimeoutReached(now), now);
 | 
					        let (l, commands) = handle_event(l, Event::TimeoutReached(now), now);
 | 
				
			||||||
        assert_eq!(commands.panel_visibility, Some(PanelCommand::Hide));
 | 
					        assert_eq!(commands.panel_visibility, Some(panel::Command::Hide));
 | 
				
			||||||
        assert_eq!(l.scheduled_wakeup, None);
 | 
					        assert_eq!(l.scheduled_wakeup, None);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "submission.h"
 | 
					#include "input-method-unstable-v2-client-protocol.h"
 | 
				
			||||||
 | 
					#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <glib.h>
 | 
					#include "submission.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct imservice;
 | 
					struct imservice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ mod locale;
 | 
				
			|||||||
mod main;
 | 
					mod main;
 | 
				
			||||||
mod manager;
 | 
					mod manager;
 | 
				
			||||||
mod outputs;
 | 
					mod outputs;
 | 
				
			||||||
 | 
					mod panel;
 | 
				
			||||||
mod popover;
 | 
					mod popover;
 | 
				
			||||||
mod resources;
 | 
					mod resources;
 | 
				
			||||||
mod state;
 | 
					mod state;
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "eek/eek-types.h"
 | 
					#include "eek/eek-types.h"
 | 
				
			||||||
#include "dbus.h"
 | 
					#include "dbus.h"
 | 
				
			||||||
 | 
					#include "panel.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct receiver;
 | 
					struct receiver;
 | 
				
			||||||
@ -24,7 +25,7 @@ struct rsobjects {
 | 
				
			|||||||
    struct squeek_wayland *wayland;
 | 
					    struct squeek_wayland *wayland;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void register_ui_loop_handler(struct receiver *receiver, ServerContextService *ui, DBusHandler *dbus_handler);
 | 
					void register_ui_loop_handler(struct receiver *receiver, struct panel_manager *panel, EekboardContextService *hint_manager, DBusHandler *dbus_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rsobjects squeek_init(void);
 | 
					struct rsobjects squeek_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										76
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								src/main.rs
									
									
									
									
									
								
							@ -3,7 +3,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Glue for the main loop. */
 | 
					/*! Glue for the main loop. */
 | 
				
			||||||
use crate::outputs::OutputId;
 | 
					use crate::panel;
 | 
				
			||||||
use crate::debug;
 | 
					use crate::debug;
 | 
				
			||||||
use crate::state;
 | 
					use crate::state;
 | 
				
			||||||
use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
					use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
				
			||||||
@ -20,20 +20,22 @@ mod c {
 | 
				
			|||||||
    use crate::imservice::IMService;
 | 
					    use crate::imservice::IMService;
 | 
				
			||||||
    use crate::imservice::c::InputMethod;
 | 
					    use crate::imservice::c::InputMethod;
 | 
				
			||||||
    use crate::outputs::Outputs;
 | 
					    use crate::outputs::Outputs;
 | 
				
			||||||
    use crate::outputs::c::WlOutput;
 | 
					 | 
				
			||||||
    use crate::state;
 | 
					    use crate::state;
 | 
				
			||||||
    use crate::submission::Submission;
 | 
					    use crate::submission::Submission;
 | 
				
			||||||
    use crate::util::c::Wrapped;
 | 
					    use crate::util::c::Wrapped;
 | 
				
			||||||
    use crate::vkeyboard::c::ZwpVirtualKeyboardV1;
 | 
					    use crate::vkeyboard::c::ZwpVirtualKeyboardV1;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /// ServerContextService*
 | 
					 | 
				
			||||||
    #[repr(transparent)]
 | 
					 | 
				
			||||||
    pub struct UIManager(*const c_void);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /// DbusHandler*
 | 
					    /// DbusHandler*
 | 
				
			||||||
    #[repr(transparent)]
 | 
					    #[repr(transparent)]
 | 
				
			||||||
    pub struct DBusHandler(*const c_void);
 | 
					    pub struct DBusHandler(*const c_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// EekboardContextService* in the role of a hint receiver
 | 
				
			||||||
 | 
					    // The clone/copy is a concession to C style of programming.
 | 
				
			||||||
 | 
					    // It would be hard to get rid of it.
 | 
				
			||||||
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    #[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					    pub struct HintManager(*const c_void);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    /// Holds the Rust structures that are interesting from C.
 | 
					    /// Holds the Rust structures that are interesting from C.
 | 
				
			||||||
    #[repr(C)]
 | 
					    #[repr(C)]
 | 
				
			||||||
    pub struct RsObjects {
 | 
					    pub struct RsObjects {
 | 
				
			||||||
@ -76,9 +78,7 @@ mod c {
 | 
				
			|||||||
    extern "C" {
 | 
					    extern "C" {
 | 
				
			||||||
        #[allow(improper_ctypes)]
 | 
					        #[allow(improper_ctypes)]
 | 
				
			||||||
        fn init_wayland(wayland: *mut Wayland);
 | 
					        fn init_wayland(wayland: *mut Wayland);
 | 
				
			||||||
        fn server_context_service_update_keyboard(service: *const UIManager, output: WlOutput, scaled_height: u32);
 | 
					        fn eekboard_context_service_set_hint_purpose(service: HintManager, hint: u32, purpose: u32);
 | 
				
			||||||
        fn server_context_service_real_hide_keyboard(service: *const UIManager);
 | 
					 | 
				
			||||||
        fn server_context_service_set_hint_purpose(service: *const UIManager, hint: u32, purpose: u32);
 | 
					 | 
				
			||||||
        // This should probably only get called from the gtk main loop,
 | 
					        // This should probably only get called from the gtk main loop,
 | 
				
			||||||
        // given that dbus handler is using glib.
 | 
					        // given that dbus handler is using glib.
 | 
				
			||||||
        fn dbus_handler_set_visible(dbus: *const DBusHandler, visible: u8);
 | 
					        fn dbus_handler_set_visible(dbus: *const DBusHandler, visible: u8);
 | 
				
			||||||
@ -124,18 +124,20 @@ mod c {
 | 
				
			|||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn register_ui_loop_handler(
 | 
					    fn register_ui_loop_handler(
 | 
				
			||||||
        receiver: Wrapped<Receiver<Commands>>,
 | 
					        receiver: Wrapped<Receiver<Commands>>,
 | 
				
			||||||
        ui_manager: *const UIManager,
 | 
					        panel_manager: panel::c::PanelManager,
 | 
				
			||||||
 | 
					        hint_manager: HintManager,
 | 
				
			||||||
        dbus_handler: *const DBusHandler,
 | 
					        dbus_handler: *const DBusHandler,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let receiver = unsafe { receiver.unwrap() };
 | 
					        let receiver = unsafe { receiver.unwrap() };
 | 
				
			||||||
        let receiver = Rc::try_unwrap(receiver).expect("References still present");
 | 
					        let receiver = Rc::try_unwrap(receiver).expect("References still present");
 | 
				
			||||||
        let receiver = receiver.into_inner();
 | 
					        let receiver = receiver.into_inner();
 | 
				
			||||||
 | 
					        let panel_manager = Wrapped::new(panel::Manager::new(panel_manager));
 | 
				
			||||||
        let ctx = MainContext::default();
 | 
					        let ctx = MainContext::default();
 | 
				
			||||||
        let _acqu = ctx.acquire();
 | 
					        let _acqu = ctx.acquire();
 | 
				
			||||||
        receiver.attach(
 | 
					        receiver.attach(
 | 
				
			||||||
            Some(&ctx),
 | 
					            Some(&ctx),
 | 
				
			||||||
            move |msg| {
 | 
					            move |msg| {
 | 
				
			||||||
                main_loop_handle_message(msg, ui_manager, dbus_handler);
 | 
					                main_loop_handle_message(msg, panel_manager.clone(), hint_manager, dbus_handler);
 | 
				
			||||||
                Continue(true)
 | 
					                Continue(true)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
@ -149,18 +151,13 @@ mod c {
 | 
				
			|||||||
    /// and doesn't lend itself to testing other than integration.
 | 
					    /// and doesn't lend itself to testing other than integration.
 | 
				
			||||||
    fn main_loop_handle_message(
 | 
					    fn main_loop_handle_message(
 | 
				
			||||||
        msg: Commands,
 | 
					        msg: Commands,
 | 
				
			||||||
        ui_manager: *const UIManager,
 | 
					        panel_manager: Wrapped<panel::Manager>,
 | 
				
			||||||
 | 
					        hint_manager: HintManager,
 | 
				
			||||||
        dbus_handler: *const DBusHandler,
 | 
					        dbus_handler: *const DBusHandler,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        match msg.panel_visibility {
 | 
					        if let Some(visibility) = msg.panel_visibility {
 | 
				
			||||||
            Some(PanelCommand::Show { output, height }) => unsafe {
 | 
					            panel::Manager::update(panel_manager, visibility);
 | 
				
			||||||
                server_context_service_update_keyboard(ui_manager, output.0, height.as_scaled_ceiling());
 | 
					        }
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Some(PanelCommand::Hide) => unsafe {
 | 
					 | 
				
			||||||
                server_context_service_real_hide_keyboard(ui_manager);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            None => {},
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(visible) = msg.dbus_visible_set {
 | 
					        if let Some(visible) = msg.dbus_visible_set {
 | 
				
			||||||
            if dbus_handler != std::ptr::null() {
 | 
					            if dbus_handler != std::ptr::null() {
 | 
				
			||||||
@ -170,8 +167,8 @@ mod c {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if let Some(hints) = msg.layout_hint_set {
 | 
					        if let Some(hints) = msg.layout_hint_set {
 | 
				
			||||||
            unsafe {
 | 
					            unsafe {
 | 
				
			||||||
                server_context_service_set_hint_purpose(
 | 
					                eekboard_context_service_set_hint_purpose(
 | 
				
			||||||
                    ui_manager,
 | 
					                    hint_manager,
 | 
				
			||||||
                    hints.hint.bits(),
 | 
					                    hints.hint.bits(),
 | 
				
			||||||
                    hints.purpose.clone() as u32,
 | 
					                    hints.purpose.clone() as u32,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
@ -180,42 +177,11 @@ mod c {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Size in pixels that is aware of scaling
 | 
					 | 
				
			||||||
#[derive(Clone, Copy, PartialEq, Debug)]
 | 
					 | 
				
			||||||
pub struct PixelSize {
 | 
					 | 
				
			||||||
    pub pixels: u32,
 | 
					 | 
				
			||||||
    pub scale_factor: u32,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn div_ceil(a: u32, b: u32) -> u32 {
 | 
					 | 
				
			||||||
    // Given that it's for pixels on a screen, an overflow is unlikely.
 | 
					 | 
				
			||||||
    (a + b - 1) / b
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl PixelSize {
 | 
					 | 
				
			||||||
    pub fn as_scaled_floor(&self) -> u32 {
 | 
					 | 
				
			||||||
        self.pixels / self.scale_factor
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn as_scaled_ceiling(&self) -> u32 {
 | 
					 | 
				
			||||||
        div_ceil(self.pixels, self.scale_factor)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, PartialEq, Debug)]
 | 
					 | 
				
			||||||
pub enum PanelCommand {
 | 
					 | 
				
			||||||
    Show {
 | 
					 | 
				
			||||||
        output: OutputId,
 | 
					 | 
				
			||||||
        height: PixelSize,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    Hide,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The commands consumed by the main loop,
 | 
					/// The commands consumed by the main loop,
 | 
				
			||||||
/// to be sent out to external components.
 | 
					/// to be sent out to external components.
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
pub struct Commands {
 | 
					pub struct Commands {
 | 
				
			||||||
    pub panel_visibility: Option<PanelCommand>,
 | 
					    pub panel_visibility: Option<panel::Command>,
 | 
				
			||||||
    pub layout_hint_set: Option<state::InputMethodDetails>,
 | 
					    pub layout_hint_set: Option<state::InputMethodDetails>,
 | 
				
			||||||
    pub dbus_visible_set: Option<bool>,
 | 
					    pub dbus_visible_set: Option<bool>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ sources = [
 | 
				
			|||||||
  config_h,
 | 
					  config_h,
 | 
				
			||||||
  'dbus.c',
 | 
					  'dbus.c',
 | 
				
			||||||
  'imservice.c',
 | 
					  'imservice.c',
 | 
				
			||||||
 | 
					  'panel.c',
 | 
				
			||||||
  'popover.c',
 | 
					  'popover.c',
 | 
				
			||||||
  'server-context-service.c',
 | 
					  'server-context-service.c',
 | 
				
			||||||
  'wayland.c',
 | 
					  'wayland.c',
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										130
									
								
								src/panel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/panel.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					#include "eekboard/eekboard-context-service.h"
 | 
				
			||||||
 | 
					#include "wayland.h"
 | 
				
			||||||
 | 
					#include "panel.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Called from rust
 | 
				
			||||||
 | 
					/// Destroys the widget
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					panel_manager_hide(struct panel_manager *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (self->window) {
 | 
				
			||||||
 | 
					        gtk_widget_destroy (GTK_WIDGET (self->window));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (self->widget) {
 | 
				
			||||||
 | 
					        gtk_widget_destroy (GTK_WIDGET (self->widget));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    self->window = NULL;
 | 
				
			||||||
 | 
					    self->widget = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_destroy (struct panel_manager *self, GtkWidget *widget)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_assert (widget == GTK_WIDGET(self->window));
 | 
				
			||||||
 | 
					    panel_manager_hide(self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// panel::Manager. Only needed for this callback
 | 
				
			||||||
 | 
					struct squeek_panel_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Calls back into Rust
 | 
				
			||||||
 | 
					void squeek_panel_manager_configured(struct squeek_panel_manager *mgr, uint32_t width, uint32_t height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_surface_configure(struct squeek_panel_manager *self, PhoshLayerSurface *surface)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gint width;
 | 
				
			||||||
 | 
					    gint height;
 | 
				
			||||||
 | 
					    g_return_if_fail (PHOSH_IS_LAYER_SURFACE (surface));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_object_get(G_OBJECT(surface),
 | 
				
			||||||
 | 
					                 "configured-width", &width,
 | 
				
			||||||
 | 
					                 "configured-height", &height,
 | 
				
			||||||
 | 
					                 NULL);
 | 
				
			||||||
 | 
					    squeek_panel_manager_configured(self, width, height);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_widget_set_has_tooltip (self->widget, TRUE);
 | 
				
			||||||
 | 
					    gtk_container_add (GTK_CONTAINER(self->window), self->widget);
 | 
				
			||||||
 | 
					    gtk_widget_show_all(self->widget);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Called from rust
 | 
				
			||||||
 | 
					/// Creates a new panel widget
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					panel_manager_request_widget (struct panel_manager *self, struct wl_output *output, uint32_t height, struct squeek_panel_manager *mgr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (self->window) {
 | 
				
			||||||
 | 
					        g_error("Window already present");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->window = g_object_new (
 | 
				
			||||||
 | 
					        PHOSH_TYPE_LAYER_SURFACE,
 | 
				
			||||||
 | 
					        "layer-shell", squeek_wayland->layer_shell,
 | 
				
			||||||
 | 
					        "wl-output", output,
 | 
				
			||||||
 | 
					        "height", height,
 | 
				
			||||||
 | 
					        "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
 | 
				
			||||||
 | 
					        | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
 | 
				
			||||||
 | 
					        | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
 | 
				
			||||||
 | 
					        "layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
 | 
				
			||||||
 | 
					        "kbd-interactivity", FALSE,
 | 
				
			||||||
 | 
					        "exclusive-zone", height,
 | 
				
			||||||
 | 
					        "namespace", "osk",
 | 
				
			||||||
 | 
					        NULL
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_object_connect (self->window,
 | 
				
			||||||
 | 
					        "swapped-signal::destroy", G_CALLBACK(on_destroy), self,
 | 
				
			||||||
 | 
					        "swapped-signal::configured", G_CALLBACK(on_surface_configure), mgr,
 | 
				
			||||||
 | 
					        NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The properties below are just to make hacking easier.
 | 
				
			||||||
 | 
					    // The way we use layer-shell overrides some,
 | 
				
			||||||
 | 
					    // and there's no space in the protocol for others.
 | 
				
			||||||
 | 
					    // Those may still be useful in the future,
 | 
				
			||||||
 | 
					    // or for hacks with regular windows.
 | 
				
			||||||
 | 
					    gtk_widget_set_can_focus (GTK_WIDGET(self->window), FALSE);
 | 
				
			||||||
 | 
					    g_object_set (G_OBJECT(self->window), "accept_focus", FALSE, NULL);
 | 
				
			||||||
 | 
					    gtk_window_set_title (GTK_WINDOW(self->window), "Squeekboard");
 | 
				
			||||||
 | 
					    gtk_window_set_icon_name (GTK_WINDOW(self->window), "squeekboard");
 | 
				
			||||||
 | 
					    gtk_window_set_keep_above (GTK_WINDOW(self->window), TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    make_widget(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_widget_show (GTK_WIDGET(self->window));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Called from rust
 | 
				
			||||||
 | 
					/// Updates the size
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					panel_manager_resize (struct panel_manager *self, uint32_t height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    phosh_layer_surface_set_size(self->window, 0, height);
 | 
				
			||||||
 | 
					    phosh_layer_surface_set_exclusive_zone(self->window, height);
 | 
				
			||||||
 | 
					    phosh_layer_surface_wl_surface_commit(self->window);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct panel_manager mgr = {
 | 
				
			||||||
 | 
					        .state = state,
 | 
				
			||||||
 | 
					        .submission = submission,
 | 
				
			||||||
 | 
					        .layout = layout,
 | 
				
			||||||
 | 
					        .window = NULL,
 | 
				
			||||||
 | 
					        .widget = NULL,
 | 
				
			||||||
 | 
					        .current_output = NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return mgr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/panel.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/panel.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eek/layersurface.h"
 | 
				
			||||||
 | 
					#include "src/layout.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 submission *submission; // unowned
 | 
				
			||||||
 | 
					    struct squeek_layout_state *layout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PhoshLayerSurface *window;
 | 
				
			||||||
 | 
					    GtkWidget *widget; // nullable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Those should be held in Rust
 | 
				
			||||||
 | 
					    struct wl_output *current_output;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout);
 | 
				
			||||||
							
								
								
									
										248
									
								
								src/panel.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/panel.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,248 @@
 | 
				
			|||||||
 | 
					/* Copyright (C) 2022 Purism SPC
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Panel state management.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is effectively a mirror of the previous C code,
 | 
				
			||||||
 | 
					 * with an explicit state machine managing the panel size.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It still relies on a callback from Wayland to accept the panel size,
 | 
				
			||||||
 | 
					 * which makes this code somewhat prone to mistakes.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * An alternative to the callback would be
 | 
				
			||||||
 | 
					 * to send a message all the way to `state::State`
 | 
				
			||||||
 | 
					 * every time the allocated size changes.
 | 
				
			||||||
 | 
					 * That would allow for a more holistic view
 | 
				
			||||||
 | 
					 * of interactions of different pieces of state.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * However, `state::State` already has the potential to become a ball of mud,
 | 
				
			||||||
 | 
					 * tightly coupling different functionality and making it difficult to see independent units.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * For this reason, I'm taking a light touch approach with the panel manager,
 | 
				
			||||||
 | 
					 * and moving it just a bit closer to `state::State`.
 | 
				
			||||||
 | 
					 * Hopefully ths still allows us to expose assumptions that were not stated yet
 | 
				
			||||||
 | 
					 * (e.g. can the output disappear between size request andallocation?).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Tight coupling, e.g. a future one between presented hints and layout size,
 | 
				
			||||||
 | 
					 * will have to be taken into account later.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::logging;
 | 
				
			||||||
 | 
					use crate::outputs::OutputId;
 | 
				
			||||||
 | 
					use crate::util::c::Wrapped;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod c {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    use glib;
 | 
				
			||||||
 | 
					    use gtk::Continue;
 | 
				
			||||||
 | 
					    use std::os::raw::c_void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use crate::outputs::c::WlOutput;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// struct panel_manager*
 | 
				
			||||||
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    #[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					    pub struct PanelManager(*const c_void);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    extern "C" {
 | 
				
			||||||
 | 
					        #[allow(improper_ctypes)]
 | 
				
			||||||
 | 
					        pub fn panel_manager_request_widget(
 | 
				
			||||||
 | 
					            service: PanelManager,
 | 
				
			||||||
 | 
					            output: WlOutput,
 | 
				
			||||||
 | 
					            height: u32,
 | 
				
			||||||
 | 
					            // for callbacks
 | 
				
			||||||
 | 
					            panel: Wrapped<Manager>,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        pub fn panel_manager_resize(service: PanelManager, height: u32);
 | 
				
			||||||
 | 
					        pub fn panel_manager_hide(service: PanelManager);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_panel_manager_configured(panel: Wrapped<Manager>, width: u32, height: u32) {
 | 
				
			||||||
 | 
					        // This is why this needs to be moved into state::State:
 | 
				
			||||||
 | 
					        // it's getting too coupled to glib.
 | 
				
			||||||
 | 
					        glib::idle_add_local(move || {
 | 
				
			||||||
 | 
					            let panel = panel.clone_ref();
 | 
				
			||||||
 | 
					            panel.borrow_mut().set_configured(Size{width, height});
 | 
				
			||||||
 | 
					            Continue(false)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Size in pixels that is aware of scaling
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, PartialEq, Debug)]
 | 
				
			||||||
 | 
					pub struct PixelSize {
 | 
				
			||||||
 | 
					    pub pixels: u32,
 | 
				
			||||||
 | 
					    pub scale_factor: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn div_ceil(a: u32, b: u32) -> u32 {
 | 
				
			||||||
 | 
					    // Given that it's for pixels on a screen, an overflow is unlikely.
 | 
				
			||||||
 | 
					    (a + b - 1) / b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PixelSize {
 | 
				
			||||||
 | 
					    pub fn as_scaled_floor(&self) -> u32 {
 | 
				
			||||||
 | 
					        self.pixels / self.scale_factor
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn as_scaled_ceiling(&self) -> u32 {
 | 
				
			||||||
 | 
					        div_ceil(self.pixels, self.scale_factor)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					struct Size {
 | 
				
			||||||
 | 
					    width: u32,
 | 
				
			||||||
 | 
					    height: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// This state requests the Wayland layer shell protocol synchronization:
 | 
				
			||||||
 | 
					/// the application asks for some size,
 | 
				
			||||||
 | 
					/// and then receives a size that the compositor thought appropriate.
 | 
				
			||||||
 | 
					/// Stores raw values passed to Wayland, i.e. scaled dimensions.
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					enum State {
 | 
				
			||||||
 | 
					    Hidden,
 | 
				
			||||||
 | 
					    SizeRequested {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        height: u32,
 | 
				
			||||||
 | 
					        //width: u32,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    SizeAllocated {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        wanted_height: u32,
 | 
				
			||||||
 | 
					        allocated: Size,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, PartialEq, Debug)]
 | 
				
			||||||
 | 
					pub enum Command {
 | 
				
			||||||
 | 
					    Show {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        height: PixelSize,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    Hide,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Tries to contain all the panel sizing duties.
 | 
				
			||||||
 | 
					pub struct Manager {
 | 
				
			||||||
 | 
					    panel: c::PanelManager,
 | 
				
			||||||
 | 
					    state: State,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Manager {
 | 
				
			||||||
 | 
					    pub fn new(panel: c::PanelManager) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            panel,
 | 
				
			||||||
 | 
					            state: State::Hidden,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // TODO: mabe send the allocated size back to state::State,
 | 
				
			||||||
 | 
					    // to perform layout adjustments
 | 
				
			||||||
 | 
					    fn set_configured(&mut self, size: Size) {
 | 
				
			||||||
 | 
					        self.state = match self.state.clone() {
 | 
				
			||||||
 | 
					            State::Hidden => {
 | 
				
			||||||
 | 
					                // This may happen if a hide is scheduled immediately after a show.
 | 
				
			||||||
 | 
					                log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Surprise,
 | 
				
			||||||
 | 
					                    "Panel has been configured, but no request is pending. Ignoring",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                State::Hidden
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            State::SizeAllocated{output, wanted_height, ..} => {
 | 
				
			||||||
 | 
					                log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Surprise,
 | 
				
			||||||
 | 
					                    "Panel received new configuration without asking",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                State::SizeAllocated{output, wanted_height, allocated: size}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            State::SizeRequested{output, height} => State::SizeAllocated {
 | 
				
			||||||
 | 
					                output,
 | 
				
			||||||
 | 
					                wanted_height: height,
 | 
				
			||||||
 | 
					                allocated: size,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn update(mgr: Wrapped<Manager>, cmd: Command) {
 | 
				
			||||||
 | 
					        let copied = mgr.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mgr = mgr.clone_ref();
 | 
				
			||||||
 | 
					        let mut mgr = mgr.borrow_mut();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (*mgr).state = match (cmd, mgr.state.clone()) {
 | 
				
			||||||
 | 
					            (Command::Hide, State::Hidden) => State::Hidden,
 | 
				
			||||||
 | 
					            (Command::Hide, State::SizeAllocated{..}) => {
 | 
				
			||||||
 | 
					                unsafe { c::panel_manager_hide(mgr.panel); }
 | 
				
			||||||
 | 
					                State::Hidden
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (Command::Hide, State::SizeRequested{..}) => {
 | 
				
			||||||
 | 
					                unsafe { c::panel_manager_hide(mgr.panel); }
 | 
				
			||||||
 | 
					                State::Hidden
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (Command::Show{output, height}, State::Hidden) => {
 | 
				
			||||||
 | 
					                let height = height.as_scaled_ceiling();
 | 
				
			||||||
 | 
					                unsafe { c::panel_manager_request_widget(mgr.panel, output.0, height, copied); }
 | 
				
			||||||
 | 
					                State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (
 | 
				
			||||||
 | 
					                Command::Show{output, height},
 | 
				
			||||||
 | 
					                State::SizeRequested{output: req_output, height: req_height},
 | 
				
			||||||
 | 
					            ) => {
 | 
				
			||||||
 | 
					                let height = height.as_scaled_ceiling();
 | 
				
			||||||
 | 
					                if output == req_output && height == req_height {
 | 
				
			||||||
 | 
					                    State::SizeRequested{output: req_output, height: req_height}
 | 
				
			||||||
 | 
					                } else if output == req_output {
 | 
				
			||||||
 | 
					                    // I'm not sure about that.
 | 
				
			||||||
 | 
					                    // This could cause a busy loop,
 | 
				
			||||||
 | 
					                    // when two requests are being processed at the same time:
 | 
				
			||||||
 | 
					                    // one message in the compositor to allocate size A,
 | 
				
			||||||
 | 
					                    // causing the state to update to height A'
 | 
				
			||||||
 | 
					                    // the other from the state wanting height B',
 | 
				
			||||||
 | 
					                    // causing the compositor to change size to B.
 | 
				
			||||||
 | 
					                    // So better cut this short here, despite artifacts.
 | 
				
			||||||
 | 
					                    // Out of simplicty, just ignore the new request.
 | 
				
			||||||
 | 
					                    // If that causes problems, the request in flight could be stored
 | 
				
			||||||
 | 
					                    // for the purpose of handling it better somehow.
 | 
				
			||||||
 | 
					                    State::SizeRequested{output: req_output, height: req_height}
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // This looks weird, but should be safe.
 | 
				
			||||||
 | 
					                    // The stack seems to handle
 | 
				
			||||||
 | 
					                    // configure events on a dead surface.
 | 
				
			||||||
 | 
					                    unsafe {
 | 
				
			||||||
 | 
					                        c::panel_manager_hide(mgr.panel);
 | 
				
			||||||
 | 
					                        c::panel_manager_request_widget(mgr.panel, output.0, height, copied);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (
 | 
				
			||||||
 | 
					                Command::Show{output, height},
 | 
				
			||||||
 | 
					                State::SizeAllocated{output: alloc_output, allocated, wanted_height},
 | 
				
			||||||
 | 
					            ) => {
 | 
				
			||||||
 | 
					                let height = height.as_scaled_ceiling();
 | 
				
			||||||
 | 
					                if output == alloc_output && height == wanted_height {
 | 
				
			||||||
 | 
					                    State::SizeAllocated{output: alloc_output, wanted_height, allocated}
 | 
				
			||||||
 | 
					                } else if output == alloc_output && height == allocated.height {
 | 
				
			||||||
 | 
					                    State::SizeAllocated{output: alloc_output, wanted_height: height, allocated}
 | 
				
			||||||
 | 
					                } else if output == alloc_output {
 | 
				
			||||||
 | 
					                    // Should *all* other heights cause a resize?
 | 
				
			||||||
 | 
					                    // What about those between wanted and allocated?
 | 
				
			||||||
 | 
					                    unsafe { c::panel_manager_resize(mgr.panel, height); }
 | 
				
			||||||
 | 
					                    State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    unsafe {
 | 
				
			||||||
 | 
					                        c::panel_manager_hide(mgr.panel);
 | 
				
			||||||
 | 
					                        c::panel_manager_request_widget(mgr.panel, output.0, height, copied);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -20,14 +20,7 @@
 | 
				
			|||||||
#include <gtk/gtk.h>
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
#include <glib/gi18n.h>
 | 
					#include <glib/gi18n.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek/eek.h"
 | 
					 | 
				
			||||||
#include "eek/eek-gtk-keyboard.h"
 | 
					 | 
				
			||||||
#include "eek/layersurface.h"
 | 
					 | 
				
			||||||
#include "eekboard/eekboard-context-service.h"
 | 
					 | 
				
			||||||
#include "submission.h"
 | 
					 | 
				
			||||||
#include "wayland.h"
 | 
					 | 
				
			||||||
#include "server-context-service.h"
 | 
					#include "server-context-service.h"
 | 
				
			||||||
#include "wayland-client-protocol.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
    PROP_0,
 | 
					    PROP_0,
 | 
				
			||||||
@ -37,149 +30,13 @@ enum {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct _ServerContextService {
 | 
					struct _ServerContextService {
 | 
				
			||||||
    GObject parent;
 | 
					    GObject parent;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    EekboardContextService *state; // unowned
 | 
					 | 
				
			||||||
    /// Needed for instantiating the widget
 | 
					 | 
				
			||||||
    struct submission *submission; // unowned
 | 
					 | 
				
			||||||
    struct squeek_layout_state *layout;
 | 
					 | 
				
			||||||
    struct squeek_state_manager *state_manager; // shared reference
 | 
					    struct squeek_state_manager *state_manager; // shared reference
 | 
				
			||||||
 | 
					 | 
				
			||||||
    PhoshLayerSurface *window;
 | 
					 | 
				
			||||||
    GtkWidget *widget; // nullable
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct wl_output *current_output;
 | 
					 | 
				
			||||||
    guint last_requested_height;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT);
 | 
					G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_destroy (ServerContextService *self, GtkWidget *widget)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_assert (widget == GTK_WIDGET(self->window));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    self->window = NULL;
 | 
					 | 
				
			||||||
    self->widget = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
make_window (ServerContextService *self, struct wl_output *output, uint32_t height)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->window) {
 | 
					 | 
				
			||||||
        g_error("Window already present");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    self->window = g_object_new (
 | 
					 | 
				
			||||||
        PHOSH_TYPE_LAYER_SURFACE,
 | 
					 | 
				
			||||||
        "layer-shell", squeek_wayland->layer_shell,
 | 
					 | 
				
			||||||
        "wl-output", output,
 | 
					 | 
				
			||||||
        "height", height,
 | 
					 | 
				
			||||||
        "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
 | 
					 | 
				
			||||||
                  | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
 | 
					 | 
				
			||||||
                  | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
 | 
					 | 
				
			||||||
        "layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
 | 
					 | 
				
			||||||
        "kbd-interactivity", FALSE,
 | 
					 | 
				
			||||||
        "exclusive-zone", height,
 | 
					 | 
				
			||||||
        "namespace", "osk",
 | 
					 | 
				
			||||||
        NULL
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_object_connect (self->window,
 | 
					 | 
				
			||||||
                      "swapped-signal::destroy", G_CALLBACK(on_destroy), self,
 | 
					 | 
				
			||||||
                      //"swapped-signal::configured", G_CALLBACK(on_surface_configure), self,
 | 
					 | 
				
			||||||
                      NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The properties below are just to make hacking easier.
 | 
					 | 
				
			||||||
    // The way we use layer-shell overrides some,
 | 
					 | 
				
			||||||
    // and there's no space in the protocol for others.
 | 
					 | 
				
			||||||
    // Those may still be useful in the future,
 | 
					 | 
				
			||||||
    // or for hacks with regular windows.
 | 
					 | 
				
			||||||
    gtk_widget_set_can_focus (GTK_WIDGET(self->window), FALSE);
 | 
					 | 
				
			||||||
    g_object_set (G_OBJECT(self->window), "accept_focus", FALSE, NULL);
 | 
					 | 
				
			||||||
    gtk_window_set_title (GTK_WINDOW(self->window), "Squeekboard");
 | 
					 | 
				
			||||||
    gtk_window_set_icon_name (GTK_WINDOW(self->window), "squeekboard");
 | 
					 | 
				
			||||||
    gtk_window_set_keep_above (GTK_WINDOW(self->window), TRUE);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
destroy_window (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gtk_widget_destroy (GTK_WIDGET (self->window));
 | 
					 | 
				
			||||||
    self->window = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
make_widget (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->widget) {
 | 
					 | 
				
			||||||
        gtk_widget_destroy(self->widget);
 | 
					 | 
				
			||||||
        self->widget = NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->layout);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    gtk_widget_set_has_tooltip (self->widget, TRUE);
 | 
					 | 
				
			||||||
    gtk_container_add (GTK_CONTAINER(self->window), self->widget);
 | 
					 | 
				
			||||||
    gtk_widget_show_all(self->widget);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called from rust
 | 
					 | 
				
			||||||
/// Updates the type of hiddenness
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
server_context_service_real_hide_keyboard (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    //self->desired_height = 0;
 | 
					 | 
				
			||||||
    self->current_output = NULL;
 | 
					 | 
				
			||||||
    if (self->window) {
 | 
					 | 
				
			||||||
        gtk_widget_hide (GTK_WIDGET(self->window));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called from rust
 | 
					 | 
				
			||||||
/// Updates the type of visibility.
 | 
					 | 
				
			||||||
/// Height is in scaled units.
 | 
					/// Height is in scaled units.
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
server_context_service_update_keyboard (ServerContextService *self, struct wl_output *output, uint32_t scaled_height)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (output != self->current_output) {
 | 
					 | 
				
			||||||
        // Recreate on a new output
 | 
					 | 
				
			||||||
        server_context_service_real_hide_keyboard(self);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        gint h;
 | 
					 | 
				
			||||||
        PhoshLayerSurface *surface = self->window;
 | 
					 | 
				
			||||||
        g_object_get(G_OBJECT(surface),
 | 
					 | 
				
			||||||
                     "configured-height", &h,
 | 
					 | 
				
			||||||
                     NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ((uint32_t)h != scaled_height) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            //TODO: make sure that redrawing happens in the correct place (it doesn't now).
 | 
					 | 
				
			||||||
            phosh_layer_surface_set_size(self->window, 0, scaled_height);
 | 
					 | 
				
			||||||
            phosh_layer_surface_set_exclusive_zone(self->window, scaled_height);
 | 
					 | 
				
			||||||
            phosh_layer_surface_wl_surface_commit(self->window);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self->current_output = output;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    self->current_output = output;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!self->window) {
 | 
					 | 
				
			||||||
        make_window (self, output, scaled_height);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!self->widget) {
 | 
					 | 
				
			||||||
        make_widget (self);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    gtk_widget_show (GTK_WIDGET(self->window));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
server_context_service_set_property (GObject      *object,
 | 
					server_context_service_set_property (GObject      *object,
 | 
				
			||||||
                                     guint         prop_id,
 | 
					                                     guint         prop_id,
 | 
				
			||||||
                                     const GValue *value,
 | 
					                                     const GValue *value,
 | 
				
			||||||
@ -210,17 +67,6 @@ server_context_service_get_property (GObject    *object,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
server_context_service_dispose (GObject *object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ServerContextService *self = SERVER_CONTEXT_SERVICE(object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    destroy_window (self);
 | 
					 | 
				
			||||||
    self->widget = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
server_context_service_class_init (ServerContextServiceClass *klass)
 | 
					server_context_service_class_init (ServerContextServiceClass *klass)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -229,7 +75,6 @@ server_context_service_class_init (ServerContextServiceClass *klass)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    gobject_class->set_property = server_context_service_set_property;
 | 
					    gobject_class->set_property = server_context_service_set_property;
 | 
				
			||||||
    gobject_class->get_property = server_context_service_get_property;
 | 
					    gobject_class->get_property = server_context_service_get_property;
 | 
				
			||||||
    gobject_class->dispose = server_context_service_dispose;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ServerContextServie:keyboard:
 | 
					     * ServerContextServie:keyboard:
 | 
				
			||||||
@ -250,41 +95,29 @@ server_context_service_class_init (ServerContextServiceClass *klass)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
server_context_service_init (ServerContextService *self) {}
 | 
					server_context_service_init (ServerContextService *self) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					
 | 
				
			||||||
init (ServerContextService *self) {
 | 
					ServerContextService *
 | 
				
			||||||
 | 
					server_context_service_new (struct squeek_state_manager *state_manager)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ServerContextService *holder = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
 | 
				
			||||||
 | 
					    holder->state_manager = state_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *schema_name = "org.gnome.desktop.a11y.applications";
 | 
					    const char *schema_name = "org.gnome.desktop.a11y.applications";
 | 
				
			||||||
    GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
 | 
					    GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
 | 
				
			||||||
    g_autoptr(GSettingsSchema) schema = NULL;
 | 
					    g_autoptr(GSettingsSchema) schema = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!ssrc) {
 | 
					    if (!ssrc) {
 | 
				
			||||||
        g_warning("No gsettings schemas installed.");
 | 
					        g_warning("No gsettings schemas installed.");
 | 
				
			||||||
        return;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE);
 | 
					    schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE);
 | 
				
			||||||
    if (schema) {
 | 
					    if (schema) {
 | 
				
			||||||
        g_autoptr(GSettings) settings = g_settings_new (schema_name);
 | 
					        g_autoptr(GSettings) settings = g_settings_new (schema_name);
 | 
				
			||||||
        g_settings_bind (settings, "screen-keyboard-enabled",
 | 
					        g_settings_bind (settings, "screen-keyboard-enabled",
 | 
				
			||||||
                         self, "enabled", G_SETTINGS_BIND_GET);
 | 
					                         holder, "enabled", G_SETTINGS_BIND_GET);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        g_warning("Gsettings schema %s is not installed on the system. "
 | 
					        g_warning("Gsettings schema %s is not installed on the system. "
 | 
				
			||||||
                  "Enabling by default.", schema_name);
 | 
					                  "Enabling by default.", schema_name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					    return holder;
 | 
				
			||||||
 | 
					 | 
				
			||||||
ServerContextService *
 | 
					 | 
				
			||||||
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct squeek_state_manager *state_manager)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
 | 
					 | 
				
			||||||
    ui->submission = submission;
 | 
					 | 
				
			||||||
    ui->state = self;
 | 
					 | 
				
			||||||
    ui->layout = layout;
 | 
					 | 
				
			||||||
    ui->state_manager = state_manager;
 | 
					 | 
				
			||||||
    init(ui);
 | 
					 | 
				
			||||||
    return ui;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Used from Rust
 | 
					 | 
				
			||||||
void server_context_service_set_hint_purpose(ServerContextService *self, uint32_t hint,
 | 
					 | 
				
			||||||
                                              uint32_t purpose) {
 | 
					 | 
				
			||||||
    eekboard_context_service_set_hint_purpose(self->state, hint, purpose);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -17,9 +17,9 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef SERVER_CONTEXT_SERVICE_H
 | 
					#ifndef SERVER_CONTEXT_SERVICE_H
 | 
				
			||||||
#define SERVER_CONTEXT_SERVICE_H 1
 | 
					#define SERVER_CONTEXT_SERVICE_H 1
 | 
				
			||||||
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "src/layout.h"
 | 
					#include "main.h"
 | 
				
			||||||
#include "src/submission.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_BEGIN_DECLS
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -28,8 +28,8 @@ G_BEGIN_DECLS
 | 
				
			|||||||
/** Manages the lifecycle of the window displaying layouts. */
 | 
					/** Manages the lifecycle of the window displaying layouts. */
 | 
				
			||||||
G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONTEXT_SERVICE, GObject)
 | 
					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 squeek_state_manager *state_manager);
 | 
					ServerContextService *server_context_service_new(struct squeek_state_manager *state_manager);
 | 
				
			||||||
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif  /* SERVER_CONTEXT_SERVICE_H */
 | 
					#endif  /* SERVER_CONTEXT_SERVICE_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,7 @@
 | 
				
			|||||||
#include "layout.h"
 | 
					#include "layout.h"
 | 
				
			||||||
#include "main.h"
 | 
					#include "main.h"
 | 
				
			||||||
#include "outputs.h"
 | 
					#include "outputs.h"
 | 
				
			||||||
 | 
					#include "panel.h"
 | 
				
			||||||
#include "submission.h"
 | 
					#include "submission.h"
 | 
				
			||||||
#include "server-context-service.h"
 | 
					#include "server-context-service.h"
 | 
				
			||||||
#include "wayland.h"
 | 
					#include "wayland.h"
 | 
				
			||||||
@ -51,8 +52,10 @@ typedef enum _SqueekboardDebugFlags {
 | 
				
			|||||||
struct squeekboard {
 | 
					struct squeekboard {
 | 
				
			||||||
    struct squeek_wayland wayland; // Just hooks.
 | 
					    struct squeek_wayland wayland; // Just hooks.
 | 
				
			||||||
    DBusHandler *dbus_handler; // Controls visibility of the OSK.
 | 
					    DBusHandler *dbus_handler; // Controls visibility of the OSK.
 | 
				
			||||||
    EekboardContextService *settings_context; // Gsettings hooks.
 | 
					    EekboardContextService *settings_context; // Gsettings hooks for layouts.
 | 
				
			||||||
    ServerContextService *ui_context; // mess, includes the entire UI
 | 
					    /// 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
 | 
					    /// Currently wanted layout. TODO: merge into state::Application
 | 
				
			||||||
    struct squeek_layout_state layout_choice;
 | 
					    struct squeek_layout_state layout_choice;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -435,20 +438,21 @@ main (int argc, char **argv)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eekboard_context_service_set_submission(instance.settings_context, rsobjects.submission);
 | 
					    ServerContextService *setting_listener = server_context_service_new(
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ServerContextService *ui_context = server_context_service_new(
 | 
					 | 
				
			||||||
                instance.settings_context,
 | 
					 | 
				
			||||||
                rsobjects.submission,
 | 
					 | 
				
			||||||
                &instance.layout_choice,
 | 
					 | 
				
			||||||
                rsobjects.state_manager);
 | 
					                rsobjects.state_manager);
 | 
				
			||||||
    if (!ui_context) {
 | 
					    if (!setting_listener) {
 | 
				
			||||||
        g_error("Could not initialize GUI");
 | 
					        g_warning ("could not connect to gsettings");
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    instance.ui_context = ui_context;
 | 
					    instance.settings_handler = setting_listener;
 | 
				
			||||||
    register_ui_loop_handler(rsobjects.receiver, instance.ui_context, instance.dbus_handler);
 | 
					
 | 
				
			||||||
 | 
					    eekboard_context_service_set_submission(instance.settings_context, rsobjects.submission);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance.panel_manager = panel_manager_new(instance.settings_context,
 | 
				
			||||||
 | 
					        rsobjects.submission,
 | 
				
			||||||
 | 
					        &instance.layout_choice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, instance.settings_context, instance.dbus_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    session_register();
 | 
					    session_register();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,9 +8,11 @@
 | 
				
			|||||||
use crate::animation;
 | 
					use crate::animation;
 | 
				
			||||||
use crate::debug;
 | 
					use crate::debug;
 | 
				
			||||||
use crate::imservice::{ ContentHint, ContentPurpose };
 | 
					use crate::imservice::{ ContentHint, ContentPurpose };
 | 
				
			||||||
use crate::main::{ Commands, PanelCommand, PixelSize };
 | 
					use crate::main::Commands;
 | 
				
			||||||
use crate::outputs;
 | 
					use crate::outputs;
 | 
				
			||||||
use crate::outputs::{Millimeter, OutputId, OutputState};
 | 
					use crate::outputs::{Millimeter, OutputId, OutputState};
 | 
				
			||||||
 | 
					use crate::panel;
 | 
				
			||||||
 | 
					use crate::panel::PixelSize;
 | 
				
			||||||
use crate::util::Rational;
 | 
					use crate::util::Rational;
 | 
				
			||||||
use std::cmp;
 | 
					use std::cmp;
 | 
				
			||||||
use std::collections::HashMap;
 | 
					use std::collections::HashMap;
 | 
				
			||||||
@ -118,8 +120,8 @@ impl Outcome {
 | 
				
			|||||||
// FIXME: handle switching outputs
 | 
					// FIXME: handle switching outputs
 | 
				
			||||||
        let (dbus_visible_set, panel_visibility) = match new_state.visibility {
 | 
					        let (dbus_visible_set, panel_visibility) = match new_state.visibility {
 | 
				
			||||||
            animation::Outcome::Visible{output, height}
 | 
					            animation::Outcome::Visible{output, height}
 | 
				
			||||||
                => (Some(true), Some(PanelCommand::Show{output, height})),
 | 
					                => (Some(true), Some(panel::Command::Show{output, height})),
 | 
				
			||||||
            animation::Outcome::Hidden => (Some(false), Some(PanelCommand::Hide)),
 | 
					            animation::Outcome::Hidden => (Some(false), Some(panel::Command::Hide)),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Commands {
 | 
					        Commands {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,12 @@
 | 
				
			|||||||
#ifndef __SUBMISSION_H
 | 
					#ifndef __SUBMISSION_H
 | 
				
			||||||
#define __SUBMISSION_H
 | 
					#define __SUBMISSION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "input-method-unstable-v2-client-protocol.h"
 | 
					#include "inttypes.h"
 | 
				
			||||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
					
 | 
				
			||||||
#include "eek/eek-types.h"
 | 
					#include "eek/eek-types.h"
 | 
				
			||||||
#include "main.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_layout;
 | 
					struct squeek_layout;
 | 
				
			||||||
 | 
					struct submission;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Defined in Rust
 | 
					// Defined in Rust
 | 
				
			||||||
uint8_t submission_hint_available(struct submission *self);
 | 
					uint8_t submission_hint_available(struct submission *self);
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user