Files
obs-studio/frontend/widgets/OBSBasic.hpp
2026-01-14 14:49:38 -05:00

1694 lines
47 KiB
C++

/******************************************************************************
Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "ui_OBSBasic.h"
#include "OBSMainWindow.hpp"
#include <OBSApp.hpp>
#include <components/AccessibleAlignmentSelector.hpp>
#include <oauth/Auth.hpp>
#include <utility/BasicOutputHandler.hpp>
#include <utility/OBSCanvas.hpp>
#include <utility/PreviewProgramSizeObserver.hpp>
#include <utility/ThumbnailManager.hpp>
#include <utility/VCamConfig.hpp>
#include <utility/platform.hpp>
#include <utility/undo_stack.hpp>
#include <obs-frontend-internal.hpp>
#include <obs.hpp>
#include <qt-wrappers.hpp>
#include <graphics/matrix4.h>
#include <util/platform.h>
#include <util/threading.h>
#include <util/util.hpp>
#include <QAccessible>
#include <QSystemTrayIcon>
#include <deque>
extern volatile bool recording_paused;
class ColorSelect;
class OBSAbout;
class OBSBasicAdvAudio;
class OBSBasicFilters;
class OBSBasicInteraction;
class OBSBasicProperties;
class OBSBasicSourceSelect;
class OBSBasicTransform;
class OBSLogViewer;
class OBSMissingFiles;
class OBSProjector;
class VolumeControl;
#ifdef YOUTUBE_ENABLED
class YouTubeAppDock;
#endif
class QMessageBox;
class QWidgetAction;
struct QuickTransition;
namespace OBS {
class SceneCollection;
struct Rect;
enum class LogFileType;
} // namespace OBS
#define SIMPLE_ENCODER_X264 "x264"
#define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
#define SIMPLE_ENCODER_QSV "qsv"
#define SIMPLE_ENCODER_QSV_AV1 "qsv_av1"
#define SIMPLE_ENCODER_NVENC "nvenc"
#define SIMPLE_ENCODER_NVENC_AV1 "nvenc_av1"
#define SIMPLE_ENCODER_NVENC_HEVC "nvenc_hevc"
#define SIMPLE_ENCODER_AMD "amd"
#define SIMPLE_ENCODER_AMD_HEVC "amd_hevc"
#define SIMPLE_ENCODER_AMD_AV1 "amd_av1"
#define SIMPLE_ENCODER_APPLE_H264 "apple_h264"
#define SIMPLE_ENCODER_APPLE_HEVC "apple_hevc"
#define PREVIEW_EDGE_SIZE 10
enum class ProjectorType;
enum class QtDataRole {
OBSRef = Qt::UserRole,
OBSSignals,
};
struct SavedProjectorInfo {
ProjectorType type;
int monitor;
std::string geometry;
std::string name;
bool alwaysOnTop;
bool alwaysOnTopOverridden;
};
struct SourceCopyInfo {
OBSWeakSource weak_source;
bool visible;
obs_sceneitem_crop crop;
obs_transform_info transform;
obs_blending_method blend_method;
obs_blending_type blend_mode;
obs_scale_type scale_type;
const char *show_transition_id;
const char *hide_transition_id;
OBSData show_transition_settings;
OBSData hide_transition_settings;
uint32_t show_transition_duration;
uint32_t hide_transition_duration;
OBSData private_settings;
};
struct OBSProfile {
std::string name;
std::string directoryName;
std::filesystem::path path;
std::filesystem::path profileFile;
};
struct OBSPromptResult {
bool success;
std::string promptValue;
bool optionValue;
};
struct OBSPromptRequest {
std::string title;
std::string prompt;
std::string promptValue;
bool withOption;
std::string optionPrompt;
bool optionValue;
};
using OBSPromptCallback = std::function<bool(const OBSPromptResult &result)>;
using OBSProfileCache = std::map<std::string, OBSProfile>;
using SceneCollection = OBS::SceneCollection;
using OBSSceneCollectionCache = std::unordered_map<std::string, SceneCollection>;
template<typename T> static T GetOBSRef(QListWidgetItem *item)
{
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
}
template<typename T> static void SetOBSRef(QListWidgetItem *item, T &&val)
{
item->setData(static_cast<int>(QtDataRole::OBSRef), QVariant::fromValue(val));
}
#ifdef _WIN32
static inline void UpdateProcessPriority()
{
const char *priority = config_get_string(App()->GetAppConfig(), "General", "ProcessPriority");
if (priority && strcmp(priority, "Normal") != 0)
SetProcessPriority(priority);
}
static inline void ClearProcessPriority()
{
const char *priority = config_get_string(App()->GetAppConfig(), "General", "ProcessPriority");
if (priority && strcmp(priority, "Normal") != 0)
SetProcessPriority("Normal");
}
#else
#define UpdateProcessPriority() \
do { \
} while (false)
#define ClearProcessPriority() \
do { \
} while (false)
#endif
class OBSBasic : public OBSMainWindow {
Q_OBJECT
Q_PROPERTY(QIcon imageIcon READ GetImageIcon WRITE SetImageIcon DESIGNABLE true)
Q_PROPERTY(QIcon colorIcon READ GetColorIcon WRITE SetColorIcon DESIGNABLE true)
Q_PROPERTY(QIcon slideshowIcon READ GetSlideshowIcon WRITE SetSlideshowIcon DESIGNABLE true)
Q_PROPERTY(QIcon audioInputIcon READ GetAudioInputIcon WRITE SetAudioInputIcon DESIGNABLE true)
Q_PROPERTY(QIcon audioOutputIcon READ GetAudioOutputIcon WRITE SetAudioOutputIcon DESIGNABLE true)
Q_PROPERTY(QIcon desktopCapIcon READ GetDesktopCapIcon WRITE SetDesktopCapIcon DESIGNABLE true)
Q_PROPERTY(QIcon windowCapIcon READ GetWindowCapIcon WRITE SetWindowCapIcon DESIGNABLE true)
Q_PROPERTY(QIcon gameCapIcon READ GetGameCapIcon WRITE SetGameCapIcon DESIGNABLE true)
Q_PROPERTY(QIcon cameraIcon READ GetCameraIcon WRITE SetCameraIcon DESIGNABLE true)
Q_PROPERTY(QIcon textIcon READ GetTextIcon WRITE SetTextIcon DESIGNABLE true)
Q_PROPERTY(QIcon mediaIcon READ GetMediaIcon WRITE SetMediaIcon DESIGNABLE true)
Q_PROPERTY(QIcon browserIcon READ GetBrowserIcon WRITE SetBrowserIcon DESIGNABLE true)
Q_PROPERTY(QIcon groupIcon READ GetGroupIcon WRITE SetGroupIcon DESIGNABLE true)
Q_PROPERTY(QIcon sceneIcon READ GetSceneIcon WRITE SetSceneIcon DESIGNABLE true)
Q_PROPERTY(QIcon defaultIcon READ GetDefaultIcon WRITE SetDefaultIcon DESIGNABLE true)
Q_PROPERTY(QIcon audioProcessOutputIcon READ GetAudioProcessOutputIcon WRITE SetAudioProcessOutputIcon
DESIGNABLE true)
friend class OBSAbout;
friend class OBSBasicPreview;
friend class OBSBasicStatusBar;
friend class OBSBasicSourceSelect;
friend class OBSBasicSettings;
friend class Auth;
friend class AutoConfig;
friend class AutoConfigStreamPage;
friend class ExtraBrowsersModel;
friend class OBSYoutubeActions;
friend struct BasicOutputHandler;
friend struct OBSStudioAPI;
friend class ScreenshotObj;
enum class MoveDir { Up, Down, Left, Right };
enum DropType {
DropType_RawText,
DropType_Text,
DropType_Image,
DropType_Media,
DropType_Html,
DropType_Url,
};
enum ContextBarSize { ContextBarSize_Minimized, ContextBarSize_Reduced, ContextBarSize_Normal };
enum class CenterType {
Scene,
Vertical,
Horizontal,
};
/* -------------------------------------
* MARK: - General
* -------------------------------------
*/
private:
obs_frontend_callbacks *api = nullptr;
std::vector<OBSSignal> signalHandlers;
bool loaded = false;
bool isClosing_ = false;
bool isClosePromptOpen_ = false;
bool handledShutdown = false;
// TODO: Remove, orphaned variable
bool copyVisible = true;
// TODO: Unused thread pointer, remove.
QScopedPointer<QThread> devicePropertiesThread;
QScopedPointer<QThread> logUploadThread;
ConfigFile activeConfiguration;
QScopedPointer<QThread> patronJsonThread;
std::string patronJson;
std::unique_ptr<Ui::OBSBasic> ui;
void OnEvent(enum obs_frontend_event event);
bool InitBasicConfigDefaults();
void InitBasicConfigDefaults2();
bool InitBasicConfig();
void InitOBSCallbacks();
void OnFirstLoad();
void GetFPSCommon(uint32_t &num, uint32_t &den) const;
void GetFPSInteger(uint32_t &num, uint32_t &den) const;
void GetFPSFraction(uint32_t &num, uint32_t &den) const;
void GetFPSNanoseconds(uint32_t &num, uint32_t &den) const;
void GetConfigFPS(uint32_t &num, uint32_t &den) const;
OBSPromptResult PromptForName(const OBSPromptRequest &request, const OBSPromptCallback &callback);
// TODO: Remove, orphaned instance method
void NewProject();
// TODO: Remove, orphaned instance method
void LoadProject();
ThumbnailManager *thumbnailManager = nullptr;
public slots:
void close();
void UpdatePatronJson(const QString &text, const QString &error);
void UpdateEditMenu();
void applicationShutdown() noexcept;
void toggleMixerLayout();
public:
/* `undo_s` needs to be declared after `ui` to prevent an uninitialized
* warning for `ui` while initializing `undo_s`. */
undo_stack undo_s;
explicit OBSBasic(QWidget *parent = 0);
virtual ~OBSBasic();
virtual void OBSInit() override;
virtual config_t *Config() const override;
int ResetVideo();
bool ResetAudio();
void UpdateTitleBar();
static OBSBasic *Get();
void SetDisplayAffinity(QWindow *window);
void saveAll();
bool shouldPromptForClose();
inline bool isClosing() { return isClosing_; }
inline bool isClosePromptOpen() { return isClosePromptOpen_; }
void closeWindow();
ThumbnailManager *thumbnails() const { return thumbnailManager; }
protected:
bool isReadyToClose();
bool promptToClose();
virtual void closeEvent(QCloseEvent *event) override;
virtual bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;
virtual void changeEvent(QEvent *event) override;
signals:
void mainWindowClosed();
void appSettingChanged(const std::string &category, const std::string &name);
void userSettingChanged(const std::string &category, const std::string &name);
void profileSettingChanged(const std::string &category, const std::string &name);
void mixerStatusChanged(QString sourceUuid);
/* -------------------------------------
* MARK: - OAuth
* -------------------------------------
*/
private:
std::shared_ptr<Auth> auth;
public:
inline Auth *GetAuth() { return auth.get(); }
/* -------------------------------------
* MARK: - OBSBasic_Browser
* -------------------------------------
*/
private:
QPointer<QWidget> extraBrowsers;
#ifdef BROWSER_AVAILABLE
QPointer<QAction> extraBrowserMenuDocksSeparator;
QList<std::shared_ptr<QDockWidget>> extraBrowserDocks;
QStringList extraBrowserDockNames;
QStringList extraBrowserDockTargets;
void ClearExtraBrowserDocks();
void LoadExtraBrowserDocks();
void SaveExtraBrowserDocks();
void ManageExtraBrowserDocks();
void AddExtraBrowserDock(const QString &title, const QString &url, const QString &uuid, bool firstCreate);
#endif
public:
static void InitBrowserPanelSafeBlock();
/* -------------------------------------
* MARK: - OBSBasic_Clipboard
* -------------------------------------
*/
private:
std::deque<SourceCopyInfo> clipboard;
OBSWeakSourceAutoRelease copyFiltersSource_;
obs_transform_info copiedTransformInfo;
obs_sceneitem_crop copiedCropInfo;
bool hasCopiedTransform = false;
int copySourceTransitionDuration;
OBSWeakSourceAutoRelease copySourceTransition;
private slots:
void on_actionCopySource_triggered();
void on_actionPasteRef_triggered();
void on_actionPasteDup_triggered();
void on_actionCopyFilters_triggered();
void on_actionPasteFilters_triggered();
void SourcePasteFilters(OBSSource source, OBSSource dstSource);
void SceneCopyFilters();
void ScenePasteFilters();
void on_actionCopyTransform_triggered();
void on_actionPasteTransform_triggered();
public slots:
void actionCopyFilters();
void actionPasteFilters();
public:
obs_weak_source_t *copyFiltersSource() { return copyFiltersSource_; }
OBSWeakSource copyFilter;
void CreateFilterPasteUndoRedoAction(const QString &text, obs_source_t *source, obs_data_array_t *undo_array,
obs_data_array_t *redo_array);
/* -------------------------------------
* MARK: - OBSBasic_ContextToolbar
* -------------------------------------
*/
private:
ContextBarSize contextBarSize = ContextBarSize_Normal;
void SourceToolBarActionsSetEnabled();
void copyActionsDynamicProperties();
private slots:
void on_toggleContextBar_toggled(bool visible);
public slots:
void ShowContextBar();
void HideContextBar();
void ClearContextBar();
void UpdateContextBar(bool force = false);
void UpdateContextBarDeferred(bool force = false);
void UpdateContextBarVisibility();
/* -------------------------------------
* MARK: - OBSBasic_Docks
* -------------------------------------
*/
private:
QPointer<QDockWidget> statsDock;
QByteArray startingDockLayout;
QStringList extraDockNames;
QList<std::shared_ptr<QDockWidget>> extraDocks;
QStringList extraCustomDockNames;
QList<QPointer<QDockWidget>> extraCustomDocks;
QPointer<OBSDock> controlsDock;
QPointer<OBSDock> mixerDock;
public:
void AddDockWidget(QDockWidget *dock, Qt::DockWidgetArea area, bool extraBrowser = false);
void RemoveDockWidget(const QString &name);
bool IsDockObjectNameUsed(const QString &name);
void AddCustomDockWidget(QDockWidget *dock);
void setDockCornersVertical(bool vertical);
private slots:
void on_resetDocks_triggered(bool force = false);
void on_lockDocks_toggled(bool lock);
void on_sideDocks_toggled(bool side);
void RepairCustomExtraDockName();
/* -------------------------------------
* MARK: - OBSBasic_Dropfiles
* -------------------------------------
*/
private:
void AddDropSource(const char *file, DropType image);
void AddDropURL(QUrl url, QString &name, obs_data_t *settings, const obs_video_info &ovi);
void ConfirmDropUrl(const QString &url);
void dragEnterEvent(QDragEnterEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
signals:
void sourceUuidDropped(QString uuid);
/* -------------------------------------
* MARK: - OBSBasic_Hotkeys
* -------------------------------------
*/
private:
QPointer<QObject> shortcutFilter;
obs_hotkey_id statsHotkey = 0;
obs_hotkey_id screenshotHotkey = 0;
obs_hotkey_id sourceScreenshotHotkey = 0;
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, pauseHotkeys, replayBufHotkeys, vcamHotkeys,
togglePreviewHotkeys, contextBarHotkeys;
obs_hotkey_id forceStreamingStopHotkey, splitFileHotkey, addChapterHotkey;
void InitHotkeys();
void CreateHotkeys();
void ClearHotkeys();
static void HotkeyTriggered(void *data, obs_hotkey_id id, bool pressed);
private slots:
void ProcessHotkey(obs_hotkey_id id, bool pressed);
void ResetStatsHotkey();
/* -------------------------------------
* MARK: - OBSBasic_Icons
* -------------------------------------
*/
private:
QIcon imageIcon;
QIcon colorIcon;
QIcon slideshowIcon;
QIcon audioInputIcon;
QIcon audioOutputIcon;
QIcon desktopCapIcon;
QIcon windowCapIcon;
QIcon gameCapIcon;
QIcon cameraIcon;
QIcon textIcon;
QIcon mediaIcon;
QIcon browserIcon;
QIcon groupIcon;
QIcon sceneIcon;
QIcon defaultIcon;
QIcon audioProcessOutputIcon;
QIcon GetImageIcon() const;
QIcon GetColorIcon() const;
QIcon GetSlideshowIcon() const;
QIcon GetAudioInputIcon() const;
QIcon GetAudioOutputIcon() const;
QIcon GetDesktopCapIcon() const;
QIcon GetWindowCapIcon() const;
QIcon GetGameCapIcon() const;
QIcon GetCameraIcon() const;
QIcon GetTextIcon() const;
QIcon GetMediaIcon() const;
QIcon GetBrowserIcon() const;
QIcon GetDefaultIcon() const;
QIcon GetAudioProcessOutputIcon() const;
private slots:
void SetImageIcon(const QIcon &icon);
void SetColorIcon(const QIcon &icon);
void SetSlideshowIcon(const QIcon &icon);
void SetAudioInputIcon(const QIcon &icon);
void SetAudioOutputIcon(const QIcon &icon);
void SetDesktopCapIcon(const QIcon &icon);
void SetWindowCapIcon(const QIcon &icon);
void SetGameCapIcon(const QIcon &icon);
void SetCameraIcon(const QIcon &icon);
void SetTextIcon(const QIcon &icon);
void SetMediaIcon(const QIcon &icon);
void SetBrowserIcon(const QIcon &icon);
void SetGroupIcon(const QIcon &icon);
void SetSceneIcon(const QIcon &icon);
void SetDefaultIcon(const QIcon &icon);
void SetAudioProcessOutputIcon(const QIcon &icon);
public:
QIcon GetSourceIcon(const char *id) const;
QIcon GetGroupIcon() const;
QIcon GetSceneIcon() const;
/* -------------------------------------
* MARK: - OBSBasic_MainControls
* -------------------------------------
*/
private:
QPointer<OBSBasicInteraction> interaction;
QPointer<OBSBasicProperties> properties;
QPointer<OBSBasicTransform> transformWindow;
QPointer<OBSBasicAdvAudio> advAudioWindow;
QPointer<OBSBasicFilters> filters;
QPointer<OBSAbout> about;
QPointer<OBSBasicSourceSelect> addWindow;
QPointer<OBSLogViewer> logView;
QPointer<QWidget> stats;
QPointer<QWidget> remux;
QPointer<QWidget> importer;
QPointer<QAction> showHide;
QPointer<QAction> exit;
QPointer<QMenu> scaleFilteringMenu;
QPointer<QMenu> blendingMethodMenu;
QPointer<QMenu> blendingModeMenu;
QPointer<QMenu> colorMenu;
QPointer<QMenu> deinterlaceMenu;
QPointer<QWidgetAction> colorWidgetAction;
QPointer<ColorSelect> colorSelect;
QList<QDialog *> visDialogs;
QList<QDialog *> modalDialogs;
QList<QMessageBox *> visMsgBoxes;
QList<QPoint> visDlgPositions;
void CloseDialogs();
void EnumDialogs();
private slots:
void on_actionMainUndo_triggered();
void on_actionMainRedo_triggered();
void ToggleAlwaysOnTop();
void SetShowing(bool showing);
void ToggleShowHide();
void on_actionShowAbout_triggered();
void on_actionFullscreenInterface_triggered();
void on_actionRemux_triggered();
void on_action_Settings_triggered();
void on_actionShowMacPermissions_triggered();
void on_actionShowLogs_triggered();
void on_actionUploadCurrentLog_triggered();
void on_actionUploadLastLog_triggered();
void on_actionViewCurrentLog_triggered();
void on_actionCheckForUpdates_triggered();
void on_actionRepair_triggered();
void on_actionShowWhatsNew_triggered();
void on_actionRestartSafe_triggered();
void on_actionShowCrashLogs_triggered();
void on_actionUploadLastCrashLog_triggered();
void on_OBSBasic_customContextMenuRequested(const QPoint &pos);
void on_actionHelpPortal_triggered();
void on_actionWebsite_triggered();
void on_actionDiscord_triggered();
void on_actionReleaseNotes_triggered();
void on_actionShowSettingsFolder_triggered();
void on_actionShowProfileFolder_triggered();
void on_actionAlwaysOnTop_triggered();
void on_toggleListboxToolbars_toggled(bool visible);
void on_toggleStatusBar_toggled(bool visible);
void on_autoConfigure_triggered();
void on_stats_triggered();
void on_idianPlayground_triggered();
void on_resetUI_triggered();
void logUploadFinished(const QString &text, const QString &error, OBS::LogFileType uploadType);
void updateCheckFinished();
public slots:
void on_actionAdvAudioProperties_triggered();
public:
void ResetUI();
void CreateInteractionWindow(obs_source_t *source);
void CreateFiltersWindow(obs_source_t *source);
void CreateEditTransformWindow(obs_sceneitem_t *item);
void CreatePropertiesWindow(obs_source_t *source);
void UploadLog(const char *subdir, const char *file, OBS::LogFileType uploadType);
/* -------------------------------------
* MARK: - OBSBasic_MainMenu
* -------------------------------------
*/
private:
void setupMenuItemStateHandlers();
/* -------------------------------------
* MARK: - OBSBasic_OutputHandler
* -------------------------------------
*/
private:
std::unique_ptr<BasicOutputHandler> outputHandler;
std::optional<std::pair<uint32_t, uint32_t>> lastOutputResolution;
int disableOutputsRef = 0;
inline void OnActivate(bool force = false)
{
if (ui->profileMenu->isEnabled() || force) {
ui->profileMenu->setEnabled(false);
ui->autoConfigure->setEnabled(false);
App()->IncrementSleepInhibition();
UpdateProcessPriority();
struct obs_video_info ovi;
obs_get_video_info(&ovi);
lastOutputResolution = {ovi.base_width, ovi.base_height};
TaskbarOverlaySetStatus(TaskbarOverlayStatusActive);
if (trayIcon && trayIcon->isVisible()) {
#ifdef __APPLE__
QIcon trayMask = QIcon(":/res/images/tray_active_macos.svg");
trayMask.setIsMask(true);
trayIcon->setIcon(QIcon::fromTheme("obs-tray", trayMask));
#else
trayIcon->setIcon(
QIcon::fromTheme("obs-tray-active", QIcon(":/res/images/tray_active.png")));
#endif
}
}
}
inline void OnDeactivate()
{
if (!outputHandler->Active() && !ui->profileMenu->isEnabled()) {
ui->profileMenu->setEnabled(true);
ui->autoConfigure->setEnabled(true);
App()->DecrementSleepInhibition();
ClearProcessPriority();
TaskbarOverlaySetStatus(TaskbarOverlayStatusInactive);
if (trayIcon && trayIcon->isVisible()) {
#ifdef __APPLE__
QIcon trayIconFile = QIcon(":/res/images/obs_macos.svg");
trayIconFile.setIsMask(true);
#else
QIcon trayIconFile = QIcon(":/res/images/obs.png");
#endif
trayIcon->setIcon(QIcon::fromTheme("obs-tray", trayIconFile));
}
} else if (outputHandler->Active() && trayIcon && trayIcon->isVisible()) {
if (os_atomic_load_bool(&recording_paused)) {
#ifdef __APPLE__
QIcon trayIconFile = QIcon(":/res/images/obs_paused_macos.svg");
trayIconFile.setIsMask(true);
#else
QIcon trayIconFile = QIcon(":/res/images/obs_paused.png");
#endif
trayIcon->setIcon(QIcon::fromTheme("obs-tray-paused", trayIconFile));
TaskbarOverlaySetStatus(TaskbarOverlayStatusPaused);
} else {
#ifdef __APPLE__
QIcon trayIconFile = QIcon(":/res/images/tray_active_macos.svg");
trayIconFile.setIsMask(true);
#else
QIcon trayIconFile = QIcon(":/res/images/tray_active.png");
#endif
trayIcon->setIcon(QIcon::fromTheme("obs-tray-active", trayIconFile));
TaskbarOverlaySetStatus(TaskbarOverlayStatusActive);
}
}
}
bool IsFFmpegOutputToURL() const;
bool OutputPathValid();
void OutputPathInvalidMessage();
// TODO: Unimplemented, remove.
void SetupEncoders();
// TODO: Unimplemented, remove.
void TempFileOutput(const char *path, int vBitrate, int aBitrate);
// TODO: Unimplemented, remove.
void TempStreamOutput(const char *url, const char *key, int vBitrate, int aBitrate);
public:
bool Active() const;
void ResetOutputs();
inline void EnableOutputs(bool enable)
{
if (enable) {
if (--disableOutputsRef < 0)
disableOutputsRef = 0;
} else {
disableOutputsRef++;
}
}
const char *GetCurrentOutputPath();
private slots:
void ResizeOutputSizeOfSource();
private slots:
void on_actionOpenPluginManager_triggered();
/* -------------------------------------
* MARK: - OBSBasic_Preview
* -------------------------------------
*/
private:
bool previewEnabled = true;
QPointer<QTimer> nudge_timer;
bool recent_nudge = false;
gs_vertbuffer_t *box = nullptr;
gs_vertbuffer_t *boxLeft = nullptr;
gs_vertbuffer_t *boxTop = nullptr;
gs_vertbuffer_t *boxRight = nullptr;
gs_vertbuffer_t *boxBottom = nullptr;
gs_vertbuffer_t *circle = nullptr;
gs_vertbuffer_t *actionSafeMargin = nullptr;
gs_vertbuffer_t *graphicsSafeMargin = nullptr;
gs_vertbuffer_t *fourByThreeSafeMargin = nullptr;
gs_vertbuffer_t *leftLine = nullptr;
gs_vertbuffer_t *topLine = nullptr;
gs_vertbuffer_t *rightLine = nullptr;
int previewX = 0, previewY = 0;
int previewCX = 0, previewCY = 0;
float previewScale = 0.0f;
bool drawSafeAreas = false;
QColor selectionColor;
QColor cropColor;
QColor hoverColor;
bool drawSpacingHelpers = true;
float dpi = 1.0;
void DrawBackdrop(float cx, float cy);
void InitPrimitives();
void UpdatePreviewScalingMenu();
void Nudge(int dist, MoveDir dir);
void UpdateProjectorHideCursor();
void UpdateProjectorAlwaysOnTop(bool top);
void ResetProjectors();
void UpdatePreviewSafeAreas();
QColor GetCropColor() const;
QColor GetHoverColor() const;
void UpdatePreviewSpacingHelpers();
float GetDevicePixelRatio();
void UpdatePreviewOverflowSettings();
void UpdatePreviewControls();
/* OBS Callbacks */
static void RenderMain(void *data, uint32_t cx, uint32_t cy);
void ResizePreview(uint32_t cx, uint32_t cy);
private slots:
void PreviewScalingModeChanged(int value);
void ColorChange();
void EnablePreview();
void DisablePreview();
void setPreviewScalingWindow();
void setPreviewScalingCanvas();
void setPreviewScalingOutput();
void on_actionLockPreview_triggered();
void on_scalingMenu_aboutToShow();
void on_preview_customContextMenuRequested();
void on_previewDisabledWidget_customContextMenuRequested();
void EnablePreviewDisplay(bool enable);
void TogglePreview();
public:
inline void GetDisplayRect(int &x, int &y, int &cx, int &cy)
{
x = previewX;
y = previewY;
cx = previewCX;
cy = previewCY;
}
QColor GetSelectionColor() const;
signals:
void CanvasResized(uint32_t width, uint32_t height);
void OutputResized(uint32_t width, uint32_t height);
/* Preview signals */
void PreviewZoomIn();
void PreviewZoomOut();
void PreviewResetZoom();
/* -------------------------------------
* MARK: - OBSBasic_Profiles
* -------------------------------------
*/
private:
OBSProfileCache profiles{};
void SetupNewProfile(const std::string &profileName, bool useWizard = false);
void SetupDuplicateProfile(const std::string &profileName);
void SetupRenameProfile(const std::string &profileName);
const OBSProfile &CreateProfile(const std::string &profileName);
void RemoveProfile(OBSProfile profile);
void ChangeProfile();
void RefreshProfileCache();
void RefreshProfiles(bool refreshCache = false);
void ActivateProfile(const OBSProfile &profile, bool reset = false);
void UpdateProfileEncoders();
std::vector<std::string> GetRestartRequirements(const ConfigFile &config) const;
void ResetProfileData();
void CheckForSimpleModeX264Fallback();
public:
inline const OBSProfileCache &GetProfileCache() const noexcept { return profiles; };
const OBSProfile &GetCurrentProfile() const;
std::optional<OBSProfile> GetProfileByName(const std::string &profileName) const;
std::optional<OBSProfile> GetProfileByDirectoryName(const std::string &directoryName) const;
private slots:
void on_actionNewProfile_triggered();
void on_actionDupProfile_triggered();
void on_actionRenameProfile_triggered();
void on_actionRemoveProfile_triggered(bool skipConfirmation = false);
void on_actionImportProfile_triggered();
void on_actionExportProfile_triggered();
public slots:
bool CreateNewProfile(const QString &name);
bool CreateDuplicateProfile(const QString &name);
void DeleteProfile(const QString &profileName);
/* -------------------------------------
* MARK: - OBSBasic_Projectors
* -------------------------------------
*/
private:
std::vector<OBSProjector *> projectors;
QPointer<QMenu> previewProjector;
QPointer<QMenu> previewProjectorSource;
QPointer<QMenu> previewProjectorMain;
void updateMultiviewProjectorMenu();
void ClearProjectors();
OBSProjector *OpenProjector(obs_source_t *source, int monitor, ProjectorType type);
obs_data_array_t *SaveProjectors();
void LoadSavedProjectors(obs_data_array_t *savedProjectors);
private slots:
void OpenSavedProjector(SavedProjectorInfo *info);
void OpenPreviewProjector();
void OpenSourceProjector();
void OpenMultiviewProjector();
void OpenSceneProjector();
void OpenPreviewWindow();
void OpenSourceWindow();
void OpenSceneWindow();
void openMultiviewWindow();
public:
void DeleteProjector(OBSProjector *projector);
static QList<QString> GetProjectorMenuMonitorsFormatted();
template<typename Receiver, typename... Args>
static void AddProjectorMenuMonitors(QMenu *parent, Receiver *target, void (Receiver::*slot)(Args...))
{
auto projectors = GetProjectorMenuMonitorsFormatted();
for (int i = 0; i < projectors.size(); i++) {
QString str = projectors[i];
QAction *action = parent->addAction(str, target, slot);
action->setProperty("monitor", i);
}
}
/* -------------------------------------
* MARK: - OBSBasic_Recording
* -------------------------------------
*/
private:
QPointer<QTimer> diskFullTimer;
bool recordingStopping = false;
bool recordingStarted = false;
bool isRecordingPausable = false;
bool recordingPaused = false;
void AutoRemux(QString input, bool no_show = false);
void UpdateIsRecordingPausable();
bool LowDiskSpace();
void DiskSpaceMessage();
private slots:
void on_actionShow_Recordings_triggered();
/* Record action (start/stop) slot */
void RecordActionTriggered();
/* Record pause (pause/unpause) slot */
void RecordPauseToggled();
public slots:
void StartRecording();
void StopRecording();
void RecordingStart();
void RecordStopping();
void RecordingStop(int code, QString last_error);
void RecordingFileChanged(QString lastRecordingPath);
void PauseRecording();
void UnpauseRecording();
void CheckDiskSpaceRemaining();
bool RecordingActive();
signals:
/* Recording signals */
void RecordingStarted(bool pausable = false);
void RecordingPaused();
void RecordingUnpaused();
void RecordingStopping();
void RecordingStopped();
/* -------------------------------------
* MARK: - OBSBasic_ReplayBuffer
* -------------------------------------
*/
private:
bool replayBufferStopping = false;
std::string lastReplay;
public slots:
void ShowReplayBufferPauseWarning();
void StartReplayBuffer();
void StopReplayBuffer();
void ReplayBufferStart();
void ReplayBufferSave();
void ReplayBufferSaved();
void ReplayBufferStopping();
void ReplayBufferStop(int code);
bool ReplayBufferActive();
private slots:
/* Replay Buffer action (start/stop) slot */
void ReplayBufferActionTriggered();
signals:
/* Replay Buffer signals */
void ReplayBufEnabled(bool enabled);
void ReplayBufStarted();
void ReplayBufStopping();
void ReplayBufStopped();
/* -------------------------------------
* MARK: - OBSBasic_SceneCollections
* -------------------------------------
*/
private:
OBSDataAutoRelease collectionModuleData;
long disableSaving = 1;
bool projectChanged = false;
bool clearingFailed = false;
QPointer<OBSMissingFiles> missDialog;
OBSSceneCollectionCache collections;
void DisableRelativeCoordinates(bool disable);
void CreateDefaultScene(bool firstStart);
void Save(SceneCollection &collection);
void LoadData(obs_data_t *data, SceneCollection &collection);
void Load(SceneCollection &collection);
void ClearSceneData();
void LogScenes();
void SaveProjectNow();
void ShowMissingFilesDialog(obs_missing_files_t *files);
void SetupNewSceneCollection(const std::string &collectionName);
void SetupDuplicateSceneCollection(const std::string &collectionName);
void SetupRenameSceneCollection(const std::string &collectionName);
SceneCollection &CreateSceneCollection(const std::string &collectionName);
void RemoveSceneCollection(SceneCollection collection);
bool CreateDuplicateSceneCollection(const QString &name);
void DeleteSceneCollection(const QString &name);
void ChangeSceneCollection();
void RefreshSceneCollectionCache();
void RefreshSceneCollections(bool refreshCache = false);
void ActivateSceneCollection(SceneCollection &collection);
public slots:
void DeferSaveBegin();
void DeferSaveEnd();
void SaveProjectDeferred();
void SaveProject();
bool CreateNewSceneCollection(const QString &name);
private slots:
void on_actionShowMissingFiles_triggered();
void on_actionNewSceneCollection_triggered();
void on_actionDupSceneCollection_triggered();
void on_actionRenameSceneCollection_triggered();
void on_actionRemoveSceneCollection_triggered(bool skipConfirmation = false);
void on_actionImportSceneCollection_triggered();
void on_actionExportSceneCollection_triggered();
void on_actionRemigrateSceneCollection_triggered();
public:
inline bool SavingDisabled() const { return disableSaving; }
inline const OBSSceneCollectionCache &GetSceneCollectionCache() const noexcept { return collections; };
SceneCollection &GetCurrentSceneCollection();
std::optional<SceneCollection> GetSceneCollectionByName(const std::string &collectionName) const;
std::optional<SceneCollection> GetSceneCollectionByFileName(const std::string &fileName) const;
/* -------------------------------------
* MARK: - OBSBasic_Canvases
* -------------------------------------
*/
private:
std::vector<OBS::Canvas> canvases;
static void CanvasRemoved(void *data, calldata_t *params);
void ClearCanvases();
public:
const std::vector<OBS::Canvas> &GetCanvases() const noexcept { return canvases; }
const OBS::Canvas &AddCanvas(const std::string &name, obs_video_info *ovi = nullptr, int flags = 0);
public slots:
bool RemoveCanvas(OBSCanvas canvas);
/* -------------------------------------
* MARK: - OBSBasic_SceneItems
* -------------------------------------
*/
private:
QPointer<QMenu> sourceProjector;
QPointer<QAction> renameSource;
void CreateFirstRunSources();
OBSSceneItem GetSceneItem(QListWidgetItem *item);
OBSSceneItem GetCurrentSceneItem();
bool QueryRemoveSource(obs_source_t *source);
int GetTopSelectedSourceItem();
QModelIndexList GetAllSelectedSourceItems();
// TODO: Move back to transitions
QMenu *CreateVisibilityTransitionMenu(bool visible);
void CenterSelectedSceneItems(const CenterType &centerType);
/* OBS Callbacks */
static void SourceCreated(void *data, calldata_t *params);
static void SourceRemoved(void *data, calldata_t *params);
static void SourceRenamed(void *data, calldata_t *params);
private slots:
void AddSourceDialog();
void RenameSources(OBSSource source, QString newName, QString prevName);
void ReorderSources(OBSScene scene);
void RefreshSources(OBSScene scene);
void SetDeinterlacingMode();
void SetDeinterlacingOrder();
void SetScaleFilter();
void SetBlendingMethod();
void SetBlendingMode();
void on_actionRotate90CW_triggered();
void on_actionRotate90CCW_triggered();
void on_actionRotate180_triggered();
void on_actionFlipHorizontal_triggered();
void on_actionFlipVertical_triggered();
void on_actionFitToScreen_triggered();
void on_actionStretchToScreen_triggered();
void on_actionCenterToScreen_triggered();
void on_actionVerticalCenter_triggered();
void on_actionHorizontalCenter_triggered();
void on_actionEditTransform_triggered();
void on_sources_customContextMenuRequested(const QPoint &pos);
// Source Context Buttons
void on_sourcePropertiesButton_clicked();
void on_sourceFiltersButton_clicked();
void on_sourceInteractButton_clicked();
void on_actionAddSource_triggered();
void on_actionRemoveSource_triggered();
void on_actionInteract_triggered();
void on_actionSourceProperties_triggered();
void on_actionSourceUp_triggered();
void on_actionSourceDown_triggered();
void on_actionMoveUp_triggered();
void on_actionMoveDown_triggered();
void on_actionMoveToTop_triggered();
void on_actionMoveToBottom_triggered();
void on_toggleSourceIcons_toggled(bool visible);
void OpenFilters(OBSSource source = nullptr);
void OpenProperties(OBSSource source = nullptr);
void OpenInteraction(OBSSource source = nullptr);
void OpenEditTransform(OBSSceneItem item = nullptr);
public:
void ResetAudioDevice(const char *sourceId, const char *deviceId, const char *deviceDesc, int channel);
QMenu *AddDeinterlacingMenu(QMenu *menu, obs_source_t *source);
QMenu *AddScaleFilteringMenu(QMenu *menu, obs_sceneitem_t *item);
QMenu *AddBlendingMethodMenu(QMenu *menu, obs_sceneitem_t *item);
QMenu *AddBlendingModeMenu(QMenu *menu, obs_sceneitem_t *item);
QMenu *AddBackgroundColorMenu(QMenu *menu, QWidgetAction *widgetAction, ColorSelect *select,
obs_sceneitem_t *item);
void CreateSourcePopupMenu(int idx, bool preview);
void actionOpenSourceFilters();
void actionOpenSourceProperties();
/* -------------------------------------
* MARK: - OBSBasic_Scenes
* -------------------------------------
*/
private:
QPointer<QMenu> sceneProjectorMenu;
QPointer<QAction> renameScene;
std::atomic<obs_scene_t *> currentScene = nullptr;
OBSWeakSource lastScene;
OBSWeakSource swapScene;
void LoadSceneListOrder(obs_data_array_t *array);
obs_data_array_t *SaveSceneListOrder();
void ChangeSceneIndex(bool relative, int idx, int invalidIdx);
void MoveSceneItem(enum obs_order_movement movement, const QString &action_name);
/* OBS Callbacks */
static void SceneReordered(void *data, calldata_t *params);
static void SceneRefreshed(void *data, calldata_t *params);
static void SceneItemAdded(void *data, calldata_t *params);
public slots:
void on_actionResetTransform_triggered();
private slots:
void AddSceneItem(OBSSceneItem item);
void AddScene(OBSSource source);
void RemoveScene(OBSSource source);
void DuplicateSelectedScene();
void RemoveSelectedScene();
SourceTreeItem *GetItemWidgetFromSceneItem(obs_sceneitem_t *sceneItem);
void on_actionSceneFilters_triggered();
void on_scenes_currentItemChanged(QListWidgetItem *current, QListWidgetItem *prev);
void on_scenes_customContextMenuRequested(const QPoint &pos);
void GridActionClicked();
void on_actionSceneListMode_triggered();
void on_actionSceneGridMode_triggered();
void on_actionAddScene_triggered();
void on_actionRemoveScene_triggered();
void on_actionSceneUp_triggered();
void on_actionSceneDown_triggered();
void on_scenes_itemDoubleClicked(QListWidgetItem *item);
void MoveSceneToTop();
void MoveSceneToBottom();
void EditSceneName();
void EditSceneItemName();
void SceneNameEdited(QWidget *editor);
void OpenSceneFilters();
public:
static OBSData BackupScene(obs_scene_t *scene, std::vector<obs_source_t *> *sources = nullptr);
static inline OBSData BackupScene(obs_source_t *scene_source, std::vector<obs_source_t *> *sources = nullptr)
{
obs_scene_t *scene = obs_scene_from_source(scene_source);
return BackupScene(scene, sources);
}
OBSScene GetCurrentScene();
inline OBSSource GetCurrentSceneSource()
{
OBSScene curScene = GetCurrentScene();
return OBSSource(obs_scene_get_source(curScene));
}
void CreateSceneUndoRedoAction(const QString &action_name, OBSData undo_data, OBSData redo_data);
/* -------------------------------------
* MARK: - OBSBasic_Screenshots
* -------------------------------------
*/
private:
QPointer<QObject> screenshotData;
std::string lastScreenshot;
private slots:
void Screenshot(OBSSource source_ = nullptr);
void ScreenshotSelectedSource();
void ScreenshotProgram();
void ScreenshotScene();
/* -------------------------------------
* MARK: - OBSBasic_Service
* -------------------------------------
*/
private:
OBSService service;
bool InitService();
public:
obs_service_t *GetService();
void SetService(obs_service_t *service);
void SaveService();
bool LoadService();
/* -------------------------------------
* MARK: - OBSBasic_StatusBar
* -------------------------------------
*/
private:
QPointer<QTimer> cpuUsageTimer;
os_cpu_usage_info_t *cpuUsageInfo = nullptr;
public:
inline double GetCPUUsage() const { return os_cpu_usage_info_query(cpuUsageInfo); }
void ShowStatusBarMessage(const QString &message);
/* -------------------------------------
* MARK: - OBSBasic_Streaming
* -------------------------------------
*/
private:
std::shared_future<void> setupStreamingGuard;
bool streamingStopping = false;
bool streamingStarting = false;
public slots:
void DisplayStreamStartError();
void StartStreaming();
void StopStreaming();
void ForceStopStreaming();
void StreamDelayStarting(int sec);
void StreamDelayStopping(int sec);
void StreamingStart();
void StreamStopping();
void StreamingStop(int errorcode, QString last_error);
bool StreamingActive();
private slots:
/* Stream action (start/stop) slot */
void StreamActionTriggered();
signals:
/* Streaming signals */
void StreamingPreparing();
void StreamingStarting(bool broadcastAutoStart);
void StreamingStarted(bool withDelay = false);
void StreamingStopping();
void StreamingStopped(bool withDelay = false);
/* -------------------------------------
* MARK: - OBSBasic_StudioMode
* -------------------------------------
*/
private:
QPointer<QMenu> studioProgramProjector;
QPointer<QWidget> programWidget;
QPointer<QVBoxLayout> programLayout;
QPointer<QLabel> programLabel;
QPointer<QWidget> programOptions;
QPointer<OBSQTDisplay> program;
OBSWeakSource lastProgramScene;
bool editPropertiesMode = false;
bool sceneDuplicationMode = true;
OBSWeakSource programScene;
volatile bool previewProgramMode = false;
obs_hotkey_pair_id togglePreviewProgramHotkeys = 0;
int programX = 0, programY = 0;
int programCX = 0, programCY = 0;
float programScale = 0.0f;
QPointer<PreviewProgramSizeObserver> sizeObserver;
void CreateProgramDisplay();
void CreateProgramOptions();
void SetPreviewProgramMode(bool enabled);
void ResizeProgram(uint32_t cx, uint32_t cy);
static void RenderProgram(void *data, uint32_t cx, uint32_t cy);
void UpdatePreviewProgramIndicators();
private slots:
void EnablePreviewProgram();
void DisablePreviewProgram();
void ProgramViewContextMenuRequested();
void OpenStudioProgramProjector();
void OpenStudioProgramWindow();
/* Studio Mode toggle slot */
void TogglePreviewProgramMode();
public:
OBSSource GetProgramSource();
inline bool IsPreviewProgramMode() const { return os_atomic_load_bool(&previewProgramMode); }
signals:
/* Studio Mode signal */
void PreviewProgramModeChanged(bool enabled);
/* -------------------------------------
* MARK: - OBSBasic_SysTray
* -------------------------------------
*/
private:
QPointer<QSystemTrayIcon> trayIcon;
QPointer<QAction> sysTrayStream;
QPointer<QAction> sysTrayRecord;
QPointer<QAction> sysTrayReplayBuffer;
QPointer<QAction> sysTrayVirtualCam;
QPointer<QMenu> trayMenu;
bool sysTrayMinimizeToTray();
void updateSysTrayProjectorMenu();
private slots:
void IconActivated(QSystemTrayIcon::ActivationReason reason);
public:
void SysTrayNotify(const QString &text, QSystemTrayIcon::MessageIcon n);
void SystemTrayInit();
void SystemTray(bool firstStarted);
/* -------------------------------------
* MARK: - OBSBasic_Transitions
* -------------------------------------
*/
private:
std::vector<OBSDataAutoRelease> safeModeTransitions;
QPointer<QPushButton> transitionButton;
QPointer<QMenu> perSceneTransitionMenu;
std::unordered_map<std::string, OBSSource> transitions;
// FIXME: Any code accessing this collection relies on order of insertion
std::vector<std::string> transitionUuids;
// FIXME: Replace usages of a name to identify a transition
std::unordered_map<std::string, std::string> transitionNameToUuids;
int transitionDuration;
std::string currentTransitionUuid;
obs_source_t *fadeTransition;
obs_source_t *cutTransition;
std::vector<QuickTransition> quickTransitions;
bool swapScenesMode = true;
obs_hotkey_id transitionHotkey = 0;
int quickTransitionIdCounter = 1;
bool overridingTransition = false;
QSlider *tBar;
bool tBarActive = false;
OBSSource prevFTBSource = nullptr;
void InitDefaultTransitions();
void InitTransition(obs_source_t *transition);
obs_source_t *FindTransition(const char *name);
OBSSource GetCurrentTransition();
obs_data_array_t *SaveTransitions();
void LoadTransitions(obs_data_array_t *transitions, obs_load_source_cb cb, void *private_data);
void AddQuickTransitionId(int id);
void AddQuickTransition();
void AddQuickTransitionHotkey(QuickTransition *qt);
void RemoveQuickTransitionHotkey(QuickTransition *qt);
void LoadQuickTransitions(obs_data_array_t *array);
obs_data_array_t *SaveQuickTransitions();
void ClearQuickTransitionWidgets();
void RefreshQuickTransitions();
// TODO: Remove orphaned method.
void DisableQuickTransitionWidgets();
void EnableTransitionWidgets(bool enable);
void CreateDefaultQuickTransitions();
QuickTransition *GetQuickTransition(int id);
int GetQuickTransitionIdx(int id);
QMenu *CreateTransitionMenu(QWidget *parent, QuickTransition *qt);
void ClearQuickTransitions();
void QuickTransitionClicked();
void QuickTransitionChange();
void QuickTransitionChangeDuration(int value);
void QuickTransitionRemoveClicked();
OBSSource GetOverrideTransition(OBSSource source);
int GetOverrideTransitionDuration(OBSSource source);
QMenu *CreatePerSceneTransitionMenu();
void SetCurrentScene(obs_scene_t *scene, bool force = false);
void PasteShowHideTransition(obs_sceneitem_t *item, bool show, obs_source_t *tr, int duration);
void UpdateCurrentTransition(const std::string &uuid, bool setTransition);
public slots:
void SetCurrentScene(OBSSource scene, bool force = false);
void SetTransition(OBSSource transition);
void OverrideTransition(OBSSource transition);
void TransitionToScene(OBSScene scene, bool force = false);
void TransitionToScene(OBSSource scene, bool force = false, bool quickTransition = false, int quickDuration = 0,
bool black = false, bool manual = false);
void SetCurrentTransition(const QString &uuid);
void SetTransitionDuration(int duration);
private slots:
void AddTransition(const char *id);
void RenameTransition(OBSSource transition);
void TransitionClicked();
void TransitionStopped();
void TransitionFullyStopped();
void TriggerQuickTransition(int id);
void TBarChanged(int value);
void TBarReleased();
void on_transitionAdd_clicked();
void on_transitionRemove_clicked();
void on_transitionProps_clicked();
void ShowTransitionProperties();
void HideTransitionProperties();
signals:
void TransitionAdded(const QString &name, const QString &uuid);
void TransitionRenamed(const QString &uuid, const QString &newName);
void TransitionRemoved(const QString &uuid);
void TransitionsCleared();
void CurrentTransitionChanged(const QString &uuid);
void TransitionDurationChanged(const int &duration);
public:
int GetTransitionDuration();
int GetTbarPosition();
/* -------------------------------------
* MARK: - OBSBasic_Updater
* -------------------------------------
*/
private:
QScopedPointer<QThread> whatsNewInitThread;
QScopedPointer<QThread> updateCheckThread;
QScopedPointer<QThread> introCheckThread;
void TimedCheckForUpdates();
void CheckForUpdates(bool manualUpdate);
void MacBranchesFetched(const QString &branch, bool manualUpdate);
void ReceivedIntroJson(const QString &text);
void ShowWhatsNew(const QString &url);
/* -------------------------------------
* MARK: - OBSBasic_VirtualCam
* -------------------------------------
*/
private:
bool vcamEnabled = false;
VCamConfig vcamConfig;
bool restartingVCam = false;
public slots:
void StartVirtualCam();
void StopVirtualCam();
void OnVirtualCamStart();
void OnVirtualCamStop(int code);
bool VirtualCamActive();
private slots:
void UpdateVirtualCamConfig(const VCamConfig &config);
void RestartVirtualCam(const VCamConfig &config);
void RestartingVirtualCam();
/* Virtual Cam action (start/stop) slots */
void VirtualCamActionTriggered();
void OpenVirtualCamConfig();
public:
inline bool VCamEnabled() const { return vcamEnabled; }
signals:
/* Virtual Camera signals */
void VirtualCamEnabled();
void VirtualCamStarted();
void VirtualCamStopped();
/* -------------------------------------
* MARK: - OBSBasic_YouTube
* -------------------------------------
*/
private:
bool autoStartBroadcast = true;
bool autoStopBroadcast = true;
bool broadcastActive = false;
bool broadcastReady = false;
QPointer<QThread> youtubeStreamCheckThread;
#ifdef YOUTUBE_ENABLED
QPointer<YouTubeAppDock> youtubeAppDock;
uint64_t lastYouTubeAppDockCreationTime = 0;
void YoutubeStreamCheck(const std::string &key);
void ShowYouTubeAutoStartWarning();
void YouTubeActionDialogOk(const QString &broadcast_id, const QString &stream_id, const QString &key,
bool autostart, bool autostop, bool start_now);
#endif
void BroadcastButtonClicked();
void SetBroadcastFlowEnabled(bool enabled);
public:
#ifdef YOUTUBE_ENABLED
void NewYouTubeAppDock();
void DeleteYouTubeAppDock();
YouTubeAppDock *GetYouTubeAppDock();
#endif
public slots:
void SetupBroadcast();
signals:
/* Broadcast Flow signals */
void BroadcastFlowEnabled(bool enabled);
void BroadcastStreamReady(bool ready);
void BroadcastStreamActive();
void BroadcastStreamStarted(bool autoStop);
};