Compare commits

...

97 Commits
1.6 ... 1.6.2

Author SHA1 Message Date
WarmUpTill
255d10e603 fix auto fill not wokring for modified entries on time tab 2020-08-09 20:48:49 +02:00
WarmUpTill
ab3e93ab84 add fallback to old format for sequence import 2020-08-02 20:22:13 +02:00
WarmUpTill
3b5f88c14f do not sort sequence and region on add 2020-08-02 19:38:32 +02:00
WarmUpTill
2f33b6bdc3 fix data loss for sequence delay 2020-08-02 19:37:37 +02:00
WarmUpTill
3c1e240722 add option to set startup behavior 2020-08-02 18:45:44 +02:00
WarmUpTill
91831a1075 fix autoStop not being persisted 2020-08-02 18:00:50 +02:00
WarmUpTill
ccc824abc1 fix loading of old delay values 2020-08-02 17:46:36 +02:00
WarmUpTill
6f39d4648b add included 'thread' and 'QAction' for Linux and macOS build 2020-08-01 20:34:12 +02:00
WarmUpTill
74cb400426 Merge branch 'master' of https://github.com/WarmUpTill/SceneSwitcher 2020-08-01 20:15:49 +02:00
WarmUpTill
910b1dde99 set sceneRoundTripDelayUnits 2020-08-01 16:19:57 +02:00
WarmUpTill
e462d7f420 fix sequence not stopping when manually switching scene 2020-08-01 16:11:54 +02:00
WarmUpTill
0cdd8bf1d0 move UI init of tabs to respective source files 2020-08-01 11:14:54 +02:00
WarmUpTill
f8ad8c31be scene sequence adjustments
use double internally instead of two ints
rework save / load to file to reuse existing functionality
add option to select between seconds / minutes / hours
2020-08-01 10:12:32 +02:00
WarmUpTill
93c889c215 fix MacOS CI issue 2020-07-31 22:18:52 +02:00
WarmUpTill
f8b505fa4e silence warnings 2020-07-31 22:05:55 +02:00
WarmUpTill
1516263d2a save and load tab order 2020-07-31 21:58:17 +02:00
WarmUpTill
79f5ec340d allow reordering of tabs and silence a few UI warnings 2020-07-29 20:23:03 +02:00
WarmUpTill
cd54cc17c0 fix switch priority falling back to default values on startup 2020-07-09 19:57:55 +02:00
WarmUpTill
098159dc0f increase window size on mac
currently the general tab will be compressed to an almost unusable level due to the differences in Windows and Macintosh styles
2020-06-30 20:11:44 +02:00
WarmUpTill
a4418996f4 disable mediaTime selection if restriction is set to none 2020-06-19 19:52:43 +02:00
WarmUpTill
340cb559ee add option to override transitionOverrides 2020-06-17 22:16:47 +02:00
WarmUpTill
eeefd8279f allow reordering of file/media/sequence/region 2020-06-16 20:25:25 +02:00
WarmUpTill
e62dc91cd7 fix linux/mac build error 2020-06-15 21:46:58 +02:00
WarmUpTill
536041abd2 Merge branch 'master' of https://github.com/WarmUpTill/SceneSwitcher 2020-06-15 21:20:02 +02:00
WarmUpTill
d3ab9e01c5 add support for remote file using libcurl 2020-06-15 21:19:34 +02:00
WarmUpTill
2113025877 undo switch to Visual Studio 15 2017
windows-latest image only supports Visual Studio 16 2019
2020-06-15 18:48:32 +02:00
WarmUpTill
6aaffeb5a4 use CMAKE_GENERATOR "Visual Studio 15 2017"
the 2017 version of the Microsoft Visual C++ Redistributable for Visual Studio is more widespread than the 2019 one and thus is less likely to require users to install the Redistributable manually
2020-06-15 18:32:01 +02:00
WarmUpTill
2a92df4f3c add draft of remote file support 2020-06-14 20:35:02 +02:00
WarmUpTill
560044bbbf implement export/import of settings 2020-06-14 15:22:34 +02:00
WarmUpTill
4bd8cdf5a0 move auto start/stop to gernal.cpp 2020-06-14 14:17:03 +02:00
WarmUpTill
c17cbb66d9 write to OBS log if verbose logging is enabled 2020-06-14 14:14:00 +02:00
WarmUpTill
8d23dd46b0 add export/import button and verbose log checkbox 2020-06-14 13:57:11 +02:00
WarmUpTill
bf70bd7c60 move saving and loading to separate files 2020-06-13 21:56:26 +02:00
WarmUpTill
1a144d84f5 set correct qt lib path for macos builds 2020-06-12 21:42:23 +02:00
WarmUpTill
6810ba71e8 remove using namespace std 2020-06-12 21:40:06 +02:00
WarmUpTill
bbe6a30506 clarify idle detection inputs 2020-06-12 18:48:30 +02:00
WarmUpTill
08c668f90a Merge pull request #24 from Myned/master
General improvements, changes, and fixes
2020-06-12 18:39:08 +02:00
WarmUpTill
3151a7542f return true in isFullscreen() if window maximized 2020-06-11 16:25:17 +02:00
Myned
7bfde0a39b Add regex matching to fullscreen check 2020-06-10 04:06:04 -04:00
Myned
7347be370e Fix type error
Pushed a little too soon
2020-06-09 17:14:22 -04:00
Myned
66d847c047 Fix ignored switches not directly matching last window 2020-06-09 17:10:14 -04:00
Myned
c9f1f9624b Use actual window titles and fix fullscreen check on macOS
Fallback to window owner if title does not exist
Remove duplicate entries from list
2020-06-09 07:49:39 -04:00
Myned
8e4a8b7e9d Use QString::fromStdString() instead of c_str() 2020-06-09 07:10:30 -04:00
Myned
e693794549 Add sorting of window lists for UI 2020-06-09 07:09:08 -04:00
Myned
7a924438bc Add .clang-format and apply to src/ files 2020-06-08 14:58:44 -04:00
Myned
7458e9f2d5 Change and fix a multitude of UI elements
Fix spelling
Add minimum size
Simplify tab names and reorder by type and use
Change layout of start, interval, and no-condition selection
2020-06-07 21:09:48 -04:00
Myned
da2e11e35e Resize UI to fit added elements
This size is what Qt Designer defaults to when saving
2020-06-07 14:19:23 -04:00
Myned
9f7ca3e4c7 Merge remote-tracking branch 'WarmUpTill/master' 2020-06-07 14:15:08 -04:00
WarmUpTill
2f77d99161 Undo "Revert "do not use QThread::create""
This reverts commit 4b86849356.
2020-06-07 14:15:01 -04:00
WarmUpTill
acd2e2863a adjust win isFullscreen() to use GetMonitorInfo()
only tested on a single monitor setup but should work on secondary monitors also as MONITOR_DEFAULTTONEAREST is set
2020-06-07 13:25:51 +02:00
WarmUpTill
513fe0728c initialize SwitcherThread to nullptr 2020-06-07 10:43:52 +02:00
Myned
cba39633aa Add ability to reorder Window and Executable switches with arrows 2020-06-06 23:23:02 -04:00
Myned
c6a26d862f Enable sorting for Ignored windows
There is no use in reordering them
2020-06-06 23:21:06 -04:00
Myned
9386109168 Remove tooltip from UI
Wasn't able to isolate it to the link, so it gets in the way
2020-06-06 23:20:14 -04:00
WarmUpTill
4b86849356 Revert "do not use QThread::create"
This reverts commit 98c3131017.
2020-06-06 22:38:22 -04:00
Myned
8fd263f44a Merge remote-tracking branch 'WarmUpTill/master' 2020-06-06 18:40:17 -04:00
Myned
5590e97f4f Fix fullscreen check only returning true if window is focused on Windows
by @WarmUpTill
2020-06-06 18:39:57 -04:00
WarmUpTill
98c3131017 do not use QThread::create
there might still be versions of QT in use which do not yet have this functionality (see Linux build fail of f03fca8)
2020-06-06 18:51:26 +02:00
WarmUpTill
f03fca85aa add thread priority option (using QThread) 2020-06-06 17:05:49 +02:00
WarmUpTill
7fef29dafb fix media delete button deleting wrong entry
the mediaSwitches UI is sorted alphabetically while the switches data strucutre is not
the previous implementation of the delete function was just using the index of the currently selected row to delete  this index of the switches data structure
the new implementation will try to find the correct entry and delete it
2020-06-06 08:59:03 +02:00
WarmUpTill
9f03264672 fix memory leak in check for media switch 2020-06-04 20:35:36 +02:00
WarmUpTill
5082f5944e prune media switches if invalid 2020-06-03 19:56:18 +02:00
WarmUpTill
b981a446b6 fix for times switch not saving when using previous scene 2020-06-03 19:55:06 +02:00
WarmUpTill
5ab8199e03 add log on start / stop of switcher thread 2020-06-02 20:53:26 +02:00
WarmUpTill
e6a3f98ab7 use source_id to identify meida sources 2020-06-02 20:45:46 +02:00
WarmUpTill
5e60cefd1c update current selection on media tab when selecting a different row 2020-06-02 19:34:15 +02:00
Myned
fabb7406bd Merge remote-tracking branch 'WarmUpTill/master' 2020-06-02 00:48:01 -04:00
Myned
cfb0a44b1f Change UI to specify greater than
Scene locking can occur when interval is equal to transition time due to inconsistencies in timers
2020-06-02 00:40:22 -04:00
Myned
78ed7415f5 Fix allocation error 2020-06-02 00:39:14 -04:00
Myned
d6380b865e Fix some windows (Steam) not being found on Linux
Reverts part of commit e61905d02f

Fallback to WM_NAME if _NET_WM_NAME does not exist

Also fixes some BadWindow errors that were due to some apps like Steam only populating WM_NAME, and only for certain windows (tooltips count as windows due to the odd way the GUI works on Linux, so they don't have either property)
2020-06-02 00:38:35 -04:00
Myned
55d8303ecf Fix isFullscreen() logic error for Linux
Not sure why this arose in the first place
2020-05-26 02:44:12 -04:00
Myned
23201100fa Fix macOS build error (again)
Adds to f0cf5a5c19

Forgot to remove vestigial code
2020-05-23 00:34:40 -04:00
Myned
3959e41e88 Add clearing of passed window list like with other platforms 2020-05-23 00:27:19 -04:00
Myned
f0cf5a5c19 Fix Windows and macOS build errors
Adds to e4b640903d and de5b6f8eb4
2020-05-23 00:25:30 -04:00
Myned
87da123c19 Change default focus value to true 2020-05-23 00:00:04 -04:00
Myned
2a0e9e9d9a Change wording 2020-05-22 23:58:18 -04:00
Myned
a7a8adb91b Remove whitespace 2020-05-21 00:54:49 -04:00
Myned
e61905d02f Change window title property on Linux to align with freedesktop spec
Freedesktop recommends using _NET_WM_NAME instead of WM_NAME, and on KDE, for example, the difference between them is including the application name for some windows (e.g. "freedesktop - Google Search - Vivaldi" compared to "freedesktop - Google Search")
2020-05-21 00:53:47 -04:00
Myned
f00c244bfa Change wording slightly 2020-05-21 00:52:41 -04:00
Myned
463b54f1fb Remove sorting when adding switches 2020-05-21 00:52:11 -04:00
Myned
70894f9302 Add regex matching to reverted isInFocus() for Windows
Reverts part of a4de8c0c59
2020-05-21 00:42:58 -04:00
Myned
de5b6f8eb4 Fix fullscreen check only returning true if window is focused on Linux 2020-05-21 00:40:37 -04:00
Myned
be83232caa Update UI for focus addition, add/change warnings, and move exe tab 2020-05-21 00:37:03 -04:00
Myned
e4b640903d Add ability to choose focus state to window title switcher 2020-05-21 00:34:22 -04:00
Myned
a4de8c0c59 Change isInFocus() check to be OS-agnostic
isInFocus() can utilize the platform-dependent GetCurrentWindowTitle() instead of re-implementing the same functionality.

Tested on Linux and macOS without issues
2020-05-18 00:11:07 -04:00
Myned
ac051a42a8 Remove unnecessary spaces 2020-05-18 00:06:19 -04:00
Myned
e33e93fd18 Change UI warning to allow direct matches and disable list sorting 2020-05-17 13:47:48 -04:00
Myned
d5052c94ca Add direct matching to window, executable, and ignored switches
Reverts part of commit 5f87a61177

Direct matching occurs in the same loop as regex in order to allow the list order to function as indicated in the UI
2020-05-17 13:44:50 -04:00
Myned
f0aa76517a Change executable switcher warning to regex requirement
Also change wording to align with Window Title, and fix an inconsequential error
2020-05-17 00:27:01 -04:00
Myned
a2543f1b85 Add ability to use existing window ignore for executable switching
Also cleaned up some logic
2020-05-17 00:24:24 -04:00
Myned
5f87a61177 Remove direct match from window switcher and reorganize
Direct matching before regex has the potential to interfere with some usecases. For example, if a user wants to enter regex syntax such as `shell[1]`, a direct match would return a window matching `shell[1]` exactly instead of `shell1`. Granted, the odds of the two conflicting each other are slim, but the core logic shouldn't prevent a user from utilizing regex to its full potential. One can always escape reserved characters if they want to match it directly. I have also added a warning and link to https://regexr.com in the UI should this be accepted.

The rest of what has changed is simply to align with the executable switcher's matching, namely the use of `QRegularExpression` to drop the need for a try/catch block and moving the check for fullscreen to the if statement in order to remove the possibility of a race condition.
2020-05-17 00:18:28 -04:00
Myned
451bb6518c Revert "Move forms/advanced-scene-switcher.ui to src/headers/"
This reverts commit 318502d8d0.
2020-05-16 23:42:26 -04:00
Myned
318502d8d0 Move forms/advanced-scene-switcher.ui to src/headers/
Out-of-tree building (at least) fails without this file in this location, and builds successfully without it under forms
2020-05-14 19:11:04 -04:00
Myned
e9b1ef58ba Change executable list to disable sorting
This allows the UI to show the order in which the executables will be checked
2020-05-14 18:56:39 -04:00
Myned
26c24d4d53 Change executable entry box to be editable 2020-05-14 18:56:39 -04:00
Myned
3654f39247 Fix scene not switching with multiple executables 2020-05-14 18:56:39 -04:00
Myned
b45b38cf6a Add ability to use regex for executable switching
Previously, only exact matches to a window title would switch scenes
2020-05-14 18:56:39 -04:00
25 changed files with 6461 additions and 4434 deletions

107
.clang-format Normal file
View File

@@ -0,0 +1,107 @@
# please use clang-format version 8 or later
Standard: Cpp11
AccessModifierOffset: -8
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
#AllowAllArgumentsOnNextLine: false # requires clang-format 9
#AllowAllConstructorInitializersOnNextLine: false # requires clang-format 9
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
#AllowShortLambdasOnASingleLine: Inline # requires clang-format 9
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakStringLiterals: false # apparently unpredictable
ColumnLimit: 80
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
FixNamespaceComments: false
ForEachMacros:
- 'json_object_foreach'
- 'json_object_foreach_safe'
- 'json_array_foreach'
IncludeBlocks: Preserve
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # requires clang-format 7
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
#SpaceAfterLogicalNot: false # requires clang-format 9
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # requires clang-format 7
#SpaceBeforeInheritanceColon: true # requires clang-format 7
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # requires clang-format 7
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
#StatementMacros: # requires clang-format 8
# - 'Q_OBJECT'
TabWidth: 8
#TypenameMacros: # requires clang-format 9
# - 'DARRAY'
UseTab: ForContinuationAndIndentation
---
Language: ObjC

View File

@@ -35,6 +35,7 @@ jobs:
shell: bash
run: |
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/CI/macos
brew update
brew bundle
cd -
- name: 'Install prerequisite: Pre-built dependencies'
@@ -70,9 +71,9 @@ jobs:
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
FILE_DATE=$(date +%Y-%m-%d)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
echo "::set-env name=FILE_NAME::${FILE_NAME}"

View File

@@ -13,6 +13,7 @@ if(BUILD_OUT_OF_TREE)
find_package(LibObs REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Libcurl REQUIRED)
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
@@ -96,14 +97,16 @@ if(BUILD_OUT_OF_TREE)
"${LIBOBS_INCLUDE_DIRS}"
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
${Qt5Core_INCLUDES}
${Qt5Widgets_INCLUDES})
${Qt5Widgets_INCLUDES}
${LIBCURL_INCLUDE_DIRS})
target_link_libraries(advanced-scene-switcher
${advanced-scene-switcher_PLATFORM_LIBS}
${LIBOBS_LIB}
${LIBOBS_FRONTEND_API_LIB}
Qt5::Core
Qt5::Widgets)
Qt5::Widgets
${LIBCURL_LIBRARIES})
# Additional commands to install the module in the correct place.
# Find all the translation files so we can copy them to the correct
@@ -224,7 +227,8 @@ else ()
${advanced-scene-switcher_PLATFORM_LIBS}
obs-frontend-api
Qt5::Widgets
libobs)
libobs
${LIBCURL_LIBRARIES})
install_obs_plugin(advanced-scene-switcher data)
endif()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,11 @@
#include "headers/advanced-scene-switcher.hpp"
int SceneSwitcher::executableFindByData(const QString& exe)
int SceneSwitcher::executableFindByData(const QString &exe)
{
int count = ui->executables->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->executables->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->executables->item(i);
QString itemExe = item->data(Qt::UserRole).toString();
if (itemExe == exe)
@@ -16,7 +15,6 @@ int SceneSwitcher::executableFindByData(const QString& exe)
return -1;
}
void SceneSwitcher::on_executables_currentRowChanged(int idx)
{
if (loading)
@@ -24,26 +22,55 @@ void SceneSwitcher::on_executables_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->executables->item(idx);
QListWidgetItem *item = ui->executables->item(idx);
QString exec = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches)
{
if (exec.compare(s.mExe) == 0)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->executableSwitches) {
if (exec.compare(s.mExe) == 0) {
QString sceneName = GetWeakSourceName(s.mScene).c_str();
QString transitionName = GetWeakSourceName(s.mTransition).c_str();
QString transitionName =
GetWeakSourceName(s.mTransition).c_str();
ui->executableScenes->setCurrentText(sceneName);
ui->executable->setCurrentText(exec);
ui->executableTransitions->setCurrentText(transitionName);
ui->executableTransitions->setCurrentText(
transitionName);
ui->requiresFocusCheckBox->setChecked(s.mInFocus);
break;
}
}
}
void SceneSwitcher::on_executableUp_clicked()
{
int index = ui->executables->currentRow();
if (index != -1 && index != 0) {
ui->executables->insertItem(index - 1,
ui->executables->takeItem(index));
ui->executables->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->executableSwitches.begin() + index,
switcher->executableSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_executableDown_clicked()
{
int index = ui->executables->currentRow();
if (index != -1 && index != ui->executables->count() - 1) {
ui->executables->insertItem(index + 1,
ui->executables->takeItem(index));
ui->executables->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->executableSwitches.begin() + index,
switcher->executableSwitches.begin() + index + 1);
}
}
void SceneSwitcher::on_executableAdd_clicked()
{
@@ -59,30 +86,28 @@ void SceneSwitcher::on_executableAdd_clicked()
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(exeName);
QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus);
QString text = MakeSwitchNameExecutable(sceneName, exeName,
transitionName, inFocus);
int idx = executableFindByData(exeName);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->executableSwitches.emplace_back(
source, transition, exeName.toUtf8().constData(), inFocus);
source, transition, exeName.toUtf8().constData(),
inFocus);
QListWidgetItem* item = new QListWidgetItem(text, ui->executables);
QListWidgetItem *item =
new QListWidgetItem(text, ui->executables);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->executables->item(idx);
} else {
QListWidgetItem *item = ui->executables->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches)
{
if (s.mExe == exeName)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->executableSwitches) {
if (s.mExe == exeName) {
s.mScene = source;
s.mTransition = transition;
s.mInFocus = inFocus;
@@ -90,30 +115,25 @@ void SceneSwitcher::on_executableAdd_clicked()
}
}
}
ui->executables->sortItems();
}
}
void SceneSwitcher::on_executableRemove_clicked()
{
QListWidgetItem* item = ui->executables->currentItem();
QListWidgetItem *item = ui->executables->currentItem();
if (!item)
return;
QString exe = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->executableSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->executableSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.mExe == exe)
{
if (s.mExe == exe) {
switches.erase(it);
break;
}
@@ -123,18 +143,138 @@ void SceneSwitcher::on_executableRemove_clicked()
delete item;
}
void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
std::string title;
QStringList runningProcesses;
bool ignored = false;
// Check if current window is ignored
GetCurrentWindowTitle(title);
for (auto &window : ignoreWindowsSwitches) {
// True if ignored switch equals title
bool equals = (title == window);
// True if ignored switch matches title
bool matches = QString::fromStdString(title).contains(
QRegularExpression(QString::fromStdString(window)));
if (equals || matches) {
ignored = true;
title = lastTitle;
break;
}
}
lastTitle = title;
// Check for match
GetProcessList(runningProcesses);
for (ExecutableSceneSwitch& s : executableSwitches)
{
if (runningProcesses.contains(s.mExe))
{
for (ExecutableSceneSwitch &s : executableSwitches) {
// True if executable switch is running (direct)
bool equals = runningProcesses.contains(s.mExe);
// True if executable switch is running (regex)
bool matches = (runningProcesses.indexOf(
QRegularExpression(s.mExe)) != -1);
// True if focus is disabled OR switch is focused
bool focus = (!s.mInFocus || isInFocus(s.mExe));
// True if current window is ignored AND switch equals OR matches last window
bool ignore =
(ignored && (title == s.mExe.toStdString() ||
QString::fromStdString(title).contains(
QRegularExpression(s.mExe))));
if ((equals || matches) && (focus || ignore)) {
match = true;
scene = s.mScene;
transition = s.mTransition;
match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe));
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher exec match");
break;
}
}
}
void SwitcherData::saveExecutableSwitches(obs_data_t *obj)
{
obs_data_array_t *executableArray = obs_data_array_create();
for (ExecutableSceneSwitch &s : switcher->executableSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.mScene);
obs_source_t *transition =
obs_weak_source_get_source(s.mTransition);
if (source && transition) {
const char *sceneName = obs_source_get_name(source);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "scene", sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_string(array_obj, "exefile",
s.mExe.toUtf8());
obs_data_set_bool(array_obj, "infocus", s.mInFocus);
obs_data_array_push_back(executableArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "executableSwitches", executableArray);
obs_data_array_release(executableArray);
}
void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
{
switcher->executableSwitches.clear();
obs_data_array_t *executableArray =
obs_data_get_array(obj, "executableSwitches");
size_t count = obs_data_array_count(executableArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(executableArray, i);
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
const char *exe = obs_data_get_string(array_obj, "exefile");
bool infocus = obs_data_get_bool(array_obj, "infocus");
switcher->executableSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), exe, infocus);
obs_data_release(array_obj);
}
obs_data_array_release(executableArray);
}
void SceneSwitcher::setupExecutableTab()
{
populateSceneSelection(ui->executableScenes, false);
populateTransitionSelection(ui->executableTransitions);
QStringList processes;
GetProcessList(processes);
for (QString &process : processes)
ui->executable->addItem(process);
for (auto &s : switcher->executableSwitches) {
std::string sceneName = GetWeakSourceName(s.mScene);
std::string transitionName = GetWeakSourceName(s.mTransition);
QString text = MakeSwitchNameExecutable(sceneName.c_str(),
s.mExe,
transitionName.c_str(),
s.mInFocus);
QListWidgetItem *item =
new QListWidgetItem(text, ui->executables);
item->setData(Qt::UserRole, s.mExe);
}
}

