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
use crate::PixelFormat;

type ImageData = Vec<u8>;

/// A rect where the image should be updated
#[derive(Debug, Clone, Copy)]
pub struct Rect {
    pub x: u16,
    pub y: u16,
    pub width: u16,
    pub height: u16,
}

/// Resolution format to resize window
#[derive(Debug, Clone)]
pub struct Screen {
    pub width: u16,
    pub height: u16,
}

impl From<(u16, u16)> for Screen {
    fn from(tuple: (u16, u16)) -> Self {
        Self {
            width: tuple.0,
            height: tuple.1,
        }
    }
}

type SrcRect = Rect;
type DstRect = Rect;

/// Events generated by the [crate::VncClient]
///
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum VncEvent {
    /// Tell the client how to display the images
    ///
    /// ```no_compile
    /// if let VncEvent::SetResolution(resolution) = event {
    ///     window.resize(screen.width, screen.height);
    /// }
    /// ```
    ///
    /// Note that this event may be recived multiple times
    ///
    /// If the [crate::VncEncoding::DesktopSizePseudo] is set
    ///
    SetResolution(Screen),
    /// If the connector doesn't call `set_pixel_format` method
    ///
    /// The engine will generate a [VncEvent::SetPixelFormat] to let the window know how to render image
    ///
    SetPixelFormat(PixelFormat),
    /// Raw image data in the order followed by informed PixelFormat
    ///
    RawImage(Rect, ImageData),
    /// Copy image data from the second rect to the first
    ///
    Copy(DstRect, SrcRect),
    /// A jpeg image if using Tight encoding,
    ///
    /// Encoding the bytes with base64 and render it with "<img src=data:image/jpeg;base64,.../>",
    ///
    JpegImage(Rect, ImageData),

    // PngImage(Rect, ImageData),
    /// Will be generated if [crate::VncEncoding::CursorPseudo] is set
    ///
    /// According to [RFC6143, section-7.8.1](https://www.rfc-editor.org/rfc/rfc6143.html#section-7.8.1)
    ///
    SetCursor(Rect, ImageData),
    /// Just ring a bell
    ///
    Bell,
    /// Will be generated everytime the vncserver's clipboarded get updated
    ///
    /// Note that only Latin-1 character set is allowed
    ///
    /// According to [RFC6143](https://www.rfc-editor.org/rfc/rfc6143.html#section-7.6.4)
    ///
    Text(String),
}

/// X11 keyboard event to notify the server
///
/// Referring to [RFC6143, section-7.5.4](https://www.rfc-editor.org/rfc/rfc6143.html#section-7.5.4)
///
#[derive(Debug, Clone)]
pub struct ClientKeyEvent {
    pub keycode: u32,
    pub down: bool,
}

impl From<(u32, bool)> for ClientKeyEvent {
    fn from(tuple: (u32, bool)) -> Self {
        Self {
            keycode: tuple.0,
            down: tuple.1,
        }
    }
}

/// X11 mouse event to notify the server
///
/// Referring to [RFC6143, seciont-7.5.5](https://www.rfc-editor.org/rfc/rfc6143.html#section-7.5.5)
///
#[derive(Debug, Clone)]
pub struct ClientMouseEvent {
    pub position_x: u16,
    pub position_y: u16,
    pub bottons: u8,
}

impl From<(u16, u16, u8)> for ClientMouseEvent {
    fn from(tuple: (u16, u16, u8)) -> Self {
        Self {
            position_x: tuple.0,
            position_y: tuple.1,
            bottons: tuple.2,
        }
    }
}

/// Client-side event which used to ask the engine send some command to the vnc server
///
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum X11Event {
    /// Require a frame update
    ///
    Refresh,
    /// Key down/up
    ///
    KeyEvent(ClientKeyEvent),
    /// Mouse move/up/down/scroll
    ///
    PointerEvent(ClientMouseEvent),
    /// Send data to the server's clipboard
    ///
    /// Only Latin-1 character set is allowed
    ///
    CopyText(String),
}