Coverage Report

Created: 2022-07-04 16:17

src/requests/ui.rs
Line
Count
Source (jump to first uncovered line)
1
//! Requests related to the user interface.
2
3
use bitflags::bitflags;
4
use serde::Serialize;
5
6
34
#[derive(
S28
eri
aliz6
e)]
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
<<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
Line
Count
Source
6
6
#[derive(Serialize)]
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
<obws::requests::ui::Request as serde::ser::Serialize>::serialize::<serde::__private::ser::FlatMapSerializer<serde_json::ser::Compound<&mut alloc::vec::Vec<u8>, serde_json::ser::CompactFormatter>>>
Line
Count
Source
6
28
#[derive(Serialize)]
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
Unexecuted instantiation: <obws::requests::ui::Request as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <obws::requests::ui::Request as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <<obws::requests::ui::Request as serde::ser::Serialize>::serialize::__AdjacentlyTagged as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <obws::requests::ui::Request as serde::ser::Serialize>::serialize::<_>
7
#[serde(tag = "requestType", content = "requestData")]
8
pub(crate) enum Request<'a> {
9
    #[serde(rename = "GetStudioModeEnabled")]
10
    GetStudioModeEnabled,
11
    #[serde(rename = "SetStudioModeEnabled")]
12
    SetStudioModeEnabled {
13
        /// Enable or disable the studio mode.
14
        #[serde(rename = "studioModeEnabled")]
15
        enabled: bool,
16
    },
17
    #[serde(rename = "OpenInputPropertiesDialog")]
18
    OpenInputPropertiesDialog {
19
        /// Name of the input to open the dialog of.
20
        #[serde(rename = "inputName")]
21
        input: &'a str,
22
    },
23
    #[serde(rename = "OpenInputFiltersDialog")]
24
    OpenInputFiltersDialog {
25
        /// Name of the input to open the dialog of.
26
        #[serde(rename = "inputName")]
27
        input: &'a str,
28
    },
29
    #[serde(rename = "OpenInputInteractDialog")]
30
    OpenInputInteractDialog {
31
        /// Name of the input to open the dialog of.
32
        #[serde(rename = "inputName")]
33
        input: &'a str,
34
    },
35
    #[serde(rename = "GetMonitorList")]
36
    GetMonitorList,
37
    #[serde(rename = "OpenVideoMixProjector")]
38
    OpenVideoMixProjector(OpenVideoMixProjectorInternal),
39
    #[serde(rename = "OpenSourceProjector")]
40
    OpenSourceProjector(OpenSourceProjectorInternal<'a>),
41
}
42
43
impl<'a> From<Request<'a>> for super::RequestType<'a> {
44
28
    fn from(value: Request<'a>) -> Self {
45
28
        super::RequestType::Ui(value)
46
28
    }
<obws::requests::RequestType as core::convert::From<obws::requests::ui::Request>>::from
Line
Count
Source
44
28
    fn from(value: Request<'a>) -> Self {
45
28
        super::RequestType::Ui(value)
46
28
    }
Unexecuted instantiation: <obws::requests::RequestType as core::convert::From<obws::requests::ui::Request>>::from
47
}
48
49
/// Request information for [`crate::client::Ui::open_video_mix_projector`].
50
pub struct OpenVideoMixProjector {
51
    /// Type of mix to open.
52
    pub r#type: VideoMixType,
53
    /// Optional location for the new projector window.
54
    pub location: Option<Location>,
55
}
56
57
/// Request information for [`crate::client::Ui::open_video_mix_projector`].
58
1
#[derive(Serialize)]
<obws::requests::ui::OpenVideoMixProjectorInternal as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
Line
Count
Source
58
1
#[derive(Serialize)]
Unexecuted instantiation: <obws::requests::ui::OpenVideoMixProjectorInternal as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <obws::requests::ui::OpenVideoMixProjectorInternal as serde::ser::Serialize>::serialize::<_>
59
pub(crate) struct OpenVideoMixProjectorInternal {
60
    /// Type of mix to open.
61
    #[serde(rename = "videoMixType")]
62
    pub r#type: VideoMixType,
63
    /// Optional location for the new projector window.
64
    #[serde(flatten)]
65
    pub location: Option<LocationInternal>,
66
}
67
68
/// Request information for [`crate::client::Ui::open_source_projector`].
69
pub struct OpenSourceProjector<'a> {
70
    /// Name of the source to open a projector for.