View File

@@ -2,14 +2,18 @@
#include <QTextStream>
#include <QDateTime>
#include <obs.hpp>
#include <curl/curl.h>
#include "headers/advanced-scene-switcher.hpp"
#define LOCAL_FILE_IDX 0
#define REMOTE_FILE_IDX 1
void SceneSwitcher::on_browseButton_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
this, tr("Select a file to write to ..."), QDir::currentPath(),
tr("Text files (*.txt)"));
if (!path.isEmpty())
ui->writePathLineEdit->setText(path);
}
@@ -19,29 +23,25 @@ void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
std::lock_guard<std::mutex> lock(switcher->m);
if (!state) {
ui->browseButton_2->setDisabled(true);
ui->readPathLineEdit->setDisabled(true);
switcher->fileIO.readEnabled = false;
}
else
{
} else {
ui->browseButton_2->setDisabled(false);
ui->readPathLineEdit->setDisabled(false);
switcher->fileIO.readEnabled = true;
}
}
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (text.isEmpty())
{
std::lock_guard<std::mutex> lock(switcher->m);
if (text.isEmpty()) {
switcher->fileIO.readEnabled = false;
return;
}
@@ -49,14 +49,13 @@ void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
switcher->fileIO.readPath = text.toUtf8().constData();
}
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (text.isEmpty())
{
std::lock_guard<std::mutex> lock(switcher->m);
if (text.isEmpty()) {
switcher->fileIO.writeEnabled = false;
return;
}
@@ -67,7 +66,8 @@ void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
void SceneSwitcher::on_browseButton_2_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
this, tr("Select a file to read from ..."), QDir::currentPath(),
tr("Any files (*.*)"));
if (!path.isEmpty())
ui->readPathLineEdit->setText(path);
}
@@ -77,31 +77,32 @@ void SwitcherData::writeSceneInfoToFile()
if (!fileIO.writeEnabled || fileIO.writePath.empty())
return;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_source_t *currentSource = obs_frontend_get_current_scene();
QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::WriteOnly))
{
const char* msg = obs_source_get_name(currentSource);
if (file.open(QIODevice::WriteOnly)) {
const char *msg = obs_source_get_name(currentSource);
file.write(msg, qstrlen(msg));
file.close();
}
obs_source_release(currentSource);
}
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
if (!fileIO.readEnabled || fileIO.readPath.empty())
return;
QFile file(QString::fromStdString(fileIO.readPath));
if (file.open(QIODevice::ReadOnly))
{
if (file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
QString sceneStr = in.readLine();
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
if (sceneRead){
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
obs_source_t *sceneRead =
obs_get_source_by_name(sceneStr.toUtf8().constData());
if (sceneRead) {
obs_weak_source_t *sceneReadWs =
obs_source_get_weak_source(sceneRead);
match = true;
scene = sceneReadWs;
@@ -114,61 +115,114 @@ void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OB
}
}
void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
void *userp)
{
for (FileSwitch& s : fileSwitches)
{
((std::string *)userp)->append((char *)contents, size * nmemb);
return size * nmemb;
}
std::string getRemoteData(std::string &url)
{
CURL *curl;
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return readBuffer;
}
bool compareIgnoringLineEnding(QString &s1, QString &s2)
{
/*
Im using QTextStream here so the conversion between different lineendings is done by QT.
QT itself uses only the linefeed internally so the input by the user is always using that,
but the files selected by the user might use different line endings.
If you are reading this and know of a cleaner way to do this, please let me know :)
*/
QTextStream s1stream(&s1);
QTextStream s2stream(&s2);
while (!s1stream.atEnd() && !s2stream.atEnd()) {
QString s1s = s1stream.readLine();
QString s2s = s2stream.readLine();
if (QString::compare(s1s, s2s, Qt::CaseSensitive) != 0) {
return false;
}
}
return true;
}
bool checkRemoteFileContent(FileSwitch &s)
{
std::string data = getRemoteData(s.file);
bool ret = false;
if (s.useRegex) {
ret = QString::fromStdString(data).contains(
QRegularExpression(QString::fromStdString(s.text)));
return ret;
}
QString t = QString::fromStdString(s.text);
QString d = QString::fromStdString(data);
return compareIgnoringLineEnding(t, d);
}
bool checkLocalFileContent(FileSwitch &s)
{
bool equal = false;
QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly))
return false;
if (s.useTime) {
QDateTime newLastMod = QFileInfo(file).lastModified();
if (s.lastMod == newLastMod)
return false;
s.lastMod = newLastMod;
}
if (s.useRegex) {
QTextStream in(&file);
QRegExp rx(t);
equal = rx.exactMatch(in.readAll());
} else {
QTextStream in(&file);
QString filedata = in.readAll();
equal = compareIgnoringLineEnding(filedata, t);
}
file.close();
return equal;
}
void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
for (FileSwitch &s : fileSwitches) {
bool equal = false;
QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly))
continue;
if (s.useTime)
{
QDateTime newLastMod = QFileInfo(file).lastModified();
if (s.lastMod == newLastMod)
continue;
s.lastMod = newLastMod;
if (s.remote) {
equal = checkRemoteFileContent(s);
} else {
equal = checkLocalFileContent(s);
}
if (s.useRegex)
{
QTextStream in(&file);
QRegExp rx(t);
equal = rx.exactMatch(in.readAll());
}
else
{
/*Im using QTextStream here so the conversion between different lineendings is done by QT.
*QT itself uses only the linefeed internally so the input by the user is always using that,
*but the files selected by the user might use different line endings.
*If you are reading this and know of a cleaner way to do this, please let me know :)
*/
QTextStream in(&file);
QTextStream text(&t);
while (!in.atEnd() && !text.atEnd())
{
QString fileLine = in.readLine();
QString textLine = text.readLine();
if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0)
{
equal = false;
break;
}
else {
equal = true;
}
}
}
file.close();
if (equal)
{
if (equal) {
scene = s.scene;
transition = s.transition;
match = true;
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher file match");
break;
}
}
@@ -177,42 +231,63 @@ void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSo
void SceneSwitcher::on_browseButton_3_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
this, tr("Select a file to read from ..."), QDir::currentPath(),
tr("Any files (*.*)"));
if (!path.isEmpty())
ui->filePathLineEdit->setText(path);
}
void SceneSwitcher::on_fileType_currentIndexChanged(int idx)
{
if (idx == -1)
return;
if (idx == LOCAL_FILE_IDX) {
ui->browseButton_3->setDisabled(false);
ui->fileContentTimeCheckBox->setDisabled(false);
ui->remoteFileWarningLabel->hide();
}
if (idx == REMOTE_FILE_IDX) {
ui->browseButton_3->setDisabled(true);
ui->fileContentTimeCheckBox->setDisabled(true);
ui->remoteFileWarningLabel->show();
}
}
void SceneSwitcher::on_fileAdd_clicked()
{
QString sceneName = ui->fileScenes->currentText();
QString transitionName = ui->fileTransitions->currentText();
QString fileName = ui->filePathLineEdit->text();
QString text = ui->fileTextEdit->toPlainText();
bool remote = (ui->fileType->currentIndex() == REMOTE_FILE_IDX);
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
bool useTime = ui->fileContentTimeCheckBox->isChecked();
if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty())
if (sceneName.isEmpty() || transitionName.isEmpty() ||
fileName.isEmpty() || text.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime);
QString switchText = MakeFileSwitchName(
sceneName, transitionName, fileName, text, useRegex, useTime);
QVariant v = QVariant::fromValue(switchText);
QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList);
QListWidgetItem *item =
new QListWidgetItem(switchText, ui->fileScenesList);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back(
source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back(source, transition,
fileName.toUtf8().constData(),
text.toUtf8().constData(), remote,
useRegex, useTime);
}
void SceneSwitcher::on_fileRemove_clicked()
{
QListWidgetItem* item = ui->fileScenesList->currentItem();
QListWidgetItem *item = ui->fileScenesList->currentItem();
if (!item)
return;
@@ -221,9 +296,9 @@ void SceneSwitcher::on_fileRemove_clicked()
return;
{
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->fileSwitches;
auto &switches = switcher->fileSwitches;
switches.erase(switches.begin() + idx);
}
qDeleteAll(ui->fileScenesList->selectedItems());
@@ -236,19 +311,165 @@ void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
if (idx == -1)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
if (switcher->fileSwitches.size() <= idx)
return;
FileSwitch s = switcher->fileSwitches[idx];
string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
ui->fileScenes->setCurrentText(sceneName.c_str());
ui->fileTransitions->setCurrentText(transitionName.c_str());
ui->fileTextEdit->setPlainText(s.text.c_str());
ui->filePathLineEdit->setText(s.file.c_str());
if (s.remote)
ui->fileType->setCurrentIndex(REMOTE_FILE_IDX);
else
ui->fileType->setCurrentIndex(LOCAL_FILE_IDX);
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
ui->fileContentTimeCheckBox->setChecked(s.useTime);
}
void SceneSwitcher::on_fileUp_clicked()
{
int index = ui->fileScenesList->currentRow();
if (index != -1 && index != 0) {
ui->fileScenesList->insertItem(
index - 1, ui->fileScenesList->takeItem(index));
ui->fileScenesList->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->fileSwitches.begin() + index,
switcher->fileSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_fileDown_clicked()
{
int index = ui->fileScenesList->currentRow();
if (index != -1 && index != ui->fileScenesList->count() - 1) {
ui->fileScenesList->insertItem(
index + 1, ui->fileScenesList->takeItem(index));
ui->fileScenesList->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->fileSwitches.begin() + index,
switcher->fileSwitches.begin() + index + 1);
}
}
void SwitcherData::saveFileSwitches(obs_data_t *obj)
{
obs_data_array_t *fileArray = obs_data_array_create();
for (FileSwitch &s : switcher->fileSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source && transition) {
const char *sceneName = obs_source_get_name(source);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "scene", sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_string(array_obj, "file", s.file.c_str());
obs_data_set_string(array_obj, "text", s.text.c_str());
obs_data_set_bool(array_obj, "remote", s.remote);
obs_data_set_bool(array_obj, "useRegex", s.useRegex);
obs_data_set_bool(array_obj, "useTime", s.useTime);
obs_data_array_push_back(fileArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "fileSwitches", fileArray);
obs_data_array_release(fileArray);
obs_data_set_bool(obj, "readEnabled", switcher->fileIO.readEnabled);
obs_data_set_string(obj, "readPath", switcher->fileIO.readPath.c_str());
obs_data_set_bool(obj, "writeEnabled", switcher->fileIO.writeEnabled);
obs_data_set_string(obj, "writePath",
switcher->fileIO.writePath.c_str());
}
void SwitcherData::loadFileSwitches(obs_data_t *obj)
{
switcher->fileSwitches.clear();
obs_data_array_t *fileArray = obs_data_get_array(obj, "fileSwitches");
size_t count = obs_data_array_count(fileArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(fileArray, i);
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
const char *file = obs_data_get_string(array_obj, "file");
const char *text = obs_data_get_string(array_obj, "text");
bool remote = obs_data_get_bool(array_obj, "remote");
bool useRegex = obs_data_get_bool(array_obj, "useRegex");
bool useTime = obs_data_get_bool(array_obj, "useTime");
switcher->fileSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), file, text, remote,
useRegex, useTime);
obs_data_release(array_obj);
}
obs_data_array_release(fileArray);
obs_data_set_default_bool(obj, "readEnabled", false);
switcher->fileIO.readEnabled = obs_data_get_bool(obj, "readEnabled");
switcher->fileIO.readPath = obs_data_get_string(obj, "readPath");
obs_data_set_default_bool(obj, "writeEnabled", false);
switcher->fileIO.writeEnabled = obs_data_get_bool(obj, "writeEnabled");
switcher->fileIO.writePath = obs_data_get_string(obj, "writePath");
}
void SceneSwitcher::setupFileTab()
{
populateSceneSelection(ui->fileScenes, false);
populateTransitionSelection(ui->fileTransitions);
ui->fileType->addItem("local");
ui->fileType->addItem("remote");
ui->remoteFileWarningLabel->setText(
"Note that the scene switcher will try to access the remote location every " +
QString::number(switcher->interval) + "ms");
for (auto &s : switcher->fileSwitches) {
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeFileSwitchName(
sceneName.c_str(), transitionName.c_str(),
s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->fileScenesList);
item->setData(Qt::UserRole, listText);
}
ui->readPathLineEdit->setText(
QString::fromStdString(switcher->fileIO.readPath.c_str()));
ui->readFileCheckBox->setChecked(switcher->fileIO.readEnabled);
ui->writePathLineEdit->setText(
QString::fromStdString(switcher->fileIO.writePath.c_str()));
if (ui->readFileCheckBox->checkState()) {
ui->browseButton_2->setDisabled(false);
ui->readPathLineEdit->setDisabled(false);
} else {
ui->browseButton_2->setDisabled(true);
ui->readPathLineEdit->setDisabled(true);
}
}

View File

