ironrdp_server/display.rs
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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
use core::num::NonZeroU16;
use anyhow::Result;
use ironrdp_displaycontrol::pdu::DisplayControlMonitorLayout;
use ironrdp_pdu::pointer::PointerPositionAttribute;
#[rustfmt::skip]
pub use ironrdp_acceptor::DesktopSize;
pub use ironrdp_graphics::image_processing::PixelFormat;
/// Display Update
///
/// Contains all types of display updates currently supported by the server implementation
/// and the RDP spec
///
#[derive(Debug, Clone)]
pub enum DisplayUpdate {
Resize(DesktopSize),
Bitmap(BitmapUpdate),
PointerPosition(PointerPositionAttribute),
ColorPointer(ColorPointer),
RGBAPointer(RGBAPointer),
HidePointer,
DefaultPointer,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PixelOrder {
TopToBottom,
BottomToTop,
}
#[derive(Clone)]
pub struct RGBAPointer {
pub width: u16,
pub height: u16,
pub hot_x: u16,
pub hot_y: u16,
pub data: Vec<u8>,
}
impl core::fmt::Debug for RGBAPointer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RGBAPointer")
.field("with", &self.width)
.field("height", &self.height)
.field("hot_x", &self.hot_x)
.field("hot_y", &self.hot_y)
.field("data_len", &self.data.len())
.finish()
}
}
#[derive(Debug, Clone)]
pub struct ColorPointer {
pub width: u16,
pub height: u16,
pub hot_x: u16,
pub hot_y: u16,
pub and_mask: Vec<u8>,
pub xor_mask: Vec<u8>,
}
/// Bitmap Display Update
///
/// Bitmap updates are encoded using RDP 6.0 compression, fragmented and sent using
/// Fastpath Server Updates
///
#[derive(Clone)]
pub struct BitmapUpdate {
pub top: u16,
pub left: u16,
pub width: NonZeroU16,
pub height: NonZeroU16,
pub format: PixelFormat,
pub order: PixelOrder,
pub data: Vec<u8>,
pub stride: usize,
}
impl core::fmt::Debug for BitmapUpdate {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BitmapUpdate")
.field("top", &self.top)
.field("left", &self.left)
.field("width", &self.width)
.field("height", &self.height)
.field("format", &self.format)
.field("order", &self.order)
.finish()
}
}
/// Display Updates receiver for an RDP server
///
/// The RDP server will repeatedly call the `next_update` method to receive
/// display updates which will then be encoded and sent to the client
///
/// See [`RdpServerDisplay`] example.
#[async_trait::async_trait]
pub trait RdpServerDisplayUpdates {
/// # Cancel safety
///
/// This method MUST be cancellation safe because it is used in a
/// `tokio::select!` statement. If some other branch completes first, it
/// MUST be guaranteed that no data is lost.
async fn next_update(&mut self) -> Option<DisplayUpdate>;
}
/// Display for an RDP server
///
/// # Example
///
/// ```
///# use anyhow::Result;
/// use ironrdp_server::{DesktopSize, DisplayUpdate, RdpServerDisplay, RdpServerDisplayUpdates};
///
/// pub struct DisplayUpdates {
/// receiver: tokio::sync::mpsc::Receiver<DisplayUpdate>,
/// }
///
/// #[async_trait::async_trait]
/// impl RdpServerDisplayUpdates for DisplayUpdates {
/// async fn next_update(&mut self) -> Option<DisplayUpdate> {
/// self.receiver.recv().await
/// }
/// }
///
/// pub struct DisplayHandler {
/// width: u16,
/// height: u16,
/// }
///
/// #[async_trait::async_trait]
/// impl RdpServerDisplay for DisplayHandler {
/// async fn size(&mut self) -> DesktopSize {
/// DesktopSize { width: self.width, height: self.height }
/// }
///
/// async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
/// Ok(Box::new(DisplayUpdates { receiver: todo!() }))
/// }
/// }
/// ```
#[async_trait::async_trait]
pub trait RdpServerDisplay: Send {
/// This method should return the current size of the display.
/// Currently, there is no way for the client to negotiate resolution,
/// so the size returned by this method will be enforced.
async fn size(&mut self) -> DesktopSize;
/// Return a display updates receiver
async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>>;
/// Request a new size for the display
fn request_layout(&mut self, layout: DisplayControlMonitorLayout) {
debug!(?layout, "Requesting layout")
}
}