git.lucas.co / cce-compositor
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 }