2013-11-07 16:45:03 -07:00
/******************************************************************************
2023-05-18 17:37:26 -07:00
Copyright ( C ) 2023 by Lain Bailey < lain @ obsproject . com >
Zachary Lund < admin @ computerquip . com >
Philippe Groarke < philippe . groarke @ gmail . com >
2013-11-07 16:45:03 -07:00
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
2013-12-02 22:24:38 -07:00
the Free Software Foundation , either version 2 of the License , or
2013-11-07 16:45:03 -07:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
2013-11-09 00:19:38 -07:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2013-11-07 16:45:03 -07:00
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/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2024-12-11 17:43:35 +01:00
# include "OBSBasic.hpp"
# include "ui-config.h"
# include "ColorSelect.hpp"
# include "OBSBasicControls.hpp"
# include "OBSBasicStats.hpp"
# include "VolControl.hpp"
2013-12-29 09:17:00 -07:00
2023-07-12 23:10:52 +09:00
# ifdef YOUTUBE_ENABLED
2024-12-11 17:43:35 +01:00
# include <docks/YouTubeAppDock.hpp>
# endif
# include <dialogs/NameDialog.hpp>
# include <dialogs/OBSAbout.hpp>
# include <dialogs/OBSBasicAdvAudio.hpp>
# include <dialogs/OBSBasicFilters.hpp>
# include <dialogs/OBSBasicInteraction.hpp>
# include <dialogs/OBSBasicProperties.hpp>
# include <dialogs/OBSBasicTransform.hpp>
2025-01-22 20:44:35 +01:00
# include <models/SceneCollection.hpp>
2024-12-11 17:43:35 +01:00
# include <settings/OBSBasicSettings.hpp>
# include <utility/QuickTransition.hpp>
# include <utility/SceneRenameDelegate.hpp>
# if defined(_WIN32) || defined(WHATSNEW_ENABLED)
# include <utility/WhatsNewInfoThread.hpp>
# endif
# include <widgets/OBSProjector.hpp>
# include <OBSStudioAPI.hpp>
# ifdef BROWSER_AVAILABLE
# include <browser-panel.hpp>
2022-11-05 22:32:43 +01:00
# endif
2020-08-19 15:09:26 -03:00
# ifdef ENABLE_WAYLAND
# include <obs-nix-platform.h>
# endif
2024-12-11 17:43:35 +01:00
# include <qt-wrappers.hpp>
2020-08-19 15:09:26 -03:00
2024-12-11 17:43:35 +01:00
# include <QActionGroup>
# include <QThread>
# include <QWidgetAction>
2013-11-22 16:20:52 -07:00
2024-12-11 17:43:35 +01:00
# ifdef _WIN32
# include <sstream>
2018-07-27 21:35:08 -07:00
# endif
2024-12-11 17:43:35 +01:00
# include <string>
# include <unordered_set>
2018-07-27 21:35:08 -07:00
2024-12-11 17:43:35 +01:00
# ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include "Windows.h"
# endif
2019-02-06 22:44:28 -08:00
2024-12-11 17:43:35 +01:00
# include "moc_OBSBasic.cpp"
2019-02-06 22:10:08 -08:00
2024-12-11 17:43:35 +01:00
using namespace std ;
2019-02-06 22:10:08 -08:00
2024-12-11 17:43:35 +01:00
extern bool portable_mode ;
extern bool disable_3p_plugins ;
extern bool opt_studio_mode ;
extern bool opt_always_on_top ;
extern bool opt_minimize_tray ;
2024-10-10 14:02:54 +02:00
extern std : : string opt_starting_profile ;
extern std : : string opt_starting_collection ;
2024-12-11 17:43:35 +01:00
extern bool safe_mode ;
extern bool opt_start_recording ;
extern bool opt_start_replaybuffer ;
extern bool opt_start_virtualcam ;
2015-12-05 05:53:38 -08:00
2019-03-26 22:01:22 -07:00
extern volatile long insideEventLoop ;
2024-12-11 17:43:35 +01:00
extern bool restart ;
2019-03-26 22:01:22 -07:00
2024-12-11 17:43:35 +01:00
extern bool EncoderAvailable ( const char * encoder ) ;
2014-02-02 14:26:23 -07:00
2024-12-11 17:43:35 +01:00
extern void RegisterTwitchAuth ( ) ;
extern void RegisterRestreamAuth ( ) ;
# ifdef YOUTUBE_ENABLED
extern void RegisterYoutubeAuth ( ) ;
# endif
2019-08-27 20:08:43 +12:00
2024-12-11 17:43:35 +01:00
struct QCef ;
2019-08-27 20:08:43 +12:00
2024-12-11 17:43:35 +01:00
extern QCef * cef ;
extern bool cef_js_avail ;
2015-06-28 03:21:45 +02:00
2024-12-11 17:43:35 +01:00
extern void DestroyPanelCookieManager ( ) ;
extern void CheckExistingCookieId ( ) ;
2015-06-28 03:21:45 +02:00
2014-07-27 12:48:14 -07:00
static void AddExtraModulePaths ( )
{
2022-10-06 23:39:31 +02:00
string plugins_path , plugins_data_path ;
char * s ;
s = getenv ( " OBS_PLUGINS_PATH " ) ;
if ( s )
plugins_path = s ;
s = getenv ( " OBS_PLUGINS_DATA_PATH " ) ;
if ( s )
plugins_data_path = s ;
if ( ! plugins_path . empty ( ) & & ! plugins_data_path . empty ( ) ) {
2024-10-31 18:16:28 +01:00
# if defined(__APPLE__)
plugins_path + = " /%module%.plugin/Contents/MacOS " ;
plugins_data_path + = " /%module%.plugin/Contents/Resources " ;
obs_add_module_path ( plugins_path . c_str ( ) , plugins_data_path . c_str ( ) ) ;
# else
2021-01-14 17:34:21 +03:00
string data_path_with_module_suffix ;
data_path_with_module_suffix + = plugins_data_path ;
data_path_with_module_suffix + = " /%module% " ;
2022-10-06 23:39:31 +02:00
obs_add_module_path ( plugins_path . c_str ( ) , data_path_with_module_suffix . c_str ( ) ) ;
2024-10-31 18:16:28 +01:00
# endif
2021-01-14 17:34:21 +03:00
}
2023-01-18 11:30:35 +01:00
if ( portable_mode )
return ;
2015-01-15 23:44:38 -08:00
char base_module_dir [ 512 ] ;
2022-08-16 16:27:17 +02:00
# if defined(_WIN32)
2016-07-06 01:35:12 -07:00
int ret = GetProgramDataPath ( base_module_dir , sizeof ( base_module_dir ) , " obs-studio/plugins/%module% " ) ;
2022-08-16 16:27:17 +02:00
# elif defined(__APPLE__)
2024-09-03 16:28:36 +02:00
int ret = GetAppConfigPath ( base_module_dir , sizeof ( base_module_dir ) , " obs-studio/plugins/%module%.plugin " ) ;
2016-07-06 01:35:12 -07:00
# else
2024-09-03 16:28:36 +02:00
int ret = GetAppConfigPath ( base_module_dir , sizeof ( base_module_dir ) , " obs-studio/plugins/%module% " ) ;
2016-07-06 01:35:12 -07:00
# endif
2014-08-31 16:28:36 +02:00
2015-01-15 23:44:38 -08:00
if ( ret < = 0 )
2014-07-27 12:48:14 -07:00
return ;
2019-08-17 08:49:08 -07:00
string path = base_module_dir ;
2015-07-14 18:05:26 -07:00
# if defined(__APPLE__)
2022-03-16 23:11:58 +01:00
/* User Application Support Search Path */
2022-08-16 16:27:17 +02:00
obs_add_module_path ( ( path + " /Contents/MacOS " ) . c_str ( ) , ( path + " /Contents/Resources " ) . c_str ( ) ) ;
2022-03-16 23:11:58 +01:00
2022-08-16 02:38:55 +02:00
# ifndef __aarch64__
2022-03-16 23:11:58 +01:00
/* Legacy System Library Search Path */
2022-08-16 16:27:17 +02:00
char system_legacy_module_dir [ PATH_MAX ] ;
GetProgramDataPath ( system_legacy_module_dir , sizeof ( system_legacy_module_dir ) , " obs-studio/plugins/%module% " ) ;
std : : string path_system_legacy = system_legacy_module_dir ;
obs_add_module_path ( ( path_system_legacy + " /bin " ) . c_str ( ) , ( path_system_legacy + " /data " ) . c_str ( ) ) ;
2017-05-28 12:27:58 -05:00
2022-03-16 23:11:58 +01:00
/* Legacy User Application Support Search Path */
2022-08-16 16:27:17 +02:00
char user_legacy_module_dir [ PATH_MAX ] ;
2024-09-03 16:28:36 +02:00
GetAppConfigPath ( user_legacy_module_dir , sizeof ( user_legacy_module_dir ) , " obs-studio/plugins/%module% " ) ;
2022-08-16 16:27:17 +02:00
std : : string path_user_legacy = user_legacy_module_dir ;
obs_add_module_path ( ( path_user_legacy + " /bin " ) . c_str ( ) , ( path_user_legacy + " /data " ) . c_str ( ) ) ;
2022-08-16 02:38:55 +02:00
# endif
2022-03-16 23:11:58 +01:00
# else
# if ARCH_BITS == 64
2015-07-14 18:05:26 -07:00
obs_add_module_path ( ( path + " /bin/64bit " ) . c_str ( ) , ( path + " /data " ) . c_str ( ) ) ;
# else
obs_add_module_path ( ( path + " /bin/32bit " ) . c_str ( ) , ( path + " /data " ) . c_str ( ) ) ;
# endif
2022-03-16 23:11:58 +01:00
# endif
2014-07-27 12:48:14 -07:00
}
2023-03-13 03:09:52 +01:00
/* First-party modules considered to be potentially unsafe to load in Safe Mode
* due to them allowing external code ( e . g . scripts ) to modify OBS ' s state . */
static const unordered_set < string > unsafe_modules = {
" frontend-tools " , // Scripting
" obs-websocket " , // Allows outside modifications
} ;
static void SetSafeModuleNames ( )
{
# ifndef SAFE_MODULES
return ;
# else
string module ;
stringstream modules ( SAFE_MODULES ) ;
while ( getline ( modules , module , ' | ' ) ) {
/* When only disallowing third-party plugins, still add
* " unsafe " bundled modules to the safe list . */
if ( disable_3p_plugins | | ! unsafe_modules . count ( module ) )
obs_add_safe_module ( module . c_str ( ) ) ;
}
# endif
}
2024-12-11 17:43:35 +01:00
extern void setupDockAction ( QDockWidget * dock ) ;
2019-02-06 22:44:28 -08:00
2014-02-02 15:23:38 -07:00
OBSBasic : : OBSBasic ( QWidget * parent ) : OBSMainWindow ( parent ) , undo_s ( ui ) , ui ( new Ui : : OBSBasic )
{
2025-01-22 20:44:35 +01:00
collections = { } ;
2017-01-25 00:45:22 -02:00
setAttribute ( Qt : : WA_NativeWindow ) ;
2023-07-12 23:10:52 +09:00
# ifdef TWITCH_ENABLED
2019-02-06 22:45:06 -08:00
RegisterTwitchAuth ( ) ;
# endif
2023-07-12 23:10:52 +09:00
# ifdef RESTREAM_ENABLED
2019-02-14 20:35:47 +02:00
RegisterRestreamAuth ( ) ;
# endif
2023-07-12 23:10:52 +09:00
# ifdef YOUTUBE_ENABLED
2021-06-27 15:30:00 -07:00
RegisterYoutubeAuth ( ) ;
# endif
2019-02-06 22:44:28 -08:00
2016-09-26 12:40:23 -07:00
setAcceptDrops ( true ) ;
2020-02-14 23:30:34 +11:00
setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
2024-04-11 16:28:40 +02:00
QEvent : : registerEventType ( QEvent : : User + QEvent : : Close ) ;
2018-06-01 22:42:11 -07:00
api = InitializeAPIInterface ( this ) ;
2014-02-02 15:23:38 -07:00
ui - > setupUi ( this ) ;
2019-07-12 11:11:49 -05:00
ui - > previewDisabledWidget - > setVisible ( false ) ;
2024-04-03 15:14:29 +02:00
2024-04-06 15:37:34 +02:00
/* Set up streaming connections */
connect (
this , & OBSBasic : : StreamingStarting , this , [ this ] { this - > streamingStarting = true ; } ,
Qt : : DirectConnection ) ;
connect (
this , & OBSBasic : : StreamingStarted , this , [ this ] { this - > streamingStarting = false ; } ,
Qt : : DirectConnection ) ;
connect (
this , & OBSBasic : : StreamingStopped , this , [ this ] { this - > streamingStarting = false ; } ,
Qt : : DirectConnection ) ;
2024-04-03 17:08:14 +02:00
/* Set up recording connections */
connect (
this , & OBSBasic : : RecordingStarted , this ,
[ this ] ( ) {
this - > recordingStarted = true ;
this - > recordingPaused = false ;
} ,
Qt : : DirectConnection ) ;
connect (
this , & OBSBasic : : RecordingPaused , this , [ this ] ( ) { this - > recordingPaused = true ; } ,
Qt : : DirectConnection ) ;
connect (
this , & OBSBasic : : RecordingUnpaused , this , [ this ] ( ) { this - > recordingPaused = false ; } ,
Qt : : DirectConnection ) ;
connect (
this , & OBSBasic : : RecordingStopped , this ,
[ this ] ( ) {
this - > recordingStarted = false ;
this - > recordingPaused = false ;
} ,
Qt : : DirectConnection ) ;
2024-04-03 14:35:10 +02:00
/* Add controls dock */
OBSBasicControls * controls = new OBSBasicControls ( this ) ;
controlsDock = new OBSDock ( this ) ;
controlsDock - > setObjectName ( QString : : fromUtf8 ( " controlsDock " ) ) ;
controlsDock - > setWindowTitle ( QTStr ( " Basic.Main.Controls " ) ) ;
/* Parenting is done there so controls will be deleted alongside controlsDock */
controlsDock - > setWidget ( controls ) ;
addDockWidget ( Qt : : BottomDockWidgetArea , controlsDock ) ;
connect ( controls , & OBSBasicControls : : StreamButtonClicked , this , & OBSBasic : : StreamActionTriggered ) ;
connect ( controls , & OBSBasicControls : : StartStreamMenuActionClicked , this , & OBSBasic : : StartStreaming ) ;
connect ( controls , & OBSBasicControls : : StopStreamMenuActionClicked , this , & OBSBasic : : StopStreaming ) ;
connect ( controls , & OBSBasicControls : : ForceStopStreamMenuActionClicked , this , & OBSBasic : : ForceStopStreaming ) ;
connect ( controls , & OBSBasicControls : : BroadcastButtonClicked , this , & OBSBasic : : BroadcastButtonClicked ) ;
connect ( controls , & OBSBasicControls : : RecordButtonClicked , this , & OBSBasic : : RecordActionTriggered ) ;
connect ( controls , & OBSBasicControls : : PauseRecordButtonClicked , this , & OBSBasic : : RecordPauseToggled ) ;
connect ( controls , & OBSBasicControls : : ReplayBufferButtonClicked , this , & OBSBasic : : ReplayBufferActionTriggered ) ;
connect ( controls , & OBSBasicControls : : SaveReplayBufferButtonClicked , this , & OBSBasic : : ReplayBufferSave ) ;
connect ( controls , & OBSBasicControls : : VirtualCamButtonClicked , this , & OBSBasic : : VirtualCamActionTriggered ) ;
connect ( controls , & OBSBasicControls : : VirtualCamConfigButtonClicked , this , & OBSBasic : : OpenVirtualCamConfig ) ;
connect ( controls , & OBSBasicControls : : StudioModeButtonClicked , this , & OBSBasic : : TogglePreviewProgramMode ) ;
connect ( controls , & OBSBasicControls : : SettingsButtonClicked , this , & OBSBasic : : on_action_Settings_triggered ) ;
2017-07-27 02:40:41 -07:00
startingDockLayout = saveState ( ) ;
2019-03-05 14:37:01 -08:00
statsDock = new OBSDock ( ) ;
2018-09-16 10:02:43 -07:00
statsDock - > setObjectName ( QStringLiteral ( " statsDock " ) ) ;
2020-06-07 15:31:13 -07:00
statsDock - > setFeatures ( QDockWidget : : DockWidgetClosable | QDockWidget : : DockWidgetMovable |
QDockWidget : : DockWidgetFloatable ) ;
2018-09-16 10:02:43 -07:00
statsDock - > setWindowTitle ( QTStr ( " Basic.Stats " ) ) ;
addDockWidget ( Qt : : BottomDockWidgetArea , statsDock ) ;
statsDock - > setVisible ( false ) ;
statsDock - > setFloating ( true ) ;
statsDock - > resize ( 700 , 200 ) ;
2015-02-17 02:45:34 -05:00
copyActionsDynamicProperties ( ) ;
2014-04-16 22:35:01 +02:00
2021-07-02 22:54:59 +02:00
qRegisterMetaType < int64_t > ( " int64_t " ) ;
qRegisterMetaType < uint32_t > ( " uint32_t " ) ;
2014-10-29 15:54:45 +01:00
qRegisterMetaType < OBSScene > ( " OBSScene " ) ;
qRegisterMetaType < OBSSceneItem > ( " OBSSceneItem " ) ;
qRegisterMetaType < OBSSource > ( " OBSSource " ) ;
2014-11-01 21:48:58 +01:00
qRegisterMetaType < obs_hotkey_id > ( " obs_hotkey_id " ) ;
2019-06-01 13:13:24 +10:00
qRegisterMetaType < SavedProjectorInfo * > ( " SavedProjectorInfo * " ) ;
2014-10-29 15:54:45 +01:00
2014-10-29 17:18:00 +01:00
ui - > scenes - > setAttribute ( Qt : : WA_MacShowFocusRect , false ) ;
ui - > sources - > setAttribute ( Qt : : WA_MacShowFocusRect , false ) ;
2024-09-03 16:28:36 +02:00
bool sceneGrid = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " gridMode " ) ;
2019-08-27 20:08:43 +12:00
ui - > scenes - > SetGridMode ( sceneGrid ) ;
2023-02-08 03:57:51 -06:00
if ( sceneGrid )
ui - > actionSceneGridMode - > setChecked ( true ) ;
else
ui - > actionSceneListMode - > setChecked ( true ) ;
2019-04-07 03:34:21 -04:00
ui - > scenes - > setItemDelegate ( new SceneRenameDelegate ( ui - > scenes ) ) ;
2016-01-09 14:47:58 -08:00
auto displayResize = [ this ] ( ) {
2014-04-16 22:35:01 +02:00
struct obs_video_info ovi ;
if ( obs_get_video_info ( & ovi ) )
ResizePreview ( ovi . base_width , ovi . base_height ) ;
2021-10-13 13:23:11 +02:00
UpdateContextBarVisibility ( ) ;
2024-08-23 23:08:07 -05:00
UpdatePreviewControls ( ) ;
2022-07-29 20:31:13 +02:00
dpi = devicePixelRatioF ( ) ;
2016-01-09 14:47:58 -08:00
} ;
2022-07-29 20:31:13 +02:00
dpi = devicePixelRatioF ( ) ;
2016-01-09 14:47:58 -08:00
connect ( windowHandle ( ) , & QWindow : : screenChanged , displayResize ) ;
connect ( ui - > preview , & OBSQTDisplay : : DisplayResized , displayResize ) ;
2014-05-15 14:04:18 -07:00
2024-07-31 10:53:59 -04:00
/* TODO: Move these into window-basic-preview */
/* Preview Scaling label */
connect ( ui - > preview , & OBSBasicPreview : : scalingChanged , ui - > previewScalePercent ,
& OBSPreviewScalingLabel : : PreviewScaleChanged ) ;
/* Preview Scaling dropdown */
connect ( ui - > preview , & OBSBasicPreview : : scalingChanged , ui - > previewScalingMode ,
& OBSPreviewScalingComboBox : : PreviewScaleChanged ) ;
connect ( ui - > preview , & OBSBasicPreview : : fixedScalingChanged , ui - > previewScalingMode ,
& OBSPreviewScalingComboBox : : PreviewFixedScalingChanged ) ;
connect ( ui - > previewScalingMode , & OBSPreviewScalingComboBox : : currentIndexChanged , this ,
& OBSBasic : : PreviewScalingModeChanged ) ;
2024-08-23 23:08:07 -05:00
/* Preview Controls */
connect ( ui - > previewXScrollBar , & QScrollBar : : sliderMoved , ui - > preview , & OBSBasicPreview : : xScrollBarChanged ) ;
connect ( ui - > previewYScrollBar , & QScrollBar : : valueChanged , ui - > preview , & OBSBasicPreview : : yScrollBarChanged ) ;
connect ( ui - > previewZoomInButton , & QPushButton : : clicked , ui - > preview , & OBSBasicPreview : : increaseScalingLevel ) ;
connect ( ui - > previewZoomOutButton , & QPushButton : : clicked , ui - > preview , & OBSBasicPreview : : decreaseScalingLevel ) ;
/* Preview Actions */
connect ( ui - > actionScaleWindow , & QAction : : triggered , this , & OBSBasic : : setPreviewScalingWindow ) ;
connect ( ui - > actionScaleCanvas , & QAction : : triggered , this , & OBSBasic : : setPreviewScalingCanvas ) ;
connect ( ui - > actionScaleOutput , & QAction : : triggered , this , & OBSBasic : : setPreviewScalingOutput ) ;
connect ( ui - > actionPreviewZoomIn , & QAction : : triggered , ui - > preview , & OBSBasicPreview : : increaseScalingLevel ) ;
connect ( ui - > actionPreviewZoomOut , & QAction : : triggered , ui - > preview , & OBSBasicPreview : : decreaseScalingLevel ) ;
connect ( ui - > actionPreviewResetZoom , & QAction : : triggered , ui - > preview , & OBSBasicPreview : : resetScalingLevel ) ;
2024-07-31 10:53:59 -04:00
connect ( this , & OBSBasic : : CanvasResized , ui - > previewScalingMode , & OBSPreviewScalingComboBox : : CanvasResized ) ;
connect ( this , & OBSBasic : : OutputResized , ui - > previewScalingMode , & OBSPreviewScalingComboBox : : OutputResized ) ;
2020-04-19 09:31:18 -05:00
delete shortcutFilter ;
shortcutFilter = CreateShortcutFilter ( ) ;
2019-01-31 03:33:15 +01:00
installEventFilter ( shortcutFilter ) ;
2014-11-01 21:48:58 +01:00
2015-07-05 23:41:36 -07:00
stringstream name ;
2016-08-21 11:26:15 -07:00
name < < " OBS " < < App ( ) - > GetVersionString ( ) ;
2015-07-05 23:41:36 -07:00
blog ( LOG_INFO , " %s " , name . str ( ) . c_str ( ) ) ;
blog ( LOG_INFO , " --------------------------------- " ) ;
2015-07-03 17:55:55 -07:00
UpdateTitleBar ( ) ;
2014-06-30 00:06:01 -07:00
2023-03-28 22:04:34 +02:00
connect ( ui - > scenes - > itemDelegate ( ) , & QAbstractItemDelegate : : closeEditor , this , & OBSBasic : : SceneNameEdited ) ;
2014-06-30 00:06:01 -07:00
2014-07-06 16:18:16 -07:00
cpuUsageInfo = os_cpu_usage_info_start ( ) ;
2014-07-06 16:19:27 -07:00
cpuUsageTimer = new QTimer ( this ) ;
2023-03-28 22:04:34 +02:00
connect ( cpuUsageTimer . data ( ) , & QTimer : : timeout , ui - > statusbar , & OBSBasicStatusBar : : UpdateCPUUsage ) ;
2014-07-06 16:19:27 -07:00
cpuUsageTimer - > start ( 3000 ) ;
2014-07-13 21:46:23 +02:00
2019-06-12 04:56:00 -05:00
diskFullTimer = new QTimer ( this ) ;
2023-03-28 22:04:34 +02:00
connect ( diskFullTimer , & QTimer : : timeout , this , & OBSBasic : : CheckDiskSpaceRemaining ) ;
2019-06-12 04:56:00 -05:00
2023-05-27 04:54:05 -05:00
renameScene = new QAction ( QTStr ( " Rename " ) , ui - > scenesDock ) ;
2018-08-31 21:42:44 -03:00
renameScene - > setShortcutContext ( Qt : : WidgetWithChildrenShortcut ) ;
2023-03-28 22:04:34 +02:00
connect ( renameScene , & QAction : : triggered , this , & OBSBasic : : EditSceneName ) ;
2018-08-31 21:42:44 -03:00
ui - > scenesDock - > addAction ( renameScene ) ;
2023-05-27 04:54:05 -05:00
renameSource = new QAction ( QTStr ( " Rename " ) , ui - > sourcesDock ) ;
2018-08-31 21:42:44 -03:00
renameSource - > setShortcutContext ( Qt : : WidgetWithChildrenShortcut ) ;
2023-03-28 22:04:34 +02:00
connect ( renameSource , & QAction : : triggered , this , & OBSBasic : : EditSceneItemName ) ;
2018-08-31 21:42:44 -03:00
ui - > sourcesDock - > addAction ( renameSource ) ;
2014-07-13 21:46:23 +02:00
# ifdef __APPLE__
2018-08-31 21:42:44 -03:00
renameScene - > setShortcut ( { Qt : : Key_Return } ) ;
renameSource - > setShortcut ( { Qt : : Key_Return } ) ;
2018-03-03 02:54:12 -03:00
ui - > actionRemoveSource - > setShortcuts ( { Qt : : Key_Backspace } ) ;
ui - > actionRemoveScene - > setShortcuts ( { Qt : : Key_Backspace } ) ;
2014-07-21 03:06:02 +02:00
2022-01-23 12:14:22 +01:00
ui - > actionCheckForUpdates - > setMenuRole ( QAction : : AboutQtRole ) ;
2014-07-21 03:06:02 +02:00
ui - > action_Settings - > setMenuRole ( QAction : : PreferencesRole ) ;
2022-07-26 01:31:12 +02:00
ui - > actionShowMacPermissions - > setMenuRole ( QAction : : ApplicationSpecificRole ) ;
2014-07-21 03:06:02 +02:00
ui - > actionE_xit - > setMenuRole ( QAction : : QuitRole ) ;
2018-08-31 21:42:44 -03:00
# else
renameScene - > setShortcut ( { Qt : : Key_F2 } ) ;
renameSource - > setShortcut ( { Qt : : Key_F2 } ) ;
2014-07-13 21:46:23 +02:00
# endif
2015-04-02 23:09:13 -07:00
2020-10-01 11:45:46 -04:00
# ifdef __linux__
2022-07-19 15:31:49 +02:00
ui - > actionE_xit - > setShortcut ( Qt : : CTRL | Qt : : Key_Q ) ;
2020-10-01 11:45:46 -04:00
# endif
2023-02-12 22:48:44 +01:00
auto addNudge = [ this ] ( const QKeySequence & seq , MoveDir direction , int distance ) {
2015-04-02 23:09:13 -07:00
QAction * nudge = new QAction ( ui - > preview ) ;
nudge - > setShortcut ( seq ) ;
nudge - > setShortcutContext ( Qt : : WidgetShortcut ) ;
ui - > preview - > addAction ( nudge ) ;
2023-02-12 22:48:44 +01:00
connect ( nudge , & QAction : : triggered , [ this , distance , direction ] ( ) { Nudge ( distance , direction ) ; } ) ;
2015-04-02 23:09:13 -07:00
} ;
2023-02-12 22:48:44 +01:00
addNudge ( Qt : : Key_Up , MoveDir : : Up , 1 ) ;
addNudge ( Qt : : Key_Down , MoveDir : : Down , 1 ) ;
addNudge ( Qt : : Key_Left , MoveDir : : Left , 1 ) ;
addNudge ( Qt : : Key_Right , MoveDir : : Right , 1 ) ;
addNudge ( Qt : : SHIFT | Qt : : Key_Up , MoveDir : : Up , 10 ) ;
addNudge ( Qt : : SHIFT | Qt : : Key_Down , MoveDir : : Down , 10 ) ;
addNudge ( Qt : : SHIFT | Qt : : Key_Left , MoveDir : : Left , 10 ) ;
addNudge ( Qt : : SHIFT | Qt : : Key_Right , MoveDir : : Right , 10 ) ;
2017-07-27 02:40:41 -07:00
2022-10-21 16:35:56 +02:00
/* Setup dock toggle action
* And hide all docks before restoring parent geometry */
# define SETUP_DOCK(dock) \
setupDockAction ( dock ) ; \
ui - > menuDocks - > addAction ( dock - > toggleViewAction ( ) ) ; \
dock - > setVisible ( false ) ;
SETUP_DOCK ( ui - > scenesDock ) ;
SETUP_DOCK ( ui - > sourcesDock ) ;
SETUP_DOCK ( ui - > mixerDock ) ;
SETUP_DOCK ( ui - > transitionsDock ) ;
2024-04-03 14:35:10 +02:00
SETUP_DOCK ( controlsDock ) ;
2022-10-21 16:35:56 +02:00
SETUP_DOCK ( statsDock ) ;
# undef SETUP_DOCK
2017-08-12 19:45:25 +02:00
2021-03-22 00:39:02 -04:00
// Register shortcuts for Undo/Redo
2022-07-19 15:31:49 +02:00
ui - > actionMainUndo - > setShortcut ( Qt : : CTRL | Qt : : Key_Z ) ;
2021-03-22 00:39:02 -04:00
QList < QKeySequence > shrt ;
2022-07-19 15:31:49 +02:00
shrt < < QKeySequence ( ( Qt : : CTRL | Qt : : SHIFT ) | Qt : : Key_Z ) < < QKeySequence ( Qt : : CTRL | Qt : : Key_Y ) ;
2021-03-22 00:39:02 -04:00
ui - > actionMainRedo - > setShortcuts ( shrt ) ;
ui - > actionMainUndo - > setShortcutContext ( Qt : : ApplicationShortcut ) ;
ui - > actionMainRedo - > setShortcutContext ( Qt : : ApplicationShortcut ) ;
2018-09-16 10:02:43 -07:00
QPoint curPos ;
2017-08-12 19:45:25 +02:00
//restore parent window geometry
2024-09-03 16:28:36 +02:00
const char * geometry = config_get_string ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " geometry " ) ;
2017-08-12 19:45:25 +02:00
if ( geometry ! = NULL ) {
QByteArray byteArray = QByteArray : : fromBase64 ( QByteArray ( geometry ) ) ;
restoreGeometry ( byteArray ) ;
QRect windowGeometry = normalGeometry ( ) ;
if ( ! WindowPositionValid ( windowGeometry ) ) {
2021-03-04 21:30:03 -08:00
QRect rect = QGuiApplication : : primaryScreen ( ) - > geometry ( ) ;
2017-08-12 19:45:25 +02:00
setGeometry ( QStyle : : alignedRect ( Qt : : LeftToRight , Qt : : AlignCenter , size ( ) , rect ) ) ;
}
2018-09-16 10:02:43 -07:00
curPos = pos ( ) ;
} else {
QRect desktopRect = QGuiApplication : : primaryScreen ( ) - > geometry ( ) ;
QSize adjSize = desktopRect . size ( ) / 2 - size ( ) / 2 ;
curPos = QPoint ( adjSize . width ( ) , adjSize . height ( ) ) ;
2017-08-12 19:45:25 +02:00
}
2018-09-16 10:02:43 -07:00
QPoint curSize ( width ( ) , height ( ) ) ;
2020-05-15 07:34:54 -05:00
2018-09-16 10:02:43 -07:00
QPoint statsDockSize ( statsDock - > width ( ) , statsDock - > height ( ) ) ;
QPoint statsDockPos = curSize / 2 - statsDockSize / 2 ;
QPoint newPos = curPos + statsDockPos ;
statsDock - > move ( newPos ) ;
2019-02-28 15:29:41 -06:00
2020-03-22 11:32:01 +11:00
# ifdef HAVE_OBSCONFIG_H
ui - > actionReleaseNotes - > setVisible ( true ) ;
# endif
2019-07-12 11:11:49 -05:00
ui - > previewDisabledWidget - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
2023-03-28 22:04:34 +02:00
connect ( ui - > enablePreviewButton , & QPushButton : : clicked , this , & OBSBasic : : TogglePreview ) ;
2019-10-10 20:12:20 -05:00
2023-03-28 22:04:34 +02:00
connect ( ui - > scenes , & SceneTree : : scenesReordered , [ ] ( ) { OBSProjector : : UpdateMultiviewProjectors ( ) ; } ) ;
2021-06-27 15:30:00 -07:00
2024-06-18 14:18:22 -05:00
connect ( App ( ) , & OBSApp : : StyleChanged , this , [ this ] ( ) { OnEvent ( OBS_FRONTEND_EVENT_THEME_CHANGED ) ; } ) ;
2022-08-18 07:50:24 -05:00
2023-02-08 03:57:51 -06:00
QActionGroup * actionGroup = new QActionGroup ( this ) ;
actionGroup - > addAction ( ui - > actionSceneListMode ) ;
actionGroup - > addAction ( ui - > actionSceneGridMode ) ;
2021-08-19 23:56:49 -05:00
UpdatePreviewSafeAreas ( ) ;
2021-11-01 02:16:56 -05:00
UpdatePreviewSpacingHelpers ( ) ;
2023-02-10 13:27:08 +01:00
UpdatePreviewOverflowSettings ( ) ;
2014-02-02 15:23:38 -07:00
}
2024-12-11 17:43:35 +01:00
static const double scaled_vals [ ] = { 1.0 , 1.25 , ( 1.0 / 0.75 ) , 1.5 , ( 1.0 / 0.6 ) , 1.75 , 2.0 , 2.25 , 2.5 , 2.75 , 3.0 , 0.0 } ;
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
# ifdef __APPLE__
# define DEFAULT_CONTAINER "fragmented_mov"
# elif OBS_RELEASE_CANDIDATE == 0 && OBS_BETA == 0
# define DEFAULT_CONTAINER "mkv"
# else
# define DEFAULT_CONTAINER "hybrid_mp4"
# endif
2014-04-26 23:47:50 -07:00
2024-12-11 17:43:35 +01:00
bool OBSBasic : : InitBasicConfigDefaults ( )
2015-02-17 02:45:34 -05:00
{
2024-12-11 17:43:35 +01:00
QList < QScreen * > screens = QGuiApplication : : screens ( ) ;
2023-02-10 14:52:15 +03:00
2024-12-11 17:43:35 +01:00
if ( ! screens . size ( ) ) {
OBSErrorBox ( NULL , " There appears to be no monitors. Er, this "
" technically shouldn't be possible. " ) ;
return false ;
2015-02-17 02:45:34 -05:00
}
2024-12-11 17:43:35 +01:00
QScreen * primaryScreen = QGuiApplication : : primaryScreen ( ) ;
2023-02-10 14:52:15 +03:00
2024-12-11 17:43:35 +01:00
uint32_t cx = primaryScreen - > size ( ) . width ( ) ;
uint32_t cy = primaryScreen - > size ( ) . height ( ) ;
2022-07-25 07:22:24 -05:00
2024-12-11 17:43:35 +01:00
cx * = devicePixelRatioF ( ) ;
cy * = devicePixelRatioF ( ) ;
2022-07-25 07:22:24 -05:00
2024-12-11 17:43:35 +01:00
bool oldResolutionDefaults = config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " Pre19Defaults " ) ;
2023-02-10 14:52:15 +03:00
2024-12-11 17:43:35 +01:00
/* use 1920x1080 for new default base res if main monitor is above
* 1920 x1080 , but don ' t apply for people from older builds - - only to
* new users */
if ( ! oldResolutionDefaults & & ( cx * cy ) > ( 1920 * 1080 ) ) {
cx = 1920 ;
cy = 1080 ;
2022-07-25 07:22:24 -05:00
}
2015-02-17 02:45:34 -05:00
2024-12-11 17:43:35 +01:00
bool changed = false ;
/* ----------------------------------------------------- */
/* move over old FFmpeg track settings */
if ( config_has_user_value ( activeConfiguration , " AdvOut " , " FFAudioTrack " ) & &
! config_has_user_value ( activeConfiguration , " AdvOut " , " Pre22.1Settings " ) ) {
2018-01-09 18:45:20 -02:00
2024-12-11 17:43:35 +01:00
int track = ( int ) config_get_int ( activeConfiguration , " AdvOut " , " FFAudioTrack " ) ;
config_set_int ( activeConfiguration , " AdvOut " , " FFAudioMixes " , 1LL < < ( track - 1 ) ) ;
config_set_bool ( activeConfiguration , " AdvOut " , " Pre22.1Settings " , true ) ;
changed = true ;
2018-01-09 18:45:20 -02:00
}
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
/* move over mixer values in advanced if older config */
if ( config_has_user_value ( activeConfiguration , " AdvOut " , " RecTrackIndex " ) & &
! config_has_user_value ( activeConfiguration , " AdvOut " , " RecTracks " ) ) {
2018-01-19 22:57:36 +01:00
2024-12-11 17:43:35 +01:00
uint64_t track = config_get_uint ( activeConfiguration , " AdvOut " , " RecTrackIndex " ) ;
track = 1ULL < < ( track - 1 ) ;
config_set_uint ( activeConfiguration , " AdvOut " , " RecTracks " , track ) ;
config_remove_value ( activeConfiguration , " AdvOut " , " RecTrackIndex " ) ;
changed = true ;
2018-01-19 22:57:36 +01:00
}
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
/* set twitch chat extensions to "both" if prev version */
/* is under 24.1 */
if ( config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " Pre24.1Defaults " ) & &
! config_has_user_value ( activeConfiguration , " Twitch " , " AddonChoice " ) ) {
config_set_int ( activeConfiguration , " Twitch " , " AddonChoice " , 3 ) ;
changed = true ;
2018-01-19 22:57:36 +01:00
}
2014-05-03 22:54:38 -07:00
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
/* move bitrate enforcement setting to new value */
if ( config_has_user_value ( activeConfiguration , " SimpleOutput " , " EnforceBitrate " ) & &
! config_has_user_value ( activeConfiguration , " Stream1 " , " IgnoreRecommended " ) & &
! config_has_user_value ( activeConfiguration , " Stream1 " , " MovedOldEnforce " ) ) {
bool enforce = config_get_bool ( activeConfiguration , " SimpleOutput " , " EnforceBitrate " ) ;
config_set_bool ( activeConfiguration , " Stream1 " , " IgnoreRecommended " , ! enforce ) ;
config_set_bool ( activeConfiguration , " Stream1 " , " MovedOldEnforce " , true ) ;
changed = true ;
2021-07-03 17:55:47 +12:00
}
2015-06-25 03:53:48 -07:00
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
/* enforce minimum retry delay of 1 second prior to 27.1 */
if ( config_has_user_value ( activeConfiguration , " Output " , " RetryDelay " ) ) {
int retryDelay = config_get_uint ( activeConfiguration , " Output " , " RetryDelay " ) ;
if ( retryDelay < 1 ) {
config_set_uint ( activeConfiguration , " Output " , " RetryDelay " , 1 ) ;
changed = true ;
}
2015-06-25 03:53:48 -07:00
}
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
/* Migrate old container selection (if any) to new key. */
2016-12-29 09:21:53 -06:00
2024-12-11 17:43:35 +01:00
auto MigrateFormat = [ & ] ( const char * section ) {
bool has_old_key = config_has_user_value ( activeConfiguration , section , " RecFormat " ) ;
bool has_new_key = config_has_user_value ( activeConfiguration , section , " RecFormat2 " ) ;
if ( ! has_new_key & & ! has_old_key )
2018-02-28 17:49:47 -03:00
return ;
2017-11-08 22:38:44 -05:00
2024-12-11 17:43:35 +01:00
string old_format =
config_get_string ( activeConfiguration , section , has_new_key ? " RecFormat2 " : " RecFormat " ) ;
string new_format = old_format ;
if ( old_format = = " ts " )
new_format = " mpegts " ;
else if ( old_format = = " m3u8 " )
new_format = " hls " ;
else if ( old_format = = " fmp4 " )
new_format = " fragmented_mp4 " ;
else if ( old_format = = " fmov " )
new_format = " fragmented_mov " ;
2020-04-27 23:26:20 +02:00
2024-12-11 17:43:35 +01:00
if ( new_format ! = old_format | | ! has_new_key ) {
config_set_string ( activeConfiguration , section , " RecFormat2 " , new_format . c_str ( ) ) ;
changed = true ;
2018-03-01 02:10:32 -03:00
}
2018-02-28 17:49:47 -03:00
} ;
2017-11-08 22:38:44 -05:00
2024-12-11 17:43:35 +01:00
MigrateFormat ( " AdvOut " ) ;
MigrateFormat ( " SimpleOutput " ) ;
2022-08-18 10:50:13 +02:00
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
/* Migrate output scale setting to GPU scaling options. */
2024-04-07 20:31:15 +02:00
2024-12-11 17:43:35 +01:00
if ( config_get_bool ( activeConfiguration , " AdvOut " , " Rescale " ) & &
! config_has_user_value ( activeConfiguration , " AdvOut " , " RescaleFilter " ) ) {
config_set_int ( activeConfiguration , " AdvOut " , " RescaleFilter " , OBS_SCALE_BILINEAR ) ;
2016-08-28 14:24:14 -07:00
}
2024-12-11 17:43:35 +01:00
if ( config_get_bool ( activeConfiguration , " AdvOut " , " RecRescale " ) & &
! config_has_user_value ( activeConfiguration , " AdvOut " , " RecRescaleFilter " ) ) {
config_set_int ( activeConfiguration , " AdvOut " , " RecRescaleFilter " , OBS_SCALE_BILINEAR ) ;
2023-12-19 00:04:46 +01:00
}
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
if ( changed ) {
activeConfiguration . SaveSafe ( " tmp " ) ;
2024-04-23 05:05:50 +02:00
}
2024-12-11 17:43:35 +01:00
/* ----------------------------------------------------- */
2018-02-04 23:36:56 +02:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " Output " , " Mode " , " Simple " ) ;
2020-04-07 21:11:29 +02:00
2024-12-11 17:43:35 +01:00
config_set_default_bool ( activeConfiguration , " Stream1 " , " IgnoreRecommended " , false ) ;
config_set_default_bool ( activeConfiguration , " Stream1 " , " EnableMultitrackVideo " , false ) ;
config_set_default_bool ( activeConfiguration , " Stream1 " , " MultitrackVideoMaximumAggregateBitrateAuto " , true ) ;
config_set_default_bool ( activeConfiguration , " Stream1 " , " MultitrackVideoMaximumVideoTracksAuto " , true ) ;
2014-05-03 22:54:38 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " SimpleOutput " , " FilePath " , GetDefaultVideoSavePath ( ) . c_str ( ) ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " RecFormat2 " , DEFAULT_CONTAINER ) ;
config_set_default_uint ( activeConfiguration , " SimpleOutput " , " VBitrate " , 2500 ) ;
config_set_default_uint ( activeConfiguration , " SimpleOutput " , " ABitrate " , 160 ) ;
config_set_default_bool ( activeConfiguration , " SimpleOutput " , " UseAdvanced " , false ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " Preset " , " veryfast " ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " NVENCPreset2 " , " p5 " ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " RecQuality " , " Stream " ) ;
config_set_default_bool ( activeConfiguration , " SimpleOutput " , " RecRB " , false ) ;
config_set_default_int ( activeConfiguration , " SimpleOutput " , " RecRBTime " , 20 ) ;
config_set_default_int ( activeConfiguration , " SimpleOutput " , " RecRBSize " , 512 ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " RecRBPrefix " , " Replay " ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " StreamAudioEncoder " , " aac " ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " RecAudioEncoder " , " aac " ) ;
config_set_default_uint ( activeConfiguration , " SimpleOutput " , " RecTracks " , ( 1 < < 0 ) ) ;
2021-11-26 22:25:39 +13:00
2024-12-11 17:43:35 +01:00
config_set_default_bool ( activeConfiguration , " AdvOut " , " ApplyServiceSettings " , true ) ;
config_set_default_bool ( activeConfiguration , " AdvOut " , " UseRescale " , false ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " TrackIndex " , 1 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " VodTrackIndex " , 2 ) ;
config_set_default_string ( activeConfiguration , " AdvOut " , " Encoder " , " obs_x264 " ) ;
2014-05-03 22:54:38 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " AdvOut " , " RecType " , " Standard " ) ;
2015-06-23 18:47:22 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " AdvOut " , " RecFilePath " , GetDefaultVideoSavePath ( ) . c_str ( ) ) ;
config_set_default_string ( activeConfiguration , " AdvOut " , " RecFormat2 " , DEFAULT_CONTAINER ) ;
config_set_default_bool ( activeConfiguration , " AdvOut " , " RecUseRescale " , false ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " RecTracks " , ( 1 < < 0 ) ) ;
config_set_default_string ( activeConfiguration , " AdvOut " , " RecEncoder " , " none " ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " FLVTrack " , 1 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " StreamMultiTrackAudioMixes " , 1 ) ;
config_set_default_bool ( activeConfiguration , " AdvOut " , " FFOutputToFile " , true ) ;
config_set_default_string ( activeConfiguration , " AdvOut " , " FFFilePath " , GetDefaultVideoSavePath ( ) . c_str ( ) ) ;
config_set_default_string ( activeConfiguration , " AdvOut " , " FFExtension " , " mp4 " ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " FFVBitrate " , 2500 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " FFVGOPSize " , 250 ) ;
config_set_default_bool ( activeConfiguration , " AdvOut " , " FFUseRescale " , false ) ;
config_set_default_bool ( activeConfiguration , " AdvOut " , " FFIgnoreCompat " , false ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " FFABitrate " , 160 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " FFAudioMixes " , 1 ) ;
2015-06-23 18:47:22 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_uint ( activeConfiguration , " AdvOut " , " Track1Bitrate " , 160 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " Track2Bitrate " , 160 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " Track3Bitrate " , 160 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " Track4Bitrate " , 160 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " Track5Bitrate " , 160 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " Track6Bitrate " , 160 ) ;
2015-06-23 18:47:22 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_uint ( activeConfiguration , " AdvOut " , " RecSplitFileTime " , 15 ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " RecSplitFileSize " , 2048 ) ;
2015-06-23 18:47:22 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_bool ( activeConfiguration , " AdvOut " , " RecRB " , false ) ;
config_set_default_uint ( activeConfiguration , " AdvOut " , " RecRBTime " , 20 ) ;
config_set_default_int ( activeConfiguration , " AdvOut " , " RecRBSize " , 512 ) ;
2015-06-23 18:47:22 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_uint ( activeConfiguration , " Video " , " BaseCX " , cx ) ;
config_set_default_uint ( activeConfiguration , " Video " , " BaseCY " , cy ) ;
2015-06-23 18:47:22 -07:00
2024-12-11 17:43:35 +01:00
/* don't allow BaseCX/BaseCY to be susceptible to defaults changing */
if ( ! config_has_user_value ( activeConfiguration , " Video " , " BaseCX " ) | |
! config_has_user_value ( activeConfiguration , " Video " , " BaseCY " ) ) {
config_set_uint ( activeConfiguration , " Video " , " BaseCX " , cx ) ;
config_set_uint ( activeConfiguration , " Video " , " BaseCY " , cy ) ;
config_save_safe ( activeConfiguration , " tmp " , nullptr ) ;
2024-08-18 02:21:15 +02:00
}
2015-09-11 21:49:21 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " Output " , " FilenameFormatting " , " %CCYY-%MM-%DD %hh-%mm-%ss " ) ;
2015-09-11 21:49:21 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_bool ( activeConfiguration , " Output " , " DelayEnable " , false ) ;
config_set_default_uint ( activeConfiguration , " Output " , " DelaySec " , 20 ) ;
config_set_default_bool ( activeConfiguration , " Output " , " DelayPreserve " , true ) ;
2015-09-11 21:49:21 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_bool ( activeConfiguration , " Output " , " Reconnect " , true ) ;
config_set_default_uint ( activeConfiguration , " Output " , " RetryDelay " , 2 ) ;
config_set_default_uint ( activeConfiguration , " Output " , " MaxRetries " , 25 ) ;
2015-06-30 05:49:31 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " Output " , " BindIP " , " default " ) ;
config_set_default_string ( activeConfiguration , " Output " , " IPFamily " , " IPv4+IPv6 " ) ;
config_set_default_bool ( activeConfiguration , " Output " , " NewSocketLoopEnable " , false ) ;
config_set_default_bool ( activeConfiguration , " Output " , " LowLatencyEnable " , false ) ;
2014-05-03 22:54:38 -07:00
2024-12-11 17:43:35 +01:00
int i = 0 ;
uint32_t scale_cx = cx ;
uint32_t scale_cy = cy ;
2015-06-25 03:53:48 -07:00
2024-12-11 17:43:35 +01:00
/* use a default scaled resolution that has a pixel count no higher
* than 1280 x720 */
while ( ( ( scale_cx * scale_cy ) > ( 1280 * 720 ) ) & & scaled_vals [ i ] > 0.0 ) {
double scale = scaled_vals [ i + + ] ;
scale_cx = uint32_t ( double ( cx ) / scale ) ;
scale_cy = uint32_t ( double ( cy ) / scale ) ;
2015-06-25 03:53:48 -07:00
}
2024-12-11 17:43:35 +01:00
config_set_default_uint ( activeConfiguration , " Video " , " OutputCX " , scale_cx ) ;
config_set_default_uint ( activeConfiguration , " Video " , " OutputCY " , scale_cy ) ;
2015-06-25 03:53:48 -07:00
2024-12-11 17:43:35 +01:00
/* don't allow OutputCX/OutputCY to be susceptible to defaults
* changing */
if ( ! config_has_user_value ( activeConfiguration , " Video " , " OutputCX " ) | |
! config_has_user_value ( activeConfiguration , " Video " , " OutputCY " ) ) {
config_set_uint ( activeConfiguration , " Video " , " OutputCX " , scale_cx ) ;
config_set_uint ( activeConfiguration , " Video " , " OutputCY " , scale_cy ) ;
config_save_safe ( activeConfiguration , " tmp " , nullptr ) ;
2018-11-13 14:39:56 +08:00
}
2024-12-11 17:43:35 +01:00
config_set_default_uint ( activeConfiguration , " Video " , " FPSType " , 0 ) ;
config_set_default_string ( activeConfiguration , " Video " , " FPSCommon " , " 30 " ) ;
config_set_default_uint ( activeConfiguration , " Video " , " FPSInt " , 30 ) ;
config_set_default_uint ( activeConfiguration , " Video " , " FPSNum " , 30 ) ;
config_set_default_uint ( activeConfiguration , " Video " , " FPSDen " , 1 ) ;
config_set_default_string ( activeConfiguration , " Video " , " ScaleType " , " bicubic " ) ;
config_set_default_string ( activeConfiguration , " Video " , " ColorFormat " , " NV12 " ) ;
config_set_default_string ( activeConfiguration , " Video " , " ColorSpace " , " 709 " ) ;
config_set_default_string ( activeConfiguration , " Video " , " ColorRange " , " Partial " ) ;
config_set_default_uint ( activeConfiguration , " Video " , " SdrWhiteLevel " , 300 ) ;
config_set_default_uint ( activeConfiguration , " Video " , " HdrNominalPeakLevel " , 1000 ) ;
2016-12-29 09:21:53 -06:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " Audio " , " MonitoringDeviceId " , " default " ) ;
config_set_default_string ( activeConfiguration , " Audio " , " MonitoringDeviceName " ,
Str ( " Basic.Settings.Advanced.Audio.MonitoringDevice "
" .Default " ) ) ;
config_set_default_uint ( activeConfiguration , " Audio " , " SampleRate " , 48000 ) ;
config_set_default_string ( activeConfiguration , " Audio " , " ChannelSetup " , " Stereo " ) ;
config_set_default_double ( activeConfiguration , " Audio " , " MeterDecayRate " , VOLUME_METER_DECAY_FAST ) ;
config_set_default_uint ( activeConfiguration , " Audio " , " PeakMeterType " , 0 ) ;
2016-12-29 09:21:53 -06:00
2024-12-11 17:43:35 +01:00
CheckExistingCookieId ( ) ;
2020-04-27 23:26:20 +02:00
2024-12-11 17:43:35 +01:00
return true ;
2017-10-21 15:51:01 -02:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : InitBasicConfigDefaults2 ( )
2016-08-05 17:43:30 -07:00
{
2024-12-11 17:43:35 +01:00
bool oldEncDefaults = config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " Pre23Defaults " ) ;
bool useNV = EncoderAvailable ( " ffmpeg_nvenc " ) & & ! oldEncDefaults ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " StreamEncoder " ,
useNV ? SIMPLE_ENCODER_NVENC : SIMPLE_ENCODER_X264 ) ;
config_set_default_string ( activeConfiguration , " SimpleOutput " , " RecEncoder " ,
useNV ? SIMPLE_ENCODER_NVENC : SIMPLE_ENCODER_X264 ) ;
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
const char * aac_default = " ffmpeg_aac " ;
if ( EncoderAvailable ( " CoreAudio_AAC " ) )
aac_default = " CoreAudio_AAC " ;
else if ( EncoderAvailable ( " libfdk_aac " ) )
aac_default = " libfdk_aac " ;
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
config_set_default_string ( activeConfiguration , " AdvOut " , " AudioEncoder " , aac_default ) ;
config_set_default_string ( activeConfiguration , " AdvOut " , " RecAudioEncoder " , aac_default ) ;
2016-08-05 17:43:30 -07:00
}
2024-12-11 17:43:35 +01:00
bool OBSBasic : : InitBasicConfig ( )
2016-08-05 17:43:30 -07:00
{
2024-12-11 17:43:35 +01:00
ProfileScope ( " OBSBasic::InitBasicConfig " ) ;
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
RefreshProfiles ( true ) ;
2017-03-02 13:05:38 -08:00
2024-12-11 17:43:35 +01:00
const std : : string currentProfileName { config_get_string ( App ( ) - > GetUserConfig ( ) , " Basic " , " Profile " ) } ;
const std : : optional < OBSProfile > currentProfile = GetProfileByName ( currentProfileName ) ;
const std : : optional < OBSProfile > foundProfile = GetProfileByName ( opt_starting_profile ) ;
2017-03-02 13:05:38 -08:00
2024-12-11 17:43:35 +01:00
try {
if ( foundProfile ) {
ActivateProfile ( foundProfile . value ( ) ) ;
} else if ( currentProfile ) {
ActivateProfile ( currentProfile . value ( ) ) ;
} else {
const OBSProfile & newProfile = CreateProfile ( currentProfileName ) ;
ActivateProfile ( newProfile ) ;
}
} catch ( const std : : logic_error & ) {
OBSErrorBox ( NULL , " Failed to open basic.ini: %d " , - 1 ) ;
return false ;
2017-03-02 13:05:38 -08:00
}
2024-12-11 17:43:35 +01:00
2016-08-05 17:43:30 -07:00
return true ;
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : InitOBSCallbacks ( )
2016-08-05 17:43:30 -07:00
{
2024-12-11 17:43:35 +01:00
ProfileScope ( " OBSBasic::InitOBSCallbacks " ) ;
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
signalHandlers . reserve ( signalHandlers . size ( ) + 9 ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_create " , OBSBasic : : SourceCreated , this ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_remove " , OBSBasic : : SourceRemoved , this ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_activate " , OBSBasic : : SourceActivated , this ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_deactivate " , OBSBasic : : SourceDeactivated , this ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_audio_activate " , OBSBasic : : SourceAudioActivated ,
this ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_audio_deactivate " ,
OBSBasic : : SourceAudioDeactivated , this ) ;
signalHandlers . emplace_back ( obs_get_signal_handler ( ) , " source_rename " , OBSBasic : : SourceRenamed , this ) ;
signalHandlers . emplace_back (
obs_get_signal_handler ( ) , " source_filter_add " ,
[ ] ( void * data , calldata_t * ) {
QMetaObject : : invokeMethod ( static_cast < OBSBasic * > ( data ) , " UpdateEditMenu " ,
Qt : : QueuedConnection ) ;
} ,
this ) ;
signalHandlers . emplace_back (
obs_get_signal_handler ( ) , " source_filter_remove " ,
[ ] ( void * data , calldata_t * ) {
QMetaObject : : invokeMethod ( static_cast < OBSBasic * > ( data ) , " UpdateEditMenu " ,
Qt : : QueuedConnection ) ;
} ,
this ) ;
}
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
# define STARTUP_SEPARATOR "==== Startup complete ==============================================="
# define SHUTDOWN_SEPARATOR "==== Shutting down =================================================="
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
# define UNSUPPORTED_ERROR \
" Failed to initialize video: \n \n Required graphics API functionality " \
" not found. Your GPU may not be supported. "
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
# define UNKNOWN_ERROR \
" Failed to initialize video. Your GPU may not be supported, " \
" or your graphics drivers may need to be updated. "
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
static inline void LogEncoders ( )
2014-04-26 23:47:50 -07:00
{
2024-12-11 17:43:35 +01:00
constexpr uint32_t hide_flags = OBS_ENCODER_CAP_DEPRECATED | OBS_ENCODER_CAP_INTERNAL ;
2024-07-29 22:46:38 +02:00
2024-12-11 17:43:35 +01:00
auto list_encoders = [ ] ( obs_encoder_type type ) {
size_t idx = 0 ;
const char * encoder_type ;
2024-09-03 16:28:36 +02:00
2024-12-11 17:43:35 +01:00
while ( obs_enum_encoder_types ( idx + + , & encoder_type ) ) {
if ( obs_get_encoder_caps ( encoder_type ) & hide_flags | |
obs_get_encoder_type ( encoder_type ) ! = type ) {
continue ;
}
2024-09-03 16:28:36 +02:00
2024-12-11 17:43:35 +01:00
blog ( LOG_INFO , " \t - %s (%s) " , encoder_type , obs_encoder_get_display_name ( encoder_type ) ) ;
}
} ;
2014-04-26 23:47:50 -07:00
2024-12-11 17:43:35 +01:00
blog ( LOG_INFO , " --------------------------------- " ) ;
blog ( LOG_INFO , " Available Encoders: " ) ;
blog ( LOG_INFO , " Video Encoders: " ) ;
list_encoders ( OBS_ENCODER_VIDEO ) ;
blog ( LOG_INFO , " Audio Encoders: " ) ;
list_encoders ( OBS_ENCODER_AUDIO ) ;
2021-03-22 01:20:11 -04:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : OBSInit ( )
2022-07-20 03:44:43 -05:00
{
2024-12-11 17:43:35 +01:00
ProfileScope ( " OBSBasic::OBSInit " ) ;
2022-07-20 03:44:43 -05:00
2024-12-11 17:43:35 +01:00
if ( ! InitBasicConfig ( ) )
throw " Failed to load basic.ini " ;
if ( ! ResetAudio ( ) )
throw " Failed to initialize audio " ;
2022-07-20 03:44:43 -05:00
2024-12-11 17:43:35 +01:00
int ret = 0 ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
ret = ResetVideo ( ) ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
switch ( ret ) {
case OBS_VIDEO_MODULE_NOT_FOUND :
throw " Failed to initialize video: Graphics module not found " ;
case OBS_VIDEO_NOT_SUPPORTED :
throw UNSUPPORTED_ERROR ;
case OBS_VIDEO_INVALID_PARAM :
throw " Failed to initialize video: Invalid parameters " ;
default :
if ( ret ! = OBS_VIDEO_SUCCESS )
throw UNKNOWN_ERROR ;
}
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
/* load audio monitoring */
if ( obs_audio_monitoring_available ( ) ) {
const char * device_name = config_get_string ( activeConfiguration , " Audio " , " MonitoringDeviceName " ) ;
const char * device_id = config_get_string ( activeConfiguration , " Audio " , " MonitoringDeviceId " ) ;
2015-07-02 16:17:55 -07:00
2024-12-11 17:43:35 +01:00
obs_set_audio_monitoring_device ( device_name , device_id ) ;
blog ( LOG_INFO , " Audio monitoring device: \n \t name: %s \n \t id: %s " , device_name , device_id ) ;
2023-05-03 14:59:48 +02:00
}
2024-12-11 17:43:35 +01:00
InitOBSCallbacks ( ) ;
InitHotkeys ( ) ;
ui - > preview - > Init ( ) ;
2023-05-03 14:59:48 +02:00
2024-12-11 17:43:35 +01:00
/* hack to prevent elgato from loading its own QtNetwork that it tries
* to ship with */
# if defined(_WIN32) && !defined(_DEBUG)
LoadLibraryW ( L " Qt6Network " ) ;
# endif
struct obs_module_failure_info mfi ;
/* Safe Mode disables third-party plugins so we don't need to add earch
* paths outside the OBS bundle / installation . */
if ( safe_mode | | disable_3p_plugins ) {
SetSafeModuleNames ( ) ;
} else {
AddExtraModulePaths ( ) ;
2020-08-25 06:30:59 -07:00
}
2024-12-11 17:43:35 +01:00
/* Modules can access frontend information (i.e. profile and scene collection data) during their initialization, and some modules (e.g. obs-websockets) are known to use the filesystem location of the current profile in their own code.
Thus the profile and scene collection discovery needs to happen before any access to that information ( but after intializing global settings ) to ensure legacy code gets valid path information .
*/
RefreshSceneCollections ( true ) ;
2020-08-25 06:30:59 -07:00
2024-12-11 17:43:35 +01:00
blog ( LOG_INFO , " --------------------------------- " ) ;
obs_load_all_modules2 ( & mfi ) ;
blog ( LOG_INFO , " --------------------------------- " ) ;
obs_log_loaded_modules ( ) ;
blog ( LOG_INFO , " --------------------------------- " ) ;
obs_post_load_modules ( ) ;
2016-04-13 18:59:27 -07:00
2024-12-11 17:43:35 +01:00
BPtr < char * > failed_modules = mfi . failed_modules ;
UI: Implement transitions and preview/program mode
Implements transitions, and introduces "Studio Mode" which allows live
editing of the same or different scenes while preserving what's
currently being displayed.
Studio Mode offers a number of new features:
- The ability to edit different scenes or the same scene without
modifying what's currently being displayed (of course)
- The ability to set up "quick transitions" with a desired transition
and duration that can be assigned hotkeys
- The option to create full copies of all sources in the program scene
to allow editing of source properties of the same scene live without
modifying the output, or (by default) just use references. (Note
however that certain sources cannot be duplicated, such as capture
sources, media sources, and device sources)
- Swap Mode (enabled by default) which swaps the program scene with
the preview scene when a transition completes
Currently, only non-configurable transitions (transitions without
properties) are listed, and the only transitions available as of this
writing are fade and cut. In future versions more transitions will be
added, such as swipe, stingers, and many other various sort of
transitions, and the UI will support being able to add/configure/remove
those sort of configurable transitions.
2016-01-23 11:19:29 -08:00
2024-12-11 17:43:35 +01:00
# ifdef BROWSER_AVAILABLE
cef = obs_browser_init_panel ( ) ;
cef_js_avail = cef & & obs_browser_qcef_version ( ) > = 3 ;
# endif
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
vcamEnabled = ( obs_get_output_flags ( VIRTUAL_CAM_ID ) & OBS_OUTPUT_VIDEO ) ! = 0 ;
if ( vcamEnabled ) {
emit VirtualCamEnabled ( ) ;
}
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
UpdateProfileEncoders ( ) ;
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
LogEncoders ( ) ;
2014-04-26 23:47:50 -07:00
2024-12-11 17:43:35 +01:00
blog ( LOG_INFO , STARTUP_SEPARATOR ) ;
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
if ( ! InitService ( ) )
throw " Failed to initialize service " ;
2014-05-03 22:54:38 -07:00
2024-12-11 17:43:35 +01:00
ResetOutputs ( ) ;
CreateHotkeys ( ) ;
2018-07-15 18:50:33 -07:00
2024-12-11 17:43:35 +01:00
InitPrimitives ( ) ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
sceneDuplicationMode = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SceneDuplicationMode " ) ;
swapScenesMode = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SwapScenesMode " ) ;
editPropertiesMode = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " EditPropertiesMode " ) ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
if ( ! opt_studio_mode ) {
SetPreviewProgramMode ( config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " PreviewProgramMode " ) ) ;
} else {
SetPreviewProgramMode ( true ) ;
opt_studio_mode = false ;
2024-04-23 05:05:50 +02:00
}
2024-12-11 17:43:35 +01:00
# define SET_VISIBILITY(name, control) \
do { \
if ( config_has_user_value ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , name ) ) { \
bool visible = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , name ) ; \
ui - > control - > setChecked ( visible ) ; \
} \
} while ( false )
SET_VISIBILITY ( " ShowListboxToolbars " , toggleListboxToolbars ) ;
SET_VISIBILITY ( " ShowStatusBar " , toggleStatusBar ) ;
# undef SET_VISIBILITY
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
bool sourceIconsVisible = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " ShowSourceIcons " ) ;
ui - > toggleSourceIcons - > setChecked ( sourceIconsVisible ) ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
bool contextVisible = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " ShowContextToolbars " ) ;
ui - > toggleContextBar - > setChecked ( contextVisible ) ;
ui - > contextContainer - > setVisible ( contextVisible ) ;
if ( contextVisible )
UpdateContextBar ( true ) ;
UpdateEditMenu ( ) ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
{
ProfileScope ( " OBSBasic::Load " ) ;
const std : : string sceneCollectionName {
config_get_string ( App ( ) - > GetUserConfig ( ) , " Basic " , " SceneCollection " ) } ;
2025-01-22 20:44:35 +01:00
std : : optional < OBS : : SceneCollection > configuredCollection =
2024-12-11 17:43:35 +01:00
GetSceneCollectionByName ( sceneCollectionName ) ;
2025-01-22 20:44:35 +01:00
std : : optional < OBS : : SceneCollection > foundCollection = GetSceneCollectionByName ( opt_starting_collection ) ;
2024-04-23 05:05:50 +02:00
2024-12-11 17:43:35 +01:00
if ( foundCollection ) {
ActivateSceneCollection ( foundCollection . value ( ) ) ;
} else if ( configuredCollection ) {
ActivateSceneCollection ( configuredCollection . value ( ) ) ;
} else {
disableSaving - - ;
SetupNewSceneCollection ( sceneCollectionName ) ;
disableSaving + + ;
2024-04-23 05:05:50 +02:00
}
2024-12-11 17:43:35 +01:00
if ( foundCollection | | configuredCollection ) {
2025-02-24 20:01:11 +01:00
disableSaving - - ;
2024-12-11 17:43:35 +01:00
OnEvent ( OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED ) ;
OnEvent ( OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED ) ;
2025-02-24 20:01:11 +01:00
OnEvent ( OBS_FRONTEND_EVENT_SCENE_CHANGED ) ;
OnEvent ( OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED ) ;
disableSaving + + ;
2024-04-23 05:05:50 +02:00
}
}
2024-12-11 17:43:35 +01:00
loaded = true ;
2014-04-26 23:47:50 -07:00
2024-12-11 17:43:35 +01:00
previewEnabled = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " PreviewEnabled " ) ;
2015-06-25 03:53:48 -07:00
2024-12-11 17:43:35 +01:00
if ( ! previewEnabled & & ! IsPreviewProgramMode ( ) )
QMetaObject : : invokeMethod ( this , " EnablePreviewDisplay " , Qt : : QueuedConnection ,
Q_ARG ( bool , previewEnabled ) ) ;
else if ( ! previewEnabled & & IsPreviewProgramMode ( ) )
QMetaObject : : invokeMethod ( this , " EnablePreviewDisplay " , Qt : : QueuedConnection , Q_ARG ( bool , true ) ) ;
UI: Implement transitions and preview/program mode
Implements transitions, and introduces "Studio Mode" which allows live
editing of the same or different scenes while preserving what's
currently being displayed.
Studio Mode offers a number of new features:
- The ability to edit different scenes or the same scene without
modifying what's currently being displayed (of course)
- The ability to set up "quick transitions" with a desired transition
and duration that can be assigned hotkeys
- The option to create full copies of all sources in the program scene
to allow editing of source properties of the same scene live without
modifying the output, or (by default) just use references. (Note
however that certain sources cannot be duplicated, such as capture
sources, media sources, and device sources)
- Swap Mode (enabled by default) which swaps the program scene with
the preview scene when a transition completes
Currently, only non-configurable transitions (transitions without
properties) are listed, and the only transitions available as of this
writing are fade and cut. In future versions more transitions will be
added, such as swipe, stingers, and many other various sort of
transitions, and the UI will support being able to add/configure/remove
those sort of configurable transitions.
2016-01-23 11:19:29 -08:00
2024-12-11 17:43:35 +01:00
disableSaving - - ;
UI: Implement transitions and preview/program mode
Implements transitions, and introduces "Studio Mode" which allows live
editing of the same or different scenes while preserving what's
currently being displayed.
Studio Mode offers a number of new features:
- The ability to edit different scenes or the same scene without
modifying what's currently being displayed (of course)
- The ability to set up "quick transitions" with a desired transition
and duration that can be assigned hotkeys
- The option to create full copies of all sources in the program scene
to allow editing of source properties of the same scene live without
modifying the output, or (by default) just use references. (Note
however that certain sources cannot be duplicated, such as capture
sources, media sources, and device sources)
- Swap Mode (enabled by default) which swaps the program scene with
the preview scene when a transition completes
Currently, only non-configurable transitions (transitions without
properties) are listed, and the only transitions available as of this
writing are fade and cut. In future versions more transitions will be
added, such as swipe, stingers, and many other various sort of
transitions, and the UI will support being able to add/configure/remove
those sort of configurable transitions.
2016-01-23 11:19:29 -08:00
2024-12-11 17:43:35 +01:00
auto addDisplay = [ this ] ( OBSQTDisplay * window ) {
obs_display_add_draw_callback ( window - > GetDisplay ( ) , OBSBasic : : RenderMain , this ) ;
2016-04-13 18:59:27 -07:00
2024-12-11 17:43:35 +01:00
struct obs_video_info ovi ;
if ( obs_get_video_info ( & ovi ) )
ResizePreview ( ovi . base_width , ovi . base_height ) ;
} ;
2016-04-13 18:59:27 -07:00
2024-12-11 17:43:35 +01:00
connect ( ui - > preview , & OBSQTDisplay : : DisplayCreated , addDisplay ) ;
2023-11-30 20:31:34 +01:00
2024-12-11 17:43:35 +01:00
/* Show the main window, unless the tray icon isn't available
* or neither the setting nor flag for starting minimized is set . */
bool sysTrayEnabled = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SysTrayEnabled " ) ;
bool sysTrayWhenStarted = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SysTrayWhenStarted " ) ;
bool hideWindowOnStart = QSystemTrayIcon : : isSystemTrayAvailable ( ) & & sysTrayEnabled & &
( opt_minimize_tray | | sysTrayWhenStarted ) ;
2021-12-30 21:10:50 -08:00
2024-12-11 17:43:35 +01:00
# ifdef _WIN32
SetWin32DropStyle ( this ) ;
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
if ( ! hideWindowOnStart )
show ( ) ;
# endif
2018-02-27 20:26:22 -03:00
2024-12-11 17:43:35 +01:00
bool alwaysOnTop = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " AlwaysOnTop " ) ;
2018-02-27 20:26:22 -03:00
2024-12-11 17:43:35 +01:00
# ifdef ENABLE_WAYLAND
bool isWayland = obs_get_nix_platform ( ) = = OBS_NIX_PLATFORM_WAYLAND ;
# else
bool isWayland = false ;
# endif
2018-02-27 20:26:22 -03:00
2024-12-11 17:43:35 +01:00
if ( ! isWayland & & ( alwaysOnTop | | opt_always_on_top ) ) {
SetAlwaysOnTop ( this , true ) ;
ui - > actionAlwaysOnTop - > setChecked ( true ) ;
} else if ( isWayland ) {
if ( opt_always_on_top )
blog ( LOG_INFO , " Always On Top not available on Wayland, ignoring. " ) ;
ui - > actionAlwaysOnTop - > setEnabled ( false ) ;
ui - > actionAlwaysOnTop - > setVisible ( false ) ;
2018-02-27 20:26:22 -03:00
}
2024-12-11 17:43:35 +01:00
# ifndef _WIN32
if ( ! hideWindowOnStart )
show ( ) ;
# endif
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
/* setup stats dock */
OBSBasicStats * statsDlg = new OBSBasicStats ( statsDock , false ) ;
statsDock - > setWidget ( statsDlg ) ;
2015-06-23 19:29:07 -07:00
2024-12-11 17:43:35 +01:00
/* ----------------------------- */
/* add custom browser docks */
# if defined(BROWSER_AVAILABLE) && defined(YOUTUBE_ENABLED)
YouTubeAppDock : : CleanupYouTubeUrls ( ) ;
# endif
UI: Implement transitions and preview/program mode
Implements transitions, and introduces "Studio Mode" which allows live
editing of the same or different scenes while preserving what's
currently being displayed.
Studio Mode offers a number of new features:
- The ability to edit different scenes or the same scene without
modifying what's currently being displayed (of course)
- The ability to set up "quick transitions" with a desired transition
and duration that can be assigned hotkeys
- The option to create full copies of all sources in the program scene
to allow editing of source properties of the same scene live without
modifying the output, or (by default) just use references. (Note
however that certain sources cannot be duplicated, such as capture
sources, media sources, and device sources)
- Swap Mode (enabled by default) which swaps the program scene with
the preview scene when a transition completes
Currently, only non-configurable transitions (transitions without
properties) are listed, and the only transitions available as of this
writing are fade and cut. In future versions more transitions will be
added, such as swipe, stingers, and many other various sort of
transitions, and the UI will support being able to add/configure/remove
those sort of configurable transitions.
2016-01-23 11:19:29 -08:00
2024-12-11 17:43:35 +01:00
# ifdef BROWSER_AVAILABLE
if ( cef ) {
QAction * action = new QAction ( QTStr ( " Basic.MainMenu.Docks. "
" CustomBrowserDocks " ) ,
this ) ;
ui - > menuDocks - > insertAction ( ui - > scenesDock - > toggleViewAction ( ) , action ) ;
connect ( action , & QAction : : triggered , this , & OBSBasic : : ManageExtraBrowserDocks ) ;
ui - > menuDocks - > insertSeparator ( ui - > scenesDock - > toggleViewAction ( ) ) ;
UI: Implement transitions and preview/program mode
Implements transitions, and introduces "Studio Mode" which allows live
editing of the same or different scenes while preserving what's
currently being displayed.
Studio Mode offers a number of new features:
- The ability to edit different scenes or the same scene without
modifying what's currently being displayed (of course)
- The ability to set up "quick transitions" with a desired transition
and duration that can be assigned hotkeys
- The option to create full copies of all sources in the program scene
to allow editing of source properties of the same scene live without
modifying the output, or (by default) just use references. (Note
however that certain sources cannot be duplicated, such as capture
sources, media sources, and device sources)
- Swap Mode (enabled by default) which swaps the program scene with
the preview scene when a transition completes
Currently, only non-configurable transitions (transitions without
properties) are listed, and the only transitions available as of this
writing are fade and cut. In future versions more transitions will be
added, such as swipe, stingers, and many other various sort of
transitions, and the UI will support being able to add/configure/remove
those sort of configurable transitions.
2016-01-23 11:19:29 -08:00
2024-12-11 17:43:35 +01:00
LoadExtraBrowserDocks ( ) ;
}
# endif
2016-07-26 01:32:43 -07:00
2024-12-11 17:43:35 +01:00
# ifdef YOUTUBE_ENABLED
/* setup YouTube app dock */
if ( YouTubeAppDock : : IsYTServiceSelected ( ) )
NewYouTubeAppDock ( ) ;
# endif
2017-05-13 13:13:55 -04:00
2024-12-11 17:43:35 +01:00
const char * dockStateStr = config_get_string ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " DockState " ) ;
2017-05-13 13:13:55 -04:00
2024-12-11 17:43:35 +01:00
if ( ! dockStateStr ) {
on_resetDocks_triggered ( true ) ;
} else {
QByteArray dockState = QByteArray : : fromBase64 ( QByteArray ( dockStateStr ) ) ;
if ( ! restoreState ( dockState ) )
on_resetDocks_triggered ( true ) ;
2016-11-05 12:48:46 -04:00
}
2024-07-31 10:53:59 -04:00
2024-12-11 17:43:35 +01:00
bool pre23Defaults = config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " Pre23Defaults " ) ;
if ( pre23Defaults ) {
bool resetDockLock23 = config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " ResetDockLock23 " ) ;
if ( ! resetDockLock23 ) {
config_set_bool ( App ( ) - > GetUserConfig ( ) , " General " , " ResetDockLock23 " , true ) ;
config_remove_value ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " DocksLocked " ) ;
config_save_safe ( App ( ) - > GetUserConfig ( ) , " tmp " , nullptr ) ;
2022-11-15 10:00:41 +01:00
}
2022-08-22 16:04:13 +02:00
}
2022-08-18 10:50:13 +02:00
2024-12-11 17:43:35 +01:00
bool docksLocked = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " DocksLocked " ) ;
on_lockDocks_toggled ( docksLocked ) ;
ui - > lockDocks - > blockSignals ( true ) ;
ui - > lockDocks - > setChecked ( docksLocked ) ;
ui - > lockDocks - > blockSignals ( false ) ;
2024-06-01 18:42:34 +02:00
2024-12-11 17:43:35 +01:00
bool sideDocks = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SideDocks " ) ;
on_sideDocks_toggled ( sideDocks ) ;
ui - > sideDocks - > blockSignals ( true ) ;
ui - > sideDocks - > setChecked ( sideDocks ) ;
ui - > sideDocks - > blockSignals ( false ) ;
2016-11-05 12:48:46 -04:00
2024-12-11 17:43:35 +01:00
SystemTray ( true ) ;
2016-08-28 14:24:14 -07:00
2024-12-11 17:43:35 +01:00
TaskbarOverlayInit ( ) ;
2015-06-30 05:49:31 -07:00
2024-12-11 17:43:35 +01:00
# ifdef __APPLE__
disableColorSpaceConversion ( this ) ;
# endif
2016-04-13 18:59:27 -07:00
2024-12-11 17:43:35 +01:00
bool has_last_version = config_has_user_value ( App ( ) - > GetAppConfig ( ) , " General " , " LastVersion " ) ;
bool first_run = config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " FirstRun " ) ;
2016-04-13 19:00:12 -07:00
2024-12-11 17:43:35 +01:00
if ( ! first_run ) {
config_set_bool ( App ( ) - > GetUserConfig ( ) , " General " , " FirstRun " , true ) ;
config_save_safe ( App ( ) - > GetUserConfig ( ) , " tmp " , nullptr ) ;
2016-04-13 19:00:12 -07:00
}
2024-12-11 17:43:35 +01:00
if ( ! first_run & & ! has_last_version & & ! Active ( ) )
QMetaObject : : invokeMethod ( this , " on_autoConfigure_triggered " , Qt : : QueuedConnection ) ;
2017-01-11 13:19:17 -06:00
2024-12-11 17:43:35 +01:00
# if (defined(_WIN32) || defined(__APPLE__)) && (OBS_RELEASE_CANDIDATE > 0 || OBS_BETA > 0)
/* Automatically set branch to "beta" the first time a pre-release build is run. */
if ( ! config_get_bool ( App ( ) - > GetAppConfig ( ) , " General " , " AutoBetaOptIn " ) ) {
config_set_string ( App ( ) - > GetAppConfig ( ) , " General " , " UpdateBranch " , " beta " ) ;
config_set_bool ( App ( ) - > GetAppConfig ( ) , " General " , " AutoBetaOptIn " , true ) ;
config_save_safe ( App ( ) - > GetAppConfig ( ) , " tmp " , nullptr ) ;
2020-06-20 07:42:14 -07:00
}
2024-12-11 17:43:35 +01:00
# endif
TimedCheckForUpdates ( ) ;
2020-06-20 07:42:14 -07:00
2024-12-11 17:43:35 +01:00
ToggleMixerLayout ( config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " VerticalVolControl " ) ) ;
2016-08-05 17:43:30 -07:00
2024-12-11 17:43:35 +01:00
if ( config_get_bool ( activeConfiguration , " General " , " OpenStatsOnStartup " ) )
on_stats_triggered ( ) ;
2020-02-18 21:06:17 +13:00
2024-12-11 17:43:35 +01:00
OBSBasicStats : : InitializeValues ( ) ;
2017-12-25 13:38:02 -08:00
2024-12-11 17:43:35 +01:00
/* ----------------------- */
/* Add multiview menu */
2021-03-22 00:39:02 -04:00
2024-12-11 17:43:35 +01:00
ui - > viewMenu - > addSeparator ( ) ;
2018-06-02 09:45:01 -07:00
2024-11-04 12:33:14 -05:00
connect ( ui - > viewMenu - > menuAction ( ) , & QAction : : hovered , this , & OBSBasic : : updateMultiviewProjectorMenu ) ;
OBSBasic : : updateMultiviewProjectorMenu ( ) ;
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
ui - > sources - > UpdateIcons ( ) ;
# if !defined(_WIN32)
delete ui - > actionShowCrashLogs ;
delete ui - > actionUploadLastCrashLog ;
delete ui - > menuCrashLogs ;
delete ui - > actionRepair ;
ui - > actionShowCrashLogs = nullptr ;
ui - > actionUploadLastCrashLog = nullptr ;
ui - > menuCrashLogs = nullptr ;
ui - > actionRepair = nullptr ;
# if !defined(__APPLE__)
delete ui - > actionCheckForUpdates ;
ui - > actionCheckForUpdates = nullptr ;
# endif
# endif
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
# ifdef __APPLE__
/* Remove OBS' Fullscreen Interface menu in favor of the one macOS adds by default */
delete ui - > actionFullscreenInterface ;
ui - > actionFullscreenInterface = nullptr ;
# else
/* Don't show menu to raise macOS-only permissions dialog */
delete ui - > actionShowMacPermissions ;
ui - > actionShowMacPermissions = nullptr ;
# endif
2017-10-14 01:49:37 -04:00
2024-12-11 17:43:35 +01:00
# if defined(_WIN32) || defined(__APPLE__)
if ( App ( ) - > IsUpdaterDisabled ( ) ) {
ui - > actionCheckForUpdates - > setEnabled ( false ) ;
# if defined(_WIN32)
ui - > actionRepair - > setEnabled ( false ) ;
# endif
2019-10-04 22:33:06 -07:00
}
2024-12-11 17:43:35 +01:00
# endif
2019-10-04 22:33:06 -07:00
2024-12-11 17:43:35 +01:00
# ifndef WHATSNEW_ENABLED
delete ui - > actionShowWhatsNew ;
ui - > actionShowWhatsNew = nullptr ;
# endif
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
if ( safe_mode ) {
ui - > actionRestartSafe - > setText ( QTStr ( " Basic.MainMenu.Help.RestartNormal " ) ) ;
}
2021-05-12 22:07:40 -07:00
2024-12-11 17:43:35 +01:00
UpdatePreviewProgramIndicators ( ) ;
OnFirstLoad ( ) ;
2021-05-12 22:07:40 -07:00
2024-12-11 17:43:35 +01:00
if ( ! hideWindowOnStart )
activateWindow ( ) ;
2021-09-28 16:14:20 -04:00
2024-12-11 17:43:35 +01:00
/* ------------------------------------------- */
/* display warning message for failed modules */
2021-10-15 21:44:01 -07:00
2024-12-11 17:43:35 +01:00
if ( mfi . count ) {
QString failed_plugins ;
2021-10-15 21:44:01 -07:00
2024-12-11 17:43:35 +01:00
char * * plugin = mfi . failed_modules ;
while ( * plugin ) {
failed_plugins + = * plugin ;
failed_plugins + = " \n " ;
plugin + + ;
2021-09-28 16:14:20 -04:00
}
2018-07-15 18:58:53 -07:00
2024-12-11 17:43:35 +01:00
QString failed_msg = QTStr ( " PluginsFailedToLoad.Text " ) . arg ( failed_plugins ) ;
OBSMessageBox : : warning ( this , QTStr ( " PluginsFailedToLoad.Title " ) , failed_msg ) ;
2019-10-04 22:33:06 -07:00
}
2017-03-25 04:19:29 -07:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : OnFirstLoad ( )
2017-03-25 04:19:29 -07:00
{
2024-12-11 17:43:35 +01:00
OnEvent ( OBS_FRONTEND_EVENT_FINISHED_LOADING ) ;
2021-05-12 22:07:40 -07:00
2024-12-11 17:43:35 +01:00
# ifdef WHATSNEW_ENABLED
/* Attempt to load init screen if available */
if ( cef ) {
WhatsNewInfoThread * wnit = new WhatsNewInfoThread ( ) ;
connect ( wnit , & WhatsNewInfoThread : : Result , this , & OBSBasic : : ReceivedIntroJson , Qt : : QueuedConnection ) ;
2021-05-12 22:07:40 -07:00
2024-12-11 17:43:35 +01:00
introCheckThread . reset ( wnit ) ;
introCheckThread - > start ( ) ;
2019-10-04 22:33:06 -07:00
}
2024-12-11 17:43:35 +01:00
# endif
2021-05-12 22:07:40 -07:00
2024-12-11 17:43:35 +01:00
Auth : : Load ( ) ;
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
bool showLogViewerOnStartup = config_get_bool ( App ( ) - > GetUserConfig ( ) , " LogViewer " , " ShowLogStartup " ) ;
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
if ( showLogViewerOnStartup )
on_actionViewCurrentLog_triggered ( ) ;
2017-03-25 04:19:29 -07:00
}
2024-12-11 17:43:35 +01:00
OBSBasic : : ~ OBSBasic ( )
2021-04-29 23:51:04 -07:00
{
2024-12-11 17:43:35 +01:00
/* clear out UI event queue */
QApplication : : sendPostedEvents ( nullptr ) ;
QApplication : : sendPostedEvents ( nullptr , QEvent : : DeferredDelete ) ;
2021-04-29 23:51:04 -07:00
2024-12-11 17:43:35 +01:00
if ( updateCheckThread & & updateCheckThread - > isRunning ( ) )
updateCheckThread - > wait ( ) ;
2021-04-29 23:51:04 -07:00
2024-12-11 17:43:35 +01:00
if ( patronJsonThread & & patronJsonThread - > isRunning ( ) )
patronJsonThread - > wait ( ) ;
2021-04-29 23:51:04 -07:00
2024-12-11 17:43:35 +01:00
delete screenshotData ;
delete previewProjector ;
delete studioProgramProjector ;
delete previewProjectorSource ;
delete previewProjectorMain ;
delete sourceProjector ;
delete sceneProjectorMenu ;
delete scaleFilteringMenu ;
delete blendingModeMenu ;
delete colorMenu ;
delete colorWidgetAction ;
delete colorSelect ;
delete deinterlaceMenu ;
delete perSceneTransitionMenu ;
delete shortcutFilter ;
delete trayMenu ;
delete programOptions ;
delete program ;
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
/* XXX: any obs data must be released before calling obs_shutdown.
* currently , we can ' t automate this with C + + RAII because of the
* delicate nature of obs_shutdown needing to be freed before the UI
* can be freed , and we have no control over the destruction order of
* the Qt UI stuff , so we have to manually clear any references to
* libobs . */
delete cpuUsageTimer ;
os_cpu_usage_info_destroy ( cpuUsageInfo ) ;
2017-03-25 04:19:29 -07:00
2024-12-11 17:43:35 +01:00
obs_hotkey_set_callback_routing_func ( nullptr , nullptr ) ;
ClearHotkeys ( ) ;
2017-05-06 12:13:56 -07:00
2024-12-11 17:43:35 +01:00
service = nullptr ;
outputHandler . reset ( ) ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
delete interaction ;
delete properties ;
delete filters ;
delete transformWindow ;
delete advAudioWindow ;
delete about ;
delete remux ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
obs_display_remove_draw_callback ( ui - > preview - > GetDisplay ( ) , OBSBasic : : RenderMain , this ) ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
obs_enter_graphics ( ) ;
gs_vertexbuffer_destroy ( box ) ;
gs_vertexbuffer_destroy ( boxLeft ) ;
gs_vertexbuffer_destroy ( boxTop ) ;
gs_vertexbuffer_destroy ( boxRight ) ;
gs_vertexbuffer_destroy ( boxBottom ) ;
gs_vertexbuffer_destroy ( circle ) ;
gs_vertexbuffer_destroy ( actionSafeMargin ) ;
gs_vertexbuffer_destroy ( graphicsSafeMargin ) ;
gs_vertexbuffer_destroy ( fourByThreeSafeMargin ) ;
gs_vertexbuffer_destroy ( leftLine ) ;
gs_vertexbuffer_destroy ( topLine ) ;
gs_vertexbuffer_destroy ( rightLine ) ;
obs_leave_graphics ( ) ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
/* When shutting down, sometimes source references can get in to the
* event queue , and if we don ' t forcibly process those events they
* won ' t get processed until after obs_shutdown has been called . I
* really wish there were a more elegant way to deal with this via C + + ,
* but Qt doesn ' t use C + + in a normal way , so you can ' t really rely on
* normal C + + behavior for your data to be freed in the order that you
* expect or want it to . */
QApplication : : sendPostedEvents ( nullptr ) ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
config_set_int ( App ( ) - > GetAppConfig ( ) , " General " , " LastVersion " , LIBOBS_API_VER ) ;
config_save_safe ( App ( ) - > GetAppConfig ( ) , " tmp " , nullptr ) ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " PreviewEnabled " , previewEnabled ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " AlwaysOnTop " , ui - > actionAlwaysOnTop - > isChecked ( ) ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SceneDuplicationMode " , sceneDuplicationMode ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SwapScenesMode " , swapScenesMode ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " EditPropertiesMode " , editPropertiesMode ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " PreviewProgramMode " , IsPreviewProgramMode ( ) ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " DocksLocked " , ui - > lockDocks - > isChecked ( ) ) ;
config_set_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " SideDocks " , ui - > sideDocks - > isChecked ( ) ) ;
config_save_safe ( App ( ) - > GetUserConfig ( ) , " tmp " , nullptr ) ;
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
# ifdef BROWSER_AVAILABLE
DestroyPanelCookieManager ( ) ;
delete cef ;
cef = nullptr ;
2018-08-02 08:23:12 +12:00
# endif
}
2024-12-11 17:43:35 +01:00
static inline int AttemptToResetVideo ( struct obs_video_info * ovi )
2018-08-02 08:23:12 +12:00
{
2024-12-11 17:43:35 +01:00
return obs_reset_video ( ovi ) ;
2018-08-02 08:23:12 +12:00
}
2024-12-11 17:43:35 +01:00
static inline enum obs_scale_type GetScaleType ( ConfigFile & activeConfiguration )
2017-05-06 12:13:56 -07:00
{
2024-12-11 17:43:35 +01:00
const char * scaleTypeStr = config_get_string ( activeConfiguration , " Video " , " ScaleType " ) ;
if ( astrcmpi ( scaleTypeStr , " bilinear " ) = = 0 )
return OBS_SCALE_BILINEAR ;
else if ( astrcmpi ( scaleTypeStr , " lanczos " ) = = 0 )
return OBS_SCALE_LANCZOS ;
else if ( astrcmpi ( scaleTypeStr , " area " ) = = 0 )
return OBS_SCALE_AREA ;
else
return OBS_SCALE_BICUBIC ;
2017-05-06 12:13:56 -07:00
}
2017-05-10 19:37:45 -07:00
2024-12-11 17:43:35 +01:00
static inline enum video_format GetVideoFormatFromName ( const char * name )
2017-05-10 19:37:45 -07:00
{
2024-12-11 17:43:35 +01:00
if ( astrcmpi ( name , " I420 " ) = = 0 )
return VIDEO_FORMAT_I420 ;
else if ( astrcmpi ( name , " NV12 " ) = = 0 )
return VIDEO_FORMAT_NV12 ;
else if ( astrcmpi ( name , " I444 " ) = = 0 )
return VIDEO_FORMAT_I444 ;
else if ( astrcmpi ( name , " I010 " ) = = 0 )
return VIDEO_FORMAT_I010 ;
else if ( astrcmpi ( name , " P010 " ) = = 0 )
return VIDEO_FORMAT_P010 ;
else if ( astrcmpi ( name , " P216 " ) = = 0 )
return VIDEO_FORMAT_P216 ;
else if ( astrcmpi ( name , " P416 " ) = = 0 )
return VIDEO_FORMAT_P416 ;
#if 0 //currently unsupported
else if ( astrcmpi ( name , " YVYU " ) = = 0 )
return VIDEO_FORMAT_YVYU ;
else if ( astrcmpi ( name , " YUY2 " ) = = 0 )
return VIDEO_FORMAT_YUY2 ;
else if ( astrcmpi ( name , " UYVY " ) = = 0 )
return VIDEO_FORMAT_UYVY ;
# endif
else
return VIDEO_FORMAT_BGRA ;
2017-05-10 19:37:45 -07:00
}
2018-08-02 08:23:12 +12:00
2024-12-11 17:43:35 +01:00
static inline enum video_colorspace GetVideoColorSpaceFromName ( const char * name )
2018-08-18 01:13:20 -05:00
{
2024-12-11 17:43:35 +01:00
enum video_colorspace colorspace = VIDEO_CS_SRGB ;
if ( strcmp ( name , " 601 " ) = = 0 )
colorspace = VIDEO_CS_601 ;
else if ( strcmp ( name , " 709 " ) = = 0 )
colorspace = VIDEO_CS_709 ;
else if ( strcmp ( name , " 2100PQ " ) = = 0 )
colorspace = VIDEO_CS_2100_PQ ;
else if ( strcmp ( name , " 2100HLG " ) = = 0 )
colorspace = VIDEO_CS_2100_HLG ;
2018-08-18 01:13:20 -05:00
2024-12-11 17:43:35 +01:00
return colorspace ;
2018-08-18 01:13:20 -05:00
}
2024-12-11 17:43:35 +01:00
int OBSBasic : : ResetVideo ( )
2022-09-02 22:52:35 +02:00
{
2024-12-11 17:43:35 +01:00
if ( outputHandler & & outputHandler - > Active ( ) )
return OBS_VIDEO_CURRENTLY_ACTIVE ;
2022-09-02 22:52:35 +02:00
2024-12-11 17:43:35 +01:00
ProfileScope ( " OBSBasic::ResetVideo " ) ;
2022-09-02 22:52:35 +02:00
2024-12-11 17:43:35 +01:00
struct obs_video_info ovi ;
int ret ;
2022-09-02 22:52:35 +02:00
2024-12-11 17:43:35 +01:00
GetConfigFPS ( ovi . fps_num , ovi . fps_den ) ;
2022-09-02 22:52:35 +02:00
2024-12-11 17:43:35 +01:00
const char * colorFormat = config_get_string ( activeConfiguration , " Video " , " ColorFormat " ) ;
const char * colorSpace = config_get_string ( activeConfiguration , " Video " , " ColorSpace " ) ;
const char * colorRange = config_get_string ( activeConfiguration , " Video " , " ColorRange " ) ;
2022-09-02 22:52:35 +02:00
2024-12-11 17:43:35 +01:00
ovi . graphics_module = App ( ) - > GetRenderModule ( ) ;
ovi . base_width = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " BaseCX " ) ;
ovi . base_height = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " BaseCY " ) ;
ovi . output_width = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " OutputCX " ) ;
ovi . output_height = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " OutputCY " ) ;
ovi . output_format = GetVideoFormatFromName ( colorFormat ) ;
ovi . colorspace = GetVideoColorSpaceFromName ( colorSpace ) ;
ovi . range = astrcmpi ( colorRange , " Full " ) = = 0 ? VIDEO_RANGE_FULL : VIDEO_RANGE_PARTIAL ;
ovi . adapter = config_get_uint ( App ( ) - > GetUserConfig ( ) , " Video " , " AdapterIdx " ) ;
ovi . gpu_conversion = true ;
ovi . scale_type = GetScaleType ( activeConfiguration ) ;
2022-09-02 22:52:35 +02:00
2024-12-11 17:43:35 +01:00
if ( ovi . base_width < 32 | | ovi . base_height < 32 ) {
ovi . base_width = 1920 ;
ovi . base_height = 1080 ;
config_set_uint ( activeConfiguration , " Video " , " BaseCX " , 1920 ) ;
config_set_uint ( activeConfiguration , " Video " , " BaseCY " , 1080 ) ;
}
2022-10-22 09:49:27 +02:00
2024-12-11 17:43:35 +01:00
if ( ovi . output_width < 32 | | ovi . output_height < 32 ) {
ovi . output_width = ovi . base_width ;
ovi . output_height = ovi . base_height ;
config_set_uint ( activeConfiguration , " Video " , " OutputCX " , ovi . base_width ) ;
config_set_uint ( activeConfiguration , " Video " , " OutputCY " , ovi . base_height ) ;
}
2022-10-21 16:53:06 +02:00
2024-12-11 17:43:35 +01:00
ret = AttemptToResetVideo ( & ovi ) ;
if ( ret = = OBS_VIDEO_CURRENTLY_ACTIVE ) {
blog ( LOG_WARNING , " Tried to reset when already active " ) ;
return ret ;
2019-02-06 13:57:59 -08:00
}
2024-12-11 17:43:35 +01:00
if ( ret = = OBS_VIDEO_SUCCESS ) {
ResizePreview ( ovi . base_width , ovi . base_height ) ;
if ( program )
ResizeProgram ( ovi . base_width , ovi . base_height ) ;
2019-02-06 13:57:59 -08:00
2024-12-11 17:43:35 +01:00
const float sdr_white_level = ( float ) config_get_uint ( activeConfiguration , " Video " , " SdrWhiteLevel " ) ;
const float hdr_nominal_peak_level =
( float ) config_get_uint ( activeConfiguration , " Video " , " HdrNominalPeakLevel " ) ;
obs_set_video_levels ( sdr_white_level , hdr_nominal_peak_level ) ;
OBSBasicStats : : InitializeValues ( ) ;
OBSProjector : : UpdateMultiviewProjectors ( ) ;
2022-10-22 09:49:27 +02:00
2025-01-22 20:44:35 +01:00
if ( ! collections . empty ( ) ) {
const OBS : : SceneCollection currentSceneCollection = OBSBasic : : GetCurrentSceneCollection ( ) ;
bool usingAbsoluteCoordinates = currentSceneCollection . getCoordinateMode ( ) = =
OBS : : SceneCoordinateMode : : Absolute ;
OBS : : Rect migrationResolution = currentSceneCollection . getMigrationResolution ( ) ;
OBS : : Rect videoResolution = OBS : : Rect ( ovi . base_width , ovi . base_height ) ;
bool canMigrate = usingAbsoluteCoordinates | |
( ! migrationResolution . isZero ( ) & & migrationResolution ! = videoResolution ) ;
ui - > actionRemigrateSceneCollection - > setEnabled ( canMigrate ) ;
} else {
ui - > actionRemigrateSceneCollection - > setEnabled ( false ) ;
}
2022-10-22 09:49:27 +02:00
2024-12-11 17:43:35 +01:00
emit CanvasResized ( ovi . base_width , ovi . base_height ) ;
emit OutputResized ( ovi . output_width , ovi . output_height ) ;
}
2022-10-22 09:49:27 +02:00
2024-12-11 17:43:35 +01:00
return ret ;
2022-10-22 09:49:27 +02:00
}
2024-12-11 17:43:35 +01:00
bool OBSBasic : : ResetAudio ( )
2022-10-21 16:53:06 +02:00
{
2024-12-11 17:43:35 +01:00
ProfileScope ( " OBSBasic::ResetAudio " ) ;
2022-10-21 16:53:06 +02:00
2024-12-11 17:43:35 +01:00
struct obs_audio_info2 ai = { } ;
ai . samples_per_sec = config_get_uint ( activeConfiguration , " Audio " , " SampleRate " ) ;
2022-10-21 16:53:06 +02:00
2024-12-11 17:43:35 +01:00
const char * channelSetupStr = config_get_string ( activeConfiguration , " Audio " , " ChannelSetup " ) ;
2022-10-21 16:53:06 +02:00
2024-12-11 17:43:35 +01:00
if ( strcmp ( channelSetupStr , " Mono " ) = = 0 )
ai . speakers = SPEAKERS_MONO ;
else if ( strcmp ( channelSetupStr , " 2.1 " ) = = 0 )
ai . speakers = SPEAKERS_2POINT1 ;
else if ( strcmp ( channelSetupStr , " 4.0 " ) = = 0 )
ai . speakers = SPEAKERS_4POINT0 ;
else if ( strcmp ( channelSetupStr , " 4.1 " ) = = 0 )
ai . speakers = SPEAKERS_4POINT1 ;
else if ( strcmp ( channelSetupStr , " 5.1 " ) = = 0 )
ai . speakers = SPEAKERS_5POINT1 ;
else if ( strcmp ( channelSetupStr , " 7.1 " ) = = 0 )
ai . speakers = SPEAKERS_7POINT1 ;
2022-10-21 16:53:06 +02:00
else
2024-12-11 17:43:35 +01:00
ai . speakers = SPEAKERS_STEREO ;
2022-10-21 16:53:06 +02:00
2024-12-11 17:43:35 +01:00
bool lowLatencyAudioBuffering = config_get_bool ( App ( ) - > GetUserConfig ( ) , " Audio " , " LowLatencyAudioBuffering " ) ;
if ( lowLatencyAudioBuffering ) {
ai . max_buffering_ms = 20 ;
ai . fixed_buffering = true ;
2022-10-22 11:51:30 +02:00
}
2024-12-11 17:43:35 +01:00
return obs_reset_audio2 ( & ai ) ;
2022-10-22 11:51:30 +02:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : closeEvent ( QCloseEvent * event )
2022-10-22 11:51:30 +02:00
{
2024-12-11 17:43:35 +01:00
/* Wait for multitrack video stream to start/finish processing in the background */
if ( setupStreamingGuard . valid ( ) & &
setupStreamingGuard . wait_for ( std : : chrono : : seconds { 0 } ) ! = std : : future_status : : ready ) {
QTimer : : singleShot ( 1000 , this , & OBSBasic : : close ) ;
event - > ignore ( ) ;
2022-10-22 11:51:30 +02:00
return ;
}
2024-12-11 17:43:35 +01:00
/* Do not close window if inside of a temporary event loop because we
* could be inside of an Auth : : LoadUI call . Keep trying once per
* second until we ' ve exit any known sub - loops . */
if ( os_atomic_load_long ( & insideEventLoop ) ! = 0 ) {
QTimer : : singleShot ( 1000 , this , & OBSBasic : : close ) ;
event - > ignore ( ) ;
return ;
}
2019-02-18 19:28:26 -08:00
2024-12-11 17:43:35 +01:00
# ifdef YOUTUBE_ENABLED
/* Also don't close the window if the youtube stream check is active */
if ( youtubeStreamCheckThread ) {
QTimer : : singleShot ( 1000 , this , & OBSBasic : : close ) ;
event - > ignore ( ) ;
return ;
}
# endif
2019-02-18 19:28:26 -08:00
2024-12-11 17:43:35 +01:00
if ( isVisible ( ) )
config_set_string ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " geometry " ,
saveGeometry ( ) . toBase64 ( ) . constData ( ) ) ;
2019-04-07 03:34:21 -04:00
2024-12-11 17:43:35 +01:00
bool confirmOnExit = config_get_bool ( App ( ) - > GetUserConfig ( ) , " General " , " ConfirmOnExit " ) ;
2021-11-03 21:11:06 +01:00
2024-12-11 17:43:35 +01:00
if ( confirmOnExit & & outputHandler & & outputHandler - > Active ( ) & & ! clearingFailed ) {
SetShowing ( true ) ;
2019-04-07 03:34:21 -04:00
2024-12-11 17:43:35 +01:00
QMessageBox : : StandardButton button =
OBSMessageBox : : question ( this , QTStr ( " ConfirmExit.Title " ) , QTStr ( " ConfirmExit.Text " ) ) ;
2019-04-23 15:56:30 +08:00
2024-12-11 17:43:35 +01:00
if ( button = = QMessageBox : : No ) {
event - > ignore ( ) ;
restart = false ;
return ;
2019-04-23 15:56:30 +08:00
}
}
2024-12-11 17:43:35 +01:00
if ( remux & & ! remux - > close ( ) ) {
event - > ignore ( ) ;
restart = false ;
2019-05-05 20:00:06 -07:00
return ;
2024-12-11 17:43:35 +01:00
}
2019-05-05 20:00:06 -07:00
2024-12-11 17:43:35 +01:00
QWidget : : closeEvent ( event ) ;
if ( ! event - > isAccepted ( ) )
2019-07-07 15:47:29 -07:00
return ;
2024-12-11 17:43:35 +01:00
blog ( LOG_INFO , SHUTDOWN_SEPARATOR ) ;
2019-10-02 19:44:47 -04:00
2024-12-11 17:43:35 +01:00
closing = true ;
2020-04-14 20:16:33 +02:00
2024-12-11 17:43:35 +01:00
/* While closing, a resize event to OBSQTDisplay could be triggered.
* The graphics thread on macOS dispatches a lambda function to be
* executed asynchronously in the main thread . However , the display is
* sometimes deleted before the lambda function is actually executed .
* To avoid such a case , destroy displays earlier than others such as
* deleting browser docks . */
ui - > preview - > DestroyDisplay ( ) ;
if ( program )
program - > DestroyDisplay ( ) ;
2019-10-02 19:44:47 -04:00
2024-12-11 17:43:35 +01:00
if ( outputHandler - > VirtualCamActive ( ) )
outputHandler - > StopVirtualCam ( ) ;
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
if ( introCheckThread )
introCheckThread - > wait ( ) ;
if ( whatsNewInitThread )
whatsNewInitThread - > wait ( ) ;
if ( updateCheckThread )
updateCheckThread - > wait ( ) ;
if ( logUploadThread )
logUploadThread - > wait ( ) ;
if ( devicePropertiesThread & & devicePropertiesThread - > isRunning ( ) ) {
devicePropertiesThread - > wait ( ) ;
devicePropertiesThread . reset ( ) ;
2019-07-07 15:47:29 -07:00
}
2024-12-11 17:43:35 +01:00
QApplication : : sendPostedEvents ( nullptr ) ;
signalHandlers . clear ( ) ;
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
Auth : : Save ( ) ;
SaveProjectNow ( ) ;
auth . reset ( ) ;
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
delete extraBrowsers ;
2024-02-29 20:46:07 +00:00
2024-12-11 17:43:35 +01:00
config_set_string ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " DockState " , saveState ( ) . toBase64 ( ) . constData ( ) ) ;
2019-10-02 19:44:47 -04:00
2024-12-11 17:43:35 +01:00
# ifdef BROWSER_AVAILABLE
if ( cef )
SaveExtraBrowserDocks ( ) ;
2020-04-14 20:16:33 +02:00
2024-12-11 17:43:35 +01:00
ClearExtraBrowserDocks ( ) ;
2020-11-12 23:39:32 +01:00
# endif
2019-10-02 19:44:47 -04:00
2024-12-11 17:43:35 +01:00
OnEvent ( OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN ) ;
disableSaving + + ;
/* Clear all scene data (dialogs, widgets, widget sub-items, scenes,
* sources , etc ) so that all references are released before shutdown */
ClearSceneData ( ) ;
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
OnEvent ( OBS_FRONTEND_EVENT_EXIT ) ;
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
// Destroys the frontend API so plugins can't continue calling it
obs_frontend_set_callbacks_internal ( nullptr ) ;
api = nullptr ;
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
QMetaObject : : invokeMethod ( App ( ) , " quit " , Qt : : QueuedConnection ) ;
2019-07-07 15:47:29 -07:00
}
2024-12-11 17:43:35 +01:00
bool OBSBasic : : nativeEvent ( const QByteArray & , void * message , qintptr * )
2019-07-07 15:47:29 -07:00
{
2024-12-11 17:43:35 +01:00
# ifdef _WIN32
const MSG & msg = * static_cast < MSG * > ( message ) ;
switch ( msg . message ) {
case WM_MOVE :
for ( OBSQTDisplay * const display : findChildren < OBSQTDisplay * > ( ) ) {
display - > OnMove ( ) ;
}
break ;
case WM_DISPLAYCHANGE :
for ( OBSQTDisplay * const display : findChildren < OBSQTDisplay * > ( ) ) {
display - > OnDisplayChange ( ) ;
2019-07-07 15:47:29 -07:00
}
}
2024-12-11 17:43:35 +01:00
# else
UNUSED_PARAMETER ( message ) ;
# endif
2019-07-07 15:47:29 -07:00
2024-12-11 17:43:35 +01:00
return false ;
2024-04-03 17:08:14 +02:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : changeEvent ( QEvent * event )
2019-09-27 15:04:07 +02:00
{
2024-12-11 17:43:35 +01:00
if ( event - > type ( ) = = QEvent : : WindowStateChange ) {
QWindowStateChangeEvent * stateEvent = ( QWindowStateChangeEvent * ) event ;
2019-09-27 15:04:07 +02:00
2024-12-11 17:43:35 +01:00
if ( isMinimized ( ) ) {
if ( trayIcon & & trayIcon - > isVisible ( ) & & sysTrayMinimizeToTray ( ) ) {
ToggleShowHide ( ) ;
return ;
}
2019-09-27 15:04:07 +02:00
2024-12-11 17:43:35 +01:00
if ( previewEnabled )
EnablePreviewDisplay ( false ) ;
} else if ( stateEvent - > oldState ( ) & Qt : : WindowMinimized & & isVisible ( ) ) {
if ( previewEnabled )
EnablePreviewDisplay ( true ) ;
2019-09-27 15:04:07 +02:00
}
}
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : GetFPSCommon ( uint32_t & num , uint32_t & den ) const
2019-12-27 17:12:31 +08:00
{
2024-12-11 17:43:35 +01:00
const char * val = config_get_string ( activeConfiguration , " Video " , " FPSCommon " ) ;
2019-12-27 17:12:31 +08:00
2024-12-11 17:43:35 +01:00
if ( strcmp ( val , " 10 " ) = = 0 ) {
num = 10 ;
den = 1 ;
} else if ( strcmp ( val , " 20 " ) = = 0 ) {
num = 20 ;
den = 1 ;
} else if ( strcmp ( val , " 24 NTSC " ) = = 0 ) {
num = 24000 ;
den = 1001 ;
} else if ( strcmp ( val , " 25 PAL " ) = = 0 ) {
num = 25 ;
den = 1 ;
} else if ( strcmp ( val , " 29.97 " ) = = 0 ) {
num = 30000 ;
den = 1001 ;
} else if ( strcmp ( val , " 48 " ) = = 0 ) {
num = 48 ;
den = 1 ;
} else if ( strcmp ( val , " 50 PAL " ) = = 0 ) {
num = 50 ;
den = 1 ;
} else if ( strcmp ( val , " 59.94 " ) = = 0 ) {
num = 60000 ;
den = 1001 ;
} else if ( strcmp ( val , " 60 " ) = = 0 ) {
num = 60 ;
den = 1 ;
} else {
num = 30 ;
den = 1 ;
}
2019-12-27 17:12:31 +08:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : GetFPSInteger ( uint32_t & num , uint32_t & den ) const
2019-12-27 17:12:31 +08:00
{
2024-12-11 17:43:35 +01:00
num = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " FPSInt " ) ;
den = 1 ;
2024-03-28 16:43:12 -04:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : GetFPSFraction ( uint32_t & num , uint32_t & den ) const
2024-03-28 16:43:12 -04:00
{
2024-12-11 17:43:35 +01:00
num = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " FPSNum " ) ;
den = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " FPSDen " ) ;
2019-12-27 17:12:31 +08:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : GetFPSNanoseconds ( uint32_t & num , uint32_t & den ) const
2019-06-12 04:56:00 -05:00
{
2024-12-11 17:43:35 +01:00
num = 1000000000 ;
den = ( uint32_t ) config_get_uint ( activeConfiguration , " Video " , " FPSNS " ) ;
2019-06-12 04:56:00 -05:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : GetConfigFPS ( uint32_t & num , uint32_t & den ) const
2019-06-12 04:56:00 -05:00
{
2024-12-11 17:43:35 +01:00
uint32_t type = config_get_uint ( activeConfiguration , " Video " , " FPSType " ) ;
2019-06-12 04:56:00 -05:00
2024-12-11 17:43:35 +01:00
if ( type = = 1 ) //"Integer"
GetFPSInteger ( num , den ) ;
else if ( type = = 2 ) //"Fraction"
GetFPSFraction ( num , den ) ;
/*
* else if ( false ) //"Nanoseconds", currently not implemented
* GetFPSNanoseconds ( num , den ) ;
*/
2019-06-12 04:56:00 -05:00
else
2024-12-11 17:43:35 +01:00
GetFPSCommon ( num , den ) ;
2019-06-12 04:56:00 -05:00
}
2024-12-11 17:43:35 +01:00
config_t * OBSBasic : : Config ( ) const
2019-06-12 04:56:00 -05:00
{
2024-12-11 17:43:35 +01:00
return activeConfiguration ;
2019-06-12 04:56:00 -05:00
}
2019-10-10 20:12:20 -05:00
2024-12-11 17:43:35 +01:00
void OBSBasic : : UpdateEditMenu ( )
2019-10-15 23:20:35 -05:00
{
2024-12-11 17:43:35 +01:00
QModelIndexList items = GetAllSelectedSourceItems ( ) ;
int totalCount = items . count ( ) ;
size_t filter_count = 0 ;
2019-10-15 23:20:35 -05:00
2024-12-11 17:43:35 +01:00
if ( totalCount = = 1 ) {
OBSSceneItem sceneItem = ui - > sources - > Get ( GetTopSelectedSourceItem ( ) ) ;
OBSSource source = obs_sceneitem_get_source ( sceneItem ) ;
filter_count = obs_source_filter_count ( source ) ;
2023-10-04 17:32:44 -04:00
}
2020-02-14 23:30:34 +11:00
2024-12-11 17:43:35 +01:00
bool allowPastingDuplicate = ! ! clipboard . size ( ) ;
for ( size_t i = clipboard . size ( ) ; i > 0 ; i - - ) {
const size_t idx = i - 1 ;
OBSWeakSource & weak = clipboard [ idx ] . weak_source ;
if ( obs_weak_source_expired ( weak ) ) {
clipboard . erase ( clipboard . begin ( ) + idx ) ;
continue ;
}
OBSSourceAutoRelease strong = obs_weak_source_get_source ( weak . Get ( ) ) ;
if ( allowPastingDuplicate & & obs_source_get_output_flags ( strong ) & OBS_SOURCE_DO_NOT_DUPLICATE )
allowPastingDuplicate = false ;
2022-02-22 00:40:17 +11:00
}
2024-12-11 17:43:35 +01:00
int videoCount = 0 ;
bool canTransformMultiple = false ;
for ( int i = 0 ; i < totalCount ; i + + ) {
OBSSceneItem item = ui - > sources - > Get ( items . value ( i ) . row ( ) ) ;
OBSSource source = obs_sceneitem_get_source ( item ) ;
const uint32_t flags = obs_source_get_output_flags ( source ) ;
const bool hasVideo = ( flags & OBS_SOURCE_VIDEO ) ! = 0 ;
if ( hasVideo & & ! obs_sceneitem_locked ( item ) )
canTransformMultiple = true ;
if ( hasVideo )
videoCount + + ;
2022-02-22 00:40:17 +11:00
}
2024-12-11 17:43:35 +01:00
const bool canTransformSingle = videoCount = = 1 & & totalCount = = 1 ;
2020-06-13 21:00:55 -05:00
2024-12-11 17:43:35 +01:00
OBSSceneItem curItem = GetCurrentSceneItem ( ) ;
bool locked = curItem & & obs_sceneitem_locked ( curItem ) ;
2020-06-13 21:00:55 -05:00
2024-12-11 17:43:35 +01:00
ui - > actionCopySource - > setEnabled ( totalCount > 0 ) ;
ui - > actionEditTransform - > setEnabled ( canTransformSingle & & ! locked ) ;
ui - > actionCopyTransform - > setEnabled ( canTransformSingle ) ;
ui - > actionPasteTransform - > setEnabled ( canTransformMultiple & & hasCopiedTransform & & videoCount > 0 ) ;
ui - > actionCopyFilters - > setEnabled ( filter_count > 0 ) ;
ui - > actionPasteFilters - > setEnabled ( ! obs_weak_source_expired ( copyFiltersSource ) & & totalCount > 0 ) ;
ui - > actionPasteRef - > setEnabled ( ! ! clipboard . size ( ) ) ;
ui - > actionPasteDup - > setEnabled ( allowPastingDuplicate ) ;
2018-08-23 20:43:44 -05:00
2024-12-11 17:43:35 +01:00
ui - > actionMoveUp - > setEnabled ( totalCount > 0 ) ;
ui - > actionMoveDown - > setEnabled ( totalCount > 0 ) ;
ui - > actionMoveToTop - > setEnabled ( totalCount > 0 ) ;
ui - > actionMoveToBottom - > setEnabled ( totalCount > 0 ) ;
2020-08-23 05:12:46 -05:00
2024-12-11 17:43:35 +01:00
ui - > actionResetTransform - > setEnabled ( canTransformMultiple ) ;
ui - > actionRotate90CW - > setEnabled ( canTransformMultiple ) ;
ui - > actionRotate90CCW - > setEnabled ( canTransformMultiple ) ;
ui - > actionRotate180 - > setEnabled ( canTransformMultiple ) ;
ui - > actionFlipHorizontal - > setEnabled ( canTransformMultiple ) ;
ui - > actionFlipVertical - > setEnabled ( canTransformMultiple ) ;
ui - > actionFitToScreen - > setEnabled ( canTransformMultiple ) ;
ui - > actionStretchToScreen - > setEnabled ( canTransformMultiple ) ;
ui - > actionCenterToScreen - > setEnabled ( canTransformMultiple ) ;
ui - > actionVerticalCenter - > setEnabled ( canTransformMultiple ) ;
ui - > actionHorizontalCenter - > setEnabled ( canTransformMultiple ) ;
2018-08-23 20:43:44 -05:00
}
2024-12-11 17:43:35 +01:00
void OBSBasic : : UpdateTitleBar ( )
2018-08-23 20:43:44 -05:00
{
2024-12-11 17:43:35 +01:00
stringstream name ;
2021-01-11 23:26:02 -06:00
2024-12-11 17:43:35 +01:00
const char * profile = config_get_string ( App ( ) - > GetUserConfig ( ) , " Basic " , " Profile " ) ;
const char * sceneCollection = config_get_string ( App ( ) - > GetUserConfig ( ) , " Basic " , " SceneCollection " ) ;
2022-09-09 07:20:48 -05:00
2024-12-11 17:43:35 +01:00
name < < " OBS " ;
if ( previewProgramMode )
name < < " Studio " ;
2022-09-09 07:20:48 -05:00
2024-12-11 17:43:35 +01:00
name < < App ( ) - > GetVersionString ( false ) ;
if ( safe_mode )
name < < " ( " < < Str ( " TitleBar.SafeMode " ) < < " ) " ;
if ( App ( ) - > IsPortableMode ( ) )
name < < " - " < < Str ( " TitleBar.PortableMode " ) ;
2021-02-04 06:01:35 -06:00
2024-12-11 17:43:35 +01:00
name < < " - " < < Str ( " TitleBar.Profile " ) < < " : " < < profile ;
name < < " - " < < Str ( " TitleBar.Scenes " ) < < " : " < < sceneCollection ;
setWindowTitle ( QT_UTF8 ( name . str ( ) . c_str ( ) ) ) ;
2021-02-04 06:01:35 -06:00
}
2021-08-19 23:56:49 -05:00
2024-12-11 17:43:35 +01:00
OBSBasic * OBSBasic : : Get ( )
2021-08-19 23:56:49 -05:00
{
2024-12-11 17:43:35 +01:00
return reinterpret_cast < OBSBasic * > ( App ( ) - > GetMainWindow ( ) ) ;
2021-08-19 23:56:49 -05:00
}
2020-06-27 02:31:08 +02:00
2024-12-11 17:43:35 +01:00
void OBSBasic : : UpdatePatronJson ( const QString & text , const QString & error )
2023-02-10 13:27:08 +01:00
{
2024-12-11 17:43:35 +01:00
if ( ! error . isEmpty ( ) )
return ;
2023-02-10 13:27:08 +01:00
2024-12-11 17:43:35 +01:00
patronJson = QT_TO_UTF8 ( text ) ;
2023-02-10 13:27:08 +01:00
}
2020-06-27 02:31:08 +02:00
void OBSBasic : : SetDisplayAffinity ( QWindow * window )
{
if ( ! SetDisplayAffinitySupported ( ) )
return ;
2024-09-03 16:28:36 +02:00
bool hideFromCapture = config_get_bool ( App ( ) - > GetUserConfig ( ) , " BasicWindow " , " HideOBSWindowsFromCapture " ) ;
2020-06-27 02:31:08 +02:00
// Don't hide projectors, those are designed to be visible / captured
if ( window - > property ( " isOBSProjectorWindow " ) = = true )
return ;
# ifdef _WIN32
HWND hwnd = ( HWND ) window - > winId ( ) ;
2022-01-27 02:37:32 +01:00
DWORD curAffinity ;
if ( GetWindowDisplayAffinity ( hwnd , & curAffinity ) ) {
if ( hideFromCapture & & curAffinity ! = WDA_EXCLUDEFROMCAPTURE )
SetWindowDisplayAffinity ( hwnd , WDA_EXCLUDEFROMCAPTURE ) ;
2022-03-31 17:22:22 +02:00
else if ( ! hideFromCapture & & curAffinity ! = WDA_NONE )
2022-01-27 02:37:32 +01:00
SetWindowDisplayAffinity ( hwnd , WDA_NONE ) ;
}
2020-06-27 02:31:08 +02:00
# else
2022-01-28 23:52:18 +01:00
// TODO: Implement for other platforms if possible. Don't forget to
// implement SetDisplayAffinitySupported too!
UNUSED_PARAMETER ( hideFromCapture ) ;
2020-06-27 02:31:08 +02:00
# endif
}
2021-07-03 17:55:47 +12:00
2024-06-18 14:18:22 -05:00
void OBSBasic : : OnEvent ( enum obs_frontend_event event )
{
if ( api )
api - > on_event ( event ) ;
}
2024-07-31 10:53:59 -04:00
2024-09-03 16:29:30 +02:00
OBSPromptResult OBSBasic : : PromptForName ( const OBSPromptRequest & request , const OBSPromptCallback & callback )
{
OBSPromptResult result ;
for ( ; ; ) {
result . success = false ;
if ( request . withOption & & ! request . optionPrompt . empty ( ) ) {
result . optionValue = request . optionValue ;
result . success = NameDialog : : AskForNameWithOption (
this , request . title . c_str ( ) , request . prompt . c_str ( ) , result . promptValue ,
request . optionPrompt . c_str ( ) , result . optionValue ,
( request . promptValue . empty ( ) ? nullptr : request . promptValue . c_str ( ) ) ) ;
} else {
result . success = NameDialog : : AskForName (
this , request . title . c_str ( ) , request . prompt . c_str ( ) , result . promptValue ,
( request . promptValue . empty ( ) ? nullptr : request . promptValue . c_str ( ) ) ) ;
}
if ( ! result . success ) {
break ;
}
if ( result . promptValue . empty ( ) ) {
OBSMessageBox : : warning ( this , QTStr ( " NoNameEntered.Title " ) , QTStr ( " NoNameEntered.Text " ) ) ;
continue ;
}
if ( ! callback ( result ) ) {
OBSMessageBox : : warning ( this , QTStr ( " NameExists.Title " ) , QTStr ( " NameExists.Text " ) ) ;
continue ;
}
break ;
}
return result ;
}