mirror of https://github.com/dnaka91/obws
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1279 lines
44 KiB
Rust
1279 lines
44 KiB
Rust
//! All requests that can be send to the API.
|
|
|
|
use std::path::Path;
|
|
|
|
use bitflags::bitflags;
|
|
use chrono::Duration;
|
|
use either::Either;
|
|
use serde::Serialize;
|
|
use serde_with::skip_serializing_none;
|
|
|
|
pub use rgb::RGBA8;
|
|
|
|
use crate::common::{Align, Alignment, BoundsType, FontFlags, MonitorType, StreamType, Valign};
|
|
|
|
mod ser;
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub(crate) struct Request<'a> {
|
|
pub message_id: &'a str,
|
|
#[serde(flatten)]
|
|
pub ty: RequestType<'a>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(tag = "request-type")]
|
|
pub(crate) enum RequestType<'a> {
|
|
// --------------------------------
|
|
// General
|
|
// --------------------------------
|
|
GetVersion,
|
|
GetAuthRequired,
|
|
Authenticate {
|
|
/// Response to the auth challenge.
|
|
auth: &'a str,
|
|
},
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetFilenameFormatting {
|
|
/// Filename formatting string to set.
|
|
filename_formatting: &'a str,
|
|
},
|
|
GetFilenameFormatting,
|
|
GetStats,
|
|
BroadcastCustomMessage {
|
|
/// Identifier to be choosen by the client.
|
|
realm: &'a str,
|
|
/// User-defined data.
|
|
data: &'a serde_json::Value,
|
|
},
|
|
GetVideoInfo,
|
|
OpenProjector(ProjectorInternal<'a>),
|
|
#[serde(rename_all = "camelCase")]
|
|
TriggerHotkeyByName {
|
|
/// Unique name of the hotkey, as defined when registering the hotkey (e.g.
|
|
/// "ReplayBuffer.Save").
|
|
hotkey_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
TriggerHotkeyBySequence {
|
|
/// Main key identifier (e.g. `OBS_KEY_A` for key "A"). Available identifiers
|
|
/// [here](https://github.com/obsproject/obs-studio/blob/master/libobs/obs-hotkeys.h).
|
|
key_id: &'a str,
|
|
/// Optional key modifiers object. False entries can be omitted.
|
|
key_modifiers: &'a [KeyModifier],
|
|
},
|
|
// --------------------------------
|
|
// Media Control
|
|
// --------------------------------
|
|
#[serde(rename_all = "camelCase")]
|
|
PlayPauseMedia {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// Whether to pause or play the source. `false` for play, `true` for pause.
|
|
play_pause: Option<bool>,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
RestartMedia {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
StopMedia {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
NextMedia {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
PreviousMedia {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetMediaDuration {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetMediaTime {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
SetMediaTime {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// Milliseconds to set the timestamp to.
|
|
#[serde(serialize_with = "ser::duration_millis")]
|
|
timestamp: Duration,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
ScrubMedia {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// Millisecond offset (positive or negative) to offset the current media position.
|
|
#[serde(serialize_with = "ser::duration_millis")]
|
|
time_offset: Duration,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetMediaState {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
// --------------------------------
|
|
// Sources
|
|
// --------------------------------
|
|
GetMediaSourcesList,
|
|
CreateSource(CreateSource<'a>),
|
|
GetSourcesList,
|
|
GetSourceTypesList,
|
|
#[serde(rename_all = "camelCase")]
|
|
GetVolume {
|
|
/// Source name.
|
|
source: &'a str,
|
|
/// Output volume in decibels of attenuation instead of amplitude/mul.
|
|
use_decibel: Option<bool>,
|
|
},
|
|
SetVolume(Volume<'a>),
|
|
GetMute {
|
|
/// Source name.
|
|
source: &'a str,
|
|
},
|
|
SetMute {
|
|
/// Source name.
|
|
source: &'a str,
|
|
/// Desired mute status.
|
|
mute: bool,
|
|
},
|
|
ToggleMute {
|
|
/// Source name.
|
|
source: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSourceActive {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetAudioActive {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
SetSourceName {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// New source name.
|
|
new_name: &'a str,
|
|
},
|
|
SetSyncOffset {
|
|
/// Source name.
|
|
source: &'a str,
|
|
/// The desired audio sync offset (in nanoseconds).
|
|
#[serde(serialize_with = "ser::duration_nanos")]
|
|
offset: Duration,
|
|
},
|
|
GetSyncOffset {
|
|
/// Source name.
|
|
source: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSourceSettings {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// Type of the specified source. Useful for type-checking if you expect a specific settings
|
|
/// schema.
|
|
source_type: Option<&'a str>,
|
|
},
|
|
SetSourceSettings(SourceSettings<'a>),
|
|
#[serde(rename = "GetTextGDIPlusProperties")]
|
|
GetTextGdiPlusProperties {
|
|
/// Source name.
|
|
source: &'a str,
|
|
},
|
|
#[serde(rename = "SetTextGDIPlusProperties")]
|
|
SetTextGdiPlusProperties(Box<TextGdiPlusProperties<'a>>),
|
|
GetTextFreetype2Properties {
|
|
/// Source name.
|
|
source: &'a str,
|
|
},
|
|
SetTextFreetype2Properties(TextFreetype2Properties<'a>),
|
|
GetSpecialSources,
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSourceFilters {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSourceFilterInfo {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// Source filter name.
|
|
filter_name: &'a str,
|
|
},
|
|
AddFilterToSource(AddFilter<'a>),
|
|
#[serde(rename_all = "camelCase")]
|
|
RemoveFilterFromSource {
|
|
/// Name of the source from which the specified filter is removed.
|
|
source_name: &'a str,
|
|
/// Name of the filter to remove.
|
|
filter_name: &'a str,
|
|
},
|
|
ReorderSourceFilter(ReorderFilter<'a>),
|
|
MoveSourceFilter(MoveFilter<'a>),
|
|
SetSourceFilterSettings(SourceFilterSettings<'a>),
|
|
SetSourceFilterVisibility(SourceFilterVisibility<'a>),
|
|
#[serde(rename_all = "camelCase")]
|
|
GetAudioMonitorType {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
SetAudioMonitorType {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
/// The monitor type to use. Options: `none`, `monitorOnly`, `monitorAndOutput`.
|
|
monitor_type: MonitorType,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSourceDefaultSettings {
|
|
/// Source kind. Also called "source id" in libobs terminology.
|
|
source_kind: &'a str,
|
|
},
|
|
TakeSourceScreenshot(SourceScreenshot<'a>),
|
|
#[serde(rename_all = "camelCase")]
|
|
RefreshBrowserSource {
|
|
/// Source name.
|
|
source_name: &'a str,
|
|
},
|
|
// --------------------------------
|
|
// Outputs
|
|
// --------------------------------
|
|
ListOutputs,
|
|
#[serde(rename_all = "camelCase")]
|
|
GetOutputInfo {
|
|
/// Output name.
|
|
output_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
StartOutput {
|
|
/// Output name.
|
|
output_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
StopOutput {
|
|
/// Output name.
|
|
output_name: &'a str,
|
|
/// Force stop (default: false).
|
|
force: Option<bool>,
|
|
},
|
|
// --------------------------------
|
|
// Profiles
|
|
// --------------------------------
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetCurrentProfile {
|
|
/// Name of the desired profile.
|
|
profile_name: &'a str,
|
|
},
|
|
GetCurrentProfile,
|
|
ListProfiles,
|
|
// --------------------------------
|
|
// Recording
|
|
// --------------------------------
|
|
GetRecordingStatus,
|
|
StartStopRecording,
|
|
StartRecording,
|
|
StopRecording,
|
|
PauseRecording,
|
|
ResumeRecording,
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetRecordingFolder {
|
|
/// Path of the recording folder.
|
|
rec_folder: &'a Path,
|
|
},
|
|
GetRecordingFolder,
|
|
// --------------------------------
|
|
// Replay Buffer
|
|
// --------------------------------
|
|
GetReplayBufferStatus,
|
|
StartStopReplayBuffer,
|
|
StartReplayBuffer,
|
|
StopReplayBuffer,
|
|
SaveReplayBuffer,
|
|
// --------------------------------
|
|
// Scene Collections
|
|
// --------------------------------
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetCurrentSceneCollection {
|
|
/// Name of the desired scene collection.
|
|
sc_name: &'a str,
|
|
},
|
|
GetCurrentSceneCollection,
|
|
ListSceneCollections,
|
|
// --------------------------------
|
|
// Scene Items
|
|
// --------------------------------
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSceneItemList {
|
|
/// Name of the scene to get the list of scene items from. Defaults to the current scene if
|
|
/// not specified.
|
|
scene_name: Option<&'a str>,
|
|
},
|
|
#[serde(rename_all = "kebab-case")]
|
|
GetSceneItemProperties {
|
|
/// Name of the scene the scene item belongs to. Defaults to the current scene.
|
|
scene_name: Option<&'a str>,
|
|
/// Scene Item name (if this field is a string) or specification (if it is an object).
|
|
#[serde(with = "either::serde_untagged")]
|
|
item: Either<&'a str, SceneItemSpecification<'a>>,
|
|
},
|
|
SetSceneItemProperties(SceneItemProperties<'a>),
|
|
#[serde(rename_all = "kebab-case")]
|
|
ResetSceneItem {
|
|
/// Name of the scene the scene item belongs to. Defaults to the current scene.
|
|
scene_name: Option<&'a str>,
|
|
/// Scene Item name (if this field is a string) or specification (if it is an object).
|
|
#[serde(with = "either::serde_untagged")]
|
|
item: Either<&'a str, SceneItemSpecification<'a>>,
|
|
},
|
|
SetSceneItemRender(SceneItemRender<'a>),
|
|
DeleteSceneItem {
|
|
/// Name of the scene the scene item belongs to. Defaults to the current scene.
|
|
scene: Option<&'a str>,
|
|
/// Scene item to delete.
|
|
item: SceneItemSpecification<'a>, // TODO: fields are actually not optional
|
|
},
|
|
AddSceneItem(AddSceneItem<'a>),
|
|
DuplicateSceneItem(DuplicateSceneItem<'a>),
|
|
// --------------------------------
|
|
// Scenes
|
|
// --------------------------------
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetCurrentScene {
|
|
/// Name of the scene to switch to.
|
|
scene_name: &'a str,
|
|
},
|
|
GetCurrentScene,
|
|
GetSceneList,
|
|
#[serde(rename_all = "camelCase")]
|
|
CreateScene {
|
|
/// Name of the scene to create.
|
|
scene_name: &'a str,
|
|
},
|
|
ReorderSceneItems {
|
|
/// Name of the scene to reorder (defaults to current).
|
|
scene: Option<&'a str>,
|
|
/// Ordered list of objects with name and/or id specified. Id preferred due to uniqueness
|
|
/// per scene.
|
|
items: &'a [SceneItem<'a>],
|
|
},
|
|
SetSceneTransitionOverride(SceneTransitionOverride<'a>),
|
|
#[serde(rename_all = "camelCase")]
|
|
RemoveSceneTransitionOverride {
|
|
/// Name of the scene to remove the override from.
|
|
scene_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
GetSceneTransitionOverride {
|
|
/// Name of the scene to get the override for.
|
|
scene_name: &'a str,
|
|
},
|
|
// --------------------------------
|
|
// Streaming
|
|
// --------------------------------
|
|
GetStreamingStatus,
|
|
StartStopStreaming,
|
|
StartStreaming {
|
|
/// Special stream configuration. Please note: these won't be saved to OBS' configuration.
|
|
stream: Option<Stream<'a>>,
|
|
},
|
|
StopStreaming,
|
|
SetStreamSettings(SetStreamSettings<'a>),
|
|
GetStreamSettings,
|
|
SaveStreamSettings,
|
|
SendCaptions {
|
|
/// Captions text.
|
|
text: &'a str,
|
|
},
|
|
// --------------------------------
|
|
// Studio Mode
|
|
// --------------------------------
|
|
GetStudioModeStatus,
|
|
GetPreviewScene,
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetPreviewScene {
|
|
/// The name of the scene to preview.
|
|
scene_name: &'a str,
|
|
},
|
|
TransitionToProgram {
|
|
/// Change the active transition before switching scenes. Defaults to the active transition.
|
|
with_transition: Option<Transition<'a>>,
|
|
},
|
|
EnableStudioMode,
|
|
DisableStudioMode,
|
|
ToggleStudioMode,
|
|
// --------------------------------
|
|
// Transitions
|
|
// --------------------------------
|
|
GetTransitionList,
|
|
GetCurrentTransition,
|
|
#[serde(rename_all = "kebab-case")]
|
|
SetCurrentTransition {
|
|
/// The name of the transition.
|
|
transition_name: &'a str,
|
|
},
|
|
SetTransitionDuration {
|
|
/// Desired duration of the transition (in milliseconds).
|
|
#[serde(serialize_with = "ser::duration_millis")]
|
|
duration: Duration,
|
|
},
|
|
GetTransitionDuration,
|
|
GetTransitionPosition,
|
|
#[serde(rename_all = "camelCase")]
|
|
GetTransitionSettings {
|
|
/// Transition name.
|
|
transition_name: &'a str,
|
|
},
|
|
#[serde(rename_all = "camelCase")]
|
|
SetTransitionSettings {
|
|
/// Transition name.
|
|
transition_name: &'a str,
|
|
/// Transition settings (they can be partial).
|
|
transition_settings: &'a serde_json::Value,
|
|
},
|
|
ReleaseTBar,
|
|
#[serde(rename_all = "camelCase")]
|
|
SetTBarPosition {
|
|
/// T-Bar position. This value must be between 0.0 and 1.0.
|
|
position: f64,
|
|
/// Whether or not the T-Bar gets released automatically after setting its new position
|
|
/// (like a user releasing their mouse button after moving the T-Bar). Call `ReleaseTBar`
|
|
/// manually if you set `release` to false. Defaults to true.
|
|
release: Option<bool>,
|
|
},
|
|
// --------------------------------
|
|
// Virtual Cam
|
|
// --------------------------------
|
|
GetVirtualCamStatus,
|
|
StartStopVirtualCam,
|
|
StartVirtualCam,
|
|
StopVirtualCam,
|
|
}
|
|
|
|
/// Request information for [`open_projector`](crate::client::General::open_projector).
|
|
#[derive(Debug, Default)]
|
|
pub struct Projector<'a> {
|
|
/// Type of projector: `Preview` (default), `Source`, `Scene`, `StudioProgram`, or `Multiview`
|
|
/// (case insensitive).
|
|
pub ty: Option<ProjectorType>,
|
|
/// Monitor to open the projector on. If -1 or omitted, opens a window.
|
|
pub monitor: Option<i64>,
|
|
/// Size and position of the projector window (only if monitor is -1). Encoded in Base64 using
|
|
/// [Qt's geometry encoding](https://doc.qt.io/qt-5/qwidget.html#saveGeometry). Corresponds to
|
|
/// OBS's saved projectors.
|
|
pub geometry: Option<&'a QtGeometry>,
|
|
/// Name of the source or scene to be displayed (ignored for other projector types).
|
|
pub name: Option<&'a str>,
|
|
}
|
|
|
|
/// Request information for [`open_projector`](crate::client::General::open_projector) as part of
|
|
/// [`Projector`].
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
|
pub enum ProjectorType {
|
|
/// Open a projector of the preview area.
|
|
Preview,
|
|
/// Open a projector for a source.
|
|
Source,
|
|
/// Open a projector for a scene.
|
|
Scene,
|
|
/// Open a projector of the program pane in studio mode.
|
|
StudioProgram,
|
|
/// Open a projector in multiview.
|
|
Multiview,
|
|
}
|
|
|
|
/// Internal version of [`Projector`] which is the one that's actually send to the API. This allows
|
|
/// to let the user define a typed version of the geometry while sending the encoded version through
|
|
/// this struct.
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub(crate) struct ProjectorInternal<'a> {
|
|
/// Type of projector: `Preview` (default), `Source`, `Scene`, `StudioProgram`, or `Multiview`
|
|
/// (case insensitive).
|
|
#[serde(rename = "type")]
|
|
pub ty: Option<ProjectorType>,
|
|
/// Monitor to open the projector on. If -1 or omitted, opens a window.
|
|
pub monitor: Option<i64>,
|
|
/// Size and position of the projector window (only if monitor is -1). Encoded in Base64 using
|
|
/// [Qt's geometry encoding](https://doc.qt.io/qt-5/qwidget.html#saveGeometry). Corresponds to
|
|
/// OBS's saved projectors.
|
|
pub geometry: Option<&'a str>,
|
|
/// Name of the source or scene to be displayed (ignored for other projector types).
|
|
pub name: Option<&'a str>,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`trigger_hotkey_by_sequence`](crate::client::General::trigger_hotkey_by_sequence).
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct KeyModifier {
|
|
/// Trigger Shift key.
|
|
pub shift: bool,
|
|
/// Trigger Alt key.
|
|
pub alt: bool,
|
|
/// Trigger Control (Ctrl) key.
|
|
pub control: bool,
|
|
/// Trigger Command key (Mac).
|
|
pub command: bool,
|
|
}
|
|
|
|
/// Request information for [`create_source`](crate::client::Sources::create_source).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CreateSource<'a> {
|
|
/// Source name.
|
|
pub source_name: &'a str,
|
|
/// Source kind, Eg. `vlc_source`.
|
|
pub source_kind: &'a str,
|
|
/// Scene to add the new source to.
|
|
pub scene_name: &'a str,
|
|
/// Source settings data.
|
|
pub source_settings: Option<&'a serde_json::Value>,
|
|
/// Set the created SceneItem as visible or not. Defaults to true.
|
|
pub set_visible: Option<bool>,
|
|
}
|
|
|
|
/// Request information for [`set_volume`](crate::client::Sources::set_volume).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Volume<'a> {
|
|
/// Source name.
|
|
pub source: &'a str,
|
|
/// Desired volume. Must be between `0.0` and `20.0` for mul, and under 26.0 for dB. OBS will
|
|
/// interpret dB values under -100.0 as Inf. Note: The OBS volume sliders only reach a maximum
|
|
/// of 1.0mul/0.0dB, however OBS actually supports larger values.
|
|
pub volume: f64,
|
|
/// Interpret `volume` data as decibels instead of amplitude/mul.
|
|
pub use_decibel: Option<bool>,
|
|
}
|
|
|
|
/// Request information for [`set_source_settings`](crate::client::Sources::set_source_settings).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SourceSettings<'a> {
|
|
/// Source name.
|
|
pub source_name: &'a str,
|
|
/// Type of the specified source. Useful for type-checking to avoid settings a set of settings
|
|
/// incompatible with the actual source's type.
|
|
pub source_type: Option<&'a str>,
|
|
/// Source settings (varies between source types, may require some probing around).
|
|
pub source_settings: &'a serde_json::Value,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_text_gdi_plus_properties`](crate::client::Sources::set_text_gdi_plus_properties).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct TextGdiPlusProperties<'a> {
|
|
/// Name of the source.
|
|
pub source: &'a str,
|
|
/// Text Alignment ("left", "center", "right").
|
|
pub align: Option<Align>,
|
|
/// Background color.
|
|
pub bk_color: Option<u32>,
|
|
/// Background opacity (0-100).
|
|
pub bk_opacity: Option<u8>,
|
|
/// Chat log.
|
|
pub chatlog: Option<bool>,
|
|
/// Chat log lines.
|
|
pub chatlog_lines: Option<u64>,
|
|
/// Text color.
|
|
pub color: Option<u32>,
|
|
/// Extents wrap.
|
|
pub extents: Option<bool>,
|
|
/// Extents cx.
|
|
pub extents_cx: Option<i64>,
|
|
/// Extents cy.
|
|
pub extents_cy: Option<i64>,
|
|
/// File path name.
|
|
pub file: Option<&'a Path>,
|
|
/// Read text from the specified file.
|
|
pub read_from_file: Option<bool>,
|
|
/// Holds data for the font. Ex:
|
|
/// `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }`.
|
|
pub font: Option<Font<'a>>,
|
|
/// Gradient enabled.
|
|
pub gradient: Option<bool>,
|
|
/// Gradient color.
|
|
pub gradient_color: Option<u32>,
|
|
/// Gradient direction.
|
|
pub gradient_dir: Option<f32>,
|
|
/// Gradient opacity (0-100).
|
|
pub gradient_opacity: Option<u8>,
|
|
/// Outline.
|
|
pub outline: Option<bool>,
|
|
/// Outline color.
|
|
pub outline_color: Option<u32>,
|
|
/// Outline size.
|
|
pub outline_size: Option<u64>,
|
|
/// Outline opacity (0-100).
|
|
pub outline_opacity: Option<u8>,
|
|
/// Text content to be displayed.
|
|
pub text: Option<&'a str>,
|
|
/// Text vertical alignment ("top", "center", "bottom").
|
|
pub valign: Option<Valign>,
|
|
/// Vertical text enabled.
|
|
pub vertical: Option<bool>,
|
|
/// Visibility of the scene item.
|
|
pub render: Option<bool>,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_text_freetype2_properties`](crate::client::Sources::set_text_freetype2_properties).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct TextFreetype2Properties<'a> {
|
|
/// Source name.
|
|
pub source: &'a str,
|
|
/// Gradient top color.
|
|
#[serde(serialize_with = "ser::rgba8_inverse_opt")]
|
|
pub color1: Option<RGBA8>,
|
|
/// Gradient bottom color.
|
|
#[serde(serialize_with = "ser::rgba8_inverse_opt")]
|
|
pub color2: Option<RGBA8>,
|
|
/// Custom width (0 to disable).
|
|
pub custom_width: Option<u32>,
|
|
/// Drop shadow.
|
|
pub drop_shadow: Option<bool>,
|
|
/// Holds data for the font. Ex:
|
|
/// `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }`.
|
|
pub font: Option<Font<'a>>,
|
|
/// Read text from the specified file.
|
|
pub from_file: Option<bool>,
|
|
/// Chat log.
|
|
pub log_mode: Option<bool>,
|
|
/// Outline.
|
|
pub outline: Option<bool>,
|
|
/// Text content to be displayed.
|
|
pub text: Option<&'a str>,
|
|
/// File path.
|
|
pub text_file: Option<&'a Path>,
|
|
/// Word wrap.
|
|
pub word_wrap: Option<bool>,
|
|
}
|
|
|
|
impl<'a> From<&'a crate::responses::TextFreetype2Properties> for TextFreetype2Properties<'a> {
|
|
fn from(p: &'a crate::responses::TextFreetype2Properties) -> Self {
|
|
Self {
|
|
source: &p.source,
|
|
color1: p.color1,
|
|
color2: p.color2,
|
|
custom_width: p.custom_width,
|
|
drop_shadow: Some(p.drop_shadow),
|
|
font: p.font.as_ref().map(Into::into),
|
|
from_file: Some(p.from_file),
|
|
log_mode: Some(p.log_mode),
|
|
outline: Some(p.outline),
|
|
text: Some(&p.text),
|
|
text_file: p.text_file.as_deref(),
|
|
word_wrap: Some(p.word_wrap),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for [`add_filter_to_source`](crate::client::Sources::add_filter_to_source).
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct AddFilter<'a> {
|
|
/// Name of the source on which the filter is added.
|
|
pub source_name: &'a str,
|
|
/// Name of the new filter.
|
|
pub filter_name: &'a str,
|
|
/// Filter type.
|
|
pub filter_type: &'a str,
|
|
/// Filter settings.
|
|
pub filter_settings: &'a serde_json::Value,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`reorder_source_filter`](crate::client::Sources::reorder_source_filter).
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ReorderFilter<'a> {
|
|
/// Name of the source to which the filter belongs.
|
|
pub source_name: &'a str,
|
|
/// Name of the filter to reorder.
|
|
pub filter_name: &'a str,
|
|
/// Desired position of the filter in the chain.
|
|
pub new_index: u32,
|
|
}
|
|
|
|
/// Request information for [`move_source_filter`](crate::client::Sources::move_source_filter).
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MoveFilter<'a> {
|
|
/// Name of the source to which the filter belongs.
|
|
pub source_name: &'a str,
|
|
/// Name of the filter to reorder.
|
|
pub filter_name: &'a str,
|
|
/// How to move the filter around in the source's filter chain. Either "up", "down", "top" or
|
|
/// "bottom".
|
|
pub movement_type: MovementType,
|
|
}
|
|
|
|
/// Request information for [`move_source_filter`](crate::client::Sources::move_source_filter) as
|
|
/// part of [`MoveFilter`].
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum MovementType {
|
|
/// Move up by one position.
|
|
Up,
|
|
/// Move down by one position.
|
|
Down,
|
|
/// Move to the very top.
|
|
Top,
|
|
/// Move to the very bottom.
|
|
Bottom,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_source_filter_settings`](crate::client::Sources::set_source_filter_settings).
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SourceFilterSettings<'a> {
|
|
/// Name of the source to which the filter belongs.
|
|
pub source_name: &'a str,
|
|
/// Name of the filter to reconfigure.
|
|
pub filter_name: &'a str,
|
|
/// New settings. These will be merged to the current filter settings.
|
|
pub filter_settings: &'a serde_json::Value,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_source_filter_visibility`](crate::client::Sources::set_source_filter_visibility).
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SourceFilterVisibility<'a> {
|
|
/// Source name.
|
|
pub source_name: &'a str,
|
|
/// Source filter name.
|
|
pub filter_name: &'a str,
|
|
/// New filter state.
|
|
pub filter_enabled: bool,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`take_source_screenshot`](crate::client::Sources::take_source_screenshot).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SourceScreenshot<'a> {
|
|
/// Source name.
|
|
///
|
|
/// Note: Since scenes are also sources, you can also provide a scene name. If not provided, the
|
|
/// currently active scene is used.
|
|
pub source_name: Option<&'a str>,
|
|
/// Format of the Data URI encoded picture. Can be "png", "jpg", "jpeg" or "bmp" (or any other
|
|
/// value supported by Qt's Image module).
|
|
pub embed_picture_format: Option<&'a str>,
|
|
/// Full file path (file extension included) where the captured image is to be saved. Can be in
|
|
/// a format different from [`embed_picture_format`](SourceScreenshot::embed_picture_format).
|
|
/// Can be a relative path.
|
|
pub save_to_file_path: Option<&'a Path>,
|
|
/// Format to save the image file as (one of the values provided in the
|
|
/// [`supported_image_export_formats`](crate::responses::Version::supported_image_export_formats)
|
|
/// response field of [`get_version`](crate::client::General::get_version)). If not specified,
|
|
/// tries to guess based on file extension.
|
|
pub file_format: Option<&'a str>,
|
|
/// Compression ratio between -1 and 100 to write the image with. -1 is automatic, 1 is smallest
|
|
/// file/most compression, 100 is largest file/least compression. Varies with image type.
|
|
pub compress_quality: Option<i8>,
|
|
/// Screenshot width. Defaults to the source's base width.
|
|
pub width: Option<u32>,
|
|
/// Screenshot height. Defaults to the source's base height.
|
|
pub height: Option<u32>,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub struct SceneItemProperties<'a> {
|
|
/// Name of the scene the source item belongs to. Defaults to the current scene.
|
|
pub scene_name: Option<&'a str>,
|
|
/// Scene Item name (if this field is a string) or specification (if it is an object).
|
|
#[serde(with = "either::serde_untagged")]
|
|
pub item: Either<&'a str, SceneItemSpecification<'a>>,
|
|
/// Position of the scene item.
|
|
pub position: Option<Position>,
|
|
/// The new clockwise rotation of the item in degrees.
|
|
pub rotation: Option<f64>,
|
|
/// Scaling factor of the scene item.
|
|
pub scale: Option<Scale>,
|
|
/// Pixel cropping of the scene item before scaling.
|
|
pub crop: Option<Crop>,
|
|
/// The new visibility of the source. 'true' shows source, 'false' hides source.
|
|
pub visible: Option<bool>,
|
|
/// The new locked status of the source. 'true' keeps it in its current position, 'false' allows
|
|
/// movement.
|
|
pub locked: Option<bool>,
|
|
/// Bounding box of the scene item.
|
|
pub bounds: Option<Bounds>,
|
|
}
|
|
|
|
impl<'a> Default for SceneItemProperties<'a> {
|
|
fn default() -> Self {
|
|
Self {
|
|
scene_name: None,
|
|
item: Either::Left(""),
|
|
position: None,
|
|
rotation: None,
|
|
scale: None,
|
|
crop: None,
|
|
visible: None,
|
|
locked: None,
|
|
bounds: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_item_render`](crate::client::SceneItems::set_scene_item_render).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub struct SceneItemRender<'a> {
|
|
/// Name of the scene the scene item belongs to. Defaults to the currently active scene.
|
|
pub scene_name: Option<&'a str>,
|
|
/// Scene Item name.
|
|
pub source: &'a str,
|
|
/// Scene Item id.
|
|
pub item: Option<i64>,
|
|
/// true = shown ; false = hidden.
|
|
pub render: bool,
|
|
}
|
|
|
|
/// Request information for [`add_scene_item`](crate::client::SceneItems::add_scene_item).
|
|
#[derive(Debug, Default, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct AddSceneItem<'a> {
|
|
/// Name of the scene to create the scene item in.
|
|
pub scene_name: &'a str,
|
|
/// Name of the source to be added.
|
|
pub source_name: &'a str,
|
|
/// Whether to make the sceneitem visible on creation or not. Default `true`.
|
|
pub set_visible: bool,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`duplicate_scene_item`](crate::client::SceneItems::duplicate_scene_item).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct DuplicateSceneItem<'a> {
|
|
/// Name of the scene to copy the item from. Defaults to the current scene.
|
|
pub from_scene: Option<&'a str>,
|
|
/// Name of the scene to create the item in. Defaults to the current scene.
|
|
pub to_scene: Option<&'a str>,
|
|
/// Scene Item to duplicate from the source scene.
|
|
pub item: SceneItemSpecification<'a>, // TODO: fields are actually not optional
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_transition_override`](crate::client::Scenes::set_scene_transition_override).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SceneTransitionOverride<'a> {
|
|
/// Name of the scene to switch to.
|
|
pub scene_name: &'a str,
|
|
/// Name of the transition to use.
|
|
pub transition_name: &'a str,
|
|
/// Duration in milliseconds of the transition if transition is not fixed. Defaults to the
|
|
/// current duration specified in the UI if there is no current override and this value is not
|
|
/// given.
|
|
#[serde(serialize_with = "ser::duration_millis_opt")]
|
|
pub transition_duration: Option<Duration>,
|
|
}
|
|
|
|
/// Request information for [`set_stream_settings`](crate::client::Streaming::set_stream_settings).
|
|
#[derive(Debug, Serialize)]
|
|
pub struct SetStreamSettings<'a> {
|
|
/// The type of streaming service configuration, usually `rtmp_custom` or `rtmp_common`.
|
|
#[serde(rename = "type")]
|
|
pub ty: StreamType,
|
|
/// The actual settings of the stream.
|
|
pub settings: StreamSettings<'a>,
|
|
/// Persist the settings to disk.
|
|
pub save: bool,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_text_gdi_plus_properties`](crate::client::Sources::set_text_gdi_plus_properties) as part
|
|
/// of [`TextGdiPlusProperties`] and
|
|
/// [`set_text_freetype2_properties`](crate::client::Sources::set_text_freetype2_properties) as part
|
|
/// of [`TextFreetype2Properties`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct Font<'a> {
|
|
/// Font face.
|
|
pub face: Option<&'a str>,
|
|
/// Font text styling flag. `Bold=1, Italic=2, Bold Italic=3, Underline=5, Strikeout=8`.
|
|
#[serde(serialize_with = "ser::bitflags_u8_opt")]
|
|
pub flags: Option<FontFlags>,
|
|
/// Font text size.
|
|
pub size: Option<u32>,
|
|
/// Font Style (unknown function).
|
|
pub style: Option<&'a str>,
|
|
}
|
|
|
|
impl<'a> From<&'a crate::responses::Font> for Font<'a> {
|
|
fn from(f: &'a crate::responses::Font) -> Self {
|
|
Self {
|
|
face: Some(&f.face),
|
|
flags: Some(f.flags),
|
|
size: Some(f.size),
|
|
style: Some(&f.style),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties),
|
|
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
|
/// [`SceneItemProperties`], [`reset_scene_item`](crate::client::SceneItems::reset_scene_item),
|
|
/// [`delete_scene_item`](crate::client::SceneItems::delete_scene_item) and
|
|
/// [`duplicate_scene_item`](crate::client::SceneItems::duplicate_scene_item) as part of
|
|
/// [`DuplicateSceneItem`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct SceneItemSpecification<'a> {
|
|
/// Scene Item name.
|
|
pub name: Option<&'a str>,
|
|
/// Scene Item ID.
|
|
pub id: Option<i64>,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
|
/// [`SceneItemProperties`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct Position {
|
|
/// The new x position of the source.
|
|
pub x: Option<f64>,
|
|
/// The new y position of the source.
|
|
pub y: Option<f64>,
|
|
/// The new alignment of the source.
|
|
#[serde(serialize_with = "ser::bitflags_u8_opt")]
|
|
pub alignment: Option<Alignment>,
|
|
}
|
|
|
|
impl From<&crate::common::Position> for Position {
|
|
fn from(p: &crate::common::Position) -> Self {
|
|
Self {
|
|
x: Some(p.x),
|
|
y: Some(p.y),
|
|
alignment: Some(p.alignment),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
|
/// [`SceneItemProperties`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct Scale {
|
|
/// The new x scale of the item.
|
|
pub x: Option<f64>,
|
|
/// The new y scale of the item.
|
|
pub y: Option<f64>,
|
|
}
|
|
|
|
impl From<&crate::common::Scale> for Scale {
|
|
fn from(s: &crate::common::Scale) -> Self {
|
|
Self {
|
|
x: Some(s.x),
|
|
y: Some(s.y),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
|
/// [`SceneItemProperties`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct Crop {
|
|
/// The new amount of pixels cropped off the top of the source before scaling.
|
|
pub top: Option<u32>,
|
|
/// The new amount of pixels cropped off the bottom of the source before scaling.
|
|
pub bottom: Option<u32>,
|
|
/// The new amount of pixels cropped off the left of the source before scaling.
|
|
pub left: Option<u32>,
|
|
/// The new amount of pixels cropped off the right of the source before scaling.
|
|
pub right: Option<u32>,
|
|
}
|
|
|
|
impl From<&crate::common::Crop> for Crop {
|
|
fn from(c: &crate::common::Crop) -> Self {
|
|
Self {
|
|
top: Some(c.top),
|
|
bottom: Some(c.bottom),
|
|
left: Some(c.left),
|
|
right: Some(c.right),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
|
/// [`SceneItemProperties`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct Bounds {
|
|
/// The new bounds type of the source. Can be "OBS_BOUNDS_STRETCH", "OBS_BOUNDS_SCALE_INNER",
|
|
/// "OBS_BOUNDS_SCALE_OUTER", "OBS_BOUNDS_SCALE_TO_WIDTH", "OBS_BOUNDS_SCALE_TO_HEIGHT",
|
|
/// "OBS_BOUNDS_MAX_ONLY" or "OBS_BOUNDS_NONE".
|
|
#[serde(rename = "type")]
|
|
pub ty: Option<BoundsType>,
|
|
/// The new alignment of the bounding box. (0-2, 4-6, 8-10).
|
|
#[serde(serialize_with = "ser::bitflags_u8_opt")]
|
|
pub alignment: Option<Alignment>,
|
|
/// The new width of the bounding box.
|
|
pub x: Option<f64>,
|
|
/// The new height of the bounding box.
|
|
pub y: Option<f64>,
|
|
}
|
|
|
|
impl From<&crate::common::Bounds> for Bounds {
|
|
fn from(b: &crate::common::Bounds) -> Self {
|
|
Self {
|
|
ty: Some(b.ty),
|
|
alignment: Some(b.alignment),
|
|
x: Some(b.x),
|
|
y: Some(b.y),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`reorder_scene_items`](crate::client::Scenes::reorder_scene_items).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct SceneItem<'a> {
|
|
/// Id of a specific scene item. Unique on a scene by scene basis.
|
|
pub id: Option<i64>,
|
|
/// Name of a scene item. Sufficiently unique if no scene items share sources within the scene.
|
|
pub name: Option<&'a str>,
|
|
}
|
|
|
|
/// Request information for [`start_streaming`](crate::client::Streaming::start_streaming).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct Stream<'a> {
|
|
/// If specified ensures the type of stream matches the given type (usually 'rtmp_custom' or
|
|
/// 'rtmp_common'). If the currently configured stream type does not match the given stream
|
|
/// type, all settings must be specified in the `settings` object or an error will occur when
|
|
/// starting the stream.
|
|
#[serde(rename = "type")]
|
|
pub ty: Option<StreamType>,
|
|
/// Adds the given object parameters as encoded query string parameters to the 'key' of the RTMP
|
|
/// stream. Used to pass data to the RTMP service about the streaming. May be any String,
|
|
/// Numeric, or Boolean field.
|
|
pub metadata: Option<&'a serde_json::Value>,
|
|
/// Settings for the stream.
|
|
pub settings: Option<StreamSettings<'a>>,
|
|
}
|
|
|
|
/// Request information for [`start_streaming`](crate::client::Streaming::start_streaming) as part
|
|
/// of [`Stream`] and [`set_stream_settings`](crate::client::Streaming::set_stream_settings) as part
|
|
/// of [`SetStreamSettings`].
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Default, Serialize)]
|
|
pub struct StreamSettings<'a> {
|
|
/// The publish URL.
|
|
pub server: Option<&'a str>,
|
|
/// The publish key of the stream.
|
|
pub key: Option<&'a str>,
|
|
/// Indicates whether authentication should be used when connecting to the streaming server.
|
|
pub use_auth: Option<bool>,
|
|
/// If authentication is enabled, the username for the streaming server. Ignored if
|
|
/// [`use_auth`](Self::use_auth) is not set to `true`.
|
|
pub username: Option<&'a str>,
|
|
/// If authentication is enabled, the password for the streaming server. Ignored if
|
|
/// [`use_auth`](Self::use_auth) is not set to `true`.
|
|
pub password: Option<&'a str>,
|
|
}
|
|
|
|
/// Request information for
|
|
/// [`transition_to_program`](crate::client::StudioMode::transition_to_program).
|
|
#[skip_serializing_none]
|
|
#[derive(Debug, Serialize)]
|
|
pub struct Transition<'a> {
|
|
/// Name of the transition.
|
|
pub name: &'a str,
|
|
/// Transition duration (in milliseconds).
|
|
#[serde(serialize_with = "ser::duration_millis_opt")]
|
|
pub duration: Option<Duration>,
|
|
}
|
|
|
|
/// Request information for [`open_projector`](crate::client::General::open_projector) as part of
|
|
/// [`Projector`].
|
|
///
|
|
/// This describes a position on the screen starting from the top left corner with 0.
|
|
///
|
|
/// ```txt
|
|
/// Screen
|
|
/// ┌────────────────────── X
|
|
/// │
|
|
/// │ top
|
|
/// │ ┌────────┐
|
|
/// │ left │ Rect │ right
|
|
/// │ └────────┘
|
|
/// │ bottom
|
|
/// │
|
|
/// Y
|
|
///
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
pub struct QtRect {
|
|
/// Left or X/horizontal position of the rectangle.
|
|
pub left: i32,
|
|
/// Top or Y/vertical position of the rectangle.
|
|
pub top: i32,
|
|
/// The right side of a rectangle counted from the left. For example with left = 100 and right =
|
|
/// 300 the width would be 200.
|
|
pub right: i32,
|
|
/// Bottom side of a rectangle counted from the top. For example with top = 100 and bottom = 300
|
|
/// the height would be 200.
|
|
pub bottom: i32,
|
|
}
|
|
|
|
bitflags! {
|
|
/// Request information for [`open_projector`](crate::client::General::open_projector) as part of
|
|
/// [`Projector`].
|
|
#[derive(Default)]
|
|
pub struct QtWindowState: u32 {
|
|
/// Window with maximum size, taking up as much space as possible but still showing
|
|
/// the window frame.
|
|
const MAXIMIZED = 2;
|
|
/// Show the window in fullscreen mode, taking up the whole display.
|
|
const FULLSCREEN = 4;
|
|
}
|
|
}
|
|
|
|
impl QtWindowState {
|
|
/// Convert the state into a byte array for usage in [`QtGeometry::serialize`] .
|
|
fn to_be_bytes(&self) -> [u8; 2] {
|
|
[
|
|
if self.contains(Self::MAXIMIZED) { 1 } else { 0 },
|
|
if self.contains(Self::FULLSCREEN) {
|
|
1
|
|
} else {
|
|
0
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
/// Request information for [`open_projector`](crate::client::General::open_projector) as part of
|
|
/// [`Projector`].
|
|
#[derive(Debug)]
|
|
pub struct QtGeometry {
|
|
/// The screen number to display a widget or [`Self::DEFAULT_SCREEN`] to let OBS pick the
|
|
/// default.
|
|
pub screen_number: i32,
|
|
/// Additional window state like maximized or fullscreen.
|
|
pub window_state: QtWindowState,
|
|
/// The width of the screen. Seems to have no specific effect but is used for some internal
|
|
/// calculations in Qt.
|
|
pub screen_width: i32,
|
|
/// The target position and size for a widget to display at.
|
|
pub rect: QtRect,
|
|
}
|
|
|
|
impl QtGeometry {
|
|
/// Value indicating to use the default screen.
|
|
pub const DEFAULT_SCREEN: i32 = -1;
|
|
|
|
/// Create a new geometry instance without only size information set.
|
|
pub fn new(rect: QtRect) -> Self {
|
|
Self {
|
|
rect,
|
|
..Self::default()
|
|
}
|
|
}
|
|
|
|
/// Serialize this instance into a base64 encoded byte array.
|
|
///
|
|
/// The exact format can be found in the
|
|
/// [Qt source code](https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#_ZNK7QWidget12saveGeometryEv).
|
|
///
|
|
/// | Length | Content |
|
|
/// |--------|----------------------------------------------------|
|
|
/// | 4 | Magic number |
|
|
/// | 2 | Major format version |
|
|
/// | 2 | Minor format version |
|
|
/// | 16 | Frame rect (lef, top, right, bottom) 4 bytes each |
|
|
/// | 16 | Normal rect (lef, top, right, bottom) 4 bytes each |
|
|
/// | 4 | Screen number |
|
|
/// | 1 | Window maximized (1 or 0) |
|
|
/// | 1 | Window fullscreen (1 or 0) |
|
|
/// | 4 | Screen width |
|
|
/// | 16 | Main rect (lef, top, right, bottom) 4 bytes each |
|
|
pub(crate) fn serialize(&self) -> String {
|
|
/// Indicator for serialized Qt geometry data.
|
|
const MAGIC_NUMBER: u32 = 0x1D9D0CB;
|
|
/// Major version of this format.
|
|
const MAJOR_VERSION: u16 = 3;
|
|
/// Minor version of this format.
|
|
const MINOR_VERSION: u16 = 0;
|
|
/// Output data length BEFORE base64 encoding. This allows to reduce allocations in the
|
|
/// byte buffer and must be updated whenever the format changes.
|
|
const DATA_LENGTH: usize = 66;
|
|
|
|
fn serialize_rect(data: &mut Vec<u8>, rect: &QtRect) {
|
|
data.extend(&rect.left.to_be_bytes());
|
|
data.extend(&rect.top.to_be_bytes());
|
|
data.extend(&rect.right.to_be_bytes());
|
|
data.extend(&rect.bottom.to_be_bytes());
|
|
}
|
|
|
|
let mut data = Vec::<u8>::with_capacity(DATA_LENGTH);
|
|
|
|
data.extend(&MAGIC_NUMBER.to_be_bytes());
|
|
data.extend(&MAJOR_VERSION.to_be_bytes());
|
|
data.extend(&MINOR_VERSION.to_be_bytes());
|
|
|
|
serialize_rect(&mut data, &self.rect); // frame geometry
|
|
serialize_rect(&mut data, &self.rect); // normal geometry
|
|
|
|
data.extend(&self.screen_number.to_be_bytes());
|
|
data.extend(&self.window_state.to_be_bytes());
|
|
data.extend(&self.screen_width.to_be_bytes());
|
|
|
|
serialize_rect(&mut data, &self.rect);
|
|
|
|
base64::encode(data)
|
|
}
|
|
}
|
|
|
|
impl Default for QtGeometry {
|
|
fn default() -> Self {
|
|
Self {
|
|
screen_number: Self::DEFAULT_SCREEN,
|
|
window_state: QtWindowState::default(),
|
|
screen_width: 0,
|
|
rect: QtRect::default(),
|
|
}
|
|
}
|
|
}
|