@@ -1,24 +1,19 @@
#include "headers/advanced-scene-switcher.hpp"
#include <obs-module.h>
#include <QFileDialog>
#include <QTextStream>
#include <QMessageBox>
#include "headers/advanced-scene-switcher.hpp"
void SceneSwitcher::on_close_clicked()
{
done(0);
}
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->startAtLaunch = value;
}
void SceneSwitcher::UpdateNonMatchingScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws;
@@ -31,7 +26,7 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
@@ -41,7 +36,7 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = SWITCH;
ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
@@ -52,17 +47,26 @@ void SceneSwitcher::on_noMatchRandomSwitch_clicked()
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
void SceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->startupBehavior = (StartupBehavior)index;
}
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text)
{
if (loading)
return;
std::lock_guard<std::mutex> lock(switcher->m);
UpdateNonMatchingScene(text);
}
@@ -71,7 +75,7 @@ void SceneSwitcher::on_checkInterval_valueChanged(int value)
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->interval = value;
}
@@ -89,19 +93,487 @@ void SceneSwitcher::SetStopped()
void SceneSwitcher::on_toggleStartButton_clicked()
{
if (switcher->th.joinable())
{
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
SetStopped();
}
else
{
} else {
switcher->Start();
SetStarted();
}
}
void SceneSwitcher::closeEvent(QCloseEvent*)
void SceneSwitcher::closeEvent(QCloseEvent *)
{
obs_frontend_save();
}
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
{
if (loading)
return;
std::lock_guard<std::mutex> lock(switcher->m);
UpdateAutoStopScene(text);
}
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
{
if (loading)
return;
std::lock_guard<std::mutex> lock(switcher->m);
if (!state) {
ui->autoStopScenes->setDisabled(true);
switcher->autoStopEnable = false;
} else {
ui->autoStopScenes->setDisabled(false);
switcher->autoStopEnable = true;
if (!switcher->autoStopScene)
UpdateAutoStopScene(ui->autoStopScenes->currentText());
}
}
void SceneSwitcher::UpdateAutoStopScene(const QString &name)
{
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->autoStopScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SwitcherData::autoStopStreamAndRecording()
{
obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
if (ws && autoStopScene == ws) {
if (obs_frontend_streaming_active())
obs_frontend_streaming_stop();
if (obs_frontend_recording_active())
obs_frontend_recording_stop();
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}
void SceneSwitcher::on_verboseLogging_stateChanged(int state)
{
if (loading)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switcher->verbose = state;
}
void SceneSwitcher::on_exportSettings_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this, tr("Export Advanced Scene Switcher settings to file ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
if (directory.isEmpty())
return;
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
obs_data_t *obj = obs_data_create();
switcher->saveWindowTitleSwitches(obj);
switcher->saveScreenRegionSwitches(obj);
switcher->savePauseSwitches(obj);
switcher->saveSceneRoundTripSwitches(obj);
switcher->saveSceneTransitions(obj);
switcher->saveIdleSwitches(obj);
switcher->saveExecutableSwitches(obj);
switcher->saveRandomSwitches(obj);
switcher->saveFileSwitches(obj);
switcher->saveMediaSwitches(obj);
switcher->saveTimeSwitches(obj);
switcher->saveGeneralSettings(obj);
obs_data_save_json(obj, file.fileName().toUtf8().constData());
obs_data_release(obj);
}
void SceneSwitcher::on_importSettings_clicked()
{
std::lock_guard<std::mutex> lock(switcher->m);
QString directory = QFileDialog::getOpenFileName(
this,
tr("Import Advanced Scene Switcher settings from file ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
if (directory.isEmpty())
return;
QFile file(directory);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
obs_data_t *obj = obs_data_create_from_json_file(
file.fileName().toUtf8().constData());
if (!obj) {
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher failed to import settings");
Msgbox.exec();
return;
}
switcher->loadWindowTitleSwitches(obj);
switcher->loadScreenRegionSwitches(obj);
switcher->loadPauseSwitches(obj);
switcher->loadSceneRoundTripSwitches(obj);
switcher->loadSceneTransitions(obj);
switcher->loadIdleSwitches(obj);
switcher->loadExecutableSwitches(obj);
switcher->loadRandomSwitches(obj);
switcher->loadFileSwitches(obj);
switcher->loadMediaSwitches(obj);
switcher->loadTimeSwitches(obj);
switcher->loadGeneralSettings(obj);
obs_data_release(obj);
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher settings imported successfully");
Msgbox.exec();
close();
}
int findTabIndex(QTabBar *bar, int pos)
{
int at = -1;
QString tabName = "";
switch (pos) {
case 0:
tabName = "General";
break;
case 1:
tabName = "Transition";
break;
case 2:
tabName = "Pause";
break;
case 3:
tabName = "Title";
break;
case 4:
tabName = "Executable";
break;
case 5:
tabName = "Region";
break;
case 6:
tabName = "Media";
break;
case 7:
tabName = "File";
break;
case 8:
tabName = "Random";
break;
case 9:
tabName = "Time";
break;
case 10:
tabName = "Idle";
break;
case 11:
tabName = "Sequence";
break;
}
for (int i = 0; i < bar->count(); ++i) {
if (bar->tabText(i).compare(tabName) == 0) {
at = i;
break;
}
}
if (at == -1)
blog(LOG_INFO, "Advanced Scene Switcher failed to find tab %s",
tabName.toUtf8().constData());
return at;
}
void SceneSwitcher::setTabOrder()
{
QTabBar *bar = ui->tabWidget->tabBar();
for (int i = 0; i < bar->count(); ++i) {
int curPos = findTabIndex(bar, switcher->tabOrder[i]);
if (i != curPos && curPos != -1)
bar->moveTab(curPos, i);
}
connect(bar, &QTabBar::tabMoved, this, &SceneSwitcher::on_tabMoved);
}
void SceneSwitcher::on_tabMoved(int from, int to)
{
if (loading)
return;
std::swap(switcher->tabOrder[from], switcher->tabOrder[to]);
}
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
{
obs_data_set_int(obj, "interval", switcher->interval);
std::string nonMatchingSceneName =
GetWeakSourceName(switcher->nonMatchingScene);
obs_data_set_string(obj, "non_matching_scene",
nonMatchingSceneName.c_str());
obs_data_set_int(obj, "switch_if_not_matching",
switcher->switchIfNotMatching);
obs_data_set_bool(obj, "active", !switcher->stop);
obs_data_set_int(obj, "startup_behavior", switcher->startupBehavior);
std::string autoStopSceneName =
GetWeakSourceName(switcher->autoStopScene);
obs_data_set_bool(obj, "autoStopEnable", switcher->autoStopEnable);
obs_data_set_string(obj, "autoStopSceneName",
autoStopSceneName.c_str());
obs_data_set_bool(obj, "verbose", switcher->verbose);
obs_data_set_int(obj, "priority0",
switcher->functionNamesByPriority[0]);
obs_data_set_int(obj, "priority1",
switcher->functionNamesByPriority[1]);
obs_data_set_int(obj, "priority2",
switcher->functionNamesByPriority[2]);
obs_data_set_int(obj, "priority3",
switcher->functionNamesByPriority[3]);
obs_data_set_int(obj, "priority4",
switcher->functionNamesByPriority[4]);
obs_data_set_int(obj, "priority5",
switcher->functionNamesByPriority[5]);
obs_data_set_int(obj, "priority6",
switcher->functionNamesByPriority[6]);
obs_data_set_int(obj, "priority7",
switcher->functionNamesByPriority[7]);
obs_data_set_int(obj, "threadPriority", switcher->threadPriority);
obs_data_set_int(obj, "generalTabPos", switcher->tabOrder[0]);
obs_data_set_int(obj, "transitionTabPos", switcher->tabOrder[1]);
obs_data_set_int(obj, "pauseTabPos", switcher->tabOrder[2]);
obs_data_set_int(obj, "titleTabPos", switcher->tabOrder[3]);
obs_data_set_int(obj, "exeTabPos", switcher->tabOrder[4]);
obs_data_set_int(obj, "regionTabPos", switcher->tabOrder[5]);
obs_data_set_int(obj, "mediaTabPos", switcher->tabOrder[6]);
obs_data_set_int(obj, "fileTabPos", switcher->tabOrder[7]);
obs_data_set_int(obj, "randomTabPos", switcher->tabOrder[8]);
obs_data_set_int(obj, "timeTabPos", switcher->tabOrder[9]);
obs_data_set_int(obj, "idleTabPos", switcher->tabOrder[10]);
obs_data_set_int(obj, "sequenceTabPos", switcher->tabOrder[11]);
}
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
{
obs_data_set_default_int(obj, "interval", DEFAULT_INTERVAL);
switcher->interval = obs_data_get_int(obj, "interval");
obs_data_set_default_int(obj, "switch_if_not_matching", NO_SWITCH);
switcher->switchIfNotMatching =
(NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
std::string nonMatchingScene =
obs_data_get_string(obj, "non_matching_scene");
switcher->nonMatchingScene =
GetWeakSourceByName(nonMatchingScene.c_str());
switcher->stop = !obs_data_get_bool(obj, "active");
switcher->startupBehavior =
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
if (switcher->startupBehavior == START)
switcher->stop = false;
if (switcher->startupBehavior == STOP)
switcher->stop = true;
std::string autoStopScene =
obs_data_get_string(obj, "autoStopSceneName");
switcher->autoStopEnable = obs_data_get_bool(obj, "autoStopEnable");
switcher->autoStopScene = GetWeakSourceByName(autoStopScene.c_str());
switcher->verbose = obs_data_get_bool(obj, "verbose");
obs_data_set_default_int(obj, "priority0", DEFAULT_PRIORITY_0);
obs_data_set_default_int(obj, "priority1", DEFAULT_PRIORITY_1);
obs_data_set_default_int(obj, "priority2", DEFAULT_PRIORITY_2);
obs_data_set_default_int(obj, "priority3", DEFAULT_PRIORITY_3);
obs_data_set_default_int(obj, "priority4", DEFAULT_PRIORITY_4);
obs_data_set_default_int(obj, "priority5", DEFAULT_PRIORITY_5);
obs_data_set_default_int(obj, "priority6", DEFAULT_PRIORITY_6);
obs_data_set_default_int(obj, "priority7", DEFAULT_PRIORITY_7);
switcher->functionNamesByPriority[0] =
(obs_data_get_int(obj, "priority0"));
switcher->functionNamesByPriority[1] =
(obs_data_get_int(obj, "priority1"));
switcher->functionNamesByPriority[2] =
(obs_data_get_int(obj, "priority2"));
switcher->functionNamesByPriority[3] =
(obs_data_get_int(obj, "priority3"));
switcher->functionNamesByPriority[4] =
(obs_data_get_int(obj, "priority4"));
switcher->functionNamesByPriority[5] =
(obs_data_get_int(obj, "priority5"));
switcher->functionNamesByPriority[6] =
(obs_data_get_int(obj, "priority6"));
switcher->functionNamesByPriority[7] =
(obs_data_get_int(obj, "priority7"));
if (!switcher->prioFuncsValid()) {
switcher->functionNamesByPriority[0] = (DEFAULT_PRIORITY_0);
switcher->functionNamesByPriority[1] = (DEFAULT_PRIORITY_1);
switcher->functionNamesByPriority[2] = (DEFAULT_PRIORITY_2);
switcher->functionNamesByPriority[3] = (DEFAULT_PRIORITY_3);
switcher->functionNamesByPriority[4] = (DEFAULT_PRIORITY_4);
switcher->functionNamesByPriority[5] = (DEFAULT_PRIORITY_5);
switcher->functionNamesByPriority[6] = (DEFAULT_PRIORITY_6);
switcher->functionNamesByPriority[7] = (DEFAULT_PRIORITY_7);
}
obs_data_set_default_int(obj, "threadPriority",
QThread::NormalPriority);
switcher->threadPriority = obs_data_get_int(obj, "threadPriority");
obs_data_set_default_int(obj, "generalTabPos", 0);
obs_data_set_default_int(obj, "transitionTabPos", 1);
obs_data_set_default_int(obj, "pauseTabPos", 2);
obs_data_set_default_int(obj, "titleTabPos", 3);
obs_data_set_default_int(obj, "exeTabPos", 4);
obs_data_set_default_int(obj, "regionTabPos", 5);
obs_data_set_default_int(obj, "mediaTabPos", 6);
obs_data_set_default_int(obj, "fileTabPos", 7);
obs_data_set_default_int(obj, "randomTabPos", 8);
obs_data_set_default_int(obj, "timeTabPos", 9);
obs_data_set_default_int(obj, "idleTabPos", 10);
obs_data_set_default_int(obj, "sequenceTabPos", 11);
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "generalTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "transitionTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "pauseTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "titleTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "exeTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "regionTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "mediaTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "fileTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "randomTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "timeTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "idleTabPos")));
switcher->tabOrder.emplace_back(
(int)(obs_data_get_int(obj, "sequenceTabPos")));
}
void SceneSwitcher::setupGeneralTab()
{
populateSceneSelection(ui->noMatchSwitchScene, false);
populateSceneSelection(ui->autoStopScenes, false);
if (switcher->switchIfNotMatching == SWITCH) {
ui->noMatchSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(true);
} else if (switcher->switchIfNotMatching == NO_SWITCH) {
ui->noMatchDontSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
} else {
ui->noMatchRandomSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
}
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->checkInterval->setValue(switcher->interval);
ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable);
ui->autoStopScenes->setCurrentText(
GetWeakSourceName(switcher->autoStopScene).c_str());
if (ui->autoStopSceneCheckBox->checkState()) {
ui->autoStopScenes->setDisabled(false);
} else {
ui->autoStopScenes->setDisabled(true);
}
ui->verboseLogging->setChecked(switcher->verbose);
for (int p : switcher->functionNamesByPriority) {
std::string s = "";
switch (p) {
case READ_FILE_FUNC:
s = "File Content";
break;
case ROUND_TRIP_FUNC:
s = "Scene Sequence";
break;
case IDLE_FUNC:
s = "Idle Detection";
break;
case EXE_FUNC:
s = "Executable";
break;
case SCREEN_REGION_FUNC:
s = "Screen Region";
break;
case WINDOW_TITLE_FUNC:
s = "Window Title";
break;
case MEDIA_FUNC:
s = "Media";
break;
case TIME_FUNC:
s = "Time";
break;
}
QString text(s.c_str());
QListWidgetItem *item =
new QListWidgetItem(text, ui->priorityList);
item->setData(Qt::UserRole, text);
}
for (int i = 0; i < switcher->threadPriorities.size(); ++i) {
ui->threadPriority->addItem(
switcher->threadPriorities[i].name.c_str());
ui->threadPriority->setItemData(
i, switcher->threadPriorities[i].description.c_str(),
Qt::ToolTipRole);
if (switcher->threadPriority ==
switcher->threadPriorities[i].value) {
ui->threadPriority->setCurrentText(
switcher->threadPriorities[i].name.c_str());
}
}
ui->startupBehavior->addItem(
"Start the scene switcher if it was running");
ui->startupBehavior->addItem("Always start the scene switcher");
ui->startupBehavior->addItem("Do not start the scene switcher");
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);
if (switcher->th && switcher->th->isRunning())
SetStarted();
else
SetStopped();
}

View File

