ironrdp_pdu/rdp/
suppress_output.rs

1use ironrdp_core::{
2    ensure_fixed_part_size, ensure_size, invalid_field_err, read_padding, write_padding, Decode, DecodeResult, Encode,
3    EncodeResult, ReadCursor, WriteCursor,
4};
5
6use crate::geometry::InclusiveRectangle;
7
8#[repr(u8)]
9#[derive(Debug, PartialEq, Eq, Clone)]
10pub enum AllowDisplayUpdatesType {
11    SuppressDisplayUpdates = 0x00,
12    AllowDisplayUpdates = 0x01,
13}
14
15impl AllowDisplayUpdatesType {
16    pub fn from_u8(value: u8) -> Option<Self> {
17        match value {
18            0x00 => Some(Self::SuppressDisplayUpdates),
19            0x01 => Some(Self::AllowDisplayUpdates),
20            _ => None,
21        }
22    }
23
24    pub fn as_u8(self) -> u8 {
25        self as u8
26    }
27}
28
29/// [2.2.11.3.1] Suppress Output PDU Data (TS_SUPPRESS_OUTPUT_PDU)
30///
31/// The Suppress Output PDU is sent by the client to toggle all display updates
32/// from the server. This packet does not end the session or socket connection.
33/// Typically, a client sends this packet when its window is either minimized or
34/// restored. Server support for this PDU is indicated in the General Capability
35/// Set [2.2.7.1.1].
36///
37/// [2.2.11.3.1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/0be71491-0b01-402c-947d-080706ccf91b
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct SuppressOutputPdu {
40    pub desktop_rect: Option<InclusiveRectangle>,
41}
42
43impl SuppressOutputPdu {
44    const NAME: &'static str = "SuppressOutputPdu";
45
46    const FIXED_PART_SIZE: usize = 1 /* allowDisplayUpdates */ + 3 /* pad */;
47}
48
49impl Encode for SuppressOutputPdu {
50    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
51        ensure_size!(in: dst, size: self.size());
52
53        let allow_display_updates = if self.desktop_rect.is_some() {
54            AllowDisplayUpdatesType::AllowDisplayUpdates
55        } else {
56            AllowDisplayUpdatesType::SuppressDisplayUpdates
57        };
58
59        dst.write_u8(allow_display_updates.as_u8());
60        write_padding!(dst, 3);
61        if let Some(rect) = &self.desktop_rect {
62            rect.encode(dst)?;
63        }
64
65        Ok(())
66    }
67
68    fn name(&self) -> &'static str {
69        Self::NAME
70    }
71
72    fn size(&self) -> usize {
73        Self::FIXED_PART_SIZE + self.desktop_rect.as_ref().map_or(0, |r| r.size())
74        // desktopRect
75    }
76}
77
78impl<'de> Decode<'de> for SuppressOutputPdu {
79    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
80        ensure_fixed_part_size!(in: src);
81
82        let allow_display_updates = AllowDisplayUpdatesType::from_u8(src.read_u8())
83            .ok_or_else(|| invalid_field_err!("allowDisplayUpdates", "invalid display update type"))?;
84        read_padding!(src, 3);
85        let desktop_rect = if allow_display_updates == AllowDisplayUpdatesType::AllowDisplayUpdates {
86            Some(InclusiveRectangle::decode(src)?)
87        } else {
88            None
89        };
90        Ok(Self { desktop_rect })
91    }
92}