| 1 | use std::{ |
| 2 | any::Any, |
| 3 | fmt::{self, Display, Formatter}, |
| 4 | sync::{Arc, Mutex, Weak}, |
| 5 | }; |
| 6 | |
| 7 | use log::warn; |
| 8 | use wayland_client::{ |
| 9 | globals::GlobalList, |
| 10 | protocol::wl_output::{self, Subpixel, Transform}, |
| 11 | Connection, Dispatch, Proxy, QueueHandle, WEnum, |
| 12 | }; |
| 13 | use wayland_protocols::xdg::xdg_output::zv1::client::{ |
| 14 | zxdg_output_manager_v1::{self, ZxdgOutputManagerV1}, |
| 15 | zxdg_output_v1, |
| 16 | }; |
| 17 | |
| 18 | use crate::{ |
| 19 | globals::GlobalData, |
| 20 | registry::{GlobalProxy, ProvidesRegistryState, RegistryHandler}, |
| 21 | }; |
| 22 | |
| 23 | /// Simplified event handler for [`wl_output::WlOutput`]. |
| 24 | /// See [`OutputState`]. |
| 25 | pub trait OutputHandler: Sized { |
| 26 | fn output_state(&mut self) -> &mut OutputState; |
| 27 | |
| 28 | /// A new output has been advertised. |
| 29 | fn new_output( |
| 30 | &mut self, |
| 31 | conn: &Connection, |
| 32 | qh: &QueueHandle<Self>, |
| 33 | output: wl_output::WlOutput, |
| 34 | ); |
| 35 | |
| 36 | /// An existing output has changed. |
| 37 | fn update_output( |
| 38 | &mut self, |
| 39 | conn: &Connection, |
| 40 | qh: &QueueHandle<Self>, |
| 41 | output: wl_output::WlOutput, |
| 42 | ); |
| 43 | |
| 44 | /// An output is no longer advertised. |
| 45 | /// |
| 46 | /// The info passed to this function was the state of the output before destruction. |
| 47 | fn output_destroyed( |
| 48 | &mut self, |
| 49 | conn: &Connection, |
| 50 | qh: &QueueHandle<Self>, |
| 51 | output: wl_output::WlOutput, |
| 52 | ); |
| 53 | } |
| 54 | |
| 55 | type ScaleWatcherFn = |
| 56 | dyn Fn(&mut dyn Any, &Connection, &dyn Any, &wl_output::WlOutput) + Send + Sync; |
| 57 | |
| 58 | /// A handler for delegating [`wl_output::WlOutput`](wayland_client::protocol::wl_output::WlOutput). |
| 59 | /// |
| 60 | /// When implementing [`ProvidesRegistryState`], |
| 61 | /// [`registry_handlers!`](crate::registry_handlers) may be used to delegate all |
| 62 | /// output events to an instance of this type. It will internally store the internal state of all |
| 63 | /// outputs and allow querying them via the `OutputState::outputs` and `OutputState::info` methods. |
| 64 | /// |
| 65 | /// ## Example |
| 66 | /// |
| 67 | /// ``` |
| 68 | /// use smithay_client_toolkit::output::{OutputHandler,OutputState}; |
| 69 | /// use smithay_client_toolkit::registry::{ProvidesRegistryState,RegistryHandler}; |
| 70 | /// # use smithay_client_toolkit::registry::RegistryState; |
| 71 | /// use smithay_client_toolkit::{registry_handlers,delegate_output, delegate_registry}; |
| 72 | /// use wayland_client::{Connection,QueueHandle,protocol::wl_output}; |
| 73 | /// |
| 74 | /// struct ExampleState { |
| 75 | /// # registry_state: RegistryState, |
| 76 | /// // The state is usually kept as an attribute of the application state. |
| 77 | /// output_state: OutputState, |
| 78 | /// } |
| 79 | /// |
| 80 | /// // When using `OutputState`, an implementation of `OutputHandler` should be supplied: |
| 81 | /// impl OutputHandler for ExampleState { |
| 82 | /// // Custom implementation handling output events here ... |
| 83 | /// # fn output_state(&mut self) -> &mut OutputState { |
| 84 | /// # &mut self.output_state |
| 85 | /// # } |
| 86 | /// # |
| 87 | /// # fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) { |
| 88 | /// # } |
| 89 | /// # |
| 90 | /// # fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) { |
| 91 | /// # } |
| 92 | /// # |
| 93 | /// # fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) { |
| 94 | /// # } |
| 95 | /// } |
| 96 | /// |
| 97 | /// // Delegating to the registry is required to use `OutputState`. |
| 98 | /// delegate_registry!(ExampleState); |
| 99 | /// delegate_output!(ExampleState); |
| 100 | /// |
| 101 | /// impl ProvidesRegistryState for ExampleState { |
| 102 | /// # fn registry(&mut self) -> &mut RegistryState { |
| 103 | /// # &mut self.registry_state |
| 104 | /// # } |
| 105 | /// // ... |
| 106 | /// |
| 107 | /// registry_handlers!(OutputState); |
| 108 | /// } |
| 109 | /// ``` |
| 110 | pub struct OutputState { |
| 111 | xdg: GlobalProxy<ZxdgOutputManagerV1>, |
| 112 | outputs: Vec<OutputInner>, |
| 113 | callbacks: Vec<Weak<ScaleWatcherFn>>, |
| 114 | } |
| 115 | |
| 116 | impl fmt::Debug for OutputState { |
| 117 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| 118 | fmt&mut DebugStruct<'_, '_>.debug_struct("OutputState" ) |
| 119 | .field("xdg" , &self.xdg) |
| 120 | .field("outputs" , &self.outputs) |
| 121 | .field(name:"callbacks" , &self.callbacks.len()) |
| 122 | .finish() |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | pub struct ScaleWatcherHandle(Arc<ScaleWatcherFn>); |
| 127 | |
| 128 | impl fmt::Debug for ScaleWatcherHandle { |
| 129 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| 130 | fmt.debug_struct(name:"ScaleWatcherHandle" ).finish_non_exhaustive() |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | impl OutputState { |
| 135 | pub fn new< |
| 136 | D: Dispatch<wl_output::WlOutput, OutputData> |
| 137 | + Dispatch<zxdg_output_v1::ZxdgOutputV1, OutputData> |
| 138 | + Dispatch<zxdg_output_manager_v1::ZxdgOutputManagerV1, GlobalData> |
| 139 | + 'static, |
| 140 | >( |
| 141 | global_list: &GlobalList, |
| 142 | qh: &QueueHandle<D>, |
| 143 | ) -> OutputState { |
| 144 | let (outputs, xdg) = global_list.contents().with_list(|globals| { |
| 145 | let outputs: Vec<wl_output::WlOutput> = crate::registry::bind_all( |
| 146 | global_list.registry(), |
| 147 | globals, |
| 148 | qh, |
| 149 | 1..=4, |
| 150 | OutputData::new, |
| 151 | ) |
| 152 | .expect("Failed to bind global" ); |
| 153 | let xdg = |
| 154 | crate::registry::bind_one(global_list.registry(), globals, qh, 1..=3, GlobalData) |
| 155 | .into(); |
| 156 | (outputs, xdg) |
| 157 | }); |
| 158 | |
| 159 | let mut output_state = OutputState { xdg, outputs: vec![], callbacks: vec![] }; |
| 160 | for wl_output in outputs { |
| 161 | output_state.setup(wl_output, qh); |
| 162 | } |
| 163 | output_state |
| 164 | } |
| 165 | |
| 166 | /// Returns an iterator over all outputs. |
| 167 | pub fn outputs(&self) -> impl Iterator<Item = wl_output::WlOutput> { |
| 168 | self.outputs.iter().map(|output| &output.wl_output).cloned().collect::<Vec<_>>().into_iter() |
| 169 | } |
| 170 | |
| 171 | /// Returns information about an output. |
| 172 | /// |
| 173 | /// This may be none if the output has been destroyed or the compositor has not sent information about the |
| 174 | /// output yet. |
| 175 | pub fn info(&self, output: &wl_output::WlOutput) -> Option<OutputInfo> { |
| 176 | self.outputs |
| 177 | .iter() |
| 178 | .find(|inner| &inner.wl_output == output) |
| 179 | .and_then(|inner| inner.current_info.clone()) |
| 180 | } |
| 181 | |
| 182 | pub fn add_scale_watcher<F, D>(data: &mut D, f: F) -> ScaleWatcherHandle |
| 183 | where |
| 184 | D: OutputHandler + 'static, |
| 185 | F: Fn(&mut D, &Connection, &QueueHandle<D>, &wl_output::WlOutput) + Send + Sync + 'static, |
| 186 | { |
| 187 | let state = data.output_state(); |
| 188 | let rv = ScaleWatcherHandle(Arc::new(move |data, conn, qh, output| { |
| 189 | if let (Some(data), Some(qh)) = (data.downcast_mut(), qh.downcast_ref()) { |
| 190 | f(data, conn, qh, output); |
| 191 | } |
| 192 | })); |
| 193 | state.callbacks.retain(|f| f.upgrade().is_some()); |
| 194 | state.callbacks.push(Arc::downgrade(&rv.0)); |
| 195 | rv |
| 196 | } |
| 197 | |
| 198 | fn setup<D>(&mut self, wl_output: wl_output::WlOutput, qh: &QueueHandle<D>) |
| 199 | where |
| 200 | D: Dispatch<zxdg_output_v1::ZxdgOutputV1, OutputData> + 'static, |
| 201 | { |
| 202 | let data = wl_output.data::<OutputData>().unwrap().clone(); |
| 203 | |
| 204 | let pending_info = data.0.lock().unwrap().clone(); |
| 205 | let name = pending_info.id; |
| 206 | |
| 207 | let version = wl_output.version(); |
| 208 | let pending_xdg = self.xdg.get().is_ok(); |
| 209 | |
| 210 | let xdg_output = if pending_xdg { |
| 211 | let xdg = self.xdg.get().unwrap(); |
| 212 | |
| 213 | Some(xdg.get_xdg_output(&wl_output, qh, data)) |
| 214 | } else { |
| 215 | None |
| 216 | }; |
| 217 | |
| 218 | let inner = OutputInner { |
| 219 | name, |
| 220 | wl_output, |
| 221 | xdg_output, |
| 222 | just_created: true, |
| 223 | // wl_output::done was added in version 2. |
| 224 | // If we have an output at version 1, assume the data was already sent. |
| 225 | current_info: if version > 1 { None } else { Some(OutputInfo::new(name)) }, |
| 226 | |
| 227 | pending_info, |
| 228 | pending_wl: true, |
| 229 | pending_xdg, |
| 230 | }; |
| 231 | |
| 232 | self.outputs.push(inner); |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | #[derive (Debug, Clone)] |
| 237 | pub struct OutputData(Arc<Mutex<OutputInfo>>); |
| 238 | |
| 239 | impl OutputData { |
| 240 | pub fn new(name: u32) -> OutputData { |
| 241 | OutputData(Arc::new(Mutex::new(OutputInfo::new(name)))) |
| 242 | } |
| 243 | |
| 244 | /// Get the output scale factor. |
| 245 | pub fn scale_factor(&self) -> i32 { |
| 246 | let guard = self.0.lock().unwrap(); |
| 247 | |
| 248 | guard.scale_factor |
| 249 | } |
| 250 | |
| 251 | /// Get the output transform. |
| 252 | pub fn transform(&self) -> wl_output::Transform { |
| 253 | let guard = self.0.lock().unwrap(); |
| 254 | |
| 255 | guard.transform |
| 256 | } |
| 257 | |
| 258 | /// Access the underlying [`OutputInfo`]. |
| 259 | /// |
| 260 | /// Reentrant calls within the `callback` will deadlock. |
| 261 | pub fn with_output_info<T, F: FnOnce(&OutputInfo) -> T>(&self, callback: F) -> T { |
| 262 | let guard = self.0.lock().unwrap(); |
| 263 | callback(&guard) |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | #[derive (Debug, Clone)] |
| 268 | pub struct Mode { |
| 269 | /// Number of pixels of this mode in format `(width, height)` |
| 270 | /// |
| 271 | /// for example `(1920, 1080)` |
| 272 | pub dimensions: (i32, i32), |
| 273 | |
| 274 | /// Refresh rate for this mode. |
| 275 | /// |
| 276 | /// The refresh rate is specified in terms of millihertz (mHz). To convert approximately to Hertz, |
| 277 | /// divide the value by 1000. |
| 278 | /// |
| 279 | /// This value could be zero if an output has no correct refresh rate, such as a virtual output. |
| 280 | pub refresh_rate: i32, |
| 281 | |
| 282 | /// Whether this is the current mode for this output. |
| 283 | /// |
| 284 | /// Per the Wayland protocol, non-current modes are deprecated and clients should not rely on deprecated |
| 285 | /// modes. |
| 286 | pub current: bool, |
| 287 | |
| 288 | /// Whether this is the preferred mode for this output. |
| 289 | pub preferred: bool, |
| 290 | } |
| 291 | |
| 292 | impl Display for Mode { |
| 293 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 294 | if self.current { |
| 295 | write!(f, "(current) " )?; |
| 296 | } |
| 297 | |
| 298 | if self.preferred { |
| 299 | write!(f, "(preferred) " )?; |
| 300 | } |
| 301 | |
| 302 | write!( |
| 303 | f, |
| 304 | " {}× {}px @ {}. {:03} Hz" , |
| 305 | self.dimensions.0, |
| 306 | self.dimensions.1, |
| 307 | // Print the refresh rate in hertz since it is more familiar unit. |
| 308 | self.refresh_rate / 1000, |
| 309 | self.refresh_rate % 1000 |
| 310 | ) |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | /// Information about an output. |
| 315 | #[derive (Debug, Clone)] |
| 316 | #[non_exhaustive ] |
| 317 | pub struct OutputInfo { |
| 318 | /// The id of the output. |
| 319 | /// |
| 320 | /// This corresponds to the global `name` of the wl_output. |
| 321 | pub id: u32, |
| 322 | |
| 323 | /// The model name of this output as advertised by the server. |
| 324 | pub model: String, |
| 325 | |
| 326 | /// The make name of this output as advertised by the server. |
| 327 | pub make: String, |
| 328 | |
| 329 | /// Location of the top-left corner of this output in compositor space. |
| 330 | /// |
| 331 | /// Note that the compositor may decide to always report (0,0) if it decides clients are not allowed to |
| 332 | /// know this information. |
| 333 | pub location: (i32, i32), |
| 334 | |
| 335 | /// Physical dimensions of this output, in millimeters. |
| 336 | /// |
| 337 | /// This value may be set to (0, 0) if a physical size does not make sense for the output (e.g. projectors |
| 338 | /// and virtual outputs). |
| 339 | pub physical_size: (i32, i32), |
| 340 | |
| 341 | /// The subpixel layout for this output. |
| 342 | pub subpixel: Subpixel, |
| 343 | |
| 344 | /// The current transformation applied to this output |
| 345 | /// |
| 346 | /// You can pre-render your buffers taking this information into account and advertising it via |
| 347 | /// `wl_buffer.set_transform` for better performance. |
| 348 | pub transform: Transform, |
| 349 | |
| 350 | /// The scaling factor of this output |
| 351 | /// |
| 352 | /// Any buffer whose scaling factor does not match the one of the output it is displayed on will be |
| 353 | /// rescaled accordingly. |
| 354 | /// |
| 355 | /// For example, a buffer of scaling factor 1 will be doubled in size if the output scaling factor is 2. |
| 356 | /// |
| 357 | /// You can pre-render your buffers taking this information into account and advertising it via |
| 358 | /// `wl_surface.set_buffer_scale` so you may advertise a higher detail image. |
| 359 | pub scale_factor: i32, |
| 360 | |
| 361 | /// Possible modes for an output. |
| 362 | pub modes: Vec<Mode>, |
| 363 | |
| 364 | /// Logical position in global compositor space |
| 365 | pub logical_position: Option<(i32, i32)>, |
| 366 | |
| 367 | /// Logical size in global compositor space |
| 368 | pub logical_size: Option<(i32, i32)>, |
| 369 | |
| 370 | /// The name of the this output as advertised by the surface. |
| 371 | /// |
| 372 | /// Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do not assume that the name is a |
| 373 | /// reflection of an underlying DRM connector, X11 connection, etc. |
| 374 | /// |
| 375 | /// Compositors are not required to provide a name for the output and the value may be [`None`]. |
| 376 | /// |
| 377 | /// The name will be [`None`] if the compositor does not support version 4 of the wl-output protocol or |
| 378 | /// version 2 of the zxdg-output-v1 protocol. |
| 379 | pub name: Option<String>, |
| 380 | |
| 381 | /// The description of this output as advertised by the server |
| 382 | /// |
| 383 | /// The description is a UTF-8 string with no convention defined for its contents. The description is not |
| 384 | /// guaranteed to be unique among all wl_output globals. Examples might include 'Foocorp 11" Display' or |
| 385 | /// 'Virtual X11 output via :1'. |
| 386 | /// |
| 387 | /// Compositors are not required to provide a description of the output and the value may be [`None`]. |
| 388 | /// |
| 389 | /// The value will be [`None`] if the compositor does not support version 4 of the wl-output |
| 390 | /// protocol, version 2 of the zxdg-output-v1 protocol. |
| 391 | pub description: Option<String>, |
| 392 | } |
| 393 | |
| 394 | #[macro_export ] |
| 395 | macro_rules! delegate_output { |
| 396 | ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { |
| 397 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ |
| 398 | $crate::reexports::client::protocol::wl_output::WlOutput: $crate::output::OutputData |
| 399 | ] => $crate::output::OutputState); |
| 400 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ |
| 401 | $crate::reexports::protocols::xdg::xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1: $crate::globals::GlobalData |
| 402 | ] => $crate::output::OutputState); |
| 403 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ |
| 404 | $crate::reexports::protocols::xdg::xdg_output::zv1::client::zxdg_output_v1::ZxdgOutputV1: $crate::output::OutputData |
| 405 | ] => $crate::output::OutputState); |
| 406 | }; |
| 407 | } |
| 408 | |
| 409 | impl<D> Dispatch<wl_output::WlOutput, OutputData, D> for OutputState |
| 410 | where |
| 411 | D: Dispatch<wl_output::WlOutput, OutputData> + OutputHandler + 'static, |
| 412 | { |
| 413 | fn event( |
| 414 | state: &mut D, |
| 415 | output: &wl_output::WlOutput, |
| 416 | event: wl_output::Event, |
| 417 | data: &OutputData, |
| 418 | conn: &Connection, |
| 419 | qh: &QueueHandle<D>, |
| 420 | ) { |
| 421 | let inner = match state |
| 422 | .output_state() |
| 423 | .outputs |
| 424 | .iter_mut() |
| 425 | .find(|inner| &inner.wl_output == output) |
| 426 | { |
| 427 | Some(inner) => inner, |
| 428 | None => { |
| 429 | warn!("Received {event:?} for dead wl_output" ); |
| 430 | return; |
| 431 | } |
| 432 | }; |
| 433 | |
| 434 | match event { |
| 435 | wl_output::Event::Geometry { |
| 436 | x, |
| 437 | y, |
| 438 | physical_width, |
| 439 | physical_height, |
| 440 | subpixel, |
| 441 | make, |
| 442 | model, |
| 443 | transform, |
| 444 | } => { |
| 445 | inner.pending_info.location = (x, y); |
| 446 | inner.pending_info.physical_size = (physical_width, physical_height); |
| 447 | inner.pending_info.subpixel = match subpixel { |
| 448 | WEnum::Value(subpixel) => subpixel, |
| 449 | WEnum::Unknown(_) => todo!("Warn about invalid subpixel value" ), |
| 450 | }; |
| 451 | inner.pending_info.make = make; |
| 452 | inner.pending_info.model = model; |
| 453 | inner.pending_info.transform = match transform { |
| 454 | WEnum::Value(subpixel) => subpixel, |
| 455 | WEnum::Unknown(_) => todo!("Warn about invalid transform value" ), |
| 456 | }; |
| 457 | inner.pending_wl = true; |
| 458 | } |
| 459 | |
| 460 | wl_output::Event::Mode { flags, width, height, refresh } => { |
| 461 | // Remove the old mode |
| 462 | inner.pending_info.modes.retain(|mode| { |
| 463 | mode.dimensions != (width, height) || mode.refresh_rate != refresh |
| 464 | }); |
| 465 | |
| 466 | let flags = match flags { |
| 467 | WEnum::Value(flags) => flags, |
| 468 | WEnum::Unknown(_) => panic!("Invalid flags" ), |
| 469 | }; |
| 470 | |
| 471 | let current = flags.contains(wl_output::Mode::Current); |
| 472 | let preferred = flags.contains(wl_output::Mode::Preferred); |
| 473 | |
| 474 | // Any mode that isn't current is deprecated, let's deprecate any existing modes that may be |
| 475 | // marked as current. |
| 476 | // |
| 477 | // If a new mode is advertised as preferred, then mark the existing preferred mode as not. |
| 478 | for mode in &mut inner.pending_info.modes { |
| 479 | // This mode is no longer preferred. |
| 480 | if preferred { |
| 481 | mode.preferred = false; |
| 482 | } |
| 483 | |
| 484 | // This mode is no longer current. |
| 485 | if current { |
| 486 | mode.current = false; |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | // Now create the new mode. |
| 491 | inner.pending_info.modes.push(Mode { |
| 492 | dimensions: (width, height), |
| 493 | refresh_rate: refresh, |
| 494 | current, |
| 495 | preferred, |
| 496 | }); |
| 497 | |
| 498 | inner.pending_wl = true; |
| 499 | } |
| 500 | |
| 501 | wl_output::Event::Scale { factor } => { |
| 502 | inner.pending_info.scale_factor = factor; |
| 503 | inner.pending_wl = true; |
| 504 | } |
| 505 | |
| 506 | wl_output::Event::Name { name } => { |
| 507 | inner.pending_info.name = Some(name); |
| 508 | inner.pending_wl = true; |
| 509 | } |
| 510 | |
| 511 | wl_output::Event::Description { description } => { |
| 512 | inner.pending_info.description = Some(description); |
| 513 | inner.pending_wl = true; |
| 514 | } |
| 515 | |
| 516 | wl_output::Event::Done => { |
| 517 | let info = inner.pending_info.clone(); |
| 518 | inner.current_info = Some(info.clone()); |
| 519 | inner.pending_wl = false; |
| 520 | |
| 521 | // Set the user data, see if we need to run scale callbacks |
| 522 | let run_callbacks = data.set(info); |
| 523 | |
| 524 | // Don't call `new_output` until we have xdg output info |
| 525 | if !inner.pending_xdg { |
| 526 | if inner.just_created { |
| 527 | inner.just_created = false; |
| 528 | state.new_output(conn, qh, output.clone()); |
| 529 | } else { |
| 530 | state.update_output(conn, qh, output.clone()); |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | if run_callbacks { |
| 535 | let callbacks = state.output_state().callbacks.clone(); |
| 536 | for cb in callbacks { |
| 537 | if let Some(cb) = cb.upgrade() { |
| 538 | cb(state, conn, qh, output); |
| 539 | } |
| 540 | } |
| 541 | } |
| 542 | } |
| 543 | _ => unreachable!(), |
| 544 | } |
| 545 | } |
| 546 | } |
| 547 | |
| 548 | impl<D> Dispatch<zxdg_output_manager_v1::ZxdgOutputManagerV1, GlobalData, D> for OutputState |
| 549 | where |
| 550 | D: Dispatch<zxdg_output_manager_v1::ZxdgOutputManagerV1, GlobalData> + OutputHandler, |
| 551 | { |
| 552 | fn event( |
| 553 | _: &mut D, |
| 554 | _: &zxdg_output_manager_v1::ZxdgOutputManagerV1, |
| 555 | _: zxdg_output_manager_v1::Event, |
| 556 | _: &GlobalData, |
| 557 | _: &Connection, |
| 558 | _: &QueueHandle<D>, |
| 559 | ) { |
| 560 | unreachable!("zxdg_output_manager_v1 has no events" ) |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | impl<D> Dispatch<zxdg_output_v1::ZxdgOutputV1, OutputData, D> for OutputState |
| 565 | where |
| 566 | D: Dispatch<zxdg_output_v1::ZxdgOutputV1, OutputData> + OutputHandler, |
| 567 | { |
| 568 | fn event( |
| 569 | state: &mut D, |
| 570 | output: &zxdg_output_v1::ZxdgOutputV1, |
| 571 | event: zxdg_output_v1::Event, |
| 572 | data: &OutputData, |
| 573 | conn: &Connection, |
| 574 | qh: &QueueHandle<D>, |
| 575 | ) { |
| 576 | let inner = match state |
| 577 | .output_state() |
| 578 | .outputs |
| 579 | .iter_mut() |
| 580 | .find(|inner| inner.xdg_output.as_ref() == Some(output)) |
| 581 | { |
| 582 | Some(inner) => inner, |
| 583 | None => { |
| 584 | warn!("Received {event:?} for dead xdg_output" ); |
| 585 | return; |
| 586 | } |
| 587 | }; |
| 588 | |
| 589 | // zxdg_output_v1::done is deprecated in version 3. So we only need |
| 590 | // to wait for wl_output::done, once we get any xdg output info. |
| 591 | if output.version() >= 3 { |
| 592 | inner.pending_xdg = false; |
| 593 | } |
| 594 | |
| 595 | match event { |
| 596 | zxdg_output_v1::Event::LogicalPosition { x, y } => { |
| 597 | inner.pending_info.logical_position = Some((x, y)); |
| 598 | if output.version() < 3 { |
| 599 | inner.pending_xdg = true; |
| 600 | } |
| 601 | } |
| 602 | zxdg_output_v1::Event::LogicalSize { width, height } => { |
| 603 | inner.pending_info.logical_size = Some((width, height)); |
| 604 | if output.version() < 3 { |
| 605 | inner.pending_xdg = true; |
| 606 | } |
| 607 | } |
| 608 | zxdg_output_v1::Event::Name { name } => { |
| 609 | if inner.wl_output.version() < 4 { |
| 610 | inner.pending_info.name = Some(name); |
| 611 | } |
| 612 | if output.version() < 3 { |
| 613 | inner.pending_xdg = true; |
| 614 | } |
| 615 | } |
| 616 | |
| 617 | zxdg_output_v1::Event::Description { description } => { |
| 618 | if inner.wl_output.version() < 4 { |
| 619 | inner.pending_info.description = Some(description); |
| 620 | } |
| 621 | if output.version() < 3 { |
| 622 | inner.pending_xdg = true; |
| 623 | } |
| 624 | } |
| 625 | |
| 626 | zxdg_output_v1::Event::Done => { |
| 627 | // This event is deprecated starting in version 3, wl_output::done should be sent instead. |
| 628 | if output.version() < 3 { |
| 629 | let info = inner.pending_info.clone(); |
| 630 | inner.current_info = Some(info.clone()); |
| 631 | inner.pending_xdg = false; |
| 632 | |
| 633 | // Set the user data |
| 634 | data.set(info); |
| 635 | |
| 636 | let pending_wl = inner.pending_wl; |
| 637 | let just_created = inner.just_created; |
| 638 | let output = inner.wl_output.clone(); |
| 639 | |
| 640 | if just_created { |
| 641 | inner.just_created = false; |
| 642 | } |
| 643 | |
| 644 | if !pending_wl { |
| 645 | if just_created { |
| 646 | state.new_output(conn, qh, output); |
| 647 | } else { |
| 648 | state.update_output(conn, qh, output); |
| 649 | } |
| 650 | } |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | _ => unreachable!(), |
| 655 | } |
| 656 | } |
| 657 | } |
| 658 | |
| 659 | impl<D> RegistryHandler<D> for OutputState |
| 660 | where |
| 661 | D: Dispatch<wl_output::WlOutput, OutputData> |
| 662 | + Dispatch<zxdg_output_v1::ZxdgOutputV1, OutputData> |
| 663 | + Dispatch<zxdg_output_manager_v1::ZxdgOutputManagerV1, GlobalData> |
| 664 | + OutputHandler |
| 665 | + ProvidesRegistryState |
| 666 | + 'static, |
| 667 | { |
| 668 | fn new_global( |
| 669 | data: &mut D, |
| 670 | _: &Connection, |
| 671 | qh: &QueueHandle<D>, |
| 672 | name: u32, |
| 673 | interface: &str, |
| 674 | _version: u32, |
| 675 | ) { |
| 676 | if interface == "wl_output" { |
| 677 | let output = data |
| 678 | .registry() |
| 679 | .bind_specific(qh, name, 1..=4, OutputData::new(name)) |
| 680 | .expect("Failed to bind global" ); |
| 681 | data.output_state().setup(output, qh); |
| 682 | } |
| 683 | } |
| 684 | |
| 685 | fn remove_global( |
| 686 | data: &mut D, |
| 687 | conn: &Connection, |
| 688 | qh: &QueueHandle<D>, |
| 689 | name: u32, |
| 690 | interface: &str, |
| 691 | ) { |
| 692 | if interface == "wl_output" { |
| 693 | let output = data |
| 694 | .output_state() |
| 695 | .outputs |
| 696 | .iter() |
| 697 | .position(|o| o.name == name) |
| 698 | .expect("Removed non-existing output" ); |
| 699 | |
| 700 | let wl_output = data.output_state().outputs[output].wl_output.clone(); |
| 701 | data.output_destroyed(conn, qh, wl_output); |
| 702 | |
| 703 | let output = data.output_state().outputs.remove(output); |
| 704 | if let Some(xdg_output) = &output.xdg_output { |
| 705 | xdg_output.destroy(); |
| 706 | } |
| 707 | if output.wl_output.version() >= 3 { |
| 708 | output.wl_output.release(); |
| 709 | } |
| 710 | } |
| 711 | } |
| 712 | } |
| 713 | |
| 714 | impl OutputInfo { |
| 715 | fn new(id: u32) -> OutputInfo { |
| 716 | OutputInfo { |
| 717 | id, |
| 718 | model: String::new(), |
| 719 | make: String::new(), |
| 720 | location: (0, 0), |
| 721 | physical_size: (0, 0), |
| 722 | subpixel: Subpixel::Unknown, |
| 723 | transform: Transform::Normal, |
| 724 | scale_factor: 1, |
| 725 | modes: vec![], |
| 726 | logical_position: None, |
| 727 | logical_size: None, |
| 728 | name: None, |
| 729 | description: None, |
| 730 | } |
| 731 | } |
| 732 | } |
| 733 | |
| 734 | impl OutputData { |
| 735 | pub(crate) fn set(&self, info: OutputInfo) -> bool { |
| 736 | let mut guard: MutexGuard<'_, OutputInfo> = self.0.lock().unwrap(); |
| 737 | |
| 738 | let rv: bool = guard.scale_factor != info.scale_factor; |
| 739 | |
| 740 | *guard = info; |
| 741 | |
| 742 | rv |
| 743 | } |
| 744 | } |
| 745 | |
| 746 | #[derive (Debug)] |
| 747 | struct OutputInner { |
| 748 | /// The name of the wl_output global. |
| 749 | name: u32, |
| 750 | wl_output: wl_output::WlOutput, |
| 751 | xdg_output: Option<zxdg_output_v1::ZxdgOutputV1>, |
| 752 | /// Whether this output was just created and has not an event yet. |
| 753 | just_created: bool, |
| 754 | |
| 755 | current_info: Option<OutputInfo>, |
| 756 | pending_info: OutputInfo, |
| 757 | pending_wl: bool, |
| 758 | pending_xdg: bool, |
| 759 | } |
| 760 | |