@@ -49,21 +49,44 @@ public:
void UpdateIdleDataTransition(const QString &name);
void UpdateIdleDataScene(const QString &name);
void loadUI();
void populateSceneSelection(QComboBox *sel, bool addPrevious);
void populateTransitionSelection(QComboBox *sel);
void populateWindowSelection(QComboBox *sel);
void setupGeneralTab();
void setupTitleTab();
void setupExecutableTab();
void setupRegionTab();
void setupPauseTab();
void setupSequenceTab();
void setupTransitionsTab();
void setupIdleTab();
void setupRandomTab();
void setupMediaTab();
void setupFileTab();
void setupTimeTab();
void setTabOrder();
public slots:
void on_switches_currentRowChanged(int idx);
void on_up_clicked();
void on_down_clicked();
void on_add_clicked();
void on_remove_clicked();
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
void on_noMatchRandomSwitch_clicked();
void on_startAtLaunch_toggled(bool value);
void on_startupBehavior_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_toggleStartButton_clicked();
void on_tabMoved(int from, int to);
void on_screenRegions_currentRowChanged(int idx);
void on_screenRegionAdd_clicked();
void on_screenRegionRemove_clicked();
void on_screenRegionUp_clicked();
void on_screenRegionDown_clicked();
void on_pauseScenes_currentRowChanged(int idx);
void on_pauseScenesAdd_clicked();
@@ -82,23 +105,35 @@ public slots:
void on_sceneRoundTripRemove_clicked();
void on_sceneRoundTripSave_clicked();
void on_sceneRoundTripLoad_clicked();
void on_sceneRoundTripUp_clicked();
void on_sceneRoundTripDown_clicked();
void on_sceneRoundTripDelayUnits_currentIndexChanged(int index);
void on_autoStopSceneCheckBox_stateChanged(int state);
void on_autoStopScenes_currentTextChanged(const QString &text);
void on_verboseLogging_stateChanged(int state);
void on_exportSettings_clicked();
void on_importSettings_clicked();
void on_sceneTransitions_currentRowChanged(int idx);
void on_transitionsAdd_clicked();
void on_transitionsRemove_clicked();
void on_defaultTransitions_currentRowChanged(int idx);
void on_defaultTransitionsAdd_clicked();
void on_defaultTransitionsRemove_clicked();
void on_transitionOverridecheckBox_stateChanged(int state);
void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state);
void on_fileType_currentIndexChanged(int idx);
void on_readPathLineEdit_textChanged(const QString &text);
void on_writePathLineEdit_textChanged(const QString &text);
void on_browseButton_2_clicked();
void on_executableUp_clicked();
void on_executableDown_clicked();
void on_executableAdd_clicked();
void on_executableRemove_clicked();
void on_executables_currentRowChanged(int idx);
@@ -119,9 +154,15 @@ public slots:
void on_fileRemove_clicked();
void on_fileScenesList_currentRowChanged(int idx);
void on_browseButton_3_clicked();
void on_fileUp_clicked();
void on_fileDown_clicked();
void on_mediaSwitches_currentRowChanged(int idx);
void on_mediaAdd_clicked();
void on_mediaRemove_clicked();
void on_mediaUp_clicked();
void on_mediaDown_clicked();
void on_mediaTimeRestrictions_currentIndexChanged(int idx);
void on_timeSwitches_currentRowChanged(int idx);
void on_timeAdd_clicked();
@@ -129,6 +170,7 @@ public slots:
void on_priorityUp_clicked();
void on_priorityDown_clicked();
void on_threadPriority_currentTextChanged(const QString &text);
void updateScreenRegionCursorPos();
@@ -139,13 +181,14 @@ public slots:
* Windowtitle helper
********************************************************************************/
void GetWindowList(std::vector<std::string> &windows);
void GetWindowList(QStringList &windows); // Overloaded
void GetCurrentWindowTitle(std::string &title);
bool isFullscreen();
bool isFullscreen(std::string &title);
/********************************************************************************
* Screenregion helper
********************************************************************************/
pair<int, int> getCursorPos();
std::pair<int, int> getCursorPos();
/********************************************************************************
* Idle detection helper
@@ -156,7 +199,7 @@ int secondsSinceLastInput();
* Executable helper
********************************************************************************/
void GetProcessList(QStringList &processes);
bool isInFocus(const QString &exeToCheck);
bool isInFocus(const QString &executable);
/********************************************************************************
* Sceneswitch helper
@@ -164,10 +207,21 @@ bool isInFocus(const QString &exeToCheck);
struct obs_weak_source;
typedef struct obs_weak_source obs_weak_source_t;
obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
obs_weak_source_t *scene2);
typedef struct transitionData {
std::string name = "";
int duration = 0;
} transitionData;
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
OBSWeakSource &transition,
bool &transitionOverrideOverride, transitionData &td);
void overwriteTransitionOverride(obs_weak_source_t *sceneWs,
obs_source_t *transition, transitionData &td);
void restoreTransitionOverride(obs_source_t *scene, transitionData td);
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
unique_lock<mutex> &lock);
bool &transitionOverrideOverride,
std::unique_lock<std::mutex> &lock);
/********************************************************************************
* Hotkey helper
@@ -183,7 +237,7 @@ void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed);
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
obs_hotkey_t *hotkey, bool pressed);
void loadKeybinding(obs_hotkey_id hotkeyId, string path);
void loadKeybinding(obs_hotkey_id hotkeyId, std::string path);
/********************************************************************************
* Main SwitcherData

View File

@@ -3,7 +3,6 @@
#include <chrono>
#include <string>
#include <vector>
#include <thread>
#include <regex>
#include <mutex>
#include <fstream>
@@ -35,23 +34,24 @@
#define DEFAULT_PRIORITY_6 MEDIA_FUNC
#define DEFAULT_PRIORITY_7 TIME_FUNC
using namespace std;
/********************************************************************************
* Data structs for each scene switching method
********************************************************************************/
struct WindowSceneSwitch {
OBSWeakSource scene;
string window;
std::string window;
OBSWeakSource transition;
bool fullscreen;
bool focus;
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_,
OBSWeakSource transition_, bool fullscreen_)
OBSWeakSource transition_, bool fullscreen_,
bool focus_)
: scene(scene_),
window(window_),
transition(transition_),
fullscreen(fullscreen_)
fullscreen(fullscreen_),
focus(focus_)
{
}
};
@@ -77,12 +77,12 @@ struct ScreenRegionSwitch {
OBSWeakSource scene;
OBSWeakSource transition;
int minX, minY, maxX, maxY;
string regionStr;
std::string regionStr;
inline ScreenRegionSwitch(OBSWeakSource scene_,
OBSWeakSource transition_, int minX_,
int minY_, int maxX_, int maxY_,
string regionStr_)
std::string regionStr_)
: scene(scene_),
transition(transition_),
minX(minX_),
@@ -98,14 +98,14 @@ struct SceneRoundTripSwitch {
OBSWeakSource scene1;
OBSWeakSource scene2;
OBSWeakSource transition;
int delay;
double delay;
bool usePreviousScene;
string sceneRoundTripStr;
std::string sceneRoundTripStr;
inline SceneRoundTripSwitch(OBSWeakSource scene1_,
OBSWeakSource scene2_,
OBSWeakSource transition_, int delay_,
bool usePreviousScene_, string str)
OBSWeakSource transition_, double delay_,
bool usePreviousScene_, std::string str)
: scene1(scene1_),
scene2(scene2_),
transition(transition_),
@@ -120,10 +120,10 @@ struct RandomSwitch {
OBSWeakSource scene;
OBSWeakSource transition;
double delay;
string randomSwitchStr;
std::string randomSwitchStr;
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
double delay_, string str)
double delay_, std::string str)
: scene(scene_),
transition(transition_),
delay(delay_),
@@ -136,11 +136,11 @@ struct SceneTransition {
OBSWeakSource scene1;
OBSWeakSource scene2;
OBSWeakSource transition;
string sceneTransitionStr;
std::string sceneTransitionStr;
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_,
OBSWeakSource transition_,
string sceneTransitionStr_)
std::string sceneTransitionStr_)
: scene1(scene1_),
scene2(scene2_),
transition(transition_),
@@ -152,11 +152,11 @@ struct SceneTransition {
struct DefaultSceneTransition {
OBSWeakSource scene;
OBSWeakSource transition;
string sceneTransitionStr;
std::string sceneTransitionStr;
inline DefaultSceneTransition(OBSWeakSource scene_,
OBSWeakSource transition_,
string sceneTransitionStr_)
std::string sceneTransitionStr_)
: scene(scene_),
transition(transition_),
sceneTransitionStr(sceneTransitionStr_)
@@ -167,19 +167,21 @@ struct DefaultSceneTransition {
struct FileSwitch {
OBSWeakSource scene;
OBSWeakSource transition;
string file;
string text;
std::string file;
std::string text;
bool remote = false;
bool useRegex = false;
bool useTime = false;
QDateTime lastMod;
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
const char *file_, const char *text_, bool useRegex_,
bool useTime_)
const char *file_, const char *text_, bool remote_,
bool useRegex_, bool useTime_)
: scene(scene_),
transition(transition_),
file(file_),
text(text_),
remote(remote_),
useRegex(useRegex_),
useTime(useTime_),
lastMod()
@@ -189,9 +191,9 @@ struct FileSwitch {
struct FileIOData {
bool readEnabled = false;
string readPath;
std::string readPath;
bool writeEnabled = false;
string writePath;
std::string writePath;
};
struct IdleData {
@@ -208,22 +210,24 @@ struct MediaSwitch {
OBSWeakSource source;
OBSWeakSource transition;
obs_media_state state;
uint64_t time;
int64_t time;
time_restriction restriction;
bool matched;
bool usePreviousScene;
std::string mediaSwitchStr;
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
OBSWeakSource transition_, obs_media_state state_,
time_restriction restriction_, uint64_t time_,
bool usePreviousScene_)
bool usePreviousScene_, std::string mediaSwitchStr_)
: scene(scene_),
source(source_),
transition(transition_),
state(state_),
restriction(restriction_),
time(time_),
usePreviousScene(usePreviousScene_)
usePreviousScene(usePreviousScene_),
mediaSwitchStr(mediaSwitchStr_)
{
}
};
@@ -234,11 +238,11 @@ struct TimeSwitch {
QTime time;
bool matched;
bool usePreviousScene;
string timeSwitchStr;
std::string timeSwitchStr;
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
QTime time_, bool usePreviousScene_,
string timeSwitchStr_)
std::string timeSwitchStr_)
: scene(scene_),
transition(transition_),
time(time_),
@@ -249,19 +253,24 @@ struct TimeSwitch {
};
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
typedef enum { PERSIST = 0, START = 1, STOP = 2 } StartupBehavior;
class SwitcherThread;
/********************************************************************************
* SwitcherData
* SwitcherData
********************************************************************************/
struct SwitcherData {
thread th;
condition_variable cv;
mutex m;
SwitcherThread *th = nullptr;
std::condition_variable cv;
std::mutex m;
bool transitionActive = false;
bool waitForTransition = false;
condition_variable transitionCv;
bool startAtLaunch = false;
std::condition_variable transitionCv;
bool stop = false;
bool verbose = false;
bool tansitionOverrideOverride = false;
int interval = DEFAULT_INTERVAL;
@@ -271,56 +280,75 @@ struct SwitcherData {
OBSWeakSource lastRandomScene;
OBSWeakSource nonMatchingScene;
NoMatch switchIfNotMatching = NO_SWITCH;
StartupBehavior startupBehavior = PERSIST;
vector<WindowSceneSwitch> windowSwitches;
vector<string> ignoreIdleWindows;
string lastTitle;
std::vector<WindowSceneSwitch> windowSwitches;
std::vector<std::string> ignoreIdleWindows;
std::string lastTitle;
vector<ScreenRegionSwitch> screenRegionSwitches;
std::vector<ScreenRegionSwitch> screenRegionSwitches;
vector<OBSWeakSource> pauseScenesSwitches;
std::vector<OBSWeakSource> pauseScenesSwitches;
vector<string> pauseWindowsSwitches;
std::vector<std::string> pauseWindowsSwitches;
vector<string> ignoreWindowsSwitches;
std::vector<std::string> ignoreWindowsSwitches;
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
std::vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
int sceneRoundTripUnitMultiplier = 1;
vector<RandomSwitch> randomSwitches;
std::vector<RandomSwitch> randomSwitches;
FileIOData fileIO;
IdleData idleData;
vector<FileSwitch> fileSwitches;
std::vector<FileSwitch> fileSwitches;
vector<ExecutableSceneSwitch> executableSwitches;
std::vector<ExecutableSceneSwitch> executableSwitches;
bool autoStopEnable = false;
OBSWeakSource autoStopScene;
vector<SceneTransition> sceneTransitions;
vector<DefaultSceneTransition> defaultSceneTransitions;
std::vector<SceneTransition> sceneTransitions;
std::vector<DefaultSceneTransition> defaultSceneTransitions;
vector<MediaSwitch> mediaSwitches;
std::vector<MediaSwitch> mediaSwitches;
vector<TimeSwitch> timeSwitches;
std::vector<TimeSwitch> timeSwitches;
vector<int> functionNamesByPriority = vector<int>{
std::vector<int> functionNamesByPriority = std::vector<int>{
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
std::vector<std::string> threadPrioritiesNamesOrderdByPrio{
"Lowest", "Low", "Normal", "High", "Highest", "Time critical",
struct ThreadPrio {
std::string name;
std::string description;
uint32_t value;
};
std::map<std::string, int> threadPriorities = {
{"Lowest", QThread::LowestPriority},
{"Low", QThread::LowPriority},
{"Normal", QThread::NormalPriority},
{"High", QThread::HighPriority},
{"Highest", QThread::HighestPriority},
{"Time critical", QThread::TimeCriticalPriority},
std::vector<ThreadPrio> threadPriorities{
{"Idle",
"scheduled only when no other threads are running (lowest CPU load)",
QThread::IdlePriority},
{"Lowest", "scheduled less often than LowPriority",
QThread::LowestPriority},
{"Low", "scheduled less often than NormalPriority",
QThread::LowPriority},
{"Normal", "the default priority of the operating system",
QThread::NormalPriority},
{"High", "scheduled more often than NormalPriority",
QThread::HighPriority},
{"Highest", "scheduled more often than HighPriority",
QThread::HighestPriority},
{"Time critical",
"scheduled as often as possible (highest CPU load)",
QThread::TimeCriticalPriority},
};
uint32_t threadPriority = QThread::NormalPriority;
std::vector<int> tabOrder;
void Thread();
void Start();
void Stop();
@@ -333,7 +361,7 @@ struct SwitcherData {
bool checkPause();
void checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition,
unique_lock<mutex> &lock);
std::unique_lock<std::mutex> &lock);
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition);
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
@@ -353,6 +381,32 @@ struct SwitcherData {
void checkTimeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition);
void saveWindowTitleSwitches(obs_data_t *obj);
void saveScreenRegionSwitches(obs_data_t *obj);
void savePauseSwitches(obs_data_t *obj);
void saveSceneRoundTripSwitches(obs_data_t *obj);
void saveSceneTransitions(obs_data_t *obj);
void saveIdleSwitches(obs_data_t *obj);
void saveExecutableSwitches(obs_data_t *obj);
void saveRandomSwitches(obs_data_t *obj);
void saveFileSwitches(obs_data_t *obj);
void saveMediaSwitches(obs_data_t *obj);
void saveTimeSwitches(obs_data_t *obj);
void saveGeneralSettings(obs_data_t *obj);
void loadWindowTitleSwitches(obs_data_t *obj);
void loadScreenRegionSwitches(obs_data_t *obj);
void loadPauseSwitches(obs_data_t *obj);
void loadSceneRoundTripSwitches(obs_data_t *obj);
void loadSceneTransitions(obs_data_t *obj);
void loadIdleSwitches(obs_data_t *obj);
void loadExecutableSwitches(obs_data_t *obj);
void loadRandomSwitches(obs_data_t *obj);
void loadFileSwitches(obs_data_t *obj);
void loadMediaSwitches(obs_data_t *obj);
void loadTimeSwitches(obs_data_t *obj);
void loadGeneralSettings(obs_data_t *obj);
void Prune()
{
for (size_t i = 0; i < windowSwitches.size(); i++) {
@@ -440,7 +494,8 @@ struct SwitcherData {
for (size_t i = 0; i < timeSwitches.size(); i++) {
TimeSwitch &s = timeSwitches[i];
if (!WeakSourceValid(s.scene) ||
if ((!s.usePreviousScene &&
!WeakSourceValid(s.scene)) ||
!WeakSourceValid(s.transition))
timeSwitches.erase(timeSwitches.begin() + i--);
}
@@ -450,6 +505,23 @@ struct SwitcherData {
!WeakSourceValid(idleData.transition)) {
idleData.idleEnable = false;
}
for (size_t i = 0; i < mediaSwitches.size(); i++) {
MediaSwitch &s = mediaSwitches[i];
if ((!s.usePreviousScene &&
!WeakSourceValid(s.scene)) ||
!WeakSourceValid(s.source) ||
!WeakSourceValid(s.transition))
mediaSwitches.erase(mediaSwitches.begin() +
i--);
}
}
inline ~SwitcherData() { Stop(); }
};
extern SwitcherData *switcher;
class SwitcherThread : public QThread {
public:
explicit SwitcherThread(){};
void run() { switcher->Thread(); };
};

View File

@@ -3,7 +3,6 @@
#include <QString>
#include <obs-frontend-api.h>
#include "switcher-data-structs.hpp"
using namespace std;
static inline bool WeakSourceValid(obs_weak_source_t *ws)
{
@@ -14,14 +13,26 @@ static inline bool WeakSourceValid(obs_weak_source_t *ws)
}
static inline QString MakeSwitchName(const QString &scene, const QString &value,
const QString &transition, bool fullscreen)
const QString &transition, bool fullscreen,
bool focus)
{
if (!fullscreen)
return QStringLiteral("[") + scene + QStringLiteral(", ") +
QString name = QStringLiteral("[") + scene + QStringLiteral(", ") +
transition + QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
QStringLiteral("]: ") + value +
QStringLiteral(" (only if window is fullscreen)");
if (fullscreen || focus) {
name += QStringLiteral(" (only if");
if (fullscreen)
name += QStringLiteral(" fullscreen");
if (fullscreen && focus)
name += QStringLiteral(" and");
if (focus)
name += QStringLiteral(" focused");
name += QStringLiteral(")");
}
return name;
}
static inline QString MakeSwitchNameExecutable(const QString &scene,
@@ -34,7 +45,7 @@ static inline QString MakeSwitchNameExecutable(const QString &scene,
transition + QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
QStringLiteral("]: ") + value +
QStringLiteral(" (only if window is focused)");
QStringLiteral(" (only if focused)");
}
static inline QString MakeScreenRegionSwitchName(const QString &scene,
@@ -168,9 +179,9 @@ static inline QString MakeTimeSwitchName(const QString &scene,
return switchName;
}
static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source)
{
string name;
std::string name;
obs_source_t *source = obs_weak_source_get_source(weak_source);
if (source) {

View File

@@ -1,31 +1,30 @@
#include <obs-module.h>
#include "headers/advanced-scene-switcher.hpp"
void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed)
{
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed)
{
if (!switcher->th.joinable())
if (pressed) {
if (!(switcher->th && switcher->th->isRunning()))
switcher->Start();
}
obs_data_array* hotkeyData = obs_hotkey_save(id);
obs_data_array *hotkeyData = obs_hotkey_save(id);
if (hotkeyData != NULL)
{
char* path = obs_module_config_path("");
ofstream file;
file.open(string(path).append(START_HOTKEY_PATH), ofstream::trunc);
if (file.is_open())
{
if (hotkeyData != NULL) {
char *path = obs_module_config_path("");
std::ofstream file;
file.open(std::string(path).append(START_HOTKEY_PATH),
std::ofstream::trunc);
if (file.is_open()) {
size_t num = obs_data_array_count(hotkeyData);
for (size_t i = 0; i < num; i++)
{
obs_data_t* data = obs_data_array_item(hotkeyData, i);
string temp = obs_data_get_json(data);
for (size_t i = 0; i < num; i++) {
obs_data_t *data =
obs_data_array_item(hotkeyData, i);
std::string temp = obs_data_get_json(data);
obs_data_release(data);
file << temp;
}
@@ -36,31 +35,30 @@ void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pr
obs_data_array_release(hotkeyData);
}
void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed)
{
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed)
{
if (switcher->th.joinable())
if (pressed) {
if (switcher->th && switcher->th->isRunning())
switcher->Stop();
}
obs_data_array* hotkeyData = obs_hotkey_save(id);
obs_data_array *hotkeyData = obs_hotkey_save(id);
if (hotkeyData != NULL)
{
char* path = obs_module_config_path("");
ofstream file;
file.open(string(path).append(STOP_HOTKEY_PATH), ofstream::trunc);
if (file.is_open())
{
if (hotkeyData != NULL) {
char *path = obs_module_config_path("");
std::ofstream file;
file.open(std::string(path).append(STOP_HOTKEY_PATH),
std::ofstream::trunc);
if (file.is_open()) {
size_t num = obs_data_array_count(hotkeyData);
for (size_t i = 0; i < num; i++)
{
obs_data_t* data = obs_data_array_item(hotkeyData, i);
string temp = obs_data_get_json(data);
for (size_t i = 0; i < num; i++) {
obs_data_t *data =
obs_data_array_item(hotkeyData, i);
std::string temp = obs_data_get_json(data);
obs_data_release(data);
file << temp;
}
@@ -71,33 +69,32 @@ void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pre
obs_data_array_release(hotkeyData);
}
void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
obs_hotkey_t *hotkey, bool pressed)
{
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed)
{
if (switcher->th.joinable())
if (pressed) {
if (switcher->th && switcher->th->isRunning())
switcher->Stop();
else
switcher->Start();
}
obs_data_array* hotkeyData = obs_hotkey_save(id);
obs_data_array *hotkeyData = obs_hotkey_save(id);
if (hotkeyData != NULL)
{
char* path = obs_module_config_path("");
ofstream file;
file.open(string(path).append(TOGGLE_HOTKEY_PATH), ofstream::trunc);
if (file.is_open())
{
if (hotkeyData != NULL) {
char *path = obs_module_config_path("");
std::ofstream file;
file.open(std::string(path).append(TOGGLE_HOTKEY_PATH),
std::ofstream::trunc);
if (file.is_open()) {
size_t num = obs_data_array_count(hotkeyData);
for (size_t i = 0; i < num; i++)
{
obs_data_t* data = obs_data_array_item(hotkeyData, i);
string temp = obs_data_get_json(data);
for (size_t i = 0; i < num; i++) {
obs_data_t *data =
obs_data_array_item(hotkeyData, i);
std::string temp = obs_data_get_json(data);
obs_data_release(data);
file << temp;
}
@@ -108,32 +105,31 @@ void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotke
obs_data_array_release(hotkeyData);
}
string loadConfigFile(string filename)
std::string loadConfigFile(std::string filename)
{
ifstream settingsFile;
char* path = obs_module_config_path("");
string value;
std::ifstream settingsFile;
char *path = obs_module_config_path("");
std::string value;
settingsFile.open(string(path).append(filename));
if (settingsFile.is_open())
{
settingsFile.seekg(0, ios::end);
settingsFile.open(std::string(path).append(filename));
if (settingsFile.is_open()) {
settingsFile.seekg(0, std::ios::end);
value.reserve(settingsFile.tellg());
settingsFile.seekg(0, ios::beg);
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
settingsFile.seekg(0, std::ios::beg);
value.assign((std::istreambuf_iterator<char>(settingsFile)),
std::istreambuf_iterator<char>());
settingsFile.close();
}
bfree(path);
return value;
}
void loadKeybinding(obs_hotkey_id hotkeyId, string path)
void loadKeybinding(obs_hotkey_id hotkeyId, std::string path)
{
string bindings = loadConfigFile(path);
if (!bindings.empty())
{
obs_data_array_t* hotkeyData = obs_data_array_create();
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
std::string bindings = loadConfigFile(path);
if (!bindings.empty()) {
obs_data_array_t *hotkeyData = obs_data_array_create();
obs_data_t *data = obs_data_create_from_json(bindings.c_str());
obs_data_array_insert(hotkeyData, 0, data);
obs_data_release(data);
obs_hotkey_load(hotkeyId, hotkeyData);

View File

@@ -1,54 +1,50 @@
#include "headers/advanced-scene-switcher.hpp"
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
if (!idleData.idleEnable)
return;
string title;
std::string title;
bool ignoreIdle = false;
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : ignoreIdleWindows)
{
if (window == title)
{
for (std::string &window : ignoreIdleWindows) {
if (window == title) {
ignoreIdle = true;
break;
}
}
if (!ignoreIdle)
{
for (string& window : ignoreIdleWindows)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
if (!ignoreIdle) {
for (std::string &window : ignoreIdleWindows) {
try {
bool matches = std::regex_match(
title, std::regex(window));
if (matches) {
ignoreIdle = true;
break;
}
}
catch (const regex_error&)
{
} catch (const std::regex_error &) {
}
}
}
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
{
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
if (idleData.alreadySwitched)
return;
scene = (idleData.usePreviousScene) ? previousScene : idleData.scene;
scene = (idleData.usePreviousScene) ? previousScene
: idleData.scene;
transition = idleData.transition;
match = true;
idleData.alreadySwitched = true;
}
else
if (verbose)
blog(LOG_INFO, "Advanced Scene Switcher idle match");
} else
idleData.alreadySwitched = false;
}
@@ -57,17 +53,14 @@ void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
std::lock_guard<std::mutex> lock(switcher->m);
if (!state) {
ui->idleScenes->setDisabled(true);
ui->idleSpinBox->setDisabled(true);
ui->idleTransitions->setDisabled(true);
switcher->idleData.idleEnable = false;
}
else
{
} else {
ui->idleScenes->setDisabled(false);
ui->idleSpinBox->setDisabled(false);
ui->idleTransitions->setDisabled(false);
@@ -79,18 +72,17 @@ void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
}
}
void SceneSwitcher::UpdateIdleDataTransition(const QString& name)
void SceneSwitcher::UpdateIdleDataTransition(const QString &name)
{
obs_weak_source_t* transition = GetWeakTransitionByQString(name);
obs_weak_source_t *transition = GetWeakTransitionByQString(name);
switcher->idleData.transition = transition;
}
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
void SceneSwitcher::UpdateIdleDataScene(const QString &name)
{
switcher->idleData.usePreviousScene = (name == PREVIOUS_SCENE_NAME);
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->idleData.scene = ws;
@@ -98,21 +90,21 @@ void SceneSwitcher::UpdateIdleDataScene(const QString& name)
obs_source_release(scene);
}
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text)
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
UpdateIdleDataTransition(text);
}
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text)
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
UpdateIdleDataScene(text);
}
@@ -120,7 +112,7 @@ void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->idleData.time = i;
}
@@ -131,15 +123,13 @@ void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->ignoreIdleWindows->item(idx);
QListWidgetItem *item = ui->ignoreIdleWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& w : switcher->ignoreIdleWindows)
{
if (window.compare(w.c_str()) == 0)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &w : switcher->ignoreIdleWindows) {
if (window.compare(w.c_str()) == 0) {
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
break;
}
@@ -155,37 +145,37 @@ void SceneSwitcher::on_ignoreIdleAdd_clicked()
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
QList<QListWidgetItem *> items =
ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->ignoreIdleWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData());
std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreIdleWindows.emplace_back(
windowName.toUtf8().constData());
ui->ignoreIdleWindows->sortItems();
}
}
void SceneSwitcher::on_ignoreIdleRemove_clicked()
{
QListWidgetItem* item = ui->ignoreIdleWindows->currentItem();
QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& windows = switcher->ignoreIdleWindows;
std::lock_guard<std::mutex> lock(switcher->m);
auto &windows = switcher->ignoreIdleWindows;
for (auto it = windows.begin(); it != windows.end(); ++it)
{
auto& s = *it;
for (auto it = windows.begin(); it != windows.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData())
{
if (s == windowName.toUtf8().constData()) {
windows.erase(it);
break;
}
@@ -195,18 +185,16 @@ void SceneSwitcher::on_ignoreIdleRemove_clicked()
delete item;
}
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window)
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString &window)
{
int count = ui->ignoreIdleWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->ignoreIdleWindows->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->ignoreIdleWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
if (itemRegion == window) {
idx = i;
break;
}
@@ -214,3 +202,96 @@ int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window)
return idx;
}
void SwitcherData::saveIdleSwitches(obs_data_t *obj)
{
obs_data_array_t *ignoreIdleWindowsArray = obs_data_array_create();
for (std::string &window : switcher->ignoreIdleWindows) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "window", window.c_str());
obs_data_array_push_back(ignoreIdleWindowsArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "ignoreIdleWindows", ignoreIdleWindowsArray);
obs_data_array_release(ignoreIdleWindowsArray);
std::string idleSceneName = GetWeakSourceName(switcher->idleData.scene);
std::string idleTransitionName =
GetWeakSourceName(switcher->idleData.transition);
obs_data_set_bool(obj, "idleEnable", switcher->idleData.idleEnable);
obs_data_set_string(obj, "idleSceneName",
switcher->idleData.usePreviousScene
? PREVIOUS_SCENE_NAME
: idleSceneName.c_str());
obs_data_set_string(obj, "idleTransitionName",
idleTransitionName.c_str());
obs_data_set_int(obj, "idleTime", switcher->idleData.time);
}
void SwitcherData::loadIdleSwitches(obs_data_t *obj)
{
switcher->ignoreIdleWindows.clear();
obs_data_array_t *ignoreIdleWindowsArray =
obs_data_get_array(obj, "ignoreIdleWindows");
size_t count = obs_data_array_count(ignoreIdleWindowsArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(ignoreIdleWindowsArray, i);
const char *window = obs_data_get_string(array_obj, "window");
switcher->ignoreIdleWindows.emplace_back(window);
obs_data_release(array_obj);
}
obs_data_array_release(ignoreIdleWindowsArray);
std::string idleSceneName = obs_data_get_string(obj, "idleSceneName");
std::string idleTransitionName =
obs_data_get_string(obj, "idleTransitionName");
switcher->idleData.scene = GetWeakSourceByName(idleSceneName.c_str());
switcher->idleData.transition =
GetWeakTransitionByName(idleTransitionName.c_str());
obs_data_set_default_bool(obj, "idleEnable", false);
switcher->idleData.idleEnable = obs_data_get_bool(obj, "idleEnable");
obs_data_set_default_int(obj, "idleTime", DEFAULT_IDLE_TIME);
switcher->idleData.time = obs_data_get_int(obj, "idleTime");
switcher->idleData.usePreviousScene =
(idleSceneName == PREVIOUS_SCENE_NAME);
}
void SceneSwitcher::setupIdleTab()
{
populateSceneSelection(ui->idleScenes, true);
populateTransitionSelection(ui->idleTransitions);
populateWindowSelection(ui->ignoreIdleWindowsWindows);
for (auto &window : switcher->ignoreIdleWindows) {
QString text = QString::fromStdString(window);
QListWidgetItem *item =
new QListWidgetItem(text, ui->ignoreIdleWindows);
item->setData(Qt::UserRole, text);
}
ui->idleCheckBox->setChecked(switcher->idleData.idleEnable);
ui->idleScenes->setCurrentText(
switcher->idleData.usePreviousScene
? PREVIOUS_SCENE_NAME
: GetWeakSourceName(switcher->idleData.scene).c_str());
ui->idleTransitions->setCurrentText(
GetWeakSourceName(switcher->idleData.transition).c_str());
ui->idleSpinBox->setValue(switcher->idleData.time);
if (ui->idleCheckBox->checkState()) {
ui->idleScenes->setDisabled(false);
ui->idleSpinBox->setDisabled(false);
ui->idleTransitions->setDisabled(false);
} else {
ui->idleScenes->setDisabled(true);
ui->idleSpinBox->setDisabled(true);
ui->idleTransitions->setDisabled(true);
}
}

View File

@@ -16,9 +16,7 @@
#include <util/platform.h>
#include "../headers/advanced-scene-switcher.hpp"
using namespace std;
static Display* xdisplay = 0;
static Display *xdisplay = 0;
Display *disp()
{
@@ -40,31 +38,22 @@ void cleanupDisplay()
static bool ewmhIsSupported()
{
Display *display = disp();
Atom netSupportingWmCheck = XInternAtom(display,
"_NET_SUPPORTING_WM_CHECK", true);
Atom netSupportingWmCheck =
XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
Atom actualType;
int format = 0;
unsigned long num = 0, bytes = 0;
unsigned char *data = NULL;
Window ewmh_window = 0;
int status = XGetWindowProperty(
display,
DefaultRootWindow(display),
netSupportingWmCheck,
0L,
1L,
false,
XA_WINDOW,
&actualType,
&format,
&num,
&bytes,
&data);
int status = XGetWindowProperty(display, DefaultRootWindow(display),
netSupportingWmCheck, 0L, 1L, false,
XA_WINDOW, &actualType, &format, &num,
&bytes, &data);
if (status == Success) {
if (num > 0) {
ewmh_window = ((Window*)data)[0];
ewmh_window = ((Window *)data)[0];
}
if (data) {
XFree(data);
@@ -73,21 +62,12 @@ static bool ewmhIsSupported()
}
if (ewmh_window) {
status = XGetWindowProperty(
display,
ewmh_window,
netSupportingWmCheck,
0L,
1L,
false,
XA_WINDOW,
&actualType,
&format,
&num,
&bytes,
&data);
status = XGetWindowProperty(display, ewmh_window,
netSupportingWmCheck, 0L, 1L, false,
XA_WINDOW, &actualType, &format,
&num, &bytes, &data);
if (status != Success || num == 0 ||
ewmh_window != ((Window*)data)[0]) {
ewmh_window != ((Window *)data)[0]) {
ewmh_window = 0;
}
if (status == Success && data) {
@@ -98,6 +78,30 @@ static bool ewmhIsSupported()
return ewmh_window != 0;
}
static QStringList getStates(Window window)
{
QStringList states;
if (!ewmhIsSupported())
return states;
Atom wmState = XInternAtom(disp(), "_NET_WM_STATE", true), type;
int format;
unsigned long num, bytes;
unsigned char *data;
int status = XGetWindowProperty(disp(), window, wmState, 0, ~0L, false,
AnyPropertyType, &type, &format, &num,
&bytes, &data);
if (status == Success)
for (unsigned long i = 0; i < num; i++)
states.append(QString(
XGetAtomName(disp(), ((Atom *)data)[i])));
return states;
}
static std::vector<Window> getTopLevelWindows()
{
std::vector<Window> res;
@@ -112,24 +116,15 @@ static std::vector<Window> getTopLevelWindows()
Atom actualType;
int format;
unsigned long num, bytes;
Window* data = 0;
Window *data = 0;
for (int i = 0; i < ScreenCount(disp()); ++i) {
Window rootWin = RootWindow(disp(), i);
int status = XGetWindowProperty(
disp(),
rootWin,
netClList,
0L,
~0L,
false,
AnyPropertyType,
&actualType,
&format,
&num,
&bytes,
(uint8_t**)&data);
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
~0L, false, AnyPropertyType,
&actualType, &format, &num,
&bytes, (uint8_t **)&data);
if (status != Success) {
continue;
@@ -148,33 +143,47 @@ static std::string GetWindowTitle(size_t i)
{
Window w = getTopLevelWindows().at(i);
std::string windowTitle;
char* name;
char *name;
XTextProperty text;
int status = XGetWMName(disp(), w, &text);
name = reinterpret_cast<char*>(text.value);
if (status >= Success && name != nullptr)
{
int status = XGetTextProperty(
disp(), w, &text, XInternAtom(disp(), "_NET_WM_NAME", true));
if (status == 0)
status = XGetTextProperty(disp(), w, &text,
XInternAtom(disp(), "WM_NAME", true));
name = reinterpret_cast<char *>(text.value);
if (status != 0 && name != nullptr) {
std::string str(name);
windowTitle = str;
XFree(name);
}
XFree(name);
return windowTitle;
}
void GetWindowList(vector<string> &windows)
void GetWindowList(std::vector<std::string> &windows)
{
windows.resize(0);
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
if (GetWindowTitle(i) != "")
windows.emplace_back(GetWindowTitle(i));
}
}
void GetCurrentWindowTitle(string &title)
// Overloaded
void GetWindowList(QStringList &windows)
{
windows.clear();
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
if (GetWindowTitle(i) != "")
windows << QString::fromStdString(GetWindowTitle(i));
}
}
void GetCurrentWindowTitle(std::string &title)
{
if (!ewmhIsSupported()) {
return;
@@ -184,40 +193,39 @@ void GetCurrentWindowTitle(string &title)
Atom actualType;
int format;
unsigned long num, bytes;
Window* data = 0;
char* name;
Window *data = 0;
char *name;
Window rootWin = RootWindow(disp(), 0);
XGetWindowProperty(
disp(),
rootWin,
active,
0L,
~0L,
false,
AnyPropertyType,
&actualType,
&format,
&num,
&bytes,
(uint8_t**)&data);
int xstatus = XGetWindowProperty(disp(), rootWin, active, 0L, ~0L,
false, AnyPropertyType, &actualType,
&format, &num, &bytes,
(uint8_t **)&data);
int status = 0;
XTextProperty text;
int status = XGetWMName(disp(), data[0], &text);
name = reinterpret_cast<char*>(text.value);
if (xstatus == Success) {
status = XGetTextProperty(disp(), data[0], &text,
XInternAtom(disp(), "_NET_WM_NAME",
true));
if (status == 0)
status = XGetTextProperty(disp(), data[0], &text,
XInternAtom(disp(), "WM_NAME",
true));
}
name = reinterpret_cast<char *>(text.value);
if (status >= Success && name != nullptr) {
if (status != 0 && name != nullptr) {
std::string str(name);
title = str;
XFree(name);
}
XFree(name);
}
pair<int, int> getCursorPos()
std::pair<int, int> getCursorPos()
{
pair<int, int> pos(0, 0);
std::pair<int, int> pos(0, 0);
Display *dpy;
Window root;
Window ret_root;
@@ -231,95 +239,108 @@ pair<int, int> getCursorPos()
dpy = XOpenDisplay(NULL);
root = XDefaultRootWindow(dpy);
if(XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
&win_x, &win_y, &mask))
{
pos = pair<int, int> (root_x,root_y);
if (XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
&win_x, &win_y, &mask)) {
pos = std::pair<int, int>(root_x, root_y);
}
XCloseDisplay(dpy);
return pos;
}
bool isFullscreen()
bool isFullscreen(std::string &title)
{
if (!ewmhIsSupported()) {
if (!ewmhIsSupported())
return false;
// Find switch in top level windows
std::vector<Window> windows = getTopLevelWindows();
for (auto &window : windows) {
XTextProperty text;
int status = XGetTextProperty(
disp(), window, &text,
XInternAtom(disp(), "_NET_WM_NAME", true));
if (status == 0)
status = XGetTextProperty(disp(), window, &text,
XInternAtom(disp(), "WM_NAME",
true));
char *name = reinterpret_cast<char *>(text.value);
if (status == 0 || name == nullptr)
continue;
// True if switch equals window
bool equals = (title == name);
// True if switch matches window
bool matches = QString::fromStdString(name).contains(
QRegularExpression(QString::fromStdString(title)));
// If found, check if switch is fullscreen
if (equals || matches) {
QStringList states = getStates(window);
if (!states.isEmpty()) {
// True if window is fullscreen
bool fullscreen = states.contains(
"_NET_WM_STATE_FULLSCREEN");
// True if window is maximized vertically
bool vertical = states.contains(
"_NET_WM_STATE_MAXIMIZED_VERT");
// True if window is maximized horizontally
bool horizontal = states.contains(
"_NET_WM_STATE_MAXIMIZED_HORZ");
return (fullscreen || (vertical && horizontal));
}
break;
}
}
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
Atom actualType;
int format;
unsigned long num, bytes;
Window* data = 0;
Window rootWin = RootWindow(disp(), 0);
XGetWindowProperty(
disp(),
rootWin,
active,
0L,
~0L,
false,
AnyPropertyType,
&actualType,
&format,
&num,
&bytes,
(uint8_t**)&data);
XWindowAttributes window_attributes_return;
XWindowAttributes screen_attributes_return;
XGetWindowAttributes(disp(), rootWin, &screen_attributes_return);
XGetWindowAttributes(disp(), data[0], &window_attributes_return);
//menu bar is always 24 pixels in height
return (window_attributes_return.width >= screen_attributes_return.width &&
window_attributes_return.height + 24 >= screen_attributes_return.height) ? true : false;
return false;
}
//exe switch is not quite what is expected but it works for now
void GetProcessList(QStringList &processes)
{
processes.clear();
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
string s = GetWindowTitle(i);
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
std::string s = GetWindowTitle(i);
if (s != "")
processes << QString::fromStdString(s);
}
}
bool isInFocus(const QString &exeToCheck)
bool isInFocus(const QString &executable)
{
string curWindow;
GetCurrentWindowTitle(curWindow);
std::string current;
GetCurrentWindowTitle(current);
return (QString::compare(
QString::fromStdString(curWindow),
exeToCheck,
Qt::CaseInsensitive) == 0) ? true : false;
// True if executable switch equals current window
bool equals = (executable.toStdString() == current);
// True if executable switch matches current window
bool matches = QString::fromStdString(current).contains(
QRegularExpression(executable));
return (equals || matches);
}
int secondsSinceLastInput()
{
time_t idle_time;
static XScreenSaverInfo *mit_info;
Display *display;
int screen;
time_t idle_time;
static XScreenSaverInfo *mit_info;
Display *display;
int screen;
mit_info = XScreenSaverAllocInfo();
mit_info = XScreenSaverAllocInfo();
if((display=XOpenDisplay(NULL)) == NULL)
{
return(-1);
if ((display = XOpenDisplay(NULL)) == NULL) {
return (-1);
}
screen = DefaultScreen(display);
XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info);
idle_time = (mit_info->idle) / 1000;
XFree(mit_info);
XCloseDisplay(display);
screen = DefaultScreen(display);
XScreenSaverQueryInfo(display, RootWindow(display, screen), mit_info);
idle_time = (mit_info->idle) / 1000;
XFree(mit_info);
XCloseDisplay(display);
return idle_time;
return idle_time;
}

View File

@@ -1,6 +1,37 @@
#include <obs-module.h>
#include "headers/advanced-scene-switcher.hpp"
void SceneSwitcher::on_mediaSwitches_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->mediaSwitches->item(idx);
QString mediaSceneStr = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->mediaSwitches) {
if (mediaSceneStr.compare(s.mediaSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str();
QString sourceName =
GetWeakSourceName(s.source).c_str();
QString transitionName =
GetWeakSourceName(s.transition).c_str();
ui->mediaScenes->setCurrentText(sceneName);
ui->mediaSources->setCurrentText(sourceName);
ui->mediaTransitions->setCurrentText(transitionName);
ui->mediaStates->setCurrentIndex(s.state);
ui->mediaTimeRestrictions->setCurrentIndex(
s.restriction);
ui->mediaTime->setValue(s.time);
break;
}
}
}
void SceneSwitcher::on_mediaAdd_clicked()
{
QString sourceName = ui->mediaSources->currentText();
@@ -29,10 +60,11 @@ void SceneSwitcher::on_mediaAdd_clicked()
new QListWidgetItem(switchText, ui->mediaSwitches);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->mediaSwitches.emplace_back(
scene, source, transition, state, restriction, time,
(sceneName == QString(PREVIOUS_SCENE_NAME)));
(sceneName == QString(PREVIOUS_SCENE_NAME)),
switchText.toUtf8().constData());
}
void SceneSwitcher::on_mediaRemove_clicked()
@@ -41,17 +73,66 @@ void SceneSwitcher::on_mediaRemove_clicked()
if (!item)
return;
int idx = ui->mediaSwitches->currentRow();
std::string mediaStr =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->mediaSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.mediaSwitchStr == mediaStr) {
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_mediaUp_clicked()
{
int index = ui->mediaSwitches->currentRow();
if (index != -1 && index != 0) {
ui->mediaSwitches->insertItem(
index - 1, ui->mediaSwitches->takeItem(index));
ui->mediaSwitches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->mediaSwitches.begin() + index,
switcher->mediaSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_mediaDown_clicked()
{
int index = ui->mediaSwitches->currentRow();
if (index != -1 && index != ui->mediaSwitches->count() - 1) {
ui->mediaSwitches->insertItem(
index + 1, ui->mediaSwitches->takeItem(index));
ui->mediaSwitches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->mediaSwitches.begin() + index,
switcher->mediaSwitches.begin() + index + 1);
}
}
void SceneSwitcher::on_mediaTimeRestrictions_currentIndexChanged(int idx)
{
if (idx == -1)
return;
{
lock_guard<mutex> lock(switcher->m);
auto &switches = switcher->mediaSwitches;
switches.erase(switches.begin() + idx);
if ((time_restriction)ui->mediaTimeRestrictions->currentIndex() ==
TIME_RESTRICTION_NONE) {
ui->mediaTime->setDisabled(true);
} else {
ui->mediaTime->setDisabled(false);
}
qDeleteAll(ui->mediaSwitches->selectedItems());
}
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
@@ -84,7 +165,137 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
? previousScene
: mediaSwitch.scene;
transition = mediaSwitch.transition;
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher meida match");
}
mediaSwitch.matched = matched;
obs_source_release(source);
}
}
void SwitcherData::saveMediaSwitches(obs_data_t *obj)
{
obs_data_array_t *mediaArray = obs_data_array_create();
for (MediaSwitch &s : switcher->mediaSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.source);
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if ((s.usePreviousScene || sceneSource) && source &&
transition) {
const char *sourceName = obs_source_get_name(source);
const char *sceneName =
obs_source_get_name(sceneSource);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "source", sourceName);
obs_data_set_string(array_obj, "scene",
s.usePreviousScene
? PREVIOUS_SCENE_NAME
: sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_int(array_obj, "state", s.state);
obs_data_set_int(array_obj, "restriction",
s.restriction);
obs_data_set_int(array_obj, "time", s.time);
obs_data_array_push_back(mediaArray, array_obj);
}
obs_source_release(source);
obs_source_release(sceneSource);
obs_source_release(transition);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "mediaSwitches", mediaArray);
obs_data_array_release(mediaArray);
}
void SwitcherData::loadMediaSwitches(obs_data_t *obj)
{
obs_data_array_t *mediaArray = obs_data_get_array(obj, "mediaSwitches");
switcher->mediaSwitches.clear();
size_t count = obs_data_array_count(mediaArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(mediaArray, i);
const char *source = obs_data_get_string(array_obj, "source");
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
obs_media_state state =
(obs_media_state)obs_data_get_int(array_obj, "state");
time_restriction restriction =
(time_restriction)obs_data_get_int(array_obj,
"restriction");
uint64_t time = obs_data_get_int(array_obj, "time");
std::string mediaStr = MakeMediaSwitchName(source, scene,
transition, state,
restriction, time)
.toUtf8()
.constData();
switcher->mediaSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(source),
GetWeakTransitionByName(transition), state, restriction,
time, (strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
mediaStr);
obs_data_release(array_obj);
}
obs_data_array_release(mediaArray);
}
void SceneSwitcher::setupMediaTab()
{
populateSceneSelection(ui->mediaScenes, true);
populateTransitionSelection(ui->mediaTransitions);
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
QComboBox *combo = reinterpret_cast<QComboBox *>(data);
if (strcmp(obs_source_get_id(source), "ffmpeg_source") == 0) {
const char *name = obs_source_get_name(source);
combo->addItem(name);
}
return true;
};
obs_enum_sources(sourceEnum, ui->mediaSources);
ui->mediaStates->addItem("None");
ui->mediaStates->addItem("Playing");
ui->mediaStates->addItem("Opening");
ui->mediaStates->addItem("Buffering");
ui->mediaStates->addItem("Paused");
ui->mediaStates->addItem("Stopped");
ui->mediaStates->addItem("Ended");
ui->mediaStates->addItem("Error");
ui->mediaTimeRestrictions->addItem("None");
ui->mediaTimeRestrictions->addItem("Time shorter");
ui->mediaTimeRestrictions->addItem("Time longer");
ui->mediaTimeRestrictions->addItem("Time remaining shorter");
ui->mediaTimeRestrictions->addItem("Time remaining longer");
for (auto &s : switcher->mediaSwitches) {
std::string sourceName = GetWeakSourceName(s.source);
std::string sceneName = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeMediaSwitchName(
sourceName.c_str(), sceneName.c_str(),
transitionName.c_str(), s.state, s.restriction, s.time);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->mediaSwitches);
item->setData(Qt::UserRole, listText);
}
}

View File

@@ -6,141 +6,232 @@
#include <util/platform.h>
#include "../headers/advanced-scene-switcher.hpp"
void GetWindowList(vector<string> &windows)
void GetWindowList(std::vector<std::string> &windows)
{
windows.resize(0);
windows.resize(0);
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSArray *array = [ws runningApplications];
for (NSRunningApplication *app in array) {
NSString *name = app.localizedName;
if (!name)
continue;
@autoreleasepool {
NSMutableArray *apps =
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
kCGWindowListOptionAll, kCGNullWindowID);
for (NSDictionary *app in apps) {
// Construct string from NSString accounting for nil
std::string name([[app objectForKey:@"kCGWindowName"]
UTF8String],
[[app objectForKey:@"kCGWindowName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
UTF8String],
[[app objectForKey:@"kCGWindowOwnerName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
const char *str = name.UTF8String;
if (str && *str)
windows.emplace_back(str);
}
}
// Check if name exists
if (!name.empty() &&
find(windows.begin(), windows.end(), name) ==
windows.end())
windows.emplace_back(name);
// Check if owner exists
else if (!owner.empty() &&
find(windows.begin(), windows.end(), owner) ==
windows.end())
windows.emplace_back(owner);
}
}
}
void GetCurrentWindowTitle(string &title)
// Overloaded
void GetWindowList(QStringList &windows)
{
title.resize(0);
windows.clear();
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSRunningApplication *app = [ws frontmostApplication];
if (app) {
NSString *name = app.localizedName;
if (!name)
return;
@autoreleasepool {
NSMutableArray *apps =
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
kCGWindowListOptionAll, kCGNullWindowID);
for (NSDictionary *app in apps) {
// Construct string from NSString accounting for nil
std::string name([[app objectForKey:@"kCGWindowName"]
UTF8String],
[[app objectForKey:@"kCGWindowName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
UTF8String],
[[app objectForKey:@"kCGWindowOwnerName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
const char *str = name.UTF8String;
if (str && *str)
title = str;
}
}
// Check if name exists
if (!name.empty() &&
!windows.contains(QString::fromStdString(name)))
windows << QString::fromStdString(name);
// Check if owner exists
else if (!owner.empty() &&
!windows.contains(
QString::fromStdString(name)))
windows << QString::fromStdString(owner);
}
}
}
pair<int, int> getCursorPos() {
pair<int, int> pos(0, 0);
CGEventRef event = CGEventCreate(NULL);
CGPoint cursorPos = CGEventGetLocation(event);
CFRelease(event);
pos.first = cursorPos.x;
pos.second = cursorPos.y;
return pos;
}
void GetCurrentWindowTitle(std::string &title)
{
title.resize(0);
bool isFullscreen() {
@autoreleasepool {
AXValueRef temp;
CGSize windowSize;
CGPoint windowPosition;
AXUIElementRef frontMostApp;
AXUIElementRef frontMostWindow;
@autoreleasepool {
NSMutableArray *apps =
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly,
kCGNullWindowID);
for (NSDictionary *app in apps) {
int layer =
[[app objectForKey:@"kCGWindowLayer"] intValue];
// True if window is frontmost
if (layer == 0) {
// Construct string from NSString accounting for nil
std::string name(
[[app objectForKey:@"kCGWindowName"]
UTF8String],
[[app objectForKey:@"kCGWindowName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
std::string owner(
[[app objectForKey:@"kCGWindowOwnerName"]
UTF8String],
[[app objectForKey:@"kCGWindowOwnerName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
pid_t pid;
ProcessSerialNumber psn;
@try {
GetFrontProcess(&psn);
GetProcessPID(&psn, &pid);
frontMostApp = AXUIElementCreateApplication(pid);
if (!name.empty())
title = name;
else if (!owner.empty())
title = owner;
AXUIElementCopyAttributeValue(
frontMostApp, kAXFocusedWindowAttribute, (CFTypeRef *)&frontMostWindow);
break;
}
}
}
}
// Get the window size and position
AXUIElementCopyAttributeValue(
frontMostWindow, kAXSizeAttribute, (CFTypeRef *)&temp);
AXValueGetValue(temp, kAXValueTypeCGSize, &windowSize);
CFRelease(temp);
std::pair<int, int> getCursorPos()
{
std::pair<int, int> pos(0, 0);
CGEventRef event = CGEventCreate(NULL);
CGPoint cursorPos = CGEventGetLocation(event);
CFRelease(event);
pos.first = cursorPos.x;
pos.second = cursorPos.y;
return pos;
}
AXUIElementCopyAttributeValue(
frontMostWindow, kAXPositionAttribute, (CFTypeRef *)&temp);
AXValueGetValue(temp, kAXValueTypeCGPoint, &windowPosition);
CFRelease(temp);
bool isFullscreen(std::string &title)
{
// Check for match
@autoreleasepool {
NSArray *screens = [NSScreen screens];
NSMutableArray *apps =
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
kCGWindowListOptionAll, kCGNullWindowID);
for (NSDictionary *app in apps) {
// Construct string from NSString accounting for nil
std::string name([[app objectForKey:@"kCGWindowName"]
UTF8String],
[[app objectForKey:@"kCGWindowName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
std::string owner([[app objectForKey:@"kCGWindowOwnerName"]
UTF8String],
[[app objectForKey:@"kCGWindowOwnerName"]
lengthOfBytesUsingEncoding:
NSUTF8StringEncoding]);
CGRect screenBound = CGDisplayBounds(CGMainDisplayID());
CGSize screenSize = screenBound.size;
// True if switch equals app
bool equals = (title == name || title == owner);
// True if switch matches app
bool matches = (QString::fromStdString(name).contains(
QRegularExpression(
QString::fromStdString(
title))) ||
QString::fromStdString(owner).contains(
QRegularExpression(
QString::fromStdString(
title))));
if((windowSize.width == screenSize.width) && (windowSize.height == screenSize.height) &&
(windowPosition.x == 0) && (windowPosition.y == 0))
return true;
}
@catch (...) {
// deal with the exception
}
@catch (NSException *exception) {
// deal with the exception
}
// If found, check if fullscreen
if (equals || matches) {
// Get window bounds
NSRect bounds;
CGRectMakeWithDictionaryRepresentation(
(CFDictionaryRef)[app
objectForKey:@"kCGWindowBounds"],
&bounds);
}
return false;
// Compare to screen bounds
for (NSScreen *screen in screens) {
NSRect frame = [screen visibleFrame];
// True if flipped window origin equals screen origin
bool origin =
(bounds.origin.x ==
frame.origin.x &&
([screens[0] visibleFrame]
.size.height -
frame.size.height -
bounds.origin.y ==
frame.origin.y));
// True if window size equals screen size
bool size = NSEqualSizes(bounds.size,
frame.size);
if (origin && size)
return true;
}
}
}
}
return false;
}
int secondsSinceLastInput()
{
double time = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType) + 0.5;
return (int) time;
double time = CGEventSourceSecondsSinceLastEventType(
kCGEventSourceStateCombinedSessionState,
kCGAnyInputEventType) +
0.5;
return (int)time;
}
void GetProcessList(QStringList& list)
void GetProcessList(QStringList &list)
{
list.clear();
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSArray *array = [ws runningApplications];
for (NSRunningApplication *app in array) {
NSString *name = app.localizedName;
if (!name)
continue;
const char *str = name.UTF8String;
if (str && *str)
list << (str);
}
}
list.clear();
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSArray *array = [ws runningApplications];
for (NSRunningApplication *app in array) {
NSString *name = app.localizedName;
if (!name)
continue;
const char *str = name.UTF8String;
if (str && *str)
list << (str);
}
}
}
bool isInFocus(QString const& appQName)
bool isInFocus(const QString &executable)
{
QByteArray ba = appQName.toLocal8Bit();
const char * appName = ba.data();
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSRunningApplication *app = [ws frontmostApplication];
if (app) {
NSString *name = app.localizedName;
if (!name)
return false;
const char *str = name.UTF8String;
return (str && *str && strcmp(appName,str) == 0 )? true : false;
}
}
return false;
std::string current;
GetCurrentWindowTitle(current);
// True if executable switch equals current window
bool equals = (executable.toStdString() == current);
// True if executable switch matches current window
bool matches = QString::fromStdString(current).contains(
QRegularExpression(executable));
return (equals || matches);
}

View File

@@ -10,14 +10,15 @@ void SceneSwitcher::on_pauseScenesAdd_clicked()
OBSWeakSource source = GetWeakSourceByQString(sceneName);
QVariant v = QVariant::fromValue(sceneName);
QList<QListWidgetItem*> items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
QList<QListWidgetItem *> items =
ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(sceneName, ui->pauseScenes);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseScenesSwitches.emplace_back(source);
ui->pauseScenes->sortItems();
}
@@ -25,22 +26,20 @@ void SceneSwitcher::on_pauseScenesAdd_clicked()
void SceneSwitcher::on_pauseScenesRemove_clicked()
{
QListWidgetItem* item = ui->pauseScenes->currentItem();
QListWidgetItem *item = ui->pauseScenes->currentItem();
if (!item)
return;
QString pauseScene = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->pauseScenesSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->pauseScenesSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == GetWeakSourceByQString(pauseScene))
{
if (s == GetWeakSourceByQString(pauseScene)) {
switches.erase(it);
break;
}
@@ -59,37 +58,37 @@ void SceneSwitcher::on_pauseWindowsAdd_clicked()
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
QList<QListWidgetItem *> items =
ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->pauseWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData());
std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
ui->pauseWindows->sortItems();
}
}
void SceneSwitcher::on_pauseWindowsRemove_clicked()
{
QListWidgetItem* item = ui->pauseWindows->currentItem();
QListWidgetItem *item = ui->pauseWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->pauseWindowsSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->pauseWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData())
{
if (s == windowName.toUtf8().constData()) {
switches.erase(it);
break;
}
@@ -106,16 +105,14 @@ void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->pauseScenes->item(idx);
QListWidgetItem *item = ui->pauseScenes->item(idx);
QString scene = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->pauseScenesSwitches)
{
string name = GetWeakSourceName(s);
if (scene.compare(name.c_str()) == 0)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->pauseScenesSwitches) {
std::string name = GetWeakSourceName(s);
if (scene.compare(name.c_str()) == 0) {
ui->pauseScenesScenes->setCurrentText(name.c_str());
break;
}
@@ -129,33 +126,29 @@ void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->pauseWindows->item(idx);
QListWidgetItem *item = ui->pauseWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->pauseWindowsSwitches)
{
if (window.compare(s.c_str()) == 0)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->pauseWindowsSwitches) {
if (window.compare(s.c_str()) == 0) {
ui->pauseWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
int SceneSwitcher::PauseScenesFindByData(const QString& scene)
int SceneSwitcher::PauseScenesFindByData(const QString &scene)
{
int count = ui->pauseScenes->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->pauseScenes->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->pauseScenes->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == scene)
{
if (itemRegion == scene) {
idx = i;
break;
}
@@ -164,18 +157,16 @@ int SceneSwitcher::PauseScenesFindByData(const QString& scene)
return idx;
}
int SceneSwitcher::PauseWindowsFindByData(const QString& window)
int SceneSwitcher::PauseWindowsFindByData(const QString &window)
{
int count = ui->pauseWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->pauseWindows->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->pauseWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
if (itemRegion == window) {
idx = i;
break;
}
@@ -187,13 +178,11 @@ int SceneSwitcher::PauseWindowsFindByData(const QString& window)
bool SwitcherData::checkPause()
{
bool pause = false;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (OBSWeakSource& s : pauseScenesSwitches)
{
if (s == ws)
{
for (OBSWeakSource &s : pauseScenesSwitches) {
if (s == ws) {
pause = true;
break;
}
@@ -201,42 +190,133 @@ bool SwitcherData::checkPause()
obs_source_release(currentSource);
obs_weak_source_release(ws);
string title;
if (!pause)
{
std::string title;
if (!pause) {
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : pauseWindowsSwitches)
{
if (window == title)
{
for (std::string &window : pauseWindowsSwitches) {
if (window == title) {
pause = true;
break;
}
}
}
if (!pause)
{
if (!pause) {
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : pauseWindowsSwitches)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
for (std::string &window : pauseWindowsSwitches) {
try {
bool matches = std::regex_match(
title, std::regex(window));
if (matches) {
pause = true;
break;
}
}
catch (const regex_error&)
{
} catch (const std::regex_error &) {
}
}
}
if (verbose && pause)
blog(LOG_INFO, "Advanced Scene Switcher pause match");
return pause;
}
void SwitcherData::savePauseSwitches(obs_data_t *obj)
{
obs_data_array_t *pauseScenesArray = obs_data_array_create();
for (OBSWeakSource &scene : switcher->pauseScenesSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(scene);
if (source) {
const char *n = obs_source_get_name(source);
obs_data_set_string(array_obj, "pauseScene", n);
obs_data_array_push_back(pauseScenesArray, array_obj);
obs_source_release(source);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "pauseScenes", pauseScenesArray);
obs_data_array_release(pauseScenesArray);
obs_data_array_t *pauseWindowsArray = obs_data_array_create();
for (std::string &window : switcher->pauseWindowsSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "pauseWindow", window.c_str());
obs_data_array_push_back(pauseWindowsArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "pauseWindows", pauseWindowsArray);
obs_data_array_release(pauseWindowsArray);
}
void SwitcherData::loadPauseSwitches(obs_data_t *obj)
{
switcher->pauseScenesSwitches.clear();
obs_data_array_t *pauseScenesArray =
obs_data_get_array(obj, "pauseScenes");
size_t count = obs_data_array_count(pauseScenesArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(pauseScenesArray, i);
const char *scene =
obs_data_get_string(array_obj, "pauseScene");
switcher->pauseScenesSwitches.emplace_back(
GetWeakSourceByName(scene));
obs_data_release(array_obj);
}
obs_data_array_release(pauseScenesArray);
switcher->pauseWindowsSwitches.clear();
obs_data_array_t *pauseWindowsArray =
obs_data_get_array(obj, "pauseWindows");
count = obs_data_array_count(pauseWindowsArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(pauseWindowsArray, i);
const char *window =
obs_data_get_string(array_obj, "pauseWindow");
switcher->pauseWindowsSwitches.emplace_back(window);
obs_data_release(array_obj);
}
obs_data_array_release(pauseWindowsArray);
}
void SceneSwitcher::setupPauseTab()
{
populateSceneSelection(ui->pauseScenesScenes, false);
populateWindowSelection(ui->pauseWindowsWindows);
for (auto &scene : switcher->pauseScenesSwitches) {
std::string sceneName = GetWeakSourceName(scene);
QString text = QString::fromStdString(sceneName);
QListWidgetItem *item =
new QListWidgetItem(text, ui->pauseScenes);
item->setData(Qt::UserRole, text);
}
for (auto &window : switcher->pauseWindowsSwitches) {
QString text = QString::fromStdString(window);
QListWidgetItem *item =
new QListWidgetItem(text, ui->pauseWindows);
item->setData(Qt::UserRole, text);
}
}

View File

@@ -1,44 +1,68 @@
#include <algorithm>
#include "headers/advanced-scene-switcher.hpp"
void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
{
if (loading ||
ui->threadPriority->count() != switcher->threadPriorities.size())
return;
std::lock_guard<std::mutex> lock(switcher->m);
for (auto p : switcher->threadPriorities) {
if (p.name == text.toUtf8().constData()) {
switcher->threadPriority = p.value;
break;
}
}
}
void SceneSwitcher::on_priorityUp_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != 0)
{
ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex -1);
lock_guard<mutex> lock(switcher->m);
if (currentIndex != -1 && currentIndex != 0) {
ui->priorityList->insertItem(
currentIndex - 1,
ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1);
iter_swap(switcher->functionNamesByPriority.begin() +
currentIndex,
switcher->functionNamesByPriority.begin() +
currentIndex - 1);
}
}
void SceneSwitcher::on_priorityDown_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1)
{
ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex));
if (currentIndex != -1 &&
currentIndex != ui->priorityList->count() - 1) {
ui->priorityList->insertItem(
currentIndex + 1,
ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex + 1);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1);
iter_swap(switcher->functionNamesByPriority.begin() +
currentIndex,
switcher->functionNamesByPriority.begin() +
currentIndex + 1);
}
}
bool SwitcherData::prioFuncsValid()
{
auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end());
auto it = std::unique(functionNamesByPriority.begin(),
functionNamesByPriority.end());
bool wasUnique = (it == functionNamesByPriority.end());
if (!wasUnique)
return false;
for (int p : functionNamesByPriority)
{
for (int p : functionNamesByPriority) {
if (p < 0 || p > 7)
return false;
}
return true;
}

View File

@@ -8,17 +8,16 @@ void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->randomScenesList->item(idx);
QListWidgetItem *item = ui->randomScenesList->item(idx);
QString randomSceneStr = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches)
{
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->randomSwitches) {
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str();
QString transitionName = GetWeakSourceName(s.transition).c_str();
QString transitionName =
GetWeakSourceName(s.transition).c_str();
ui->randomScenes->setCurrentText(sceneName);
ui->randomSpinBox->setValue(s.delay);
ui->randomTransitions->setCurrentText(transitionName);
@@ -27,13 +26,12 @@ void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
}
}
int SceneSwitcher::randomFindByData(const QString& randomStr)
int SceneSwitcher::randomFindByData(const QString &randomStr)
{
int count = ui->randomScenesList->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->randomScenesList->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->randomScenesList->item(i);
QString str = item->data(Qt::UserRole).toString();
if (str == randomStr)
@@ -49,42 +47,38 @@ void SceneSwitcher::on_randomAdd_clicked()
QString transitionName = ui->randomTransitions->currentText();
double delay = ui->randomSpinBox->value();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = randomFindByData(text);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->randomSwitches.emplace_back(
source, transition, delay, text.toUtf8().constData());
QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
QListWidgetItem *item =
new QListWidgetItem(text, ui->randomScenesList);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->randomScenesList->item(idx);
} else {
QListWidgetItem *item = ui->randomScenesList->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches)
{
if (s.scene == source)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->randomSwitches) {
if (s.scene == source) {
s.delay = delay;
s.transition = transition;
s.randomSwitchStr = text.toUtf8().constData();;
s.randomSwitchStr =
text.toUtf8().constData();
;
break;
}
}
@@ -96,22 +90,21 @@ void SceneSwitcher::on_randomAdd_clicked()
void SceneSwitcher::on_randomRemove_clicked()
{
QListWidgetItem* item = ui->randomScenesList->currentItem();
QListWidgetItem *item = ui->randomScenesList->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->randomSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->randomSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.randomSwitchStr == text)
{
if (s.randomSwitchStr == text) {
switches.erase(it);
break;
}
@@ -121,17 +114,17 @@ void SceneSwitcher::on_randomRemove_clicked()
delete item;
}
void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, int &delay)
{
if (randomSwitches.size() == 0)
return;
vector<RandomSwitch> rs (randomSwitches);
std::vector<RandomSwitch> rs(randomSwitches);
std::random_device rng;
std::mt19937 urng(rng());
std::shuffle(rs.begin(), rs.end(), urng);
for (RandomSwitch& r : rs)
{
for (RandomSwitch &r : rs) {
if (r.scene == lastRandomScene)
continue;
scene = r.scene;
@@ -139,6 +132,84 @@ void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource&
delay = (int)r.delay * 1000;
match = true;
lastRandomScene = r.scene;
if (verbose)
blog(LOG_INFO, "Advanced Scene Switcher random match");
break;
}
}
void SwitcherData::saveRandomSwitches(obs_data_t *obj)
{
obs_data_array_t *randomArray = obs_data_array_create();
for (RandomSwitch &s : switcher->randomSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source && transition) {
const char *sceneName = obs_source_get_name(source);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "scene", sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_double(array_obj, "delay", s.delay);
obs_data_set_string(array_obj, "str",
s.randomSwitchStr.c_str());
obs_data_array_push_back(randomArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "randomSwitches", randomArray);
obs_data_array_release(randomArray);
}
void SwitcherData::loadRandomSwitches(obs_data_t *obj)
{
switcher->randomSwitches.clear();
obs_data_array_t *randomArray =
obs_data_get_array(obj, "randomSwitches");
size_t count = obs_data_array_count(randomArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(randomArray, i);
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
double delay = obs_data_get_double(array_obj, "delay");
const char *str = obs_data_get_string(array_obj, "str");
switcher->randomSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), delay, str);
obs_data_release(array_obj);
}
obs_data_array_release(randomArray);
}
void SceneSwitcher::setupRandomTab()
{
populateSceneSelection(ui->randomScenes, false);
populateTransitionSelection(ui->randomTransitions);
for (auto &s : switcher->randomSwitches) {
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeRandomSwitchName(
sceneName.c_str(), transitionName.c_str(), s.delay);
QListWidgetItem *item =
new QListWidgetItem(text, ui->randomScenesList);
item->setData(Qt::UserRole, text);
}
}

View File

@@ -1,9 +1,50 @@
#include <QFileDialog>
#include <QTextStream>
#include <QMessageBox>
#include <obs.hpp>
#include "headers/advanced-scene-switcher.hpp"
#define SECONDS_INDEX 0
#define MINUTES_INDEX 1
#define HOURS_INDEX 2
void SceneSwitcher::on_sceneRoundTripDelayUnits_currentIndexChanged(int index)
{
if (loading)
return;
std::lock_guard<std::mutex> lock(switcher->m);
double val = ui->sceneRoundTripSpinBox->value();
switch (switcher->sceneRoundTripUnitMultiplier) {
case 1:
val /= pow(60, index);
break;
case 60:
val /= pow(60, index - 1);
break;
case 3600:
val /= pow(60, index - 2);
break;
}
ui->sceneRoundTripSpinBox->setValue(val);
switch (index) {
case SECONDS_INDEX:
switcher->sceneRoundTripUnitMultiplier = 1;
break;
case MINUTES_INDEX:
switcher->sceneRoundTripUnitMultiplier = 60;
break;
case HOURS_INDEX:
switcher->sceneRoundTripUnitMultiplier = 3600;
break;
}
}
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
{
QString scene1Name = ui->sceneRoundTripScenes1->currentText();
@@ -13,7 +54,8 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
if (scene1Name.isEmpty() || scene2Name.isEmpty())
return;
double delay = ui->sceneRoundTripSpinBox->value();
double delay = ui->sceneRoundTripSpinBox->value() *
switcher->sceneRoundTripUnitMultiplier;
if (scene1Name == scene2Name)
return;
@@ -22,65 +64,62 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay);
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name,
transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = SceneRoundTripFindByData(scene1Name);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneRoundTrips);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneRoundTripSwitches.emplace_back(
source1, source2, transition, int(delay * 1000),
source1, source2, transition, delay,
(scene2Name == QString(PREVIOUS_SCENE_NAME)),
text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
} else {
QListWidgetItem *item = ui->sceneRoundTrips->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches)
{
if (s.scene1 == source1)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneRoundTripSwitches) {
if (s.scene1 == source1) {
s.scene2 = source2;
s.delay = int(delay * 1000);
s.delay = delay;
s.transition = transition;
s.usePreviousScene = (scene2Name == QString(PREVIOUS_SCENE_NAME));
s.sceneRoundTripStr = text.toUtf8().constData();
s.usePreviousScene =
(scene2Name ==
QString(PREVIOUS_SCENE_NAME));
s.sceneRoundTripStr =
text.toUtf8().constData();
break;
}
}
}
ui->sceneRoundTrips->sortItems();
}
}
void SceneSwitcher::on_sceneRoundTripRemove_clicked()
{
QListWidgetItem* item = ui->sceneRoundTrips->currentItem();
QListWidgetItem *item = ui->sceneRoundTrips->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->sceneRoundTripSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->sceneRoundTripSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.sceneRoundTripStr == text)
{
if (s.sceneRoundTripStr == text) {
switches.erase(it);
break;
}
@@ -90,149 +129,147 @@ void SceneSwitcher::on_sceneRoundTripRemove_clicked()
delete item;
}
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->autoStopScenes->setDisabled(true);
switcher->autoStopEnable = false;
}
else
{
ui->autoStopScenes->setDisabled(false);
switcher->autoStopEnable = true;
}
}
void SceneSwitcher::UpdateAutoStopScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->autoStopScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateAutoStopScene(text);
}
void SceneSwitcher::on_sceneRoundTripSave_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!directory.isEmpty())
{
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
{
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
if (s.usePreviousScene)
out << (PREVIOUS_SCENE_NAME) << "\n";
else
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
out << s.delay << "\n";
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
this, tr("Save Scene Round Trip to file ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
if (directory.isEmpty())
return;
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
obs_data_t *obj = obs_data_create();
switcher->saveSceneRoundTripSwitches(obj);
obs_data_save_json(obj, file.fileName().toUtf8().constData());
obs_data_release(obj);
}
// to be removed once support for old file format is dropped
bool oldSceneRoundTripLoad(QFile *file)
{
QTextStream in(file);
std::vector<QString> lines;
std::vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
while (!in.atEnd()) {
QString line = in.readLine();
lines.push_back(line);
if (lines.size() == 5) {
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
OBSWeakSource transition =
GetWeakTransitionByQString(lines[4]);
if (WeakSourceValid(scene1) &&
((lines[1] == QString(PREVIOUS_SCENE_NAME)) ||
(WeakSourceValid(scene2))) &&
WeakSourceValid(transition)) {
newSceneRoundTripSwitch.emplace_back(
SceneRoundTripSwitch(
GetWeakSourceByQString(lines[0]),
GetWeakSourceByQString(lines[1]),
GetWeakTransitionByQString(
lines[4]),
lines[2].toDouble() / 1000.,
(lines[1] ==
QString(PREVIOUS_SCENE_NAME)),
lines[3].toStdString()));
}
lines.clear();
}
}
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
return false;
switcher->sceneRoundTripSwitches.clear();
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
return true;
}
void SceneSwitcher::on_sceneRoundTripLoad_clicked()
{
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
QString directory = QFileDialog::getOpenFileName(
this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!directory.isEmpty())
{
QFile file(directory);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
this, tr("Select a file to read Scene Round Trip from ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
if (directory.isEmpty())
return;
QTextStream in(&file);
vector<QString> lines;
QFile file(directory);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
obs_data_t *obj = obs_data_create_from_json_file(
file.fileName().toUtf8().constData());
while (!in.atEnd())
{
QString line = in.readLine();
lines.push_back(line);
if (lines.size() == 5)
{
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
if (WeakSourceValid(scene1) && ((lines[1] == QString(PREVIOUS_SCENE_NAME)) || (WeakSourceValid(scene2)))
&& WeakSourceValid(transition))
{
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
GetWeakSourceByQString(lines[0]),
GetWeakSourceByQString(lines[1]),
GetWeakTransitionByQString(lines[4]),
lines[2].toInt(),
(lines[1] == QString(PREVIOUS_SCENE_NAME)),
lines[3].toStdString()));
}
lines.clear();
}
}
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
return;
switcher->sceneRoundTripSwitches.clear();
ui->sceneRoundTrips->clear();
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
{
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips);
item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr));
if (!obj) {
QMessageBox Msgbox;
QString txt =
"Advanced Scene Switcher failed to import settings!\n";
txt += "Falling back to old format.";
Msgbox.setText(txt);
Msgbox.exec();
if (oldSceneRoundTripLoad(&file)) {
QString txt =
"Advanced Scene Switcher settings imported successfully!\n";
txt += "Please resave settings as support for old format will be dropped in next version.";
Msgbox.setText(txt);
Msgbox.exec();
close();
} else {
Msgbox.setText(
"Advanced Scene Switcher failed to import settings!");
Msgbox.exec();
}
return;
}
switcher->loadSceneRoundTripSwitches(obj);
obs_data_release(obj);
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher settings imported successfully!");
Msgbox.exec();
close();
}
void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock)
void SwitcherData::checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition,
std::unique_lock<std::mutex> &lock)
{
bool sceneRoundTripActive = false;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (SceneRoundTripSwitch& s : sceneRoundTripSwitches)
{
if (s.scene1 == ws)
{
for (SceneRoundTripSwitch &s : sceneRoundTripSwitches) {
if (s.scene1 == ws) {
sceneRoundTripActive = true;
int dur = s.delay - interval;
if (dur > 0)
{
int dur = s.delay * 1000 - interval;
if (dur > 0) {
waitScene = currentSource;
cv.wait_for(lock, chrono::milliseconds(dur));
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher sequence sleep %d",
dur);
cv.wait_for(lock,
std::chrono::milliseconds(dur));
waitScene = nullptr;
}
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
obs_source_t *currentSource2 =
obs_frontend_get_current_scene();
// only switch if user hasn't changed scene manually
if (currentSource == currentSource2)
{
if (currentSource == currentSource2) {
match = true;
scene = (s.usePreviousScene) ? previousScene : s.scene2;
scene = (s.usePreviousScene) ? previousScene
: s.scene2;
transition = s.transition;
}
obs_source_release(currentSource2);
@@ -250,42 +287,42 @@ void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
QListWidgetItem *item = ui->sceneRoundTrips->item(idx);
QString sceneRoundTrip = item->text();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches)
{
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0)
{
string scene1 = GetWeakSourceName(s.scene1);
string scene2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition);
int delay = s.delay;
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
ui->sceneRoundTripSpinBox->setValue((double)delay/1000);
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneRoundTripSwitches) {
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0) {
std::string scene1 = GetWeakSourceName(s.scene1);
std::string scene2 = GetWeakSourceName(s.scene2);
std::string transitionName =
GetWeakSourceName(s.transition);
double delay = s.delay /
switcher->sceneRoundTripUnitMultiplier;
ui->sceneRoundTripScenes1->setCurrentText(
scene1.c_str());
ui->sceneRoundTripScenes2->setCurrentText(
scene2.c_str());
ui->sceneRoundTripTransitions->setCurrentText(
transitionName.c_str());
ui->sceneRoundTripSpinBox->setValue(delay);
break;
}
}
}
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
int SceneSwitcher::SceneRoundTripFindByData(const QString &scene1)
{
QRegExp rx(scene1 + " ->.*");
int count = ui->sceneRoundTrips->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->sceneRoundTrips->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->sceneRoundTrips->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
if (rx.exactMatch(itemString)) {
idx = i;
break;
}
@@ -294,19 +331,170 @@ int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
return idx;
}
void SwitcherData::autoStopStreamAndRecording()
void SceneSwitcher::on_sceneRoundTripUp_clicked()
{
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
int index = ui->sceneRoundTrips->currentRow();
if (index != -1 && index != 0) {
ui->sceneRoundTrips->insertItem(
index - 1, ui->sceneRoundTrips->takeItem(index));
ui->sceneRoundTrips->setCurrentRow(index - 1);
if (ws && autoStopScene == ws)
{
if (obs_frontend_streaming_active())
obs_frontend_streaming_stop();
if (obs_frontend_recording_active())
obs_frontend_recording_stop();
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->sceneRoundTripSwitches.begin() + index,
switcher->sceneRoundTripSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_sceneRoundTripDown_clicked()
{
int index = ui->sceneRoundTrips->currentRow();
if (index != -1 && index != ui->sceneRoundTrips->count() - 1) {
ui->sceneRoundTrips->insertItem(
index + 1, ui->sceneRoundTrips->takeItem(index));
ui->sceneRoundTrips->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->sceneRoundTripSwitches.begin() + index,
switcher->sceneRoundTripSwitches.begin() + index + 1);
}
}
void SwitcherData::saveSceneRoundTripSwitches(obs_data_t *obj)
{
obs_data_array_t *sceneRoundTripArray = obs_data_array_create();
for (SceneRoundTripSwitch &s : switcher->sceneRoundTripSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source1 = obs_weak_source_get_source(s.scene1);
obs_source_t *source2 = obs_weak_source_get_source(s.scene2);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source1 && (s.usePreviousScene || source2) && transition) {
const char *sceneName1 = obs_source_get_name(source1);
const char *sceneName2 = obs_source_get_name(source2);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "sceneRoundTripScene1",
sceneName1);
obs_data_set_string(array_obj, "sceneRoundTripScene2",
s.usePreviousScene
? PREVIOUS_SCENE_NAME
: sceneName2);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_double(array_obj, "delay", s.delay);
obs_data_set_string(array_obj, "sceneRoundTripStr",
s.sceneRoundTripStr.c_str());
obs_data_array_push_back(sceneRoundTripArray,
array_obj);
obs_source_release(source1);
obs_source_release(source2);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "sceneRoundTrip", sceneRoundTripArray);
obs_data_array_release(sceneRoundTripArray);
}
void SwitcherData::loadSceneRoundTripSwitches(obs_data_t *obj)
{
switcher->sceneRoundTripSwitches.clear();
obs_data_array_t *sceneRoundTripArray =
obs_data_get_array(obj, "sceneRoundTrip");
size_t count = obs_data_array_count(sceneRoundTripArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(sceneRoundTripArray, i);
const char *scene1 =
obs_data_get_string(array_obj, "sceneRoundTripScene1");
const char *scene2 =
obs_data_get_string(array_obj, "sceneRoundTripScene2");
const char *transition =
obs_data_get_string(array_obj, "transition");
double delay = 0;
// To be removed in future version
// to be compatible with older versions
if (!obs_data_has_user_value(array_obj, "delay")) {
delay = double(obs_data_get_int(array_obj,
"sceneRoundTripDelay"));
delay = delay * 1000. +
double(obs_data_get_int(
array_obj, "sceneRoundTripDelayMs"));
delay /= 1000.;
} else {
delay = obs_data_get_double(array_obj, "delay");
}
std::string str = MakeSceneRoundTripSwitchName(
scene1, scene2, transition, delay)
.toUtf8()
.constData();
const char *sceneRoundTripStr = str.c_str();
switcher->sceneRoundTripSwitches.emplace_back(
GetWeakSourceByName(scene1),
GetWeakSourceByName(scene2),
GetWeakTransitionByName(transition), delay,
(strcmp(scene2, PREVIOUS_SCENE_NAME) == 0),
sceneRoundTripStr);
obs_data_release(array_obj);
}
obs_data_array_release(sceneRoundTripArray);
}
void SceneSwitcher::setupSequenceTab()
{
populateSceneSelection(ui->sceneRoundTripScenes1, false);
populateSceneSelection(ui->sceneRoundTripScenes2, true);
populateTransitionSelection(ui->sceneRoundTripTransitions);
double smallestDelay = double(switcher->interval) / 1000;
for (auto &s : switcher->sceneRoundTripSwitches) {
std::string sceneName1 = GetWeakSourceName(s.scene1);
std::string sceneName2 = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene2);
std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeSceneRoundTripSwitchName(
sceneName1.c_str(), sceneName2.c_str(),
transitionName.c_str(), s.delay);
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneRoundTrips);
item->setData(Qt::UserRole, text);
if (s.delay < smallestDelay)
smallestDelay = s.delay;
}
(smallestDelay * 1000 < switcher->interval)
? ui->intervalWarning->setVisible(true)
: ui->intervalWarning->setVisible(false);
ui->sceneRoundTripDelayUnits->addItem("seconds");
ui->sceneRoundTripDelayUnits->addItem("minutes");
ui->sceneRoundTripDelayUnits->addItem("hours");
switch (switcher->sceneRoundTripUnitMultiplier) {
case 1:
ui->sceneRoundTripDelayUnits->setCurrentIndex(0);
break;
case 60:
ui->sceneRoundTripDelayUnits->setCurrentIndex(1);
break;
case 3600:
ui->sceneRoundTripDelayUnits->setCurrentIndex(2);
break;
default:
break;
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}

View File

@@ -16,33 +16,33 @@ void SceneSwitcher::on_transitionsAdd_clicked()
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
QString text =
MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneTransitions.emplace_back(
source1, source2, transition, text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->sceneTransitions->item(idx);
source1, source2, transition,
text.toUtf8().constData());
} else {
QListWidgetItem *item = ui->sceneTransitions->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions)
{
if (s.scene1 == source1 && s.scene2 == source2)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneTransitions) {
if (s.scene1 == source1 &&
s.scene2 == source2) {
s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData();
s.sceneTransitionStr =
text.toUtf8().constData();
break;
}
}
@@ -54,22 +54,21 @@ void SceneSwitcher::on_transitionsAdd_clicked()
void SceneSwitcher::on_transitionsRemove_clicked()
{
QListWidgetItem* item = ui->sceneTransitions->currentItem();
QListWidgetItem *item = ui->sceneTransitions->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->sceneTransitions;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->sceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.sceneTransitionStr == text)
{
if (s.sceneTransitionStr == text) {
switches.erase(it);
break;
}
@@ -82,7 +81,8 @@ void SceneSwitcher::on_transitionsRemove_clicked()
void SceneSwitcher::on_defaultTransitionsAdd_clicked()
{
QString sceneName = ui->defaultTransitionsScene->currentText();
QString transitionName = ui->defaultTransitionsTransitions->currentText();
QString transitionName =
ui->defaultTransitionsTransitions->currentText();
if (sceneName.isEmpty() || transitionName.isEmpty())
return;
@@ -90,33 +90,31 @@ void SceneSwitcher::on_defaultTransitionsAdd_clicked()
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeDefaultSceneTransitionName(sceneName, transitionName);
QString text =
MakeDefaultSceneTransitionName(sceneName, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = DefaultTransitionsFindByData(sceneName);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->defaultTransitions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back(
source, transition, text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->defaultTransitions->item(idx);
} else {
QListWidgetItem *item = ui->defaultTransitions->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions)
{
if (s.scene == source)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->defaultSceneTransitions) {
if (s.scene == source) {
s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData();
s.sceneTransitionStr =
text.toUtf8().constData();
break;
}
}
@@ -128,22 +126,21 @@ void SceneSwitcher::on_defaultTransitionsAdd_clicked()
void SceneSwitcher::on_defaultTransitionsRemove_clicked()
{
QListWidgetItem* item = ui->defaultTransitions->currentItem();
QListWidgetItem *item = ui->defaultTransitions->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->defaultSceneTransitions;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->defaultSceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.sceneTransitionStr == text)
{
if (s.sceneTransitionStr == text) {
switches.erase(it);
break;
}
@@ -155,17 +152,21 @@ void SceneSwitcher::on_defaultTransitionsRemove_clicked()
void SwitcherData::setDefaultSceneTransitions()
{
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (DefaultSceneTransition& s : defaultSceneTransitions)
{
if (s.scene == ws)
{
obs_source_t* transition = obs_weak_source_get_source(s.transition);
for (DefaultSceneTransition &s : defaultSceneTransitions) {
if (s.scene == ws) {
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
//This might cancel the current transition
//There is no way to be sure when the previous transition finished
obs_frontend_set_current_transition(transition);
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher default transition set");
obs_source_release(transition);
break;
}
@@ -174,19 +175,18 @@ void SwitcherData::setDefaultSceneTransitions()
obs_weak_source_release(ws);
}
int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2)
int SceneSwitcher::SceneTransitionsFindByData(const QString &scene1,
const QString &scene2)
{
QRegExp rx(scene1 + " --- .* --> " + scene2);
int count = ui->sceneTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->sceneTransitions->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->sceneTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
if (rx.exactMatch(itemString)) {
idx = i;
break;
}
@@ -195,19 +195,17 @@ int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QStri
return idx;
}
int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene)
int SceneSwitcher::DefaultTransitionsFindByData(const QString &scene)
{
QRegExp rx(scene + " --> .*");
int count = ui->defaultTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->defaultTransitions->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->defaultTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
if (rx.exactMatch(itemString)) {
idx = i;
break;
}
@@ -223,21 +221,22 @@ void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->sceneTransitions->item(idx);
QListWidgetItem *item = ui->sceneTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions)
{
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
{
string scene1 = GetWeakSourceName(s.scene1);
string scene2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition);
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->sceneTransitions) {
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
0) {
std::string scene1 = GetWeakSourceName(s.scene1);
std::string scene2 = GetWeakSourceName(s.scene2);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->transitionsScene1->setCurrentText(scene1.c_str());
ui->transitionsScene2->setCurrentText(scene2.c_str());
ui->transitionsTransitions->setCurrentText(transitionName.c_str());
ui->transitionsTransitions->setCurrentText(
transitionName.c_str());
break;
}
}
@@ -250,31 +249,45 @@ void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->defaultTransitions->item(idx);
QListWidgetItem *item = ui->defaultTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions)
{
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
{
string scene = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->defaultTransitionsScene->setCurrentText(scene.c_str());
ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str());
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->defaultSceneTransitions) {
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
0) {
std::string scene = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->defaultTransitionsScene->setCurrentText(
scene.c_str());
ui->defaultTransitionsTransitions->setCurrentText(
transitionName.c_str());
break;
}
}
}
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2)
void SceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
{
obs_weak_source_t* ws = nullptr;
if (scene1 && scene2)
{
for (SceneTransition& t : switcher->sceneTransitions)
{
if (loading)
return;
std::lock_guard<std::mutex> lock(switcher->m);
if (!state) {
switcher->tansitionOverrideOverride = false;
} else {
switcher->tansitionOverrideOverride = true;
}
}
obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
obs_weak_source_t *scene2)
{
obs_weak_source_t *ws = nullptr;
if (scene1 && scene2) {
for (SceneTransition &t : switcher->sceneTransitions) {
if (t.scene1 == scene1 && t.scene2 == scene2)
ws = t.transition;
}
@@ -282,3 +295,221 @@ obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_
}
return ws;
}
void overwriteTransitionOverride(obs_weak_source_t *sceneWs,
obs_source_t *transition, transitionData &td)
{
obs_source_t *scene = obs_weak_source_get_source(sceneWs);
obs_data_t *data = obs_source_get_private_settings(scene);
td.name = obs_data_get_string(data, "transition");
td.duration = obs_data_get_int(data, "duration");
const char *name = obs_source_get_name(transition);
int duration = obs_frontend_get_transition_duration();
obs_data_set_string(data, "transition", name);
obs_data_set_int(data, "transition_duration", duration);
obs_data_release(data);
obs_source_release(scene);
}
void restoreTransitionOverride(obs_source_t *scene, transitionData td)
{
obs_data_t *data = obs_source_get_private_settings(scene);
obs_data_set_string(data, "transition", td.name.c_str());
obs_data_set_int(data, "transition_duration", td.duration);
obs_data_release(data);
}
void setNextTransition(OBSWeakSource &targetScene, obs_source_t *currentSource,
OBSWeakSource &transition,
bool &transitionOverrideOverride, transitionData &td)
{
obs_weak_source_t *currentScene =
obs_source_get_weak_source(currentSource);
obs_weak_source_t *nextTransitionWs =
getNextTransition(currentScene, targetScene);
obs_weak_source_release(currentScene);
obs_source_t *nextTransition = nullptr;
if (nextTransitionWs) {
nextTransition = obs_weak_source_get_source(nextTransitionWs);
} else if (transition) {
nextTransition = obs_weak_source_get_source(transition);
}
if (nextTransition) {
obs_frontend_set_current_transition(nextTransition);
}
if (transitionOverrideOverride)
overwriteTransitionOverride(targetScene, nextTransition, td);
obs_weak_source_release(nextTransitionWs);
obs_source_release(nextTransition);
}
void SwitcherData::saveSceneTransitions(obs_data_t *obj)
{
obs_data_array_t *sceneTransitionsArray = obs_data_array_create();
for (SceneTransition &s : switcher->sceneTransitions) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source1 = obs_weak_source_get_source(s.scene1);
obs_source_t *source2 = obs_weak_source_get_source(s.scene2);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source1 && source2 && transition) {
const char *sceneName1 = obs_source_get_name(source1);
const char *sceneName2 = obs_source_get_name(source2);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "Scene1", sceneName1);
obs_data_set_string(array_obj, "Scene2", sceneName2);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_string(array_obj, "Str",
s.sceneTransitionStr.c_str());
obs_data_array_push_back(sceneTransitionsArray,
array_obj);
obs_source_release(source1);
obs_source_release(source2);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "sceneTransitions", sceneTransitionsArray);
obs_data_array_release(sceneTransitionsArray);
obs_data_array_t *defaultTransitionsArray = obs_data_array_create();
for (DefaultSceneTransition &s : switcher->defaultSceneTransitions) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source && transition) {
const char *sceneName = obs_source_get_name(source);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "Scene", sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_string(array_obj, "Str",
s.sceneTransitionStr.c_str());
obs_data_array_push_back(defaultTransitionsArray,
array_obj);
obs_source_release(source);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
obs_data_array_release(defaultTransitionsArray);
obs_data_set_bool(obj, "tansitionOverrideOverride",
switcher->tansitionOverrideOverride);
}
void SwitcherData::loadSceneTransitions(obs_data_t *obj)
{
switcher->sceneTransitions.clear();
obs_data_array_t *sceneTransitionsArray =
obs_data_get_array(obj, "sceneTransitions");
size_t count = obs_data_array_count(sceneTransitionsArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(sceneTransitionsArray, i);
const char *scene1 = obs_data_get_string(array_obj, "Scene1");
const char *scene2 = obs_data_get_string(array_obj, "Scene2");
const char *transition =
obs_data_get_string(array_obj, "transition");
const char *sceneTransitionsStr =
obs_data_get_string(array_obj, "Str");
switcher->sceneTransitions.emplace_back(
GetWeakSourceByName(scene1),
GetWeakSourceByName(scene2),
GetWeakTransitionByName(transition),
sceneTransitionsStr);
obs_data_release(array_obj);
}
obs_data_array_release(sceneTransitionsArray);
switcher->defaultSceneTransitions.clear();
obs_data_array_t *defaultTransitionsArray =
obs_data_get_array(obj, "defaultTransitions");
count = obs_data_array_count(defaultTransitionsArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(defaultTransitionsArray, i);
const char *scene = obs_data_get_string(array_obj, "Scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
const char *sceneTransitionsStr =
obs_data_get_string(array_obj, "Str");
switcher->defaultSceneTransitions.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition),
sceneTransitionsStr);
obs_data_release(array_obj);
}
obs_data_array_release(defaultTransitionsArray);
switcher->tansitionOverrideOverride =
obs_data_get_bool(obj, "tansitionOverrideOverride");
}
void SceneSwitcher::setupTransitionsTab()
{
populateSceneSelection(ui->transitionsScene1, false);
populateSceneSelection(ui->transitionsScene2, false);
populateSceneSelection(ui->defaultTransitionsScene, false);
populateTransitionSelection(ui->transitionsTransitions);
populateTransitionSelection(ui->defaultTransitionsTransitions);
for (auto &s : switcher->sceneTransitions) {
std::string sceneName1 = GetWeakSourceName(s.scene1);
std::string sceneName2 = GetWeakSourceName(s.scene2);
std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeSceneTransitionName(sceneName1.c_str(),
sceneName2.c_str(),
transitionName.c_str());
QListWidgetItem *item =
new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, text);
}
//(transitionDurationLongerThanInterval(switcher->interval))
// ? ui->transitionWarning->setVisible(true)
// : ui->transitionWarning->setVisible(false);
for (auto &s : switcher->defaultSceneTransitions) {
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeDefaultSceneTransitionName(
sceneName.c_str(), transitionName.c_str());
QListWidgetItem *item =
new QListWidgetItem(text, ui->defaultTransitions);
item->setData(Qt::UserRole, text);
}
ui->transitionOverridecheckBox->setChecked(
switcher->tansitionOverrideOverride);
}

View File

@@ -1,22 +1,28 @@
#include <QTimer>
#include "headers/advanced-scene-switcher.hpp"
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
pair<int, int> cursorPos = getCursorPos();
std::pair<int, int> cursorPos = getCursorPos();
int minRegionSize = 99999;
for (auto& s : screenRegionSwitches)
{
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY
&& cursorPos.first <= s.maxX && cursorPos.second <= s.maxY)
{
for (auto &s : screenRegionSwitches) {
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY &&
cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) {
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
if (regionSize < minRegionSize)
{
if (regionSize < minRegionSize) {
match = true;
scene = s.scene;
transition = s.transition;
minRegionSize = regionSize;
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher region match");
break;
}
}
}
@@ -24,9 +30,8 @@ void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OB
void SceneSwitcher::updateScreenRegionCursorPos()
{
pair<int, int> position = getCursorPos();
std::pair<int, int> position = getCursorPos();
ui->cursorXPosition->setText(QString::number(position.first));
;
ui->cursorYPosition->setText(QString::number(position.second));
}
@@ -43,69 +48,64 @@ void SceneSwitcher::on_screenRegionAdd_clicked()
int maxX = ui->screenRegionMaxX->value();
int maxY = ui->screenRegionMaxY->value();
string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", "
+ to_string(maxY);
std::string regionStr =
std::to_string(minX) + ", " + std::to_string(minY) + " x " +
std::to_string(maxX) + ", " + std::to_string(maxY);
QString region = QString::fromStdString(regionStr);
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(region);
QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY);
QString text = MakeScreenRegionSwitchName(sceneName, transitionName,
minX, minY, maxX, maxY);
int idx = ScreenRegionFindByData(region);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions);
if (idx == -1) {
QListWidgetItem *item =
new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back(
source, transition, minX, minY, maxX, maxY, regionStr);
}
else
{
QListWidgetItem* item = ui->screenRegions->item(idx);
} else {
QListWidgetItem *item = ui->screenRegions->item(idx);
item->setText(text);
string curRegion = region.toUtf8().constData();
std::string curRegion = region.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches)
{
if (s.regionStr == curRegion)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->screenRegionSwitches) {
if (s.regionStr == curRegion) {
s.scene = source;
s.transition = transition;
break;
}
}
}
ui->screenRegions->sortItems();
}
}
void SceneSwitcher::on_screenRegionRemove_clicked()
{
QListWidgetItem* item = ui->screenRegions->currentItem();
QListWidgetItem *item = ui->screenRegions->currentItem();
if (!item)
return;
string region = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string region =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->screenRegionSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->screenRegionSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.regionStr == region)
{
if (s.regionStr == region) {
switches.erase(it);
break;
}
@@ -122,19 +122,19 @@ void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->screenRegions->item(idx);
QListWidgetItem *item = ui->screenRegions->item(idx);
QString region = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches)
{
if (region.compare(s.regionStr.c_str()) == 0)
{
string name = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->screenRegionSwitches) {
if (region.compare(s.regionStr.c_str()) == 0) {
std::string name = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->screenRegionScenes->setCurrentText(name.c_str());
ui->screenRegionsTransitions->setCurrentText(transitionName.c_str());
ui->screenRegionsTransitions->setCurrentText(
transitionName.c_str());
ui->screenRegionMinX->setValue(s.minX);
ui->screenRegionMinY->setValue(s.minY);
ui->screenRegionMaxX->setValue(s.maxX);
@@ -144,18 +144,16 @@ void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
}
}
int SceneSwitcher::ScreenRegionFindByData(const QString& region)
int SceneSwitcher::ScreenRegionFindByData(const QString &region)
{
int count = ui->screenRegions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->screenRegions->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->screenRegions->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == region)
{
if (itemRegion == region) {
idx = i;
break;
}
@@ -163,3 +161,124 @@ int SceneSwitcher::ScreenRegionFindByData(const QString& region)
return idx;
}
void SceneSwitcher::on_screenRegionUp_clicked()
{
int index = ui->screenRegions->currentRow();
if (index != -1 && index != 0) {
ui->screenRegions->insertItem(
index - 1, ui->screenRegions->takeItem(index));
ui->screenRegions->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->screenRegionSwitches.begin() + index,
switcher->screenRegionSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_screenRegionDown_clicked()
{
int index = ui->screenRegions->currentRow();
if (index != -1 && index != ui->screenRegions->count() - 1) {
ui->screenRegions->insertItem(
index + 1, ui->screenRegions->takeItem(index));
ui->screenRegions->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->screenRegionSwitches.begin() + index,
switcher->screenRegionSwitches.begin() + index + 1);
}
}
void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
{
obs_data_array_t *screenRegionArray = obs_data_array_create();
for (ScreenRegionSwitch &s : switcher->screenRegionSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source && transition) {
const char *sceneName = obs_source_get_name(source);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "screenRegionScene",
sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_int(array_obj, "minX", s.minX);
obs_data_set_int(array_obj, "minY", s.minY);
obs_data_set_int(array_obj, "maxX", s.maxX);
obs_data_set_int(array_obj, "maxY", s.maxY);
obs_data_set_string(array_obj, "screenRegionStr",
s.regionStr.c_str());
obs_data_array_push_back(screenRegionArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "screenRegion", screenRegionArray);
obs_data_array_release(screenRegionArray);
}
void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
{
switcher->screenRegionSwitches.clear();
obs_data_array_t *screenRegionArray =
obs_data_get_array(obj, "screenRegion");
size_t count = obs_data_array_count(screenRegionArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(screenRegionArray, i);
const char *scene =
obs_data_get_string(array_obj, "screenRegionScene");
const char *transition =
obs_data_get_string(array_obj, "transition");
int minX = obs_data_get_int(array_obj, "minX");
int minY = obs_data_get_int(array_obj, "minY");
int maxX = obs_data_get_int(array_obj, "maxX");
int maxY = obs_data_get_int(array_obj, "maxY");
std::string regionStr =
obs_data_get_string(array_obj, "screenRegionStr");
switcher->screenRegionSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), minX, minY, maxX,
maxY, regionStr);
obs_data_release(array_obj);
}
obs_data_array_release(screenRegionArray);
}
void SceneSwitcher::setupRegionTab()
{
populateSceneSelection(ui->screenRegionScenes, false);
populateTransitionSelection(ui->screenRegionsTransitions);
for (auto &s : switcher->screenRegionSwitches) {
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeScreenRegionSwitchName(
sceneName.c_str(), transitionName.c_str(), s.minX,
s.minY, s.maxX, s.maxY);
QListWidgetItem *item =
new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, s.regionStr.c_str());
}
// screen region cursor position
QTimer *screenRegionTimer = new QTimer(this);
connect(screenRegionTimer, SIGNAL(timeout()), this,
SLOT(updateScreenRegionCursorPos()));
screenRegionTimer->start(1000);
}

View File

@@ -11,7 +11,7 @@ void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
QString timeScenestr = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->timeSwitches) {
if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str();
@@ -59,7 +59,7 @@ void SceneSwitcher::on_timeAdd_clicked()
int idx = timeFindByData(time.toString());
if (idx == -1) {
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->timeSwitches.emplace_back(
source, transition, time,
(sceneName == QString(PREVIOUS_SCENE_NAME)),
@@ -71,9 +71,10 @@ void SceneSwitcher::on_timeAdd_clicked()
} else {
QListWidgetItem *item = ui->timeSwitches->item(idx);
item->setText(text);
item->setData(Qt::UserRole, v);
{
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->timeSwitches) {
if (s.time == time) {
s.scene = source;
@@ -83,7 +84,6 @@ void SceneSwitcher::on_timeAdd_clicked()
QString(PREVIOUS_SCENE_NAME));
s.timeSwitchStr =
text.toUtf8().constData();
;
break;
}
}
@@ -99,10 +99,11 @@ void SceneSwitcher::on_timeRemove_clicked()
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string text =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->timeSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
@@ -141,7 +142,97 @@ void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
scene = (s.usePreviousScene) ? previousScene : s.scene;
transition = s.transition;
match = true;
if (verbose)
blog(LOG_INFO,
"Advanced Scene Switcher time match");
break;
}
}
}
void SwitcherData::saveTimeSwitches(obs_data_t *obj)
{
obs_data_array_t *timeArray = obs_data_array_create();
for (TimeSwitch &s : switcher->timeSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *sceneSource = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if ((s.usePreviousScene || sceneSource) && transition) {
const char *sceneName =
obs_source_get_name(sceneSource);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "scene",
s.usePreviousScene
? PREVIOUS_SCENE_NAME
: sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_string(
array_obj, "time",
s.time.toString().toStdString().c_str());
obs_data_array_push_back(timeArray, array_obj);
}
obs_source_release(sceneSource);
obs_source_release(transition);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "timeSwitches", timeArray);
obs_data_array_release(timeArray);
}
void SwitcherData::loadTimeSwitches(obs_data_t *obj)
{
switcher->timeSwitches.clear();
obs_data_array_t *timeArray = obs_data_get_array(obj, "timeSwitches");
size_t count = obs_data_array_count(timeArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(timeArray, i);
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
QTime time = QTime::fromString(
obs_data_get_string(array_obj, "time"));
std::string timeSwitchStr =
MakeTimeSwitchName(scene, transition, time)
.toUtf8()
.constData();
switcher->timeSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), time,
(strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
timeSwitchStr);
obs_data_release(array_obj);
}
obs_data_array_release(timeArray);
}
void SceneSwitcher::setupTimeTab()
{
populateSceneSelection(ui->timeScenes, true);
populateTransitionSelection(ui->timeTransitions);
for (auto &s : switcher->timeSwitches) {
std::string sceneName = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeTimeSwitchName(
sceneName.c_str(), transitionName.c_str(), s.time);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->timeSwitches);
item->setData(Qt::UserRole, listText);
}
}

