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 */
|
/*! Managing Wayland outputs */
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use ::logging;
|
use ::logging;
|
||||||
|
|
||||||
@ -103,7 +108,7 @@ pub mod c {
|
|||||||
) -> i32;
|
) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
type COutputs = ::util::c::Wrapped<Outputs>;
|
pub type COutputs = ::util::c::Wrapped<Outputs>;
|
||||||
|
|
||||||
/// A stable reference to an output.
|
/// A stable reference to an output.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -202,11 +207,12 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern fn outputs_handle_done(
|
extern fn outputs_handle_done(
|
||||||
outputs: COutputs,
|
outputs_raw: COutputs,
|
||||||
wl_output: WlOutput,
|
wl_output: WlOutput,
|
||||||
) {
|
) {
|
||||||
let outputs = outputs.clone_ref();
|
let outputs = outputs_raw.clone_ref();
|
||||||
let mut collection = outputs.borrow_mut();
|
{
|
||||||
|
let mut collection = RefCell::borrow_mut(&outputs);
|
||||||
let output = find_output_mut(&mut collection, wl_output);
|
let output = find_output_mut(&mut collection, wl_output);
|
||||||
match output {
|
match output {
|
||||||
Some(output) => { output.current = output.pending.clone(); }
|
Some(output) => { output.current = output.pending.clone(); }
|
||||||
@ -216,6 +222,13 @@ pub mod c {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
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(
|
extern fn outputs_handle_scale(
|
||||||
outputs: COutputs,
|
outputs: COutputs,
|
||||||
@ -239,7 +252,10 @@ pub mod c {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_outputs_new() -> COutputs {
|
fn squeek_outputs_new() -> COutputs {
|
||||||
COutputs::new(Outputs { outputs: Vec::new() })
|
COutputs::new(Outputs {
|
||||||
|
outputs: Vec::new(),
|
||||||
|
update_cb: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -308,7 +324,7 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generic size
|
/// Generic size
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
@ -413,6 +429,38 @@ pub struct Output {
|
|||||||
current: OutputState,
|
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 {
|
pub struct Outputs {
|
||||||
outputs: Vec<Output>,
|
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");
|
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);
|
instance.settings_context = eekboard_context_service_new(&instance.layout_choice);
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
struct ui_manager;
|
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);
|
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);
|
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.
|
* Coordinates this based on information collated from all possible sources.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ::logging;
|
use ::logging;
|
||||||
use ::outputs::OutputState;
|
use ::outputs::{ Outputs, OutputState};
|
||||||
use ::outputs::c::OutputHandle;
|
use ::outputs::c::OutputHandle;
|
||||||
|
|
||||||
mod c {
|
mod c {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use ::outputs::c::COutputs;
|
||||||
use ::util::c::Wrapped;
|
use ::util::c::Wrapped;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_uiman_new() -> Wrapped<Manager> {
|
fn squeek_uiman_new(outputs: COutputs) -> Wrapped<Manager> {
|
||||||
Wrapped::new(Manager { output: None })
|
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.
|
/// Used to size the layer surface containing all the OSK widgets.
|
||||||
@ -43,7 +53,7 @@ mod c {
|
|||||||
) {
|
) {
|
||||||
let uiman = uiman.clone_ref();
|
let uiman = uiman.clone_ref();
|
||||||
let mut uiman = uiman.borrow_mut();
|
let mut uiman = uiman.borrow_mut();
|
||||||
uiman.output = Some(output);
|
uiman.set_output(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,4 +133,30 @@ impl Manager {
|
|||||||
None => None,
|
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.
|
/// Extracts the reference to the data.
|
||||||
/// It may cause problems if attempted in more than one place
|
/// It may cause problems if attempted in more than one place
|
||||||
|
// FIXME: check for null
|
||||||
pub unsafe fn unwrap(self) -> Rc<RefCell<T>> {
|
pub unsafe fn unwrap(self) -> Rc<RefCell<T>> {
|
||||||
Rc::from_raw(self.0)
|
Rc::from_raw(self.0)
|
||||||
}
|
}
|
||||||
@ -107,6 +108,10 @@ pub mod c {
|
|||||||
Rc::into_raw(used_rc); // prevent dropping the original reference
|
Rc::into_raw(used_rc); // prevent dropping the original reference
|
||||||
rc
|
rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_null(&self) -> bool {
|
||||||
|
self.0.is_null()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for Wrapped<T> {
|
impl<T> Clone for Wrapped<T> {
|
||||||
|
|||||||
Reference in New Issue
Block a user