outputs: Pass output updates

Introduce a callback in `outputs::Outputs` that calls on every `wl_output.done`, and a dummy consumer in `ui_manager`.

This is sufficient to detect display height changes.
This commit is contained in:
Dorota Czaplejewicz
2020-03-02 09:58:24 +00:00
parent fa5c7c63d9
commit f6fc6c83dc
5 changed files with 109 additions and 20 deletions

View File

@ -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<Outputs>;
pub type COutputs = ::util::c::Wrapped<Outputs>;
/// 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<RefCell>`.
// 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<RefCell>`.
// 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<Output>,
// 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<RefCell<Box<dyn FnMut(c::OutputHandle)>>>,
}
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<dyn FnMut(c::OutputHandle)>) {
self.update_cb = Some(RefCell::new(callback));
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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<Manager> {
Wrapped::new(Manager { output: None })
fn squeek_uiman_new(outputs: COutputs) -> Wrapped<Manager> {
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<RefCell<Manager>>,
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)
}))
}

View File

@ -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<RefCell<T>> {
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<T> Clone for Wrapped<T> {