View File

@@ -6,7 +6,7 @@
using namespace std;
static bool GetWindowTitle(HWND window, string& title)
static bool GetWindowTitle(HWND window, string &title)
{
size_t len = (size_t)GetWindowTextLengthW(window);
wstring wtitle;
@@ -45,12 +45,13 @@ static bool WindowValid(HWND window)
return true;
}
void GetWindowList(vector<string>& windows)
void GetWindowList(vector<string> &windows)
{
windows.resize(0);
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
while (window)
{
while (window) {
string title;
if (WindowValid(window) && GetWindowTitle(window, title))
windows.emplace_back(title);
@@ -58,7 +59,22 @@ void GetWindowList(vector<string>& windows)
}
}
void GetCurrentWindowTitle(string& title)
// Overloaded
void GetWindowList(QStringList &windows)
{
windows.clear();
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
while (window) {
string title;
if (WindowValid(window) && GetWindowTitle(window, title))
windows << QString::fromStdString(title);
window = GetNextWindow(window, GW_HWNDNEXT);
}
}
void GetCurrentWindowTitle(string &title)
{
HWND window = GetForegroundWindow();
DWORD pid;
@@ -75,43 +91,63 @@ void GetCurrentWindowTitle(string& title)
GetWindowTitle(window, title);
}
pair<int, int> getCursorPos()
std::pair<int, int> getCursorPos()
{
pair<int, int> pos(0, 0);
std::pair<int, int> pos(0, 0);
POINT cursorPos;
if (GetPhysicalCursorPos(&cursorPos))
{
if (GetPhysicalCursorPos(&cursorPos)) {
pos.first = cursorPos.x;
pos.second = cursorPos.y;
}
return pos;
}
bool isFullscreen()
bool isFullscreen(std::string &title)
{
RECT appBounds;
RECT rc;
GetWindowRect(GetDesktopWindow(), &rc);
HWND hwnd = GetForegroundWindow();
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow())
{
MONITORINFO monitorInfo = {0};
HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
while (hwnd) {
string wtitle;
if (WindowValid(hwnd) && GetWindowTitle(hwnd, wtitle) &&
(wtitle == title ||
QString::fromStdString(wtitle).contains(QRegularExpression(
QString::fromStdString(title)))))
break;
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
}
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
&monitorInfo);
if (hwnd && hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) {
if (IsZoomed(hwnd)) {
return true;
}
GetWindowRect(hwnd, &appBounds);
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left
&& rc.right == appBounds.right)
{
if (monitorInfo.rcMonitor.bottom == appBounds.bottom &&
monitorInfo.rcMonitor.top == appBounds.top &&
monitorInfo.rcMonitor.left == appBounds.left &&
monitorInfo.rcMonitor.right == appBounds.right) {
return true;
}
}
return false;
}
void GetProcessList(QStringList &processes) {
void GetProcessList(QStringList &processes)
{
HANDLE procSnapshot;
PROCESSENTRY32 procEntry;
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (procSnapshot == INVALID_HANDLE_VALUE) return;
if (procSnapshot == INVALID_HANDLE_VALUE)
return;
procEntry.dwSize = sizeof(PROCESSENTRY32);
@@ -122,30 +158,45 @@ void GetProcessList(QStringList &processes) {
do {
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
if (tempexe == "System") continue;
if (tempexe == "[System Process]") continue;
if (processes.contains(tempexe)) continue;
if (tempexe == "System")
continue;
if (tempexe == "[System Process]")
continue;
if (processes.contains(tempexe))
continue;
processes.append(tempexe);
} while (Process32Next(procSnapshot, &procEntry));
CloseHandle(procSnapshot);
}
bool isInFocus(const QString &exeToCheck) {
bool isInFocus(const QString &executable)
{
// only checks if the current foreground window is from the same executable,
// may return true for incorrent not meant windows from a program
// may return true for any window from a program
HWND foregroundWindow = GetForegroundWindow();
DWORD processId = 0;
GetWindowThreadProcessId(foregroundWindow, &processId);
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (process == NULL) return false;
HANDLE process = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (process == NULL)
return false;
WCHAR executablePath[600];
GetModuleFileNameEx(process, 0, executablePath, 600);
CloseHandle(process);
return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back();
QString file = QString::fromWCharArray(executablePath)
.split(QRegularExpression("(/|\\\\)"))
.back();
// True if executable switch equals current window
bool equals = (executable == file);
// True if executable switch matches current window
bool matches = file.contains(QRegularExpression(executable));
return (equals || matches);
}
int getLastInputTime()

View File

@@ -1,12 +1,71 @@
#include <obs-module.h>
#include "headers/advanced-scene-switcher.hpp"
bool isRunning(std::string &title)
{
QStringList windows;
GetWindowList(windows);
// True if switch is running (direct)
bool equals = windows.contains(QString::fromStdString(title));
// True if switch is running (regex)
bool matches = (windows.indexOf(QRegularExpression(
QString::fromStdString(title))) != -1);
return (equals || matches);
}
bool isFocused(std::string &title)
{
std::string current;
GetCurrentWindowTitle(current);
// True if switch equals current window
bool equals = (title == current);
// True if switch matches current window
bool matches = QString::fromStdString(current).contains(
QRegularExpression(QString::fromStdString(title)));
return (equals || matches);
}
void SceneSwitcher::on_up_clicked()
{
int index = ui->switches->currentRow();
if (index != -1 && index != 0) {
ui->switches->insertItem(index - 1,
ui->switches->takeItem(index));
ui->switches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->windowSwitches.begin() + index,
switcher->windowSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_down_clicked()
{
int index = ui->switches->currentRow();
if (index != -1 && index != ui->switches->count() - 1) {
ui->switches->insertItem(index + 1,
ui->switches->takeItem(index));
ui->switches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->windowSwitches.begin() + index,
switcher->windowSwitches.begin() + index + 1);
}
}
void SceneSwitcher::on_add_clicked()
{
QString sceneName = ui->scenes->currentText();
QString windowName = ui->windows->currentText();
QString transitionName = ui->transitions->currentText();
bool fullscreen = ui->fullscreenCheckBox->isChecked();
bool focus = ui->focusCheckBox->isChecked();
if (windowName.isEmpty() || sceneName.isEmpty())
return;
@@ -15,62 +74,57 @@ void SceneSwitcher::on_add_clicked()
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(windowName);
QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen);
QString text = MakeSwitchName(sceneName, windowName, transitionName,
fullscreen, focus);
int idx = FindByData(windowName);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back(
source, windowName.toUtf8().constData(), transition, fullscreen);
source, windowName.toUtf8().constData(), transition,
fullscreen, focus);
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->switches->item(idx);
} else {
QListWidgetItem *item = ui->switches->item(idx);
item->setText(text);
string window = windowName.toUtf8().constData();
std::string window = windowName.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->windowSwitches)
{
if (s.window == window)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->windowSwitches) {
if (s.window == window) {
s.scene = source;
s.transition = transition;
s.fullscreen = fullscreen;
s.focus = focus;
break;
}
}
}
ui->switches->sortItems();
}
}
void SceneSwitcher::on_remove_clicked()
{
QListWidgetItem* item = ui->switches->currentItem();
QListWidgetItem *item = ui->switches->currentItem();
if (!item)
return;
string window = item->data(Qt::UserRole).toString().toUtf8().constData();
std::string window =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->windowSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->windowSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.window == window)
{
if (s.window == window) {
switches.erase(it);
break;
}
@@ -80,9 +134,6 @@ void SceneSwitcher::on_remove_clicked()
delete item;
}
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
{
QString windowName = ui->ignoreWindowsWindows->currentText();
@@ -92,37 +143,36 @@ void SceneSwitcher::on_ignoreWindowsAdd_clicked()
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
QList<QListWidgetItem *> items =
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData());
ui->ignoreWindows->sortItems();
std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
}
}
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
{
QListWidgetItem* item = ui->ignoreWindows->currentItem();
QListWidgetItem *item = ui->ignoreWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->ignoreWindowsSwitches;
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData())
{
if (s == windowName.toUtf8().constData()) {
switches.erase(it);
break;
}
@@ -132,18 +182,16 @@ void SceneSwitcher::on_ignoreWindowsRemove_clicked()
delete item;
}
int SceneSwitcher::FindByData(const QString& window)
int SceneSwitcher::FindByData(const QString &window)
{
int count = ui->switches->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->switches->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->switches->item(i);
QString itemWindow = item->data(Qt::UserRole).toString();
if (itemWindow == window)
{
if (itemWindow == window) {
idx = i;
break;
}
@@ -152,21 +200,16 @@ int SceneSwitcher::FindByData(const QString& window)
return idx;
}
int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
int SceneSwitcher::IgnoreWindowsFindByData(const QString &window)
{
int count = ui->ignoreWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->ignoreWindows->item(i);
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
if (itemRegion == window) {
idx = i;
break;
}
@@ -175,7 +218,6 @@ int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
return idx;
}
void SceneSwitcher::on_switches_currentRowChanged(int idx)
{
if (loading)
@@ -183,27 +225,26 @@ void SceneSwitcher::on_switches_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->switches->item(idx);
QListWidgetItem *item = ui->switches->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->windowSwitches)
{
if (window.compare(s.window.c_str()) == 0)
{
string name = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->windowSwitches) {
if (window.compare(s.window.c_str()) == 0) {
std::string name = GetWeakSourceName(s.scene);
std::string transitionName =
GetWeakSourceName(s.transition);
ui->scenes->setCurrentText(name.c_str());
ui->windows->setCurrentText(window);
ui->transitions->setCurrentText(transitionName.c_str());
ui->fullscreenCheckBox->setChecked(s.fullscreen);
ui->focusCheckBox->setChecked(s.focus);
break;
}
}
}
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{
if (loading)
@@ -211,70 +252,181 @@ void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
if (idx == -1)
return;
QListWidgetItem* item = ui->ignoreWindows->item(idx);
QListWidgetItem *item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->ignoreWindowsSwitches)
{
if (window.compare(s.c_str()) == 0)
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->ignoreWindowsSwitches) {
if (window.compare(s.c_str()) == 0) {
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
//check if title should be ignored
string title;
std::string title;
bool ignored = false;
// Check if current window is ignored
GetCurrentWindowTitle(title);
for (auto& window : ignoreWindowsSwitches)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
title = lastTitle;
break;
}
}
catch (const regex_error&)
{
for (auto &window : ignoreWindowsSwitches) {
// True if ignored switch equals current window
bool equals = (title == window);
// True if ignored switch matches current window
bool matches = QString::fromStdString(title).contains(
QRegularExpression(QString::fromStdString(window)));
if (equals || matches) {
ignored = true;
title = lastTitle;
break;
}
}
lastTitle = title;
//direct match
for (WindowSceneSwitch& s : windowSwitches)
{
if (s.window == title)
{
match = !s.fullscreen || (s.fullscreen && isFullscreen());
// Check for match
for (WindowSceneSwitch &s : windowSwitches) {
// True if fullscreen is disabled OR current window is fullscreen
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
// True if focus is disabled OR switch is focused
bool focus = (!s.focus || isFocused(s.window));
// True if current window is ignored AND switch equals OR matches last window
bool ignore =
(ignored &&
(title == s.window ||
QString::fromStdString(title).contains(
QRegularExpression(
QString::fromStdString(s.window)))));
if (isRunning(s.window) && (fullscreen && (focus || ignore))) {
match = true;
scene = s.scene;
transition = s.transition;
return;
break;
}
}
//regex match
for (WindowSceneSwitch& s : windowSwitches)
{
try
{
bool matches = regex_match(title, regex(s.window));
if (matches)
{
match = !s.fullscreen || (s.fullscreen && isFullscreen());
scene = s.scene;
transition = s.transition;
}
}
catch (const regex_error&)
{
}
void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
{
obs_data_array_t *windowTitleArray = obs_data_array_create();
for (WindowSceneSwitch &s : switcher->windowSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(s.scene);
obs_source_t *transition =
obs_weak_source_get_source(s.transition);
if (source && transition) {
const char *sceneName = obs_source_get_name(source);
const char *transitionName =
obs_source_get_name(transition);
obs_data_set_string(array_obj, "scene", sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_string(array_obj, "window_title",
s.window.c_str());
obs_data_set_bool(array_obj, "fullscreen",
s.fullscreen);
obs_data_set_bool(array_obj, "focus", s.focus);
obs_data_array_push_back(windowTitleArray, array_obj);
obs_source_release(source);
obs_source_release(transition);
}
obs_data_release(array_obj);
}
obs_data_set_array(obj, "switches", windowTitleArray);
obs_data_array_release(windowTitleArray);
obs_data_array_t *ignoreWindowsArray = obs_data_array_create();
for (std::string &window : switcher->ignoreWindowsSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "ignoreWindow", window.c_str());
obs_data_array_push_back(ignoreWindowsArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "ignoreWindows", ignoreWindowsArray);
obs_data_array_release(ignoreWindowsArray);
}
void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
{
switcher->windowSwitches.clear();
obs_data_array_t *windowTitleArray =
obs_data_get_array(obj, "switches");
size_t count = obs_data_array_count(windowTitleArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(windowTitleArray, i);
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
const char *window =
obs_data_get_string(array_obj, "window_title");
bool fullscreen = obs_data_get_bool(array_obj, "fullscreen");
bool focus = obs_data_get_bool(array_obj, "focus") ||
!obs_data_has_user_value(array_obj, "focus");
switcher->windowSwitches.emplace_back(
GetWeakSourceByName(scene), window,
GetWeakTransitionByName(transition), fullscreen, focus);
obs_data_release(array_obj);
}
obs_data_array_release(windowTitleArray);
switcher->ignoreWindowsSwitches.clear();
obs_data_array_t *ignoreWindowsArray =
obs_data_get_array(obj, "ignoreWindows");
count = obs_data_array_count(ignoreWindowsArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(ignoreWindowsArray, i);
const char *window =
obs_data_get_string(array_obj, "ignoreWindow");
switcher->ignoreWindowsSwitches.emplace_back(window);
obs_data_release(array_obj);
}
obs_data_array_release(ignoreWindowsArray);
}
void SceneSwitcher::setupTitleTab()
{
populateSceneSelection(ui->scenes, false);
populateTransitionSelection(ui->transitions);
populateWindowSelection(ui->windows);
populateWindowSelection(ui->ignoreWindowsWindows);
for (auto &s : switcher->windowSwitches) {
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeSwitchName(sceneName.c_str(),
s.window.c_str(),
transitionName.c_str(),
s.fullscreen, s.focus);
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, s.window.c_str());
}
for (auto &window : switcher->ignoreWindowsSwitches) {
QString text = QString::fromStdString(window);
QListWidgetItem *item =
new QListWidgetItem(text, ui->ignoreWindows);
item->setData(Qt::UserRole, text);
}
}