1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Manager that is called when an output is created or destroyed.
use std::{marker::PhantomData, panic, ptr::NonNull};
use libc;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::wlr_output;
use {compositor,
output::{self, Output, OutputState, UserOutput},
utils::Handleable};
/// Used to ensure the output sets the mode before doing any other
/// operation on the Output.
pub struct OutputBuilder<'output> {
output: output::Handle,
phantom: PhantomData<&'output Output>
}
/// Used to ensure that the builder is used to construct
/// the output::Handler instance.
pub struct BuilderResult<'output> {
pub output: output::Handle,
result: Box<output::Handler>,
phantom: PhantomData<&'output Output>
}
/// Wrapper around Output destruction so that you can't call
/// unsafe methods (e.g anything like setting the mode).
pub struct Destroyed(output::Handle);
impl<'output> OutputBuilder<'output> {
/// Build the output with the best mode.
///
/// To complete construction, return this in your implementation of
/// `output::ManagerHandler::output_added`.
pub fn build_best_mode<T: output::Handler + 'static>(mut self,
data: T)
-> BuilderResult<'output> {
with_handles!([(output: {&mut self.output})] => {
output.choose_best_mode();
}).expect("Output was borrowed");
BuilderResult { output: self.output,
result: Box::new(data),
phantom: PhantomData }
}
}
impl Destroyed {
// TODO Functions which are safe to use
}
pub type OutputAdded = fn(compositor_handle: compositor::Handle,
output_builder: OutputBuilder)
-> Option<BuilderResult>;
wayland_listener_static! {
static mut MANAGER;
(Manager, Builder): [
(OutputAdded, add_listener, output_added) => (add_notify, add_callback):
|manager: &mut Manager, data: *mut libc::c_void,| unsafe {
let data = data as *mut wlr_output;
let output = Output::new(data as *mut wlr_output);
// NOTE
// This clone is required because we pass it mutably to the output builder,
// but due to lack of NLL there's no way to tell Rust it's safe to use it in
// in the if branch.
//
// Thus, we need to clone it here and then drop the original once at the end.
//
// This is not a real clone, but an pub(crate) unsafe one we added, so it doesn't
// break safety concerns in user code. Just an unfortunate hack we have to put here.
let output_clone = output.clone();
let builder = OutputBuilder { output: output.weak_reference(), phantom: PhantomData };
let compositor = match compositor::handle() {
Some(handle) => handle,
None => return
};
let res = panic::catch_unwind(
panic::AssertUnwindSafe(|| manager.add_callback
.map(|f| f(compositor, builder))
.unwrap_or(None)));
let build_result = match res {
Ok(res) => res,
// NOTE
// Either Wayland or wlroots does not handle failure to set up output correctly.
// Calling wl_display_terminate does not work if output is incorrectly set up.
//
// Instead, execution keeps going with an eventual segfault (if lucky).
//
// To fix this, we abort the process if there was a panic in output setup.
Err(_) => ::std::process::abort()
};
if let Some(BuilderResult {result: output_ptr, .. }) = build_result {
let mut output = UserOutput::new((output_clone, output_ptr));
wl_signal_add(&mut (*data).events.frame as *mut _ as _,
output.frame_listener() as _);
wl_signal_add(&mut (*data).events.mode as *mut _ as _,
output.mode_listener() as _);
wl_signal_add(&mut (*data).events.enable as *mut _ as _,
output.enable_listener() as _);
wl_signal_add(&mut (*data).events.scale as *mut _ as _,
output.scale_listener() as _);
wl_signal_add(&mut (*data).events.transform as *mut _ as _,
output.transform_listener() as _);
wl_signal_add(&mut (*data).events.swap_buffers as *mut _ as _,
output.swap_buffers_listener() as _);
wl_signal_add(&mut (*data).events.needs_swap as *mut _ as _,
output.need_swap_listener() as _);
wl_signal_add(&mut (*data).events.destroy as *mut _ as _,
output.on_destroy_listener() as _);
let output_data = (*data).data as *mut OutputState;
(*output_data).output = NonNull::new(Box::into_raw(output));
}
};
]
}