diff --git a/src/outputs.h b/src/outputs.h index f6466a70..c81026e5 100644 --- a/src/outputs.h +++ b/src/outputs.h @@ -11,7 +11,8 @@ struct squeek_output_handle { struct squeek_outputs *squeek_outputs_new(void); 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*); int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output); #endif diff --git a/src/outputs.rs b/src/outputs.rs index a5cd517b..e82995bc 100644 --- a/src/outputs.rs +++ b/src/outputs.rs @@ -16,6 +16,7 @@ pub mod c { use super::*; use std::os::raw::{ c_char, c_void }; + use std::ptr; use ::util::c::{COpaquePtr, Wrapped}; @@ -25,6 +26,12 @@ pub mod c { #[derive(Clone, PartialEq, Copy, Debug)] pub struct WlOutput(*const c_void); + impl WlOutput { + fn null() -> Self { + Self(ptr::null()) + } + } + #[repr(C)] struct WlOutputListener { geometry: extern fn( @@ -257,14 +264,17 @@ pub mod c { #[no_mangle] 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 mut collection = collection.borrow_mut(); - collection.outputs.push(Output { - output: output.clone(), - pending: OutputState::uninitialized(), - current: OutputState::uninitialized(), - }); + collection.outputs.push(( + Output { + output: output.clone(), + pending: OutputState::uninitialized(), + current: OutputState::uninitialized(), + }, + id, + )); unsafe { squeek_output_add_listener( output, @@ -277,14 +287,29 @@ pub mod c { raw_collection, )}; } - + + /// 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] pub extern "C" fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle { let collection = raw_collection.clone_ref(); let collection = collection.borrow(); OutputHandle { - wl_output: collection.outputs[0].output.clone(), + wl_output: collection.outputs[0].0.output.clone(), outputs: raw_collection.clone(), } } @@ -371,8 +396,13 @@ struct Output { current: OutputState, } +#[derive(Debug)] +struct NotFound; + +type GlobalId = u32; + pub struct Outputs { - outputs: Vec, + outputs: Vec<(Output, GlobalId)>, sender: event_loop::driver::Threaded, } @@ -388,10 +418,27 @@ impl Outputs { self.sender.send(event.into()).unwrap() } + fn remove_output_by_global(&mut self, id: GlobalId) + -> Result + { + 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> { self.outputs .iter() - .find_map(|o| + .find_map(|(o, _global)| if o.output == wl_output { Some(o) } else { None } ) } @@ -401,7 +448,7 @@ impl Outputs { { self.outputs .iter_mut() - .find_map(|o| + .find_map(|(o, _global)| if o.output == wl_output { Some(o) } else { None } ) } diff --git a/src/server-main.c b/src/server-main.c index b2cacdc6..ec72aecc 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -126,7 +126,7 @@ registry_handle_global (void *data, } else if (!strcmp (interface, "wl_output")) { struct wl_output *output = wl_registry_bind (registry, name, &wl_output_interface, 2); - squeek_outputs_register(wayland->outputs, output); + squeek_outputs_register(wayland->outputs, output, name); } else if (!strcmp(interface, "wl_seat")) { wayland->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); @@ -138,7 +138,12 @@ registry_handle_global_remove (void *data, struct wl_registry *registry, 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 = {