Merge branch 'tiny' into 'master'
Output sensing See merge request World/Phosh/squeekboard!524
This commit is contained in:
		@ -29,7 +29,9 @@ use std::time::Instant;
 | 
			
		||||
use crate::logging::Warn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Type of the sender that waits for external events
 | 
			
		||||
type Sender = mpsc::Sender<Event>;
 | 
			
		||||
/// Type of the sender that waits for internal state changes
 | 
			
		||||
type UISender = glib::Sender<Commands>;
 | 
			
		||||
 | 
			
		||||
/// This loop driver spawns a new thread which updates the state in a loop,
 | 
			
		||||
 | 
			
		||||
@ -26,21 +26,32 @@ pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use std::os::raw::{c_char, c_void};
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
        
 | 
			
		||||
    /// struct zwp_input_method_v2*
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(PartialEq, Clone, Copy)]
 | 
			
		||||
    pub struct InputMethod(*const c_void);
 | 
			
		||||
 | 
			
		||||
    impl InputMethod {
 | 
			
		||||
        pub fn is_null(&self) -> bool {
 | 
			
		||||
            self.0.is_null()
 | 
			
		||||
        }
 | 
			
		||||
        pub fn null() -> Self {
 | 
			
		||||
            Self(ptr::null())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        fn imservice_destroy_im(im: *mut c::InputMethod);
 | 
			
		||||
        fn imservice_destroy_im(im: InputMethod);
 | 
			
		||||
 | 
			
		||||
        #[allow(improper_ctypes)] // IMService will never be dereferenced in C
 | 
			
		||||
        pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
 | 
			
		||||
        pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char);
 | 
			
		||||
        pub fn eek_input_method_delete_surrounding_text(im: *mut InputMethod, before: u32, after: u32);
 | 
			
		||||
        pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32);
 | 
			
		||||
        pub fn imservice_connect_listeners(im: InputMethod, imservice: *const IMService);
 | 
			
		||||
        pub fn eek_input_method_commit_string(im: InputMethod, text: *const c_char);
 | 
			
		||||
        pub fn eek_input_method_delete_surrounding_text(im: InputMethod, before: u32, after: u32);
 | 
			
		||||
        pub fn eek_input_method_commit(im: InputMethod, serial: u32);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
			
		||||
@ -49,7 +60,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_input_method_activate(imservice: *mut IMService,
 | 
			
		||||
        im: *const InputMethod)
 | 
			
		||||
        im: InputMethod)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
        imservice.preedit_string = String::new();
 | 
			
		||||
@ -62,7 +73,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
 | 
			
		||||
        im: *const InputMethod)
 | 
			
		||||
        im: InputMethod)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
        imservice.pending = IMProtocolState {
 | 
			
		||||
@ -74,7 +85,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_surrounding_text(imservice: *mut IMService,
 | 
			
		||||
        im: *const InputMethod,
 | 
			
		||||
        im: InputMethod,
 | 
			
		||||
        text: *const c_char, cursor: u32, _anchor: u32)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
@ -90,7 +101,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_content_type(imservice: *mut IMService,
 | 
			
		||||
        im: *const InputMethod,
 | 
			
		||||
        im: InputMethod,
 | 
			
		||||
        hint: u32, purpose: u32)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
@ -118,7 +129,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_text_change_cause(imservice: *mut IMService,
 | 
			
		||||
        im: *const InputMethod,
 | 
			
		||||
        im: InputMethod,
 | 
			
		||||
        cause: u32)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
@ -138,7 +149,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_done(imservice: *mut IMService,
 | 
			
		||||
        im: *const InputMethod)
 | 
			
		||||
        im: InputMethod)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
 | 
			
		||||
@ -156,7 +167,7 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn imservice_handle_unavailable(imservice: *mut IMService,
 | 
			
		||||
        im: *mut InputMethod)
 | 
			
		||||
        im: InputMethod)
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
        unsafe { imservice_destroy_im(im); }
 | 
			
		||||
