outputs: Handle removal

Currrently, Squeekboard doesn't do anything with this information.

It still expects one output to be present, or it will crash.
This commit is contained in:
Dorota Czaplejewicz
2022-01-24 19:04:18 +00:00
parent d3eb68ed5a
commit f15f97d4c9
3 changed files with 67 additions and 14 deletions

View File

@ -11,7 +11,8 @@ struct squeek_output_handle {
struct squeek_outputs *squeek_outputs_new(void); struct squeek_outputs *squeek_outputs_new(void);
void squeek_outputs_free(struct squeek_outputs*); void squeek_outputs_free(struct squeek_outputs*);
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output); void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output, uint32_t id);
struct wl_output *squeek_outputs_try_unregister(struct squeek_outputs*, uint32_t id);
struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*); struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*);
int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output); int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output);
#endif #endif

View File

@ -16,6 +16,7 @@ pub mod c {
use super::*; use super::*;
use std::os::raw::{ c_char, c_void }; use std::os::raw::{ c_char, c_void };
use std::ptr;
use ::util::c::{COpaquePtr, Wrapped}; use ::util::c::{COpaquePtr, Wrapped};
@ -25,6 +26,12 @@ pub mod c {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
pub struct WlOutput(*const c_void); pub struct WlOutput(*const c_void);
impl WlOutput {
fn null() -> Self {
Self(ptr::null())
}
}
#[repr(C)] #[repr(C)]
struct WlOutputListener<T: COpaquePtr> { struct WlOutputListener<T: COpaquePtr> {
geometry: extern fn( geometry: extern fn(
@ -257,14 +264,17 @@ pub mod c {
#[no_mangle] #[no_mangle]
pub extern "C" pub extern "C"
fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput) { fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput, id: u32) {
let collection = raw_collection.clone_ref(); let collection = raw_collection.clone_ref();
let mut collection = collection.borrow_mut(); let mut collection = collection.borrow_mut();
collection.outputs.push(Output { collection.outputs.push((
output: output.clone(), Output {
pending: OutputState::uninitialized(), output: output.clone(),
current: OutputState::uninitialized(), pending: OutputState::uninitialized(),
}); current: OutputState::uninitialized(),
},
id,
));
unsafe { squeek_output_add_listener( unsafe { squeek_output_add_listener(
output, output,
@ -278,13 +288,28 @@ pub mod c {
)}; )};
} }
/// This will try to unregister the output, if the id matches a registered one.
#[no_mangle]
pub extern "C"
fn squeek_outputs_try_unregister(raw_collection: COutputs, id: u32) -> WlOutput {
let collection = raw_collection.clone_ref();
let mut collection = collection.borrow_mut();
collection.remove_output_by_global(id)
.map_err(|e| log_print!(
logging::Level::Debug,
"Tried to remove global {:x} but it is not registered as an output: {:?}",
id, e,
))
.unwrap_or(WlOutput::null())
}
#[no_mangle] #[no_mangle]
pub extern "C" pub extern "C"
fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle { fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle {
let collection = raw_collection.clone_ref(); let collection = raw_collection.clone_ref();
let collection = collection.borrow(); let collection = collection.borrow();
OutputHandle { OutputHandle {
wl_output: collection.outputs[0].output.clone(), wl_output: collection.outputs[0].0.output.clone(),
outputs: raw_collection.clone(), outputs: raw_collection.clone(),
} }
} }
@ -371,8 +396,13 @@ struct Output {
current: OutputState, current: OutputState,
} }
#[derive(Debug)]
struct NotFound;
type GlobalId = u32;
pub struct Outputs { pub struct Outputs {
outputs: Vec<Output>, outputs: Vec<(Output, GlobalId)>,
sender: event_loop::driver::Threaded, sender: event_loop::driver::Threaded,
} }
@ -388,10 +418,27 @@ impl Outputs {
self.sender.send(event.into()).unwrap() self.sender.send(event.into()).unwrap()
} }
fn remove_output_by_global(&mut self, id: GlobalId)
-> Result<c::WlOutput, NotFound>
{
let index = self.outputs.iter()
.position(|(_o, global_id)| *global_id == id);
if let Some(index) = index {
let (output, _id) = self.outputs.remove(index);
self.send_event(Event {
change: ChangeType::Removed,
output: OutputId(output.output),
});
Ok(output.output)
} else {
Err(NotFound)
}
}
fn find_output(&self, wl_output: c::WlOutput) -> Option<&Output> { fn find_output(&self, wl_output: c::WlOutput) -> Option<&Output> {
self.outputs self.outputs
.iter() .iter()
.find_map(|o| .find_map(|(o, _global)|
if o.output == wl_output { Some(o) } else { None } if o.output == wl_output { Some(o) } else { None }
) )
} }
@ -401,7 +448,7 @@ impl Outputs {
{ {
self.outputs self.outputs
.iter_mut() .iter_mut()
.find_map(|o| .find_map(|(o, _global)|
if o.output == wl_output { Some(o) } else { None } if o.output == wl_output { Some(o) } else { None }
) )
} }

View File

@ -126,7 +126,7 @@ registry_handle_global (void *data,
} else if (!strcmp (interface, "wl_output")) { } else if (!strcmp (interface, "wl_output")) {
struct wl_output *output = wl_registry_bind (registry, name, struct wl_output *output = wl_registry_bind (registry, name,
&wl_output_interface, 2); &wl_output_interface, 2);
squeek_outputs_register(wayland->outputs, output); squeek_outputs_register(wayland->outputs, output, name);
} else if (!strcmp(interface, "wl_seat")) { } else if (!strcmp(interface, "wl_seat")) {
wayland->seat = wl_registry_bind(registry, name, wayland->seat = wl_registry_bind(registry, name,
&wl_seat_interface, 1); &wl_seat_interface, 1);
@ -138,7 +138,12 @@ registry_handle_global_remove (void *data,
struct wl_registry *registry, struct wl_registry *registry,
uint32_t name) uint32_t name)
{ {
// TODO: outputs (void)registry;
struct squeek_wayland *wayland = data;
struct wl_output *output = squeek_outputs_try_unregister(wayland->outputs, name);
if (output) {
wl_output_destroy(output);
}
} }
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {