wayland: Listen to output changes
This commit is contained in:
		@ -12,6 +12,7 @@ pub mod float_ord;
 | 
			
		||||
pub mod imservice;
 | 
			
		||||
mod keyboard;
 | 
			
		||||
mod layout;
 | 
			
		||||
mod outputs;
 | 
			
		||||
mod resources;
 | 
			
		||||
mod submission;
 | 
			
		||||
mod util;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								src/outputs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/outputs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef __OUTPUTS_H
 | 
			
		||||
#define __OUTPUTS_H
 | 
			
		||||
 | 
			
		||||
#include "wayland-client-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct squeek_outputs;
 | 
			
		||||
 | 
			
		||||
struct squeek_outputs *squeek_outputs_new();
 | 
			
		||||
void squeek_outputs_free(struct squeek_outputs*);
 | 
			
		||||
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
 | 
			
		||||
struct wl_output *squeek_outputs_get_current(struct squeek_outputs*);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										227
									
								
								src/outputs.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								src/outputs.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
			
		||||
/*! Managing Wayland outputs */
 | 
			
		||||
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    use std::os::raw::{ c_char, c_void };
 | 
			
		||||
 | 
			
		||||
    use ::util::c::COpaquePtr;
 | 
			
		||||
 | 
			
		||||
    // Defined in C
 | 
			
		||||
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Clone, PartialEq)]
 | 
			
		||||
    pub struct WlOutput(*const c_void);
 | 
			
		||||
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    struct WlOutputListener<T: COpaquePtr> {
 | 
			
		||||
        geometry: extern fn(
 | 
			
		||||
            T, // data
 | 
			
		||||
            WlOutput,
 | 
			
		||||
            i32, // x
 | 
			
		||||
            i32, // y
 | 
			
		||||
            i32, // physical_width
 | 
			
		||||
            i32, // physical_height
 | 
			
		||||
            i32, // subpixel
 | 
			
		||||
            *const c_char, // make
 | 
			
		||||
            *const c_char, // model
 | 
			
		||||
            i32, // transform
 | 
			
		||||
        ),
 | 
			
		||||
        mode: extern fn(
 | 
			
		||||
            T, // data
 | 
			
		||||
            WlOutput,
 | 
			
		||||
            u32, // flags
 | 
			
		||||
            i32, // width
 | 
			
		||||
            i32, // height
 | 
			
		||||
            i32, // refresh
 | 
			
		||||
        ),
 | 
			
		||||
        done: extern fn(
 | 
			
		||||
            T, // data
 | 
			
		||||
            WlOutput,
 | 
			
		||||
        ),
 | 
			
		||||
        scale: extern fn(
 | 
			
		||||
            T, // data
 | 
			
		||||
            WlOutput,
 | 
			
		||||
            i32, // factor
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bitflags!{
 | 
			
		||||
        /// Map to `wl_output.mode` values
 | 
			
		||||
        pub struct Mode: u32 {
 | 
			
		||||
            const NONE = 0x0;
 | 
			
		||||
            const CURRENT = 0x1;
 | 
			
		||||
            const PREFERRED = 0x2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        // Rustc wrongly assumes
 | 
			
		||||
        // that COutputs allows C direct access to the underlying RefCell
 | 
			
		||||
        #[allow(improper_ctypes)]
 | 
			
		||||
        fn squeek_output_add_listener(
 | 
			
		||||
            wl_output: WlOutput,
 | 
			
		||||
            listener: *const WlOutputListener<COutputs>,
 | 
			
		||||
            data: COutputs,
 | 
			
		||||
        ) -> i32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type COutputs = ::util::c::Wrapped<Outputs>;
 | 
			
		||||
 | 
			
		||||
    // Defined in Rust
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_geometry(
 | 
			
		||||
        _outputs: COutputs,
 | 
			
		||||
        _wl_output: WlOutput,
 | 
			
		||||
        _x: i32, _y: i32,
 | 
			
		||||
        _phys_width: i32, _phys_height: i32,
 | 
			
		||||
        _subpixel: i32,
 | 
			
		||||
        _make: *const c_char, _model: *const c_char,
 | 
			
		||||
        _transform: i32,
 | 
			
		||||
    ) {
 | 
			
		||||
        //println!("geometry handled {},{}", x, y);
 | 
			
		||||
        // Totally unused
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_mode(
 | 
			
		||||
        outputs: COutputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
        flags: u32,
 | 
			
		||||
        width: i32,
 | 
			
		||||
        height: i32,
 | 
			
		||||
        _refresh: i32,
 | 
			
		||||
    ) {
 | 
			
		||||
        let flags = Mode::from_bits(flags).unwrap_or_else(|| {
 | 
			
		||||
            eprintln!("Warning: received invalid wl_output.mode flags");
 | 
			
		||||
            Mode::NONE
 | 
			
		||||
        });
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut outputs = outputs.borrow_mut();
 | 
			
		||||
        let mut output_state: Option<&mut OutputState> = outputs.outputs
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .find_map(|o|
 | 
			
		||||
                if o.output == wl_output { Some(&mut o.pending) } else { None }
 | 
			
		||||
            );
 | 
			
		||||
        match output_state {
 | 
			
		||||
            Some(ref mut state) => {
 | 
			
		||||
                if flags.contains(Mode::CURRENT) {
 | 
			
		||||
                    state.current_mode = Some(super::Mode { width, height});
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            None => eprintln!("Wayland error: Got mode on unknown output"),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_done(
 | 
			
		||||
        outputs: COutputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
    ) {
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut outputs = outputs.borrow_mut();
 | 
			
		||||
        let mut output = outputs.outputs
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .find(|o| o.output == wl_output);
 | 
			
		||||
        match output {
 | 
			
		||||
            Some(ref mut output) => { output.current = output.pending.clone(); }
 | 
			
		||||
            None => eprintln!("Wayland error: Got done on unknown output"),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_scale(
 | 
			
		||||
        outputs: COutputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
        factor: i32,
 | 
			
		||||
    ) {
 | 
			
		||||
        let outputs = outputs.clone_ref();
 | 
			
		||||
        let mut outputs = outputs.borrow_mut();
 | 
			
		||||
        let output_state = outputs.outputs
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .find_map(|o|
 | 
			
		||||
                if o.output == wl_output { Some(&mut o.pending) } else { None }
 | 
			
		||||
            );
 | 
			
		||||
        match output_state {
 | 
			
		||||
            Some(state) => { state.scale = factor; }
 | 
			
		||||
            None => eprintln!("Wayland error: Got done on unknown output"),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_new() -> COutputs {
 | 
			
		||||
        COutputs::new(Outputs { outputs: Vec::new() })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_free(outputs: COutputs) {
 | 
			
		||||
        unsafe { outputs.unwrap() }; // gets dropped
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput) {
 | 
			
		||||
        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(),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        unsafe { squeek_output_add_listener(
 | 
			
		||||
            output,
 | 
			
		||||
            &WlOutputListener {
 | 
			
		||||
                geometry: outputs_handle_geometry,
 | 
			
		||||
                mode: outputs_handle_mode,
 | 
			
		||||
                done: outputs_handle_done,
 | 
			
		||||
                scale: outputs_handle_scale,
 | 
			
		||||
            } as *const WlOutputListener<COutputs>,
 | 
			
		||||
            raw_collection,
 | 
			
		||||
        )};
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_get_current(raw_collection: COutputs) -> WlOutput {
 | 
			
		||||
        let collection = raw_collection.clone_ref();
 | 
			
		||||
        let collection = collection.borrow();
 | 
			
		||||
        collection.outputs[0].output.clone()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // TODO: handle unregistration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
struct Mode {
 | 
			
		||||
    width: i32,
 | 
			
		||||
    height: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct OutputState {
 | 
			
		||||
    current_mode: Option<Mode>,
 | 
			
		||||
    scale: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl OutputState {
 | 
			
		||||
    fn uninitialized() -> OutputState {
 | 
			
		||||
        OutputState {
 | 
			
		||||
            current_mode: None,
 | 
			
		||||
            scale: 1,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Output {
 | 
			
		||||
    output: c::WlOutput,
 | 
			
		||||
    pending: OutputState,
 | 
			
		||||
    current: OutputState,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Outputs {
 | 
			
		||||
    outputs: Vec<Output>,
 | 
			
		||||
}
 | 
			
		||||
@ -120,10 +120,12 @@ make_window (ServerContextService *context)
 | 
			
		||||
    if (context->window)
 | 
			
		||||
        g_error("Window already present");
 | 
			
		||||
 | 
			
		||||
    struct wl_output *output = squeek_outputs_get_current(squeek_wayland->outputs);
 | 
			
		||||
 | 
			
		||||
    context->window = g_object_new (
 | 
			
		||||
        PHOSH_TYPE_LAYER_SURFACE,
 | 
			
		||||
        "layer-shell", squeek_wayland->layer_shell,
 | 
			
		||||
        "wl-output", g_ptr_array_index(squeek_wayland->outputs, 0), // TODO: select output as needed,
 | 
			
		||||
        "wl-output", output,
 | 
			
		||||
        "height", KEYBOARD_HEIGHT,
 | 
			
		||||
        "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
 | 
			
		||||
                  | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@
 | 
			
		||||
#include "eekboard/eekboard-service.h"
 | 
			
		||||
#include "eek/eek.h"
 | 
			
		||||
#include "imservice.h"
 | 
			
		||||
#include "outputs.h"
 | 
			
		||||
#include "server-context-service.h"
 | 
			
		||||
#include "wayland.h"
 | 
			
		||||
 | 
			
		||||
@ -116,7 +117,7 @@ registry_handle_global (void *data,
 | 
			
		||||
    } else if (!strcmp (interface, "wl_output")) {
 | 
			
		||||
        struct wl_output *output = wl_registry_bind (registry, name,
 | 
			
		||||
            &wl_output_interface, 2);
 | 
			
		||||
        g_ptr_array_add (instance->wayland.outputs, output);
 | 
			
		||||
        squeek_outputs_register(instance->wayland.outputs, output);
 | 
			
		||||
    } else if (!strcmp(interface, "wl_seat")) {
 | 
			
		||||
        instance->wayland.seat = wl_registry_bind(registry, name,
 | 
			
		||||
            &wl_seat_interface, 1);
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,10 @@ pub mod c {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Marker trait for values that can be transferred to/received from C.
 | 
			
		||||
    /// They must be either *const or *mut or repr(transparent).
 | 
			
		||||
    pub trait COpaquePtr {}
 | 
			
		||||
 | 
			
		||||
    /// Wraps structures to pass them safely to/from C
 | 
			
		||||
    /// Since C doesn't respect borrowing rules,
 | 
			
		||||
    /// RefCell will enforce them dynamically (only 1 writer/many readers)
 | 
			
		||||
@ -79,6 +83,9 @@ pub mod c {
 | 
			
		||||
    // which is a bit too complex for now.
 | 
			
		||||
 | 
			
		||||
    impl<T> Wrapped<T> {
 | 
			
		||||
        pub fn new(value: T) -> Wrapped<T> {
 | 
			
		||||
            Wrapped::wrap(Rc::new(RefCell::new(value)))
 | 
			
		||||
        }
 | 
			
		||||
        pub fn wrap(state: Rc<RefCell<T>>) -> Wrapped<T> {
 | 
			
		||||
            Wrapped(Rc::into_raw(state))
 | 
			
		||||
        }
 | 
			
		||||
@ -116,6 +123,8 @@ pub mod c {
 | 
			
		||||
            r.to_owned()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<T> COpaquePtr for Wrapped<T> {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait CloneOwned {
 | 
			
		||||
 | 
			
		||||
@ -10,3 +10,8 @@ void
 | 
			
		||||
eek_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t time, uint32_t key, uint32_t state) {
 | 
			
		||||
    zwp_virtual_keyboard_v1_key(zwp_virtual_keyboard_v1, time, key, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int squeek_output_add_listener(struct wl_output *wl_output,
 | 
			
		||||
                                const struct wl_output_listener *listener, void *data) {
 | 
			
		||||
    return wl_output_add_listener(wl_output, listener, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,19 @@
 | 
			
		||||
#ifndef WAYLAND_H
 | 
			
		||||
#define WAYLAND_H
 | 
			
		||||
 | 
			
		||||
#include <gmodule.h>
 | 
			
		||||
 | 
			
		||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
 | 
			
		||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
			
		||||
#include "input-method-unstable-v2-client-protocol.h"
 | 
			
		||||
 | 
			
		||||
#include <gmodule.h>
 | 
			
		||||
 | 
			
		||||
#include "outputs.h"
 | 
			
		||||
 | 
			
		||||
struct squeek_wayland {
 | 
			
		||||
    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;
 | 
			
		||||
    GPtrArray *outputs; // *wl_output
 | 
			
		||||
    struct squeek_outputs *outputs;
 | 
			
		||||
    struct wl_seat *seat;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -21,7 +22,7 @@ extern struct squeek_wayland *squeek_wayland;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static inline void squeek_wayland_init(struct squeek_wayland *wayland) {
 | 
			
		||||
    wayland->outputs = g_ptr_array_new();
 | 
			
		||||
    wayland->outputs = squeek_outputs_new();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
 | 
			
		||||
@ -29,7 +30,7 @@ static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void squeek_wayland_deinit(struct squeek_wayland *wayland) {
 | 
			
		||||
    g_ptr_array_free(wayland->outputs, TRUE);
 | 
			
		||||
    squeek_outputs_free(wayland->outputs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // WAYLAND_H
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user