@ -181,7 +192,7 @@ pub mod c {
 | 
			
		||||
    /// Care must be take
 | 
			
		||||
    /// not to exceed the lifetime of the pointer with the reference,
 | 
			
		||||
    /// especially not to store it.
 | 
			
		||||
    fn check_imservice(imservice: *mut IMService, im: *const InputMethod)
 | 
			
		||||
    fn check_imservice(imservice: *mut IMService, im: InputMethod)
 | 
			
		||||
        -> Result<&'static mut IMService, &'static str>
 | 
			
		||||
    {
 | 
			
		||||
        if imservice.is_null() {
 | 
			
		||||
@ -315,7 +326,7 @@ impl Default for IMProtocolState {
 | 
			
		||||
 | 
			
		||||
pub struct IMService {
 | 
			
		||||
    /// Owned reference (still created and destroyed in C)
 | 
			
		||||
    pub im: *mut c::InputMethod,
 | 
			
		||||
    pub im: c::InputMethod,
 | 
			
		||||
    sender: driver::Threaded,
 | 
			
		||||
 | 
			
		||||
    pending: IMProtocolState,
 | 
			
		||||
@ -331,7 +342,7 @@ pub enum SubmitError {
 | 
			
		||||
 | 
			
		||||
impl IMService {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        im: *mut c::InputMethod,
 | 
			
		||||
        im: c::InputMethod,
 | 
			
		||||
        sender: driver::Threaded,
 | 
			
		||||
    ) -> Box<IMService> {
 | 
			
		||||
        // IMService will be referenced to by C,
 | 
			
		||||
 | 
			
		||||
@ -21,11 +21,12 @@ struct rsobjects {
 | 
			
		||||
    struct receiver *receiver;
 | 
			
		||||
    struct squeek_state_manager *state_manager;
 | 
			
		||||
    struct submission *submission;
 | 
			
		||||
    struct squeek_wayland *wayland;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void register_ui_loop_handler(struct receiver *receiver, ServerContextService *ui, DBusHandler *dbus_handler);
 | 
			
		||||
 | 
			
		||||
struct rsobjects squeek_rsobjects_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk);
 | 
			
		||||
struct rsobjects squeek_init(void);
 | 
			
		||||
 | 
			
		||||
void squeek_state_send_force_visible(struct squeek_state_manager *state);
 | 
			
		||||
void squeek_state_send_force_hidden(struct squeek_state_manager *state);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,4 +1,4 @@
 | 
			
		||||
/* Copyright (C) 2020 Purism SPC
 | 
			
		||||
/* Copyright (C) 2020,2022 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -11,12 +11,14 @@ use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
			
		||||
mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::os::raw::c_void;
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use std::rc::Rc;
 | 
			
		||||
    use std::time::Instant;
 | 
			
		||||
 | 
			
		||||
    use crate::event_loop::driver;
 | 
			
		||||
    use crate::imservice::IMService;
 | 
			
		||||
    use crate::imservice::c::InputMethod;
 | 
			
		||||
    use crate::outputs::Outputs;
 | 
			
		||||
    use crate::state;
 | 
			
		||||
    use crate::submission::Submission;
 | 
			
		||||
    use crate::util::c::Wrapped;
 | 
			
		||||
@ -33,12 +35,45 @@ mod c {
 | 
			
		||||
    /// Holds the Rust structures that are interesting from C.
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    pub struct RsObjects {
 | 
			
		||||
        /// The handle to which Commands should be sent
 | 
			
		||||
        /// for processing in the main loop.
 | 
			
		||||
        receiver: Wrapped<Receiver<Commands>>,
 | 
			
		||||
        state_manager: Wrapped<driver::Threaded>,
 | 
			
		||||
        submission: Wrapped<Submission>,
 | 
			
		||||
        /// Not wrapped, because C needs to access this.
 | 
			
		||||
        wayland: *mut Wayland,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Corresponds to wayland.h::squeek_wayland.
 | 
			
		||||
    /// Fields unused by Rust are marked as generic data types.
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    pub struct Wayland {
 | 
			
		||||
        layer_shell: *const c_void,
 | 
			
		||||
        virtual_keyboard_manager: *const c_void,
 | 
			
		||||
        input_method_manager: *const c_void,
 | 
			
		||||
        outputs: Wrapped<Outputs>,
 | 
			
		||||
        seat: *const c_void,
 | 
			
		||||
        input_method: InputMethod,
 | 
			
		||||
        virtual_keyboard: ZwpVirtualKeyboardV1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Wayland {
 | 
			
		||||
        fn new(outputs_manager: Outputs) -> Self {
 | 
			
		||||
            Wayland {
 | 
			
		||||
                layer_shell: ptr::null(),
 | 
			
		||||
                virtual_keyboard_manager: ptr::null(),
 | 
			
		||||
                input_method_manager: ptr::null(),
 | 
			
		||||
                outputs: Wrapped::new(outputs_manager),
 | 
			
		||||
                seat: ptr::null(),
 | 
			
		||||
                input_method: InputMethod::null(),
 | 
			
		||||
                virtual_keyboard: ZwpVirtualKeyboardV1::null(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        #[allow(improper_ctypes)]
 | 
			
		||||
        fn init_wayland(wayland: *mut Wayland);
 | 
			
		||||
        fn server_context_service_real_show_keyboard(service: *const UIManager);
 | 
			
		||||
        fn server_context_service_real_hide_keyboard(service: *const UIManager);
 | 
			
		||||
        fn server_context_service_set_hint_purpose(service: *const UIManager, hint: u32, purpose: u32);
 | 
			
		||||
@ -52,19 +87,23 @@ mod c {
 | 
			
		||||
    /// and that leads to suffering.
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_rsobjects_new(
 | 
			
		||||
        im: *mut InputMethod,
 | 
			
		||||
        vk: ZwpVirtualKeyboardV1,
 | 
			
		||||
    ) -> RsObjects {
 | 
			
		||||
    fn squeek_init() -> RsObjects {
 | 
			
		||||
        // Set up channels
 | 
			
		||||
        let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT);
 | 
			
		||||
        
 | 
			
		||||
        let now = Instant::now();
 | 
			
		||||
        let state_manager = driver::Threaded::new(sender, state::Application::new(now));
 | 
			
		||||
 | 
			
		||||
        let imservice = if im.is_null() {
 | 
			
		||||
        let outputs = Outputs::new(state_manager.clone());
 | 
			
		||||
        let mut wayland = Box::new(Wayland::new(outputs));
 | 
			
		||||
        let wayland_raw = &mut *wayland as *mut _;
 | 
			
		||||
        unsafe { init_wayland(wayland_raw); }
 | 
			
		||||
 | 
			
		||||
        let vk = wayland.virtual_keyboard;
 | 
			
		||||
 | 
			
		||||
        let imservice = if wayland.input_method.is_null() {
 | 
			
		||||
            None
 | 
			
		||||
        } else {
 | 
			
		||||
            Some(IMService::new(im, state_manager.clone()))
 | 
			
		||||
            Some(IMService::new(wayland.input_method, state_manager.clone()))
 | 
			
		||||
        };
 | 
			
		||||
        let submission = Submission::new(vk, imservice);
 | 
			
		||||
        
 | 
			
		||||
@ -72,6 +111,7 @@ mod c {
 | 
			
		||||
            submission: Wrapped::new(submission),
 | 
			
		||||
            state_manager: Wrapped::new(state_manager),
 | 
			
		||||
            receiver: Wrapped::new(receiver),
 | 
			
		||||
            wayland: Box::into_raw(wayland),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,8 @@ struct squeek_output_handle {
 | 
			
		||||
 | 
			
		||||
struct squeek_outputs *squeek_outputs_new(void);
 | 
			
		||||
void squeek_outputs_free(struct squeek_outputs*);
 | 
			
		||||
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
 | 
			
		||||
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output, uint32_t id);
 | 
			
		||||
struct wl_output *squeek_outputs_try_unregister(struct squeek_outputs*, uint32_t id);
 | 
			
		||||
struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*);
 | 
			
		||||
int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										208
									
								
								src/outputs.rs
									
									
									
									
									
								
							
							
						
						
									
										208
									
								
								src/outputs.rs
									
									
									
									
									
								
							@ -1,6 +1,11 @@
 | 
			
		||||
/* Copyright (C) 2019-2022 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! Managing Wayland outputs */
 | 
			
		||||
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
use crate::event_loop;
 | 
			
		||||
use ::logging;
 | 
			
		||||
 | 
			
		||||
// traits
 | 
			
		||||
@ -11,15 +16,22 @@ pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    use std::os::raw::{ c_char, c_void };
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
 | 
			
		||||
    use ::util::c::COpaquePtr;
 | 
			
		||||
    use ::util::c::{COpaquePtr, Wrapped};
 | 
			
		||||
 | 
			
		||||
    // Defined in C
 | 
			
		||||
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Clone, PartialEq, Copy)]
 | 
			
		||||
    #[derive(Clone, PartialEq, Copy, Debug)]
 | 
			
		||||
    pub struct WlOutput(*const c_void);
 | 
			
		||||
 | 
			
		||||
    impl WlOutput {
 | 
			
		||||
        fn null() -> Self {
 | 
			
		||||
            Self(ptr::null())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    struct WlOutputListener<T: COpaquePtr> {
 | 
			
		||||
        geometry: extern fn(
 | 
			
		||||
@ -63,7 +75,7 @@ pub mod c {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Map to `wl_output.transform` values
 | 
			
		||||
    #[derive(Clone)]
 | 
			
		||||
    #[derive(Clone, Copy, Debug)]
 | 
			
		||||
    pub enum Transform {
 | 
			
		||||
        Normal = 0,
 | 
			
		||||
        Rotated90 = 1,
 | 
			
		||||
@ -103,7 +115,8 @@ pub mod c {
 | 
			
		||||
        ) -> i32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type COutputs = ::util::c::Wrapped<Outputs>;
 | 
			
		||||
    /// Wrapping Outputs is required for calling its methods from C
 | 
			
		||||
    type COutputs = Wrapped<Outputs>;
 | 
			
		||||
 | 
			
		||||
    /// A stable reference to an output.
 | 
			
		||||
    #[derive(Clone)]
 | 
			
		||||
@ -119,12 +132,16 @@ pub mod c {
 | 
			
		||||
        pub fn get_state(&self) -> Option<OutputState> {
 | 
			
		||||
            let outputs = self.outputs.clone_ref();
 | 
			
		||||
            let outputs = outputs.borrow();
 | 
			
		||||
            find_output(&outputs, self.wl_output.clone()).map(|o| o.current.clone())
 | 
			
		||||
            outputs
 | 
			
		||||
                .find_output(self.wl_output.clone())
 | 
			
		||||
                .map(|o| o.current.clone())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Defined in Rust
 | 
			
		||||
 | 
			
		||||
    // Callbacks from the output listener follow
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_geometry(
 | 
			
		||||
        outputs: COutputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
@ -143,7 +160,8 @@ pub mod c {
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut collection = outputs.borrow_mut();
 | 
			
		||||
        let output_state: Option<&mut OutputState>
 | 
			
		||||
            = find_output_mut(&mut collection, wl_output)
 | 
			
		||||
            = collection
 | 
			
		||||
                .find_output_mut(wl_output)
 | 
			
		||||
                .map(|o| &mut o.pending);
 | 
			
		||||
        match output_state {
 | 
			
		||||
            Some(state) => { state.transform = Some(transform) },
 | 
			
		||||
@ -171,7 +189,8 @@ pub mod c {
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut collection = outputs.borrow_mut();
 | 
			
		||||
        let output_state: Option<&mut OutputState>
 | 
			
		||||
            = find_output_mut(&mut collection, wl_output)
 | 
			
		||||
            = collection
 | 
			
		||||
                .find_output_mut(wl_output)
 | 
			
		||||
                .map(|o| &mut o.pending);
 | 
			
		||||
        match output_state {
 | 
			
		||||
            Some(state) => {
 | 
			
		||||
@ -192,14 +211,27 @@ pub mod c {
 | 
			
		||||
    ) {
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut collection = outputs.borrow_mut();
 | 
			
		||||
        let output = find_output_mut(&mut collection, wl_output);
 | 
			
		||||
        match output {
 | 
			
		||||
            Some(output) => { output.current = output.pending.clone(); }
 | 
			
		||||
            None => log_print!(
 | 
			
		||||
                logging::Level::Warning,
 | 
			
		||||
                "Got done on unknown output",
 | 
			
		||||
            ),
 | 
			
		||||
        let output = collection
 | 
			
		||||
            .find_output_mut(wl_output);
 | 
			
		||||
        let event = match output {
 | 
			
		||||
            Some(output) => {
 | 
			
		||||
                output.current = output.pending.clone();
 | 
			
		||||
                Some(Event {
 | 
			
		||||
                    output: OutputId(wl_output),
 | 
			
		||||
                    change: ChangeType::Altered(output.current),
 | 
			
		||||
                })
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                log_print!(
 | 
			
		||||
                    logging::Level::Warning,
 | 
			
		||||
                    "Got done on unknown output",
 | 
			
		||||
                );
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        if let Some(event) = event {
 | 
			
		||||
            collection.send_event(event);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_scale(
 | 
			
		||||
@ -210,7 +242,8 @@ pub mod c {
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut collection = outputs.borrow_mut();
 | 
			
		||||
        let output_state: Option<&mut OutputState>
 | 
			
		||||
            = find_output_mut(&mut collection, wl_output)
 | 
			
		||||
            = collection
 | 
			
		||||
                .find_output_mut(wl_output)
 | 
			
		||||
                .map(|o| &mut o.pending);
 | 
			
		||||
        match output_state {
 | 
			
		||||
            Some(state) => { state.scale = factor; }
 | 
			
		||||
@ -221,11 +254,7 @@ pub mod c {
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_new() -> COutputs {
 | 
			
		||||
        COutputs::new(Outputs { outputs: Vec::new() })
 | 
			
		||||
    }
 | 
			
		||||
    // End callbacks
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
@ -235,14 +264,17 @@ pub mod c {
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput) {
 | 
			
		||||
    fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput, id: u32) {
 | 
			
		||||
        let collection = raw_collection.clone_ref();
 | 
			
		||||
        let mut collection = collection.borrow_mut();
 | 
			
		||||
        collection.outputs.push(Output {
 | 
			
		||||
            output: output.clone(),
 | 
			
		||||
            pending: OutputState::uninitialized(),
 | 
			
		||||
            current: OutputState::uninitialized(),
 | 
			
		||||
        });
 | 
			
		||||
        collection.outputs.push((
 | 
			
		||||
            Output {
 | 
			
		||||
                output: output.clone(),
 | 
			
		||||
                pending: OutputState::uninitialized(),
 | 
			
		||||
                current: OutputState::uninitialized(),
 | 
			
		||||
            },
 | 
			
		||||
            id,
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        unsafe { squeek_output_add_listener(
 | 
			
		||||
            output,
 | 
			
		||||
@ -256,40 +288,33 @@ pub mod c {
 | 
			
		||||
        )};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// This will try to unregister the output, if the id matches a registered one.
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_try_unregister(raw_collection: COutputs, id: u32) -> WlOutput {
 | 
			
		||||
        let collection = raw_collection.clone_ref();
 | 
			
		||||
        let mut collection = collection.borrow_mut();
 | 
			
		||||
        collection.remove_output_by_global(id)
 | 
			
		||||
            .map_err(|e| log_print!(
 | 
			
		||||
                logging::Level::Debug,
 | 
			
		||||
                "Tried to remove global {:x} but it is not registered as an output: {:?}",
 | 
			
		||||
                id, e,
 | 
			
		||||
            ))
 | 
			
		||||
            .unwrap_or(WlOutput::null())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle {
 | 
			
		||||
        let collection = raw_collection.clone_ref();
 | 
			
		||||
        let collection = collection.borrow();
 | 
			
		||||
        OutputHandle {
 | 
			
		||||
            wl_output: collection.outputs[0].output.clone(),
 | 
			
		||||
            wl_output: collection.outputs[0].0.output.clone(),
 | 
			
		||||
            outputs: raw_collection.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: handle unregistration
 | 
			
		||||
    
 | 
			
		||||
    fn find_output(
 | 
			
		||||
        collection: &Outputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
    ) -> Option<&Output> {
 | 
			
		||||
        collection.outputs
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find_map(|o|
 | 
			
		||||
                if o.output == wl_output { Some(o) } else { None }
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn find_output_mut(
 | 
			
		||||
        collection: &mut Outputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
    ) -> Option<&mut Output> {
 | 
			
		||||
        collection.outputs
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .find_map(|o|
 | 
			
		||||
                if o.output == wl_output { Some(o) } else { None }
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Generic size
 | 
			
		||||
@ -300,13 +325,13 @@ pub struct Size {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// wl_output mode
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
struct Mode {
 | 
			
		||||
    width: i32,
 | 
			
		||||
    height: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
pub struct OutputState {
 | 
			
		||||
    current_mode: Option<Mode>,
 | 
			
		||||
    transform: Option<c::Transform>,
 | 
			
		||||
@ -355,12 +380,89 @@ impl OutputState {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Output {
 | 
			
		||||
/// Not guaranteed to exist,
 | 
			
		||||
/// but can be used to look up state.
 | 
			
		||||
#[derive(Clone, Copy, PartialEq, Debug)]
 | 
			
		||||
pub struct OutputId(c::WlOutput);
 | 
			
		||||
 | 
			
		||||
// WlOutput is a pointer,
 | 
			
		||||
// but in the public interface,
 | 
			
		||||
// we're only using it as a lookup key.
 | 
			
		||||
unsafe impl Send for OutputId {}
 | 
			
		||||
 | 
			
		||||
struct Output {
 | 
			
		||||
    output: c::WlOutput,
 | 
			
		||||
    pending: OutputState,
 | 
			
		||||
    current: OutputState,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct NotFound;
 | 
			
		||||
 | 
			
		||||
type GlobalId = u32;
 | 
			
		||||
 | 
			
		||||
pub struct Outputs {
 | 
			
		||||
    outputs: Vec<Output>,
 | 
			
		||||
    outputs: Vec<(Output, GlobalId)>,
 | 
			
		||||
    sender: event_loop::driver::Threaded,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Outputs {
 | 
			
		||||
    pub fn new(sender: event_loop::driver::Threaded) -> Outputs {
 | 
			
		||||
        Outputs {
 | 
			
		||||
            outputs: Vec::new(),
 | 
			
		||||
            sender,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn send_event(&self, event: Event) {
 | 
			
		||||
        self.sender.send(event.into()).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn remove_output_by_global(&mut self, id: GlobalId)
 | 
			
		||||
        -> Result<c::WlOutput, NotFound>
 | 
			
		||||
    {
 | 
			
		||||
        let index = self.outputs.iter()
 | 
			
		||||
            .position(|(_o, global_id)| *global_id == id);
 | 
			
		||||
        if let Some(index) = index {
 | 
			
		||||
            let (output, _id) = self.outputs.remove(index);
 | 
			
		||||
            self.send_event(Event {
 | 
			
		||||
                change: ChangeType::Removed,
 | 
			
		||||
                output: OutputId(output.output),
 | 
			
		||||
            });
 | 
			
		||||
            Ok(output.output)
 | 
			
		||||
        } else {
 | 
			
		||||
            Err(NotFound)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn find_output(&self, wl_output: c::WlOutput) -> Option<&Output> {
 | 
			
		||||
        self.outputs
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find_map(|(o, _global)|
 | 
			
		||||
                if o.output == wl_output { Some(o) } else { None }
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn find_output_mut(&mut self, wl_output: c::WlOutput)
 | 
			
		||||
        -> Option<&mut Output>
 | 
			
		||||
    {
 | 
			
		||||
        self.outputs
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .find_map(|(o, _global)|
 | 
			
		||||
                if o.output == wl_output { Some(o) } else { None }
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
pub enum ChangeType {
 | 
			
		||||
    /// Added or changed
 | 
			
		||||
    Altered(OutputState),
 | 
			
		||||
    Removed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
pub struct Event {
 | 
			
		||||
    output: OutputId,
 | 
			
		||||
    change: ChangeType,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -31,8 +31,6 @@ G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONT
 | 
			
		||||
 | 
			
		||||
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct squeek_state_manager *state_manager);
 | 
			
		||||
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
 | 
			
		||||
void server_context_service_force_show_keyboard (ServerContextService *self);
 | 
			
		||||
void server_context_service_hide_keyboard (ServerContextService *self);
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* SERVER_CONTEXT_SERVICE_H */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -112,34 +112,38 @@ registry_handle_global (void *data,
 | 
			
		||||
    // Even when lower version would be served, it would not be supported,
 | 
			
		||||
    // causing a hard exit
 | 
			
		||||
    (void)version;
 | 
			
		||||
    struct squeekboard *instance = data;
 | 
			
		||||
    struct squeek_wayland *wayland = data;
 | 
			
		||||
 | 
			
		||||
    if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) {
 | 
			
		||||
        instance->wayland.layer_shell = wl_registry_bind (registry, name,
 | 
			
		||||
        wayland->layer_shell = wl_registry_bind (registry, name,
 | 
			
		||||
            &zwlr_layer_shell_v1_interface, 1);
 | 
			
		||||
    } else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) {
 | 
			
		||||
        instance->wayland.virtual_keyboard_manager = wl_registry_bind(registry, name,
 | 
			
		||||
        wayland->virtual_keyboard_manager = wl_registry_bind(registry, name,
 | 
			
		||||
            &zwp_virtual_keyboard_manager_v1_interface, 1);
 | 
			
		||||
    } else if (!strcmp (interface, zwp_input_method_manager_v2_interface.name)) {
 | 
			
		||||
        instance->wayland.input_method_manager = wl_registry_bind(registry, name,
 | 
			
		||||
        wayland->input_method_manager = wl_registry_bind(registry, name,
 | 
			
		||||
            &zwp_input_method_manager_v2_interface, 1);
 | 
			
		||||
    } else if (!strcmp (interface, "wl_output")) {
 | 
			
		||||
        struct wl_output *output = wl_registry_bind (registry, name,
 | 
			
		||||
            &wl_output_interface, 2);
 | 
			
		||||
        squeek_outputs_register(instance->wayland.outputs, output);
 | 
			
		||||
        squeek_outputs_register(wayland->outputs, output, name);
 | 
			
		||||
    } else if (!strcmp(interface, "wl_seat")) {
 | 
			
		||||
        instance->wayland.seat = wl_registry_bind(registry, name,
 | 
			
		||||
        wayland->seat = wl_registry_bind(registry, name,
 | 
			
		||||
            &wl_seat_interface, 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
registry_handle_global_remove (void *data,
 | 
			
		||||
                               struct wl_registry *registry,
 | 
			
		||||
                               uint32_t name)
 | 
			
		||||
{
 | 
			
		||||
  // TODO
 | 
			
		||||
    (void)registry;
 | 
			
		||||
    struct squeek_wayland *wayland = data;
 | 
			
		||||
    struct wl_output *output = squeek_outputs_try_unregister(wayland->outputs, name);
 | 
			
		||||
    if (output) {
 | 
			
		||||
        wl_output_destroy(output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_registry_listener registry_listener = {
 | 
			
		||||
@ -147,6 +151,54 @@ static const struct wl_registry_listener registry_listener = {
 | 
			
		||||
  registry_handle_global_remove
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void init_wayland(struct squeek_wayland *wayland) {
 | 
			
		||||
    // Set up Wayland
 | 
			
		||||
    gdk_set_allowed_backends ("wayland");
 | 
			
		||||
    GdkDisplay *gdk_display = gdk_display_get_default ();
 | 
			
		||||
    struct wl_display *display = gdk_wayland_display_get_wl_display (gdk_display);
 | 
			
		||||
 | 
			
		||||
    if (display == NULL) {
 | 
			
		||||
        g_error ("Failed to get display: %m\n");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct wl_registry *registry = wl_display_get_registry (display);
 | 
			
		||||
    wl_registry_add_listener (registry, ®istry_listener, wayland);
 | 
			
		||||
    wl_display_roundtrip(display); // wait until the registry is actually populated
 | 
			
		||||
 | 
			
		||||
    if (!wayland->seat) {
 | 
			
		||||
        g_error("No seat Wayland global available.");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    if (!wayland->virtual_keyboard_manager) {
 | 
			
		||||
        g_error("No virtual keyboard manager Wayland global available.");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    if (!wayland->layer_shell) {
 | 
			
		||||
        g_error("No layer shell global available.");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!wayland->input_method_manager) {
 | 
			
		||||
        g_warning("Wayland input method interface not available");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (wayland->input_method_manager) {
 | 
			
		||||
        wayland->input_method = zwp_input_method_manager_v2_get_input_method(
 | 
			
		||||
            wayland->input_method_manager,
 | 
			
		||||
            wayland->seat);
 | 
			
		||||
    }
 | 
			
		||||
    if (wayland->virtual_keyboard_manager) {
 | 
			
		||||
        wayland->virtual_keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
 | 
			
		||||
            wayland->virtual_keyboard_manager,
 | 
			
		||||
            wayland->seat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // initialize global
 | 
			
		||||
    squeek_wayland = wayland;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SESSION_NAME "sm.puri.OSK0"
 | 
			
		||||
 | 
			
		||||
GDBusProxy *_proxy = NULL;
 | 
			
		||||
@ -284,22 +336,6 @@ phosh_theme_init (void)
 | 
			
		||||
    g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create Rust objects in one go,
 | 
			
		||||
/// to avoid crossing the language barrier and losing type information
 | 
			
		||||
static struct rsobjects create_rsobjects(struct zwp_input_method_manager_v2 *immanager,
 | 
			
		||||
                                         struct zwp_virtual_keyboard_manager_v1 *vkmanager,
 | 
			
		||||
                                         struct wl_seat *seat) {
 | 
			
		||||
    struct zwp_input_method_v2 *im = NULL;
 | 
			
		||||
    if (immanager) {
 | 
			
		||||
        im = zwp_input_method_manager_v2_get_input_method(immanager, seat);
 | 
			
		||||
    }
 | 
			
		||||
    struct zwp_virtual_keyboard_v1 *vk = NULL;
 | 
			
		||||
    if (vkmanager) {
 | 
			
		||||
        vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmanager, seat);
 | 
			
		||||
    }
 | 
			
		||||
    return squeek_rsobjects_new(im, vk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GDebugKey debug_keys[] =
 | 
			
		||||
{
 | 
			
		||||
        { .key = "force-show",
 | 
			
		||||
@ -359,44 +395,10 @@ main (int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
    phosh_theme_init ();
 | 
			
		||||
 | 
			
		||||
    // Set up Wayland
 | 
			
		||||
    gdk_set_allowed_backends ("wayland");
 | 
			
		||||
    GdkDisplay *gdk_display = gdk_display_get_default ();
 | 
			
		||||
    struct wl_display *display = gdk_wayland_display_get_wl_display (gdk_display);
 | 
			
		||||
 | 
			
		||||
    if (display == NULL) {
 | 
			
		||||
        g_error ("Failed to get display: %m\n");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    struct squeekboard instance = {0};
 | 
			
		||||
    squeek_wayland_init (&instance.wayland);
 | 
			
		||||
    struct wl_registry *registry = wl_display_get_registry (display);
 | 
			
		||||
    wl_registry_add_listener (registry, ®istry_listener, &instance);
 | 
			
		||||
    wl_display_roundtrip(display); // wait until the registry is actually populated
 | 
			
		||||
    squeek_wayland_set_global(&instance.wayland);
 | 
			
		||||
 | 
			
		||||
    if (!instance.wayland.seat) {
 | 
			
		||||
        g_error("No seat Wayland global available.");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    if (!instance.wayland.virtual_keyboard_manager) {
 | 
			
		||||
        g_error("No virtual keyboard manager Wayland global available.");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    if (!instance.wayland.layer_shell) {
 | 
			
		||||
        g_error("No layer shell global available.");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!instance.wayland.input_method_manager) {
 | 
			
		||||
        g_warning("Wayland input method interface not available");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct rsobjects rsobjects = create_rsobjects(instance.wayland.input_method_manager,
 | 
			
		||||
        instance.wayland.virtual_keyboard_manager,
 | 
			
		||||
        instance.wayland.seat);
 | 
			
		||||
    // Also initializes wayland
 | 
			
		||||
    struct rsobjects rsobjects = squeek_init();
 | 
			
		||||
 | 
			
		||||
    instance.ui_manager = squeek_uiman_new();
 | 
			
		||||
 | 
			
		||||
@ -477,6 +479,5 @@ main (int argc, char **argv)
 | 
			
		||||
    }
 | 
			
		||||
    g_main_loop_unref (loop);
 | 
			
		||||
 | 
			
		||||
    squeek_wayland_deinit (&instance.wayland);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								src/state.rs
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/state.rs
									
									
									
									
									
								
							@ -8,6 +8,7 @@
 | 
			
		||||
use crate::animation;
 | 
			
		||||
use crate::imservice::{ ContentHint, ContentPurpose };
 | 
			
		||||
use crate::main::{ Commands, PanelCommand };
 | 
			
		||||
use crate::outputs;
 | 
			
		||||
use std::time::Instant;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,12 +30,14 @@ pub enum InputMethod {
 | 
			
		||||
    InactiveSince(Instant),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Incoming events
 | 
			
		||||
/// Incoming events.
 | 
			
		||||
/// This contains events that cause a change to the internal state.
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum Event {
 | 
			
		||||
    InputMethod(InputMethod),
 | 
			
		||||
    Visibility(visibility::Event),
 | 
			
		||||
    PhysicalKeyboard(Presence),
 | 
			
		||||
    Output(outputs::Event),
 | 
			
		||||
    /// Event triggered because a moment in time passed.
 | 
			
		||||
    /// Use to animate state transitions.
 | 
			
		||||
    /// The value is the ideal arrival time.
 | 
			
		||||
@ -47,6 +50,12 @@ impl From<InputMethod> for Event {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<outputs::Event> for Event {
 | 
			
		||||
    fn from(ev: outputs::Event) -> Self {
 | 
			
		||||
        Self::Output(ev)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub mod visibility {
 | 
			
		||||
    #[derive(Clone)]
 | 
			
		||||
    pub enum Event {
 | 
			
		||||
@ -164,6 +173,11 @@ impl Application {
 | 
			
		||||
                ..self
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            Event::Output(output) => {
 | 
			
		||||
                println!("Stub: output event {:?}", output);
 | 
			
		||||
                self
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            Event::InputMethod(new_im) => match (self.im.clone(), new_im) {
 | 
			
		||||
                (InputMethod::Active(_old), InputMethod::Active(new_im))
 | 
			
		||||
                => Self {
 | 
			
		||||
 | 
			
		||||
@ -10,11 +10,18 @@ type KeyCode = u32;
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::{ c_char, c_void };
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Clone, Copy)]
 | 
			
		||||
    pub struct ZwpVirtualKeyboardV1(*const c_void);
 | 
			
		||||
 | 
			
		||||
    impl ZwpVirtualKeyboardV1 {
 | 
			
		||||
        pub fn null() -> Self {
 | 
			
		||||
            Self(ptr::null())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    pub struct KeyMap {
 | 
			
		||||
        fd: u32,
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,12 @@
 | 
			
		||||
 | 
			
		||||
struct squeek_wayland *squeek_wayland = NULL;
 | 
			
		||||
 | 
			
		||||
void squeek_wayland_init_global(struct squeek_outputs *outputs) {
 | 
			
		||||
    struct squeek_wayland *wayland = {0};
 | 
			
		||||
    wayland->outputs = outputs;
 | 
			
		||||
    squeek_wayland = wayland;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The following functions only exist
 | 
			
		||||
// to create linkable symbols out of inline functions,
 | 
			
		||||
// because those are not directly callable from Rust
 | 
			
		||||
 | 
			
		||||
@ -10,27 +10,18 @@
 | 
			
		||||
#include "outputs.h"
 | 
			
		||||
 | 
			
		||||
struct squeek_wayland {
 | 
			
		||||
    // globals
 | 
			
		||||
    struct zwlr_layer_shell_v1 *layer_shell;
 | 
			
		||||
    struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
 | 
			
		||||
    struct zwp_input_method_manager_v2 *input_method_manager;
 | 
			
		||||
    struct squeek_outputs *outputs;
 | 
			
		||||
    struct wl_seat *seat;
 | 
			
		||||
    // objects
 | 
			
		||||
    struct zwp_input_method_v2 *input_method;
 | 
			
		||||
    struct zwp_virtual_keyboard_v1 *virtual_keyboard;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern struct squeek_wayland *squeek_wayland;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static inline void squeek_wayland_init(struct squeek_wayland *wayland) {
 | 
			
		||||
    wayland->outputs = squeek_outputs_new();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
 | 
			
		||||
    squeek_wayland = wayland;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void squeek_wayland_deinit(struct squeek_wayland *wayland) {
 | 
			
		||||
    squeek_outputs_free(wayland->outputs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // WAYLAND_H
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user