Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
src/server/output_manager.rs (30.5K)
1 // SPDX-FileCopyrightText: © 2020 The River Developers
2 // SPDX-License-Identifier: GPL-3.0-only
3
4 use crate::ffi;
5 use crate::server::{Server, WlListener, WlList, wl_signal_add, wl_listener_remove, wl_list_remove};
6 use crate::output::{Output, OutputStateValue, OutputMode};
7
8 #[repr(C)]
9 pub struct WlrOutputManagerV1Events {
10 pub apply: ffi::wl_signal,
11 pub test: ffi::wl_signal,
12 pub destroy: ffi::wl_signal,
13 }
14
15 #[repr(C)]
16 pub struct WlrOutputManagerV1 {
17 pub display: *mut ffi::wl_display,
18 pub global: *mut ffi::wl_global,
19 pub resources: ffi::wl_list,
20 pub heads: ffi::wl_list,
21 pub serial: u32,
22 pub current_configuration_dirty: bool,
23 pub events: WlrOutputManagerV1Events,
24 }
25
26 #[repr(C)]
27 pub struct WlrOutputPowerManagerV1Events {
28 pub set_mode: ffi::wl_signal,
29 pub destroy: ffi::wl_signal,
30 }
31
32 #[repr(C)]
33 pub struct WlrOutputPowerManagerV1 {
34 pub global: *mut ffi::wl_global,
35 pub output_powers: ffi::wl_list,
36 pub events: WlrOutputPowerManagerV1Events,
37 }
38
39 pub struct OutputManager {
40 pub first_modeset: bool,
41 pub new_output: ffi::wl_listener,
42 pub output_layout: *mut ffi::wlr_output_layout,
43 pub presentation: *mut ffi::wlr_presentation,
44 pub xdg_output_manager: *mut ffi::wlr_xdg_output_manager_v1,
45 pub wlr_output_manager: *mut ffi::wlr_output_manager_v1,
46 pub manager_apply: ffi::wl_listener,
47 pub manager_test: ffi::wl_listener,
48 pub power_manager: *mut ffi::wlr_output_power_manager_v1,
49 pub power_manager_set_mode: ffi::wl_listener,
50 pub gamma_control_manager: *mut ffi::wlr_gamma_control_manager_v1,
51 pub outputs: ffi::wl_list,
52 }
53
54 impl OutputManager {
55 pub unsafe fn init(&mut self, server: *mut Server) -> Result<(), &'static str> {
56 self.first_modeset = true;
57
58 let output_layout = ffi::wlr_output_layout_create((*server).wl_server);
59 if output_layout.is_null() {
60 return Err("Failed to create wlr_output_layout");
61 }
62 self.output_layout = output_layout;
63
64 let gamma_control_manager = ffi::wlr_gamma_control_manager_v1_create((*server).wl_server);
65 if gamma_control_manager.is_null() {
66 ffi::wlr_output_layout_destroy(output_layout);
67 return Err("Failed to create wlr_gamma_control_manager_v1");
68 }
69 self.gamma_control_manager = gamma_control_manager;
70 ffi::wlr_scene_set_gamma_control_manager_v1((*server).scene.wlr_scene, gamma_control_manager);
71
72 let presentation = ffi::wlr_presentation_create((*server).wl_server, (*server).backend, 2);
73 if presentation.is_null() {
74 return Err("Failed to create wlr_presentation");
75 }
76 self.presentation = presentation;
77
78 let xdg_output_manager = ffi::wlr_xdg_output_manager_v1_create((*server).wl_server, output_layout);
79 if xdg_output_manager.is_null() {
80 return Err("Failed to create wlr_xdg_output_manager_v1");
81 }
82 self.xdg_output_manager = xdg_output_manager;
83
84 let wlr_output_manager = ffi::wlr_output_manager_v1_create((*server).wl_server);
85 if wlr_output_manager.is_null() {
86 return Err("Failed to create wlr_output_manager_v1");
87 }
88 self.wlr_output_manager = wlr_output_manager;
89
90 let power_manager = ffi::wlr_output_power_manager_v1_create((*server).wl_server);
91 if power_manager.is_null() {
92 return Err("Failed to create wlr_output_power_manager_v1");
93 }
94 self.power_manager = power_manager;
95
96 ffi::wl_list_init(&mut self.outputs);
97
98 // Add backend new_output listener
99 let backend_cast = (*server).backend as *mut crate::server::WlrBackend;
100 let new_output_ptr = &mut self.new_output as *mut ffi::wl_listener as *mut WlListener;
101 (*new_output_ptr).notify = Some(handle_new_output);
102 wl_signal_add(&mut (*backend_cast).events.new_output, &mut self.new_output);
103
104 // Add apply/test listeners
105 let manager_cast = self.wlr_output_manager as *mut WlrOutputManagerV1;
106
107 let apply_ptr = &mut self.manager_apply as *mut ffi::wl_listener as *mut WlListener;
108 (*apply_ptr).notify = Some(handle_manager_apply);
109 wl_signal_add(&mut (*manager_cast).events.apply, &mut self.manager_apply);
110
111 let test_ptr = &mut self.manager_test as *mut ffi::wl_listener as *mut WlListener;
112 (*test_ptr).notify = Some(handle_manager_test);
113 wl_signal_add(&mut (*manager_cast).events.test, &mut self.manager_test);
114
115 // Add power manager set_mode listener
116 let power_cast = self.power_manager as *mut WlrOutputPowerManagerV1;
117 let set_mode_ptr = &mut self.power_manager_set_mode as *mut ffi::wl_listener as *mut WlListener;
118 (*set_mode_ptr).notify = Some(handle_power_manager_set_mode);
119 wl_signal_add(&mut (*power_cast).events.set_mode, &mut self.power_manager_set_mode);
120
121 Ok(())
122 }
123
124 pub unsafe fn deinit(&mut self) {
125 wl_listener_remove(&mut self.manager_apply);
126 wl_listener_remove(&mut self.manager_test);
127 wl_listener_remove(&mut self.power_manager_set_mode);
128 wl_listener_remove(&mut self.new_output);
129
130 if !self.output_layout.is_null() {
131 ffi::wlr_output_layout_destroy(self.output_layout);
132 }
133 }
134
135 pub unsafe fn output_at(&mut self, lx: f64, ly: f64) -> *mut ffi::wlr_output {
136 let mut output_lx: f64 = 0.0;
137 let mut output_ly: f64 = 0.0;
138 ffi::wlr_output_layout_closest_point(
139 self.output_layout,
140 std::ptr::null_mut(),
141 lx,
142 ly,
143 &mut output_lx,
144 &mut output_ly,
145 );
146 ffi::wlr_output_layout_output_at(self.output_layout, output_lx, output_ly)
147 }
148
149 pub unsafe fn auto_layout(&mut self) {
150 let mut rightmost_edge: i32 = 0;
151 let mut row_y: i32 = 0;
152
153 let mut link = self.outputs.next;
154 while link != &mut self.outputs as *mut ffi::wl_list {
155 let output = &mut *crate::container_of!(link, Output, link);
156 if !output.scheduled.auto_layout {
157 let (w, _) = output.scheduled.dimensions();
158 let x = output.scheduled.x + w;
159 if x > rightmost_edge {
160 rightmost_edge = x;
161 row_y = output.scheduled.y;
162 }
163 }
164 link = (*link).next;
165 }
166
167 let mut link = self.outputs.next;
168 while link != &mut self.outputs as *mut ffi::wl_list {
169 let output = &mut *crate::container_of!(link, Output, link);
170 if output.scheduled.auto_layout {
171 output.scheduled.x = rightmost_edge;
172 output.scheduled.y = row_y;
173 let (w, _) = output.scheduled.dimensions();
174 rightmost_edge += w;
175 }
176 link = (*link).next;
177 }
178 }
179
180 pub unsafe fn commit_output_state(&mut self, server: *mut Server) {
181 let wm = &mut (*server).wm;
182
183 let mut link = wm.sent.outputs.next;
184 while link != &mut wm.sent.outputs as *mut ffi::wl_list {
185 let output = &mut *crate::container_of!(link, Output, link_sent);
186 assert!(output.sent.state != OutputStateValue::Destroying);
187 output.rendering_current = output.rendering_requested;
188
189 let wlr_output = output.wlr_output;
190 if !wlr_output.is_null() {
191 match output.sent.state {
192 OutputStateValue::Enabled | OutputStateValue::DisabledSoft => {
193 ffi::wlr_scene_output_set_position(output.scene_output, output.sent.x, output.sent.y);
194 ffi::wlr_output_layout_add(self.output_layout, wlr_output, output.sent.x, output.sent.y);
195 if let Some(lock_surface) = (*server).lock_manager.lock_surface_from_output(output) {
196 ffi::wlr_scene_node_set_position(
197 (*lock_surface).tree as *mut ffi::wlr_scene_node,
198 output.sent.x,
199 output.sent.y,
200 );
201 }
202
203 let (width, height) = output.sent.dimensions();
204 let color: [f32; 4] = [
205 ((*server).wm.layout.background_r as f64 / u32::MAX as f64) as f32,
206 ((*server).wm.layout.background_g as f64 / u32::MAX as f64) as f32,
207 ((*server).wm.layout.background_b as f64 / u32::MAX as f64) as f32,
208 ((*server).wm.layout.background_a as f64 / u32::MAX as f64) as f32,
209 ];
210 if output.background_rect.is_null() {
211 output.background_rect = ffi::wlr_scene_rect_create(
212 (*server).scene.layers.background,
213 width,
214 height,
215 color.as_ptr(),
216 );
217 } else {
218 ffi::wlr_scene_rect_set_size(output.background_rect, width, height);
219 ffi::wlr_scene_rect_set_color(output.background_rect, color.as_ptr());
220 }
221 if !output.background_rect.is_null() {
222 ffi::wlr_scene_node_set_position(
223 output.background_rect as *mut ffi::wlr_scene_node,
224 output.sent.x,
225 output.sent.y,
226 );
227 }
228 if output.grid_tree.is_null() {
229 output.grid_tree = ffi::wlr_scene_tree_create((*server).scene.layers.background);
230 }
231 if !output.grid_tree.is_null() {
232 ffi::wlr_scene_node_set_position(
233 output.grid_tree as *mut ffi::wlr_scene_node,
234 output.sent.x,
235 output.sent.y,
236 );
237 }
238 if !output.grid_backdrop_tree.is_null() {
239 ffi::wlr_scene_node_set_position(
240 output.grid_backdrop_tree as *mut ffi::wlr_scene_node,
241 output.sent.x,
242 output.sent.y,
243 );
244 }
245
246 if output.adjust_tree.is_null() {
247 output.adjust_tree = ffi::wlr_scene_tree_create((*server).scene.layers.top);
248 }
249 if !output.adjust_tree.is_null() {
250 ffi::wlr_scene_node_set_position(
251 output.adjust_tree as *mut ffi::wlr_scene_node,
252 output.sent.x,
253 output.sent.y,
254 );
255 }
256 }
257 OutputStateValue::DisabledHard => {
258 ffi::wlr_output_layout_remove(self.output_layout, wlr_output);
259 if !output.background_rect.is_null() {
260 ffi::wlr_scene_node_destroy(output.background_rect as *mut ffi::wlr_scene_node);
261 output.background_rect = std::ptr::null_mut();
262 }
263 if !output.grid_tree.is_null() {
264 ffi::wlr_scene_node_destroy(output.grid_tree as *mut ffi::wlr_scene_node);
265 output.grid_tree = std::ptr::null_mut();
266 output.grid_rect_pool.clear();
267 }
268 if !output.grid_backdrop_tree.is_null() {
269 ffi::wlr_scene_node_destroy(output.grid_backdrop_tree as *mut ffi::wlr_scene_node);
270 output.grid_backdrop_tree = std::ptr::null_mut();
271 output.grid_backdrop_rect = std::ptr::null_mut();
272 }
273 if !output.adjust_tree.is_null() {
274 ffi::wlr_scene_node_destroy(output.adjust_tree as *mut ffi::wlr_scene_node);
275 output.adjust_tree = std::ptr::null_mut();
276 output.adjust_rects.clear();
277 }
278 }
279 OutputStateValue::Destroying => unreachable!(),
280 }
281 }
282 link = (*link).next;
283 }
284
285 let mut need_modeset = false;
286 let mut link = wm.sent.outputs.next;
287 while link != &mut wm.sent.outputs as *mut ffi::wl_list {
288 let output = &mut *crate::container_of!(link, Output, link_sent);
289 let wlr_output = output.wlr_output;
290 if wlr_output.is_null() {
291 link = (*link).next;
292 continue;
293 }
294
295 let wlr_enabled = ffi::river_wlr_output_get_enabled(wlr_output);
296 match output.sent.state {
297 OutputStateValue::Enabled => {
298 if !wlr_enabled {
299 need_modeset = true;
300 break;
301 }
302 }
303 OutputStateValue::DisabledSoft | OutputStateValue::DisabledHard => {
304 if wlr_enabled {
305 need_modeset = true;
306 break;
307 }
308 }
309 OutputStateValue::Destroying => unreachable!(),
310 }
311
312 match output.sent.mode {
313 OutputMode::Standard(mode) => {
314 if mode != ffi::river_wlr_output_get_current_mode(wlr_output) {
315 need_modeset = true;
316 break;
317 }
318 }
319 OutputMode::Custom { width, height, refresh } => {
320 if width != ffi::river_wlr_output_get_width(wlr_output)
321 || height != ffi::river_wlr_output_get_height(wlr_output)
322 || refresh != ffi::river_wlr_output_get_refresh(wlr_output) {
323 need_modeset = true;
324 break;
325 }
326 }
327 OutputMode::None => {
328 assert!(output.sent.state == OutputStateValue::DisabledHard);
329 }
330 }
331
332 if output.current.mode_none() && output.sent.state == OutputStateValue::Enabled {
333 need_modeset = true;
334 break;
335 }
336
337 if output.sent.scale != output.current.scale {
338 need_modeset = true;
339 break;
340 }
341
342 let wlr_adaptive = ffi::river_wlr_output_get_adaptive_sync_status(wlr_output)
343 == ffi::wlr_output_adaptive_sync_status_WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
344 if output.sent.adaptive_sync != wlr_adaptive {
345 need_modeset = true;
346 break;
347 }
348
349 link = (*link).next;
350 }
351
352 if need_modeset {
353 log::debug!("committing output state requires modeset");
354
355 let mut states_vec = Vec::new();
356 let mut link = wm.sent.outputs.next;
357 while link != &mut wm.sent.outputs as *mut ffi::wl_list {
358 let output = &mut *crate::container_of!(link, Output, link_sent);
359 let wlr_output = output.wlr_output;
360 if wlr_output.is_null() {
361 link = (*link).next;
362 continue;
363 }
364
365 states_vec.push(ffi::wlr_backend_output_state {
366 output: wlr_output,
367 base: std::mem::zeroed(),
368 });
369
370 link = (*link).next;
371 }
372
373 for state in &mut states_vec {
374 ffi::wlr_output_state_init(&mut state.base);
375 let output = &mut *(ffi::river_wlr_output_get_data(state.output) as *mut Output);
376 output.sent.apply_modeset(&mut state.base);
377 }
378
379 let mut swapchain_manager = std::mem::zeroed();
380 ffi::wlr_output_swapchain_manager_init(&mut swapchain_manager, (*server).backend);
381
382 if !ffi::wlr_output_swapchain_manager_prepare(
383 &mut swapchain_manager,
384 states_vec.as_ptr(),
385 states_vec.len(),
386 ) {
387 log::error!("failed to prepare new output configuration");
388 self.modeset_failed(server);
389 for state in &mut states_vec {
390 ffi::wlr_output_state_finish(&mut state.base);
391 }
392 ffi::wlr_output_swapchain_manager_finish(&mut swapchain_manager);
393 return;
394 }
395
396 for state in &mut states_vec {
397 let output = &mut *(ffi::river_wlr_output_get_data(state.output) as *mut Output);
398 let sc = ffi::wlr_output_swapchain_manager_get_swapchain(&mut swapchain_manager, state.output);
399 let options = ffi::wlr_scene_output_state_options {
400 swapchain: sc,
401 ..std::mem::zeroed()
402 };
403 if !ffi::wlr_scene_output_build_state(output.scene_output, &mut state.base, &options) {
404 log::error!("failed to render scene for {:?}", std::ffi::CStr::from_ptr(ffi::river_wlr_output_get_name(state.output)));
405 }
406 }
407
408 if !ffi::wlr_backend_commit((*server).backend, states_vec.as_ptr(), states_vec.len()) {
409 log::error!("failed to commit new output configuration");
410 self.modeset_failed(server);
411 for state in &mut states_vec {
412 ffi::wlr_output_state_finish(&mut state.base);
413 }
414 ffi::wlr_output_swapchain_manager_finish(&mut swapchain_manager);
415 return;
416 }
417
418 self.first_modeset = false;
419 ffi::wlr_output_swapchain_manager_apply(&mut swapchain_manager);
420
421 for state in &mut states_vec {
422 ffi::wlr_output_state_finish(&mut state.base);
423 }
424 ffi::wlr_output_swapchain_manager_finish(&mut swapchain_manager);
425 }
426
427 if !wm.sent.output_config.is_null() {
428 ffi::wlr_output_configuration_v1_send_succeeded(wm.sent.output_config);
429 ffi::wlr_output_configuration_v1_destroy(wm.sent.output_config);
430 wm.sent.output_config = std::ptr::null_mut();
431 }
432
433 let mut link = wm.sent.outputs.next;
434 while link != &mut wm.sent.outputs as *mut ffi::wl_list {
435 let next_link = (*link).next;
436 let output = &mut *crate::container_of!(link, Output, link_sent);
437 let wlr_output = output.wlr_output;
438 if wlr_output.is_null() {
439 link = next_link;
440 continue;
441 }
442
443 if !output.sent_wl_output {
444 let global = ffi::river_wlr_output_get_global(wlr_output);
445 if !global.is_null() {
446 if !output.object.is_null() {
447 let name = ffi::wl_global_get_name(global, ffi::wl_resource_get_client(output.object));
448 crate::output::zcce_output_send_wl_output(output.object, name);
449 output.sent_wl_output = true;
450 }
451 }
452 }
453
454 match output.sent.state {
455 OutputStateValue::Enabled => {
456 assert!(ffi::river_wlr_output_get_enabled(wlr_output));
457 ffi::wlr_output_schedule_frame(wlr_output);
458 }
459 OutputStateValue::DisabledSoft | OutputStateValue::DisabledHard => {
460 assert!(!ffi::river_wlr_output_get_enabled(wlr_output));
461 output.lock_render_state = crate::output::LockRenderState::Blanked;
462 if output.sent.state == OutputStateValue::DisabledHard {
463 wl_list_remove(&mut output.link_sent as *mut ffi::wl_list as *mut WlList);
464 ffi::wl_list_init(&mut output.link_sent);
465 }
466 }
467 OutputStateValue::Destroying => unreachable!(),
468 }
469
470 output.current = output.sent;
471 link = next_link;
472 }
473
474 let _ = self.send_config(server);
475 }
476
477 pub unsafe fn modeset_failed(&mut self, server: *mut Server) {
478 let wm = &mut (*server).wm;
479
480 if self.first_modeset {
481 log::error!("initial modeset failed, exiting river");
482 ffi::wl_display_terminate((*server).wl_server);
483 return;
484 }
485
486 if !wm.sent.output_config.is_null() {
487 ffi::wlr_output_configuration_v1_send_failed(wm.sent.output_config);
488 ffi::wlr_output_configuration_v1_destroy(wm.sent.output_config);
489 wm.sent.output_config = std::ptr::null_mut();
490 }
491
492 let mut link = wm.sent.outputs.next;
493 while link != &mut wm.sent.outputs as *mut ffi::wl_list {
494 let output = &mut *crate::container_of!(link, Output, link_sent);
495 output.scheduled = output.current;
496 output.sent = output.current;
497 link = (*link).next;
498 }
499 wm.dirty_windowing();
500 }
501
502 pub unsafe fn send_config(&mut self, _server: *mut Server) -> Result<(), &'static str> {
503 let config = ffi::wlr_output_configuration_v1_create();
504 if config.is_null() {
505 return Err("Failed to create configuration v1");
506 }
507
508 let mut link = self.outputs.next;
509 while link != &mut self.outputs as *mut ffi::wl_list {
510 let output = &mut *crate::container_of!(link, Output, link);
511 let wlr_output = output.wlr_output;
512 if wlr_output.is_null() {
513 link = (*link).next;
514 continue;
515 }
516
517 let head = ffi::wlr_output_configuration_head_v1_create(config, wlr_output);
518 if head.is_null() {
519 ffi::wlr_output_configuration_v1_destroy(config);
520 return Err("Failed to create configuration head");
521 }
522
523 (*head).state.enabled = match output.current.state {
524 OutputStateValue::Enabled | OutputStateValue::DisabledSoft => true,
525 OutputStateValue::DisabledHard => false,
526 OutputStateValue::Destroying => unreachable!(),
527 };
528 (*head).state.scale = output.current.scale;
529 (*head).state.transform = output.current.transform;
530 (*head).state.x = output.current.x;
531 (*head).state.y = output.current.y;
532
533 link = (*link).next;
534 }
535
536 ffi::wlr_output_manager_v1_set_configuration(self.wlr_output_manager, config);
537 Ok(())
538 }
539
540 pub unsafe fn max_overlap_output(&mut self, box_: *const ffi::wlr_box) -> *mut ffi::wlr_output {
541 let mut max_overlap_area = 0;
542 let mut max_overlap_output = std::ptr::null_mut();
543
544 let mut link = self.outputs.next;
545 while link != &mut self.outputs as *mut ffi::wl_list {
546 let output = &mut *crate::container_of!(link, Output, link);
547 let wlr_output = output.wlr_output;
548 if wlr_output.is_null() {
549 link = (*link).next;
550 continue;
551 }
552
553 let mut overlap: ffi::wlr_box = std::mem::zeroed();
554 ffi::wlr_output_layout_get_box(self.output_layout, wlr_output, &mut overlap);
555
556 if overlap.width <= 0 || overlap.height <= 0 {
557 link = (*link).next;
558 continue;
559 }
560
561 let mut dest: ffi::wlr_box = std::mem::zeroed();
562 if ffi::wlr_box_intersection(&mut dest, &overlap, box_) {
563 let overlap_area = dest.width * dest.height;
564 if overlap_area > max_overlap_area {
565 max_overlap_area = overlap_area;
566 max_overlap_output = wlr_output;
567 }
568 }
569
570 link = (*link).next;
571 }
572
573 max_overlap_output
574 }
575 }
576
577 fn validate_config_coordinates(server: *mut Server, config: *mut ffi::wlr_output_configuration_v1) -> bool {
578 unsafe {
579 let mut head_link = (*config).heads.next;
580 while head_link != &mut (*config).heads {
581 let head = crate::container_of!(head_link, ffi::wlr_output_configuration_head_v1, link);
582 let _output_global = ffi::river_wlr_output_get_global((*head).state.output);
583
584 if (*head).state.enabled {
585 let proposed = crate::output::OutputState::from_head_state(&((*head).state));
586 if !(*server).xwayland.is_null() {
587 if proposed.x < 0 || proposed.y < 0 {
588 log::error!(
589 "Attempted to set negative coordinates for output. Negative output coordinates are disallowed if Xwayland is active."
590 );
591 return false;
592 }
593 let (width, height) = proposed.dimensions();
594 if proposed.x + width > i16::MAX as i32 || proposed.y + height > i16::MAX as i32 {
595 log::error!(
596 "Attempted to set too-large coordinates for output. Coordinates greater than {} are disallowed if Xwayland is active.",
597 i16::MAX
598 );
599 return false;
600 }
601 }
602 }
603 head_link = (*head_link).next;
604 }
605 }
606 true
607 }
608
609 unsafe extern "C" fn handle_new_output(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
610 let om = &mut *crate::container_of!(listener, OutputManager, new_output);
611 let server = crate::container_of!(om as *mut OutputManager, Server, om);
612 let wlr_output = data as *mut ffi::wlr_output;
613 log::debug!("new output {:?}", std::ffi::CStr::from_ptr(ffi::river_wlr_output_get_name(wlr_output)));
614 crate::xwayland_window::note_output_change();
615 if let Err(e) = Output::create(server, wlr_output) {
616 log::error!("failed to create output: {}", e);
617 ffi::wlr_output_destroy(wlr_output);
618 }
619 }
620
621 unsafe extern "C" fn handle_manager_test(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
622 let om = &mut *crate::container_of!(listener, OutputManager, manager_test);
623 let server = crate::container_of!(om as *mut OutputManager, Server, om);
624 let config = data as *mut ffi::wlr_output_configuration_v1;
625
626 if !validate_config_coordinates(server, config) {
627 ffi::wlr_output_configuration_v1_send_failed(config);
628 ffi::wlr_output_configuration_v1_destroy(config);
629 return;
630 }
631
632 let mut states_len: usize = 0;
633 let states = ffi::wlr_output_configuration_v1_build_state(config, &mut states_len);
634 if states.is_null() {
635 log::error!("out of memory");
636 ffi::wlr_output_configuration_v1_send_failed(config);
637 ffi::wlr_output_configuration_v1_destroy(config);
638 return;
639 }
640
641 let mut swapchain_manager = std::mem::zeroed();
642 ffi::wlr_output_swapchain_manager_init(&mut swapchain_manager, (*server).backend);
643
644 if ffi::wlr_output_swapchain_manager_prepare(&mut swapchain_manager, states, states_len) {
645 ffi::wlr_output_configuration_v1_send_succeeded(config);
646 } else {
647 ffi::wlr_output_configuration_v1_send_failed(config);
648 }
649
650 ffi::wlr_output_swapchain_manager_finish(&mut swapchain_manager);
651 libc::free(states as *mut std::ffi::c_void);
652 ffi::wlr_output_configuration_v1_destroy(config);
653 }
654
655 unsafe extern "C" fn handle_manager_apply(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
656 let om = &mut *crate::container_of!(listener, OutputManager, manager_apply);
657 let server = crate::container_of!(om as *mut OutputManager, Server, om);
658 let config = data as *mut ffi::wlr_output_configuration_v1;
659
660 log::info!("applying output configuration");
661
662 if !validate_config_coordinates(server, config) {
663 ffi::wlr_output_configuration_v1_send_failed(config);
664 ffi::wlr_output_configuration_v1_destroy(config);
665 return;
666 }
667
668 let mut head_link = (*config).heads.next;
669 while head_link != &mut (*config).heads {
670 let head = crate::container_of!(head_link, ffi::wlr_output_configuration_head_v1, link);
671 let output = &mut *(ffi::river_wlr_output_get_data((*head).state.output) as *mut Output);
672
673 if (*head).state.enabled {
674 let previous = output.scheduled.state;
675 output.scheduled = crate::output::OutputState::from_head_state(&((*head).state));
676 if previous == crate::output::OutputStateValue::DisabledSoft {
677 output.scheduled.state = crate::output::OutputStateValue::DisabledSoft;
678 } else {
679 assert!(output.scheduled.state == crate::output::OutputStateValue::Enabled);
680 }
681 } else {
682 output.scheduled.state = crate::output::OutputStateValue::DisabledHard;
683 }
684
685 head_link = (*head_link).next;
686 }
687
688 if !(*server).wm.scheduled.output_config.is_null() {
689 ffi::wlr_output_configuration_v1_send_failed((*server).wm.scheduled.output_config);
690 ffi::wlr_output_configuration_v1_destroy((*server).wm.scheduled.output_config);
691 }
692 (*server).wm.scheduled.output_config = config;
693
694 (*server).wm.dirty_windowing();
695 }
696
697 unsafe extern "C" fn handle_power_manager_set_mode(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
698 let om = &mut *crate::container_of!(listener, OutputManager, power_manager_set_mode);
699 let server = crate::container_of!(om as *mut OutputManager, Server, om);
700 let event = data as *mut ffi::wlr_output_power_v1_set_mode_event;
701
702 let output_data = ffi::river_wlr_output_get_data((*event).output);
703 if output_data.is_null() {
704 return;
705 }
706 let output = &mut *(output_data as *mut Output);
707
708 log::debug!("client requested dpms mode {:?} for output {:?}", (*event).mode, std::ffi::CStr::from_ptr(ffi::river_wlr_output_get_name((*event).output)));
709
710 match output.scheduled.state {
711 OutputStateValue::Enabled => {
712 if (*event).mode == ffi::zwlr_output_power_v1_mode_ZWLR_OUTPUT_POWER_V1_MODE_OFF {
713 output.scheduled.state = OutputStateValue::DisabledSoft;
714 } else {
715 return;
716 }
717 }
718 OutputStateValue::DisabledSoft => {
719 if (*event).mode == ffi::zwlr_output_power_v1_mode_ZWLR_OUTPUT_POWER_V1_MODE_ON {
720 output.scheduled.state = OutputStateValue::Enabled;
721 } else {
722 return;
723 }
724 }
725 OutputStateValue::DisabledHard | OutputStateValue::Destroying => return,
726 }
727
728 (*server).wm.dirty_windowing();
729 }