diff --git a/src/outputs.rs b/src/outputs.rs index 39b06e92..5dc31f9f 100644 --- a/src/outputs.rs +++ b/src/outputs.rs @@ -1,5 +1,10 @@ +/* Copyright (C) 2019-2020 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + */ + /*! Managing Wayland outputs */ +use std::cell::RefCell; use std::vec::Vec; use ::logging; @@ -103,7 +108,7 @@ pub mod c { ) -> i32; } - type COutputs = ::util::c::Wrapped; + pub type COutputs = ::util::c::Wrapped; /// A stable reference to an output. #[derive(Clone)] @@ -202,19 +207,27 @@ pub mod c { } extern fn outputs_handle_done( - outputs: COutputs, + outputs_raw: COutputs, wl_output: WlOutput, ) { - 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 outputs = outputs_raw.clone_ref(); + { + let mut collection = RefCell::borrow_mut(&outputs); + 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 collection = RefCell::borrow(&outputs); + if let Some(ref cb) = &collection.update_cb { + let mut cb = RefCell::borrow_mut(cb); + let cb = Box::as_mut(&mut cb); + cb(OutputHandle { wl_output, outputs: outputs_raw }); + } } extern fn outputs_handle_scale( @@ -239,7 +252,10 @@ pub mod c { #[no_mangle] pub extern "C" fn squeek_outputs_new() -> COutputs { - COutputs::new(Outputs { outputs: Vec::new() }) + COutputs::new(Outputs { + outputs: Vec::new(), + update_cb: None, + }) } #[no_mangle] @@ -308,7 +324,7 @@ pub mod c { } /// Generic size -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Size { pub width: u32, pub height: u32, @@ -413,6 +429,38 @@ pub struct Output { current: OutputState, } +/// The manager of all outputs. +// This is the target of several callbacks, +// so it should only be used with a stable place in memory, like `Rc`. +// It should not be instantiated externally or copied, +// or it will not receive those callbacks and be somewhat of an empty shell. +// It should be safe to use as long as the fields are not `pub`, +// and there's no `Clone`, and this module's API only ever gives out +// references wrapped in `Rc`. +// For perfectness, it would only ever give out immutable opaque references, +// but that's not practical at the moment. +// `mem::swap` could replace the value inside, +// but as long as the swap is atomic, +// that should not cause an inconsistent state. pub struct Outputs { outputs: Vec, + // The RefCell is here to let the function be called + // while holding only a read-reference to `Outputs`. + // Otherwise anything trying to get useful data from OutputHandle + // will fail to acquire reference to Outputs. + // TODO: Maybe pass only current state along with Outputs and Output hash. + // The only reason a full OutputHandle is here + // is to be able to track the right Output. + update_cb: Option>>, +} + +impl Outputs { + /// The function will get called whenever + /// any output changes or is removed or created. + /// If output handle doesn't return state, the output just went down. + /// It cannot modify anything in Outputs. + // FIXME: handle output destruction + pub fn set_update_cb(&mut self, callback: Box) { + self.update_cb = Some(RefCell::new(callback)); + } } diff --git a/src/server-main.c b/src/server-main.c index f3f5edb8..7037cb7d 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -203,7 +203,7 @@ main (int argc, char **argv) g_warning("Wayland input method interface not available"); } - instance.ui_manager = squeek_uiman_new(); + instance.ui_manager = squeek_uiman_new(instance.wayland.outputs); instance.settings_context = eekboard_context_service_new(&instance.layout_choice); diff --git a/src/ui_manager.h b/src/ui_manager.h index 57d3cc70..d61dc535 100644 --- a/src/ui_manager.h +++ b/src/ui_manager.h @@ -7,7 +7,7 @@ struct ui_manager; -struct ui_manager *squeek_uiman_new(); +struct ui_manager *squeek_uiman_new(struct squeek_outputs *outputs); void squeek_uiman_set_output(struct ui_manager *uiman, struct squeek_output_handle output); uint32_t squeek_uiman_get_perceptual_height(struct ui_manager *uiman); diff --git a/src/ui_manager.rs b/src/ui_manager.rs index 95fc7218..657674c9 100644 --- a/src/ui_manager.rs +++ b/src/ui_manager.rs @@ -7,20 +7,30 @@ * Coordinates this based on information collated from all possible sources. */ +use std::cell::RefCell; use std::cmp::min; +use std::rc::Rc; use ::logging; -use ::outputs::OutputState; +use ::outputs::{ Outputs, OutputState}; use ::outputs::c::OutputHandle; mod c { use super::*; + use ::outputs::c::COutputs; use ::util::c::Wrapped; #[no_mangle] pub extern "C" - fn squeek_uiman_new() -> Wrapped { - Wrapped::new(Manager { output: None }) + fn squeek_uiman_new(outputs: COutputs) -> Wrapped { + let uiman_raw = Wrapped::new(Manager { output: None }); + if !outputs.is_null() { + let uiman = uiman_raw.clone_ref(); + let outputs = outputs.clone_ref(); + let mut outputs = outputs.borrow_mut(); + register_output_man(uiman, &mut outputs); + } + uiman_raw } /// Used to size the layer surface containing all the OSK widgets. @@ -43,7 +53,7 @@ mod c { ) { let uiman = uiman.clone_ref(); let mut uiman = uiman.borrow_mut(); - uiman.output = Some(output); + uiman.set_output(output) } } @@ -123,4 +133,30 @@ impl Manager { None => None, } } + + fn set_output(&mut self, output: OutputHandle) { + self.output = Some(output); + } + + fn handle_output_change(&mut self, output: OutputHandle) { + match output.get_state() { + Some(os) => { + println!("{:?}", os.get_pixel_size()); + } + None => { + println!("gone"); + } + } + } +} + +fn register_output_man( + ui_man: Rc>, + output_man: &mut Outputs, +) { + let ui_man = ui_man.clone(); + output_man.set_update_cb(Box::new(move |output: OutputHandle| { + let mut ui_man = ui_man.borrow_mut(); + ui_man.handle_output_change(output) + })) } diff --git a/src/util.rs b/src/util.rs index 767c32ea..83213d3a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -94,6 +94,7 @@ pub mod c { } /// Extracts the reference to the data. /// It may cause problems if attempted in more than one place + // FIXME: check for null pub unsafe fn unwrap(self) -> Rc> { Rc::from_raw(self.0) } @@ -107,6 +108,10 @@ pub mod c { Rc::into_raw(used_rc); // prevent dropping the original reference rc } + + pub fn is_null(&self) -> bool { + self.0.is_null() + } } impl Clone for Wrapped {