71
    pub source: &'a str,
72
    /// Optional location for the new projector window.
73
    pub location: Option<Location>,
74
}
75
76
/// Request information for [`crate::client::Ui::open_source_projector`].
77
1
#[derive(Serialize)]
<obws::requests::ui::OpenSourceProjectorInternal as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
Line
Count
Source
77
1
#[derive(Serialize)]
Unexecuted instantiation: <obws::requests::ui::OpenSourceProjectorInternal as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <obws::requests::ui::OpenSourceProjectorInternal as serde::ser::Serialize>::serialize::<_>
78
pub(crate) struct OpenSourceProjectorInternal<'a> {
79
    /// Name of the source to open a projector for.
80
    #[serde(rename = "sourceName")]
81
    pub source: &'a str,
82
    /// Optional location for the new projector window.
83
    #[serde(flatten)]
84
    pub location: Option<LocationInternal>,
85
}
86
87
/// Request information for [`crate::client::Ui::open_video_mix_projector`] as part of
88
/// [`OpenVideoMixProjector`] and [`crate::client::Ui::open_source_projector`] as part of
89
/// [`OpenSourceProjector`], describing the open location of the projector.
90
pub enum Location {
91
    /// Monitor index, passing `-1` opens the projector in windowed mode.
92
    MonitorIndex(i32),
93
    /// Size/Position data for a windowed projector, in `Qt Base64` encoded format.
94
    ProjectorGeometry(QtGeometry),
95
}
96
97
/// Request information for [`crate::client::Ui::open_video_mix_projector`] as part of
98
/// [`OpenVideoMixProjector`] and [`crate::client::Ui::open_source_projector`] as part of
99
/// [`OpenSourceProjector`], describing the open location of the projector.
100
2
#[derive(Serialize)]
<obws::requests::ui::LocationInternal as serde::ser::Serialize>::serialize::<serde::__private::ser::FlatMapSerializer<serde_json::ser::Compound<&mut alloc::vec::Vec<u8>, serde_json::ser::CompactFormatter>>>
Line
Count
Source
100
2
#[derive(Serialize)]
Unexecuted instantiation: <obws::requests::ui::LocationInternal as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <obws::requests::ui::LocationInternal as serde::ser::Serialize>::serialize::<_>
101
pub enum LocationInternal {
102
    /// Monitor index, passing `-1` opens the projector in windowed mode.
103
    #[serde(rename = "monitorIndex")]
104
    MonitorIndex(i32),
105
    /// Size/Position data for a windowed projector, in `Qt Base64` encoded format.
106
    #[serde(rename = "projectorGeometry")]
107
    ProjectorGeometry(String),
108
}
109
110
impl From<Location> for LocationInternal {
111
2
    fn from(value: Location) -> Self {
112
2
        match value {
113
1
            Location::MonitorIndex(index) => Self::MonitorIndex(index),
114
1
            Location::ProjectorGeometry(geometry) => Self::ProjectorGeometry(geometry.serialize()),
115
        }
116
2
    }
<obws::requests::ui::LocationInternal as core::convert::From<obws::requests::ui::Location>>::from
Line
Count
Source
111
2
    fn from(value: Location) -> Self {
112
2
        match value {
113
1
            Location::MonitorIndex(index) => Self::MonitorIndex(index),
114
1
            Location::ProjectorGeometry(geometry) => Self::ProjectorGeometry(geometry.serialize()),
115
        }
116
2
    }
Unexecuted instantiation: <obws::requests::ui::LocationInternal as core::convert::From<obws::requests::ui::Location>>::from
117
}
118
119
/// Request information for [`crate::client::Ui::open_video_mix_projector`] as part of
120
/// [`OpenVideoMixProjector`], defining the type of video mix to open.
121
1
#[derive(Serialize)]
<obws::requests::ui::VideoMixType as serde::ser::Serialize>::serialize::<&mut serde_json::ser::Serializer<&mut alloc::vec::Vec<u8>>>
Line
Count
Source
121
1
#[derive(Serialize)]
Unexecuted instantiation: <obws::requests::ui::VideoMixType as serde::ser::Serialize>::serialize::<_>
Unexecuted instantiation: <obws::requests::ui::VideoMixType as serde::ser::Serialize>::serialize::<_>
122
pub enum VideoMixType {
123
    /// Show the preview scene.
124
    #[serde(rename = "OBS_WEBSOCKET_VIDEO_MIX_TYPE_PREVIEW")]
125
    Preview,
126
    /// Show the program scene.
127
    #[serde(rename = "OBS_WEBSOCKET_VIDEO_MIX_TYPE_PROGRAM")]
128
    Program,
129
    /// Show a multi-view.
130
    #[serde(rename = "OBS_WEBSOCKET_VIDEO_MIX_TYPE_MULTIVIEW")]
131
    Multiview,
132
}
133
134
/// Request information for [`open_projector`](crate::client::General::open_projector) as part of
135
/// [`Projector`].
136
0
#[derive(Debug)]
Unexecuted instantiation: <obws::requests::ui::QtGeometry as core::fmt::Debug>::fmt
Unexecuted instantiation: <obws::requests::ui::QtGeometry as core::fmt::Debug>::fmt
137
pub struct QtGeometry {
138
    /// The screen number to display a widget or [`Self::DEFAULT_SCREEN`] to let OBS pick the
139
    /// default.
140
    pub screen_number: i32,
141
    /// Additional window state like maximized or full-screen.
142
    pub window_state: QtWindowState,
143
    /// The width of the screen. Seems to have no specific effect but is used for some internal
144
    /// calculations in Qt.
145
    pub screen_width: i32,
146
    /// The target position and size for a widget to display at.
147
    pub rect: QtRect,
148
}
149
150
impl QtGeometry {
151
    /// Value indicating to use the default screen.
152
    pub const DEFAULT_SCREEN: i32 = -1;
153
154
    /// Create a new geometry instance without only size information set.
155
0
    pub fn new(rect: QtRect) -> Self {
156
0
        Self {
157
0
            rect,
158
0
            ..Self::default()
159
0
        }
160
0
    }
Unexecuted instantiation: <obws::requests::ui::QtGeometry>::new
Unexecuted instantiation: <obws::requests::ui::QtGeometry>::new
161
162
    /// Serialize this instance into a `base64` encoded byte array.
163
    ///
164
    /// The exact format can be found in the
165
    /// [Qt source code](https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#_ZNK7QWidget12saveGeometryEv).
166
    ///
167
    /// | Length | Content                                                  |
168
    /// |--------|----------------------------------------------------------|
169
    /// | 4      | Magic number                                             |
170
    /// | 2      | Major format version                                     |
171
    /// | 2      | Minor format version                                     |
172
    /// | 16     | Frame rectangle (left, top, right, bottom) 4 bytes each  |
173
    /// | 16     | Normal rectangle (left, top, right, bottom) 4 bytes each |
174
    /// | 4      | Screen number                                            |
175
    /// | 1      | Window maximized (1 or 0)                                |
176
    /// | 1      | Window full-screen (1 or 0)                              |
177
    /// | 4      | Screen width                                             |
178
    /// | 16     | Main rectangle (left, top, right, bottom) 4 bytes each   |
179
1
    pub(crate) fn serialize(&self) -> String {
180
1
        /// Indicator for serialized Qt geometry data.
181
1
        const MAGIC_NUMBER: u32 = 0x1D9D0CB;
182
1
        /// Major version of this format.
183
1
        const MAJOR_VERSION: u16 = 3;
184
1
        /// Minor version of this format.
185
1
        const MINOR_VERSION: u16 = 0;
186
1
        /// Output data length BEFORE `base64` encoding. This allows to reduce allocations in the
187
1
        /// byte buffer and must be updated whenever the format changes.
188
1
        const DATA_LENGTH: usize = 66;
189
1
190
3
        fn serialize_rect(data: &mut Vec<u8>, rect: &QtRect) {
191
3
            data.extend(&rect.left.to_be_bytes());
192
3
            data.extend(&rect.top.to_be_bytes());
193
3
            data.extend(&rect.right.to_be_bytes());
194
3
            data.extend(&rect.bottom.to_be_bytes());
195
3
        }
<obws::requests::ui::QtGeometry>::serialize::serialize_rect
Line
Count
Source
190
3
        fn serialize_rect(data: &mut Vec<u8>, rect: &QtRect) {
191
3
            data.extend(&rect.left.to_be_bytes());
192
3
            data.extend(&rect.top.to_be_bytes());
193
3
            data.extend(&rect.right.to_be_bytes());
194
3
            data.extend(&rect.bottom.to_be_bytes());
195
3
        }
Unexecuted instantiation: <obws::requests::ui::QtGeometry>::serialize::serialize_rect
196
1
197
1
        let mut data = Vec::<u8>::with_capacity(DATA_LENGTH);
198
1
199
1
        data.extend(&MAGIC_NUMBER.to_be_bytes());
200
1
        data.extend(&MAJOR_VERSION.to_be_bytes());
201
1
        data.extend(&MINOR_VERSION.to_be_bytes());
202
1
203
1
        serialize_rect(&mut data, &self.rect); // frame geometry
204
1
        serialize_rect(&mut data, &self.rect); // normal geometry
205
1
206
1
        data.extend(&self.screen_number.to_be_bytes());
207
1
        data.extend(&self.window_state.to_be_bytes());
208
1
        data.extend(&self.screen_width.to_be_bytes());
209
1
210
1
        serialize_rect(&mut data, &self.rect);
211
1
212
1
        base64::encode(data)
213
1
    }
<obws::requests::ui::QtGeometry>::serialize
Line
Count
Source
179
1
    pub(crate) fn serialize(&self) -> String {
180
1
        /// Indicator for serialized Qt geometry data.
181
1
        const MAGIC_NUMBER: u32 = 0x1D9D0CB;
182
1
        /// Major version of this format.
183
1
        const MAJOR_VERSION: u16 = 3;
184
1
        /// Minor version of this format.
185
1
        const MINOR_VERSION: u16 = 0;
186
1
        /// Output data length BEFORE `base64` encoding. This allows to reduce allocations in the
187
1
        /// byte buffer and must be updated whenever the format changes.
188
1
        const DATA_LENGTH: usize = 66;
189
1
190
1
        fn serialize_rect(data: &mut Vec<u8>, rect: &QtRect) {
191
1
            data.extend(&rect.left.to_be_bytes());
192
1
            data.extend(&rect.top.to_be_bytes());
193
1
            data.extend(&rect.right.to_be_bytes());
194
1
            data.extend(&rect.bottom.to_be_bytes());
195
1
        }
196
1
197
1
        let mut data = Vec::<u8>::with_capacity(DATA_LENGTH);
198
1
199
1
        data.extend(&MAGIC_NUMBER.to_be_bytes());
200
1
        data.extend(&MAJOR_VERSION.to_be_bytes());
201
1
        data.extend(&MINOR_VERSION.to_be_bytes());
202
1
203
1
        serialize_rect(&mut data, &self.rect); // frame geometry
204
1
        serialize_rect(&mut data, &self.rect); // normal geometry
205
1
206
1
        data.extend(&self.screen_number.to_be_bytes());
207
1
        data.extend(&self.window_state.to_be_bytes());
208
1
        data.extend(&self.screen_width.to_be_bytes());
209
1
210
1
        serialize_rect(&mut data, &self.rect);
211
1
212
1
        base64::encode(data)
213
1
    }
Unexecuted instantiation: <obws::requests::ui::QtGeometry>::serialize
214
}
215
216
impl Default for QtGeometry {
217
1
    fn default() -> Self {
218
1
        Self {
219
1
            screen_number: Self::DEFAULT_SCREEN,
220
1
            window_state: QtWindowState::default(),
221
1
            screen_width: 0,
222
1
            rect: QtRect::default(),
223
1
        }
224
1
    }
<obws::requests::ui::QtGeometry as core::default::Default>::default
Line
Count
Source
217
1
    fn default() -> Self {
218
1
        Self {
219
1
            screen_number: Self::DEFAULT_SCREEN,
220
1
            window_state: QtWindowState::default(),
221
1
            screen_width: 0,
222
1
            rect: QtRect::default(),
223
1
        }
224
1
    }
Unexecuted instantiation: <obws::requests::ui::QtGeometry as core::default::Default>::default
225
}
226
227
bitflags! {
228
    /// Request information for [`open_projector`](crate::client::General::open_projector) as part of
229
    /// [`Projector`].
230
1
    #[derive(Default)]
<obws::requests::ui::QtWindowState as core::default::Default>::default
Line
Count
Source
230
1
    #[derive(Default)]
Unexecuted instantiation: <obws::requests::ui::QtWindowState as core::default::Default>::default
231
    pub struct QtWindowState: u32 {
232
        /// Window with maximum size, taking up as much space as possible but still showing
233
        /// the window frame.
234
        const MAXIMIZED = 2;
235
        /// Show the window in full-screen mode, taking up the whole display.
236
        const FULLSCREEN = 4;
237
    }
238
}
239
240
impl QtWindowState {
241
    /// Convert the state into a byte array for usage in [`QtGeometry::serialize`] .
242
1
    fn to_be_bytes(self) -> [u8; 2] {
243
1
        [
244
1
            if self.contains(Self::MAXIMIZED) { 
10
} else { 0 },
245
1
            if self.contains(Self::FULLSCREEN) {
246
0
                1
247
            } else {
248
1
                0
249
            },
250
        ]
251
1
    }
<obws::requests::ui::QtWindowState>::to_be_bytes
Line
Count
Source
242
1
    fn to_be_bytes(self) -> [u8; 2] {
243
1
        [
244
1
            if self.contains(Self::MAXIMIZED) { 
10
} else { 0 },
245
1
            if self.contains(Self::FULLSCREEN) {
246
0
                1
247
            } else {
248
1
                0
249
            },
250
        ]
251
1
    }
Unexecuted instantiation: <obws::requests::ui::QtWindowState>::to_be_bytes
252
}
253
254
/// Request information for [`open_projector`](crate::client::General::open_projector) as part of
255
/// [`Projector`].
256
///
257
/// This describes a position on the screen starting from the top left corner with 0.
258
///
259
/// ```txt
260
/// Screen
261
/// ┌────────────────────── X
262
/// │
263
/// │          top
264
/// │       ┌────────┐
265
/// │  left │  Rect  │ right
266
/// │       └────────┘
267
/// │         bottom
268
/// │
269
/// Y
270
///
271
1
#[derive(
Clone0
, Copy,
Debug0
, Default)]
Unexecuted instantiation: <obws::requests::ui::QtRect as core::clone::Clone>::clone
Unexecuted instantiation: <obws::requests::ui::QtRect as core::clone::Clone>::clone
Unexecuted instantiation: <obws::requests::ui::QtRect as core::fmt::Debug>::fmt
Unexecuted instantiation: <obws::requests::ui::QtRect as core::fmt::Debug>::fmt
<obws::requests::ui::QtRect as core::default::Default>::default
Line
Count
Source
271
1
#[derive(Clone, Copy, Debug, Default)]
Unexecuted instantiation: <obws::requests::ui::QtRect as core::default::Default>::default
272
pub struct QtRect {
273
    /// Left or X/horizontal position of the rectangle.
274
    pub left: i32,
275
    /// Top or Y/vertical position of the rectangle.
276
    pub top: i32,
277
    /// The right side of a rectangle counted from the left. For example with `left = 100` and
278
    /// `right = 300` the width would be `200`.
279
    pub right: i32,
280
    /// Bottom side of a rectangle counted from the top. For example with `top = 100` and
281
    //// `bottom = 300` the height would be `200`.
282
    pub bottom: i32,
283
}