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:
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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)
|
||||
}))
|
||||
}
|
||||
|
||||
@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user