Compare commits

...

64 Commits
1.6 ... 1.6.1

Author SHA1 Message Date
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
24 changed files with 3238 additions and 2503 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

@@ -70,9 +70,9 @@ jobs:
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }} 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-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 @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/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/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/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/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/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_DATE=$(date +%Y-%m-%d)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
echo "::set-env name=FILE_NAME::${FILE_NAME}" echo "::set-env name=FILE_NAME::${FILE_NAME}"

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
{ {
ui->setupUi(this); ui->setupUi(this);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->Prune(); switcher->Prune();
@@ -64,8 +64,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{ {
QComboBox *combo = reinterpret_cast<QComboBox *>(data); QComboBox *combo = reinterpret_cast<QComboBox *>(data);
if (obs_source_media_get_state(source) != if (strcmp(obs_source_get_id(source), "ffmpeg_source") == 0) {
OBS_MEDIA_STATE_NONE) {
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
combo->addItem(name); combo->addItem(name);
} }
@@ -129,10 +128,11 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
GetWeakSourceName(switcher->nonMatchingScene).c_str()); GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->checkInterval->setValue(switcher->interval); ui->checkInterval->setValue(switcher->interval);
vector<string> windows; std::vector<std::string> windows;
GetWindowList(windows); GetWindowList(windows);
sort(windows.begin(), windows.end());
for (string &window : windows) { for (std::string &window : windows) {
ui->windows->addItem(window.c_str()); ui->windows->addItem(window.c_str());
ui->ignoreWindowsWindows->addItem(window.c_str()); ui->ignoreWindowsWindows->addItem(window.c_str());
ui->pauseWindowsWindows->addItem(window.c_str()); ui->pauseWindowsWindows->addItem(window.c_str());
@@ -145,8 +145,8 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->executable->addItem(process); ui->executable->addItem(process);
for (auto &s : switcher->executableSwitches) { for (auto &s : switcher->executableSwitches) {
string sceneName = GetWeakSourceName(s.mScene); std::string sceneName = GetWeakSourceName(s.mScene);
string transitionName = GetWeakSourceName(s.mTransition); std::string transitionName = GetWeakSourceName(s.mTransition);
QString text = MakeSwitchNameExecutable(sceneName.c_str(), QString text = MakeSwitchNameExecutable(sceneName.c_str(),
s.mExe, s.mExe,
transitionName.c_str(), transitionName.c_str(),
@@ -158,19 +158,20 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
} }
for (auto &s : switcher->windowSwitches) { for (auto &s : switcher->windowSwitches) {
string sceneName = GetWeakSourceName(s.scene); std::string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString text = QString text = MakeSwitchName(sceneName.c_str(),
MakeSwitchName(sceneName.c_str(), s.window.c_str(), s.window.c_str(),
transitionName.c_str(), s.fullscreen); transitionName.c_str(),
s.fullscreen, s.focus);
QListWidgetItem *item = new QListWidgetItem(text, ui->switches); QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, s.window.c_str()); item->setData(Qt::UserRole, s.window.c_str());
} }
for (auto &s : switcher->screenRegionSwitches) { for (auto &s : switcher->screenRegionSwitches) {
string sceneName = GetWeakSourceName(s.scene); std::string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeScreenRegionSwitchName( QString text = MakeScreenRegionSwitchName(
sceneName.c_str(), transitionName.c_str(), s.minX, sceneName.c_str(), transitionName.c_str(), s.minX,
s.minY, s.maxX, s.maxY); s.minY, s.maxX, s.maxY);
@@ -191,7 +192,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
} }
for (auto &scene : switcher->pauseScenesSwitches) { for (auto &scene : switcher->pauseScenesSwitches) {
string sceneName = GetWeakSourceName(scene); std::string sceneName = GetWeakSourceName(scene);
QString text = QString::fromStdString(sceneName); QString text = QString::fromStdString(sceneName);
QListWidgetItem *item = QListWidgetItem *item =
@@ -217,11 +218,11 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
int smallestDelay = switcher->interval; int smallestDelay = switcher->interval;
for (auto &s : switcher->sceneRoundTripSwitches) { for (auto &s : switcher->sceneRoundTripSwitches) {
string sceneName1 = GetWeakSourceName(s.scene1); std::string sceneName1 = GetWeakSourceName(s.scene1);
string sceneName2 = (s.usePreviousScene) std::string sceneName2 = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME ? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene2); : GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeSceneRoundTripSwitchName( QString text = MakeSceneRoundTripSwitchName(
sceneName1.c_str(), sceneName2.c_str(), sceneName1.c_str(), sceneName2.c_str(),
transitionName.c_str(), (double)s.delay / 1000); transitionName.c_str(), (double)s.delay / 1000);
@@ -238,9 +239,9 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
: ui->intervalWarning->setVisible(false); : ui->intervalWarning->setVisible(false);
for (auto &s : switcher->sceneTransitions) { for (auto &s : switcher->sceneTransitions) {
string sceneName1 = GetWeakSourceName(s.scene1); std::string sceneName1 = GetWeakSourceName(s.scene1);
string sceneName2 = GetWeakSourceName(s.scene2); std::string sceneName2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeSceneTransitionName(sceneName1.c_str(), QString text = MakeSceneTransitionName(sceneName1.c_str(),
sceneName2.c_str(), sceneName2.c_str(),
transitionName.c_str()); transitionName.c_str());
@@ -252,8 +253,8 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
//(transitionDurationLongerThanInterval(switcher->interval)) ? ui->transitionWarning->setVisible(true) : ui->transitionWarning->setVisible(false); //(transitionDurationLongerThanInterval(switcher->interval)) ? ui->transitionWarning->setVisible(true) : ui->transitionWarning->setVisible(false);
for (auto &s : switcher->defaultSceneTransitions) { for (auto &s : switcher->defaultSceneTransitions) {
string sceneName = GetWeakSourceName(s.scene); std::string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeDefaultSceneTransitionName( QString text = MakeDefaultSceneTransitionName(
sceneName.c_str(), transitionName.c_str()); sceneName.c_str(), transitionName.c_str());
@@ -271,8 +272,8 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
} }
for (auto &s : switcher->randomSwitches) { for (auto &s : switcher->randomSwitches) {
string sceneName = GetWeakSourceName(s.scene); std::string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString text = MakeRandomSwitchName( QString text = MakeRandomSwitchName(
sceneName.c_str(), transitionName.c_str(), s.delay); sceneName.c_str(), transitionName.c_str(), s.delay);
@@ -282,8 +283,8 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
} }
for (auto &s : switcher->fileSwitches) { for (auto &s : switcher->fileSwitches) {
string sceneName = GetWeakSourceName(s.scene); std::string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeFileSwitchName( QString listText = MakeFileSwitchName(
sceneName.c_str(), transitionName.c_str(), sceneName.c_str(), transitionName.c_str(),
s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime); s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime);
@@ -294,11 +295,11 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
} }
for (auto &s : switcher->mediaSwitches) { for (auto &s : switcher->mediaSwitches) {
string sourceName = GetWeakSourceName(s.source); std::string sourceName = GetWeakSourceName(s.source);
string sceneName = (s.usePreviousScene) std::string sceneName = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME ? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene); : GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeMediaSwitchName( QString listText = MakeMediaSwitchName(
sourceName.c_str(), sceneName.c_str(), sourceName.c_str(), sceneName.c_str(),
transitionName.c_str(), s.state, s.restriction, s.time); transitionName.c_str(), s.state, s.restriction, s.time);
@@ -309,10 +310,10 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
} }
for (auto &s : switcher->timeSwitches) { for (auto &s : switcher->timeSwitches) {
string sceneName = (s.usePreviousScene) std::string sceneName = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME ? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene); : GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeTimeSwitchName( QString listText = MakeTimeSwitchName(
sceneName.c_str(), transitionName.c_str(), s.time); sceneName.c_str(), transitionName.c_str(), s.time);
@@ -354,7 +355,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->readPathLineEdit->setDisabled(true); ui->readPathLineEdit->setDisabled(true);
} }
if (switcher->th.joinable()) if (switcher->th && switcher->th->isRunning())
SetStarted(); SetStarted();
else else
SetStopped(); SetStopped();
@@ -368,7 +369,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
screenRegionTimer->start(1000); screenRegionTimer->start(1000);
for (int p : switcher->functionNamesByPriority) { for (int p : switcher->functionNamesByPriority) {
string s = ""; std::string s = "";
switch (p) { switch (p) {
case READ_FILE_FUNC: case READ_FILE_FUNC:
s = "File Content"; s = "File Content";
@@ -401,8 +402,17 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
item->setData(Qt::UserRole, text); item->setData(Qt::UserRole, text);
} }
for (std::string p : switcher->threadPrioritiesNamesOrderdByPrio) { for (int i = 0; i < switcher->threadPriorities.size(); ++i) {
ui->threadPriority->addItem(p.c_str()); 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());
}
} }
} }
@@ -412,9 +422,9 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{ {
if (saving) { if (saving) {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
obs_data_t *obj = obs_data_create(); obs_data_t *obj = obs_data_create();
obs_data_array_t *array = obs_data_array_create(); obs_data_array_t *windowTitleArray = obs_data_array_create();
obs_data_array_t *screenRegionArray = obs_data_array_create(); obs_data_array_t *screenRegionArray = obs_data_array_create();
obs_data_array_t *pauseScenesArray = obs_data_array_create(); obs_data_array_t *pauseScenesArray = obs_data_array_create();
obs_data_array_t *pauseWindowsArray = obs_data_array_create(); obs_data_array_t *pauseWindowsArray = obs_data_array_create();
@@ -454,7 +464,9 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
s.window.c_str()); s.window.c_str());
obs_data_set_bool(array_obj, "fullscreen", obs_data_set_bool(array_obj, "fullscreen",
s.fullscreen); s.fullscreen);
obs_data_array_push_back(array, array_obj); obs_data_set_bool(array_obj, "focus", s.focus);
obs_data_array_push_back(windowTitleArray,
array_obj);
obs_source_release(source); obs_source_release(source);
obs_source_release(transition); obs_source_release(transition);
} }
@@ -511,7 +523,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(array_obj); obs_data_release(array_obj);
} }
for (string &window : switcher->pauseWindowsSwitches) { for (std::string &window : switcher->pauseWindowsSwitches) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "pauseWindow", obs_data_set_string(array_obj, "pauseWindow",
window.c_str()); window.c_str());
@@ -519,7 +531,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(array_obj); obs_data_release(array_obj);
} }
for (string &window : switcher->ignoreWindowsSwitches) { for (std::string &window : switcher->ignoreWindowsSwitches) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "ignoreWindow", obs_data_set_string(array_obj, "ignoreWindow",
window.c_str()); window.c_str());
@@ -699,7 +711,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(array_obj); obs_data_release(array_obj);
} }
for (string &window : switcher->ignoreIdleWindows) { for (std::string &window : switcher->ignoreIdleWindows) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "window", obs_data_set_string(array_obj, "window",
window.c_str()); window.c_str());
@@ -808,7 +820,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(array_obj); obs_data_release(array_obj);
} }
string nonMatchingSceneName = std::string nonMatchingSceneName =
GetWeakSourceName(switcher->nonMatchingScene); GetWeakSourceName(switcher->nonMatchingScene);
obs_data_set_int(obj, "interval", switcher->interval); obs_data_set_int(obj, "interval", switcher->interval);
@@ -818,7 +830,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
switcher->switchIfNotMatching); switcher->switchIfNotMatching);
obs_data_set_bool(obj, "active", !switcher->stop); obs_data_set_bool(obj, "active", !switcher->stop);
obs_data_set_array(obj, "switches", array); obs_data_set_array(obj, "switches", windowTitleArray);
obs_data_set_array(obj, "screenRegion", screenRegionArray); obs_data_set_array(obj, "screenRegion", screenRegionArray);
obs_data_set_array(obj, "pauseScenes", pauseScenesArray); obs_data_set_array(obj, "pauseScenes", pauseScenesArray);
obs_data_set_array(obj, "pauseWindows", pauseWindowsArray); obs_data_set_array(obj, "pauseWindows", pauseWindowsArray);
@@ -836,16 +848,16 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_array(obj, "mediaSwitches", mediaArray); obs_data_set_array(obj, "mediaSwitches", mediaArray);
obs_data_set_array(obj, "timeSwitches", timeArray); obs_data_set_array(obj, "timeSwitches", timeArray);
string autoStopSceneName = std::string autoStopSceneName =
GetWeakSourceName(switcher->autoStopScene); GetWeakSourceName(switcher->autoStopScene);
obs_data_set_bool(obj, "autoStopEnable", obs_data_set_bool(obj, "autoStopEnable",
switcher->autoStopEnable); switcher->autoStopEnable);
obs_data_set_string(obj, "autoStopSceneName", obs_data_set_string(obj, "autoStopSceneName",
autoStopSceneName.c_str()); autoStopSceneName.c_str());
string idleSceneName = std::string idleSceneName =
GetWeakSourceName(switcher->idleData.scene); GetWeakSourceName(switcher->idleData.scene);
string idleTransitionName = std::string idleTransitionName =
GetWeakSourceName(switcher->idleData.transition); GetWeakSourceName(switcher->idleData.transition);
obs_data_set_bool(obj, "idleEnable", obs_data_set_bool(obj, "idleEnable",
switcher->idleData.idleEnable); switcher->idleData.idleEnable);
@@ -883,9 +895,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_int(obj, "priority7", obs_data_set_int(obj, "priority7",
switcher->functionNamesByPriority[7]); switcher->functionNamesByPriority[7]);
obs_data_set_int(obj, "threadPriority",
switcher->threadPriority);
obs_data_set_obj(save_data, "advanced-scene-switcher", obj); obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
obs_data_array_release(array); obs_data_array_release(windowTitleArray);
obs_data_array_release(screenRegionArray); obs_data_array_release(screenRegionArray);
obs_data_array_release(pauseScenesArray); obs_data_array_release(pauseScenesArray);
obs_data_array_release(pauseWindowsArray); obs_data_array_release(pauseWindowsArray);
@@ -906,7 +921,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_t *obj = obs_data_t *obj =
obs_data_get_obj(save_data, "advanced-scene-switcher"); obs_data_get_obj(save_data, "advanced-scene-switcher");
obs_data_array_t *array = obs_data_get_array(obj, "switches"); obs_data_array_t *windowTitleArray =
obs_data_get_array(obj, "switches");
obs_data_array_t *screenRegionArray = obs_data_array_t *screenRegionArray =
obs_data_get_array(obj, "screenRegion"); obs_data_get_array(obj, "screenRegion");
obs_data_array_t *pauseScenesArray = obs_data_array_t *pauseScenesArray =
@@ -944,7 +960,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
NO_SWITCH); NO_SWITCH);
switcher->switchIfNotMatching = (NoMatch)obs_data_get_int( switcher->switchIfNotMatching = (NoMatch)obs_data_get_int(
obj, "switch_if_not_matching"); obj, "switch_if_not_matching");
string nonMatchingScene = std::string nonMatchingScene =
obs_data_get_string(obj, "non_matching_scene"); obs_data_get_string(obj, "non_matching_scene");
bool active = obs_data_get_bool(obj, "active"); bool active = obs_data_get_bool(obj, "active");
@@ -952,10 +968,11 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
GetWeakSourceByName(nonMatchingScene.c_str()); GetWeakSourceByName(nonMatchingScene.c_str());
switcher->windowSwitches.clear(); switcher->windowSwitches.clear();
size_t count = obs_data_array_count(array); size_t count = obs_data_array_count(windowTitleArray);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(array, i); obs_data_t *array_obj =
obs_data_array_item(windowTitleArray, i);
const char *scene = const char *scene =
obs_data_get_string(array_obj, "scene"); obs_data_get_string(array_obj, "scene");
@@ -965,11 +982,14 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_get_string(array_obj, "window_title"); obs_data_get_string(array_obj, "window_title");
bool fullscreen = bool fullscreen =
obs_data_get_bool(array_obj, "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( switcher->windowSwitches.emplace_back(
GetWeakSourceByName(scene), window, GetWeakSourceByName(scene), window,
GetWeakTransitionByName(transition), GetWeakTransitionByName(transition), fullscreen,
fullscreen); focus);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -989,7 +1009,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
int minY = obs_data_get_int(array_obj, "minY"); int minY = obs_data_get_int(array_obj, "minY");
int maxX = obs_data_get_int(array_obj, "maxX"); int maxX = obs_data_get_int(array_obj, "maxX");
int maxY = obs_data_get_int(array_obj, "maxY"); int maxY = obs_data_get_int(array_obj, "maxY");
string regionStr = obs_data_get_string( std::string regionStr = obs_data_get_string(
array_obj, "screenRegionStr"); array_obj, "screenRegionStr");
switcher->screenRegionSwitches.emplace_back( switcher->screenRegionSwitches.emplace_back(
@@ -1068,11 +1088,11 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_get_int( obs_data_get_int(
array_obj, array_obj,
"sceneRoundTripDelayMs"); //to be compatible with older versions "sceneRoundTripDelayMs"); //to be compatible with older versions
string str = MakeSceneRoundTripSwitchName( std::string str = MakeSceneRoundTripSwitchName(
scene1, scene2, transition, scene1, scene2, transition,
((double)delay) / 1000.0) ((double)delay) / 1000.0)
.toUtf8() .toUtf8()
.constData(); .constData();
const char *sceneRoundTripStr = str.c_str(); const char *sceneRoundTripStr = str.c_str();
switcher->sceneRoundTripSwitches.emplace_back( switcher->sceneRoundTripSwitches.emplace_back(
@@ -1240,12 +1260,19 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
array_obj, "restriction"); array_obj, "restriction");
uint64_t time = obs_data_get_int(array_obj, "time"); 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( switcher->mediaSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakSourceByName(source), GetWeakSourceByName(source),
GetWeakTransitionByName(transition), state, GetWeakTransitionByName(transition), state,
restriction, time, restriction, time,
(strcmp(scene, PREVIOUS_SCENE_NAME) == 0)); (strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
mediaStr);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -1264,7 +1291,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
QTime time = QTime::fromString( QTime time = QTime::fromString(
obs_data_get_string(array_obj, "time")); obs_data_get_string(array_obj, "time"));
string timeSwitchStr = std::string timeSwitchStr =
MakeTimeSwitchName(scene, transition, time) MakeTimeSwitchName(scene, transition, time)
.toUtf8() .toUtf8()
.constData(); .constData();
@@ -1278,16 +1305,16 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(array_obj); obs_data_release(array_obj);
} }
string autoStopScene = std::string autoStopScene =
obs_data_get_string(obj, "autoStopSceneName"); obs_data_get_string(obj, "autoStopSceneName");
switcher->autoStopEnable = switcher->autoStopEnable =
obs_data_get_bool(obj, "autoStopEnable"); obs_data_get_bool(obj, "autoStopEnable");
switcher->autoStopScene = switcher->autoStopScene =
GetWeakSourceByName(autoStopScene.c_str()); GetWeakSourceByName(autoStopScene.c_str());
string idleSceneName = std::string idleSceneName =
obs_data_get_string(obj, "idleSceneName"); obs_data_get_string(obj, "idleSceneName");
string idleTransitionName = std::string idleTransitionName =
obs_data_get_string(obj, "idleTransitionName"); obs_data_get_string(obj, "idleTransitionName");
switcher->idleData.scene = switcher->idleData.scene =
GetWeakSourceByName(idleSceneName.c_str()); GetWeakSourceByName(idleSceneName.c_str());
@@ -1356,7 +1383,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
(DEFAULT_PRIORITY_7); (DEFAULT_PRIORITY_7);
} }
obs_data_array_release(array); obs_data_set_default_int(obj, "threadPriority",
QThread::NormalPriority);
switcher->threadPriority =
obs_data_get_int(obj, "threadPriority");
obs_data_array_release(windowTitleArray);
obs_data_array_release(screenRegionArray); obs_data_array_release(screenRegionArray);
obs_data_array_release(pauseScenesArray); obs_data_array_release(pauseScenesArray);
obs_data_array_release(ignoreWindowsArray); obs_data_array_release(ignoreWindowsArray);
@@ -1386,22 +1418,23 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
********************************************************************************/ ********************************************************************************/
void SwitcherData::Thread() void SwitcherData::Thread()
{ {
blog(LOG_INFO, "Advanced Scene Switcher started");
//to avoid scene duplication when rapidly switching scene collection //to avoid scene duplication when rapidly switching scene collection
this_thread::sleep_for(chrono::seconds(2)); std::this_thread::sleep_for(std::chrono::seconds(2));
int sleep = 0; int sleep = 0;
while (true) { while (true) {
startLoop: startLoop:
unique_lock<mutex> lock(m); std::unique_lock<std::mutex> lock(m);
bool match = false; bool match = false;
OBSWeakSource scene; OBSWeakSource scene;
OBSWeakSource transition; OBSWeakSource transition;
chrono::milliseconds duration; std::chrono::milliseconds duration;
if (sleep > interval) if (sleep > interval)
duration = chrono::milliseconds(sleep); duration = std::chrono::milliseconds(sleep);
else else
duration = chrono::milliseconds(interval); duration = std::chrono::milliseconds(interval);
sleep = 0; sleep = 0;
switcher->Prune(); switcher->Prune();
writeSceneInfoToFile(); writeSceneInfoToFile();
@@ -1477,11 +1510,12 @@ void SwitcherData::Thread()
switchScene(scene, transition, lock); switchScene(scene, transition, lock);
} }
} }
endLoop:; endLoop:
blog(LOG_INFO, "Advanced Scene Switcher stopped");
} }
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition, void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
unique_lock<mutex> &lock) std::unique_lock<std::mutex> &lock)
{ {
obs_source_t *source = obs_weak_source_get_source(scene); obs_source_t *source = obs_weak_source_get_source(scene);
obs_source_t *currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
@@ -1536,19 +1570,23 @@ bool SwitcherData::sceneChangedDuringWait()
void SwitcherData::Start() void SwitcherData::Start()
{ {
if (!th.joinable()) { if (!(th && th->isRunning())) {
stop = false; stop = false;
switcher->th = thread([]() { switcher->Thread(); }); switcher->th = new SwitcherThread();
switcher->th->start(
(QThread::Priority)switcher->threadPriority);
} }
} }
void SwitcherData::Stop() void SwitcherData::Stop()
{ {
if (th.joinable()) { if (th && th->isRunning()) {
switcher->stop = true; switcher->stop = true;
transitionCv.notify_one(); transitionCv.notify_one();
cv.notify_one(); cv.notify_one();
th.join(); th->wait();
delete th;
th = nullptr;
} }
} }
@@ -1570,7 +1608,7 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
case OBS_FRONTEND_EVENT_SCENE_CHANGED: { case OBS_FRONTEND_EVENT_SCENE_CHANGED: {
SwitcherData *s = (SwitcherData *)switcher; SwitcherData *s = (SwitcherData *)switcher;
lock_guard<mutex> lock(s->m); std::lock_guard<std::mutex> lock(s->m);
//stop waiting if scene was manually changed //stop waiting if scene was manually changed
if (s->sceneChangedDuringWait()) if (s->sceneChangedDuringWait())
s->cv.notify_one(); s->cv.notify_one();

View File

@@ -1,12 +1,11 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
int SceneSwitcher::executableFindByData(const QString& exe) int SceneSwitcher::executableFindByData(const QString &exe)
{ {
int count = ui->executables->count(); int count = ui->executables->count();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->executables->item(i);
QListWidgetItem* item = ui->executables->item(i);
QString itemExe = item->data(Qt::UserRole).toString(); QString itemExe = item->data(Qt::UserRole).toString();
if (itemExe == exe) if (itemExe == exe)
@@ -16,7 +15,6 @@ int SceneSwitcher::executableFindByData(const QString& exe)
return -1; return -1;
} }
void SceneSwitcher::on_executables_currentRowChanged(int idx) void SceneSwitcher::on_executables_currentRowChanged(int idx)
{ {
if (loading) if (loading)
@@ -24,26 +22,55 @@ void SceneSwitcher::on_executables_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->executables->item(idx); QListWidgetItem *item = ui->executables->item(idx);
QString exec = item->data(Qt::UserRole).toString(); QString exec = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches) for (auto &s : switcher->executableSwitches) {
{ if (exec.compare(s.mExe) == 0) {
if (exec.compare(s.mExe) == 0)
{
QString sceneName = GetWeakSourceName(s.mScene).c_str(); 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->executableScenes->setCurrentText(sceneName);
ui->executable->setCurrentText(exec); ui->executable->setCurrentText(exec);
ui->executableTransitions->setCurrentText(transitionName); ui->executableTransitions->setCurrentText(
transitionName);
ui->requiresFocusCheckBox->setChecked(s.mInFocus); ui->requiresFocusCheckBox->setChecked(s.mInFocus);
break; 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() void SceneSwitcher::on_executableAdd_clicked()
{ {
@@ -59,30 +86,28 @@ void SceneSwitcher::on_executableAdd_clicked()
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(exeName); QVariant v = QVariant::fromValue(exeName);
QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus); QString text = MakeSwitchNameExecutable(sceneName, exeName,
transitionName, inFocus);
int idx = executableFindByData(exeName); int idx = executableFindByData(exeName);
if (idx == -1) if (idx == -1) {
{ std::lock_guard<std::mutex> lock(switcher->m);
lock_guard<mutex> lock(switcher->m);
switcher->executableSwitches.emplace_back( 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); item->setData(Qt::UserRole, v);
} } else {
else QListWidgetItem *item = ui->executables->item(idx);
{
QListWidgetItem* item = ui->executables->item(idx);
item->setText(text); item->setText(text);
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches) for (auto &s : switcher->executableSwitches) {
{ if (s.mExe == exeName) {
if (s.mExe == exeName)
{
s.mScene = source; s.mScene = source;
s.mTransition = transition; s.mTransition = transition;
s.mInFocus = inFocus; s.mInFocus = inFocus;
@@ -90,30 +115,25 @@ void SceneSwitcher::on_executableAdd_clicked()
} }
} }
} }
ui->executables->sortItems();
} }
} }
void SceneSwitcher::on_executableRemove_clicked() void SceneSwitcher::on_executableRemove_clicked()
{ {
QListWidgetItem* item = ui->executables->currentItem(); QListWidgetItem *item = ui->executables->currentItem();
if (!item) if (!item)
return; return;
QString exe = item->data(Qt::UserRole).toString(); QString exe = item->data(Qt::UserRole).toString();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->executableSwitches; auto &switches = switcher->executableSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.mExe == exe) if (s.mExe == exe) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -123,17 +143,52 @@ void SceneSwitcher::on_executableRemove_clicked()
delete item; 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; 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); GetProcessList(runningProcesses);
for (ExecutableSceneSwitch& s : executableSwitches) for (ExecutableSceneSwitch &s : executableSwitches) {
{ // True if executable switch is running (direct)
if (runningProcesses.contains(s.mExe)) 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; scene = s.mScene;
transition = s.mTransition; transition = s.mTransition;
match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe));
break; break;
} }
} }

View File

@@ -4,12 +4,11 @@
#include <obs.hpp> #include <obs.hpp>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
void SceneSwitcher::on_browseButton_clicked() void SceneSwitcher::on_browseButton_clicked()
{ {
QString path = QFileDialog::getOpenFileName( 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()) if (!path.isEmpty())
ui->writePathLineEdit->setText(path); ui->writePathLineEdit->setText(path);
} }
@@ -19,29 +18,25 @@ void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
if (!state) if (!state) {
{
ui->browseButton_2->setDisabled(true); ui->browseButton_2->setDisabled(true);
ui->readPathLineEdit->setDisabled(true); ui->readPathLineEdit->setDisabled(true);
switcher->fileIO.readEnabled = false; switcher->fileIO.readEnabled = false;
} } else {
else
{
ui->browseButton_2->setDisabled(false); ui->browseButton_2->setDisabled(false);
ui->readPathLineEdit->setDisabled(false); ui->readPathLineEdit->setDisabled(false);
switcher->fileIO.readEnabled = true; switcher->fileIO.readEnabled = true;
} }
} }
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text) void SceneSwitcher::on_readPathLineEdit_textChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
if (text.isEmpty()) if (text.isEmpty()) {
{
switcher->fileIO.readEnabled = false; switcher->fileIO.readEnabled = false;
return; return;
} }
@@ -49,14 +44,13 @@ void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
switcher->fileIO.readPath = text.toUtf8().constData(); switcher->fileIO.readPath = text.toUtf8().constData();
} }
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text) void SceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
if (text.isEmpty()) if (text.isEmpty()) {
{
switcher->fileIO.writeEnabled = false; switcher->fileIO.writeEnabled = false;
return; return;
} }
@@ -67,7 +61,8 @@ void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
void SceneSwitcher::on_browseButton_2_clicked() void SceneSwitcher::on_browseButton_2_clicked()
{ {
QString path = QFileDialog::getOpenFileName( 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()) if (!path.isEmpty())
ui->readPathLineEdit->setText(path); ui->readPathLineEdit->setText(path);
} }
@@ -77,31 +72,32 @@ void SwitcherData::writeSceneInfoToFile()
if (!fileIO.writeEnabled || fileIO.writePath.empty()) if (!fileIO.writeEnabled || fileIO.writePath.empty())
return; 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)); QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::WriteOnly)) if (file.open(QIODevice::WriteOnly)) {
{ const char *msg = obs_source_get_name(currentSource);
const char* msg = obs_source_get_name(currentSource);
file.write(msg, qstrlen(msg)); file.write(msg, qstrlen(msg));
file.close(); file.close();
} }
obs_source_release(currentSource); 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()) if (!fileIO.readEnabled || fileIO.readPath.empty())
return; return;
QFile file(QString::fromStdString(fileIO.readPath)); QFile file(QString::fromStdString(fileIO.readPath));
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly)) {
{
QTextStream in(&file); QTextStream in(&file);
QString sceneStr = in.readLine(); QString sceneStr = in.readLine();
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData()); obs_source_t *sceneRead =
if (sceneRead){ obs_get_source_by_name(sceneStr.toUtf8().constData());
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead); if (sceneRead) {
obs_weak_source_t *sceneReadWs =
obs_source_get_weak_source(sceneRead);
match = true; match = true;
scene = sceneReadWs; scene = sceneReadWs;
@@ -114,32 +110,28 @@ void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OB
} }
} }
void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition) void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{ {
for (FileSwitch& s : fileSwitches) for (FileSwitch &s : fileSwitches) {
{
bool equal = false; bool equal = false;
QString t = QString::fromStdString(s.text); QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file)); QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly)) if (!file.open(QIODevice::ReadOnly))
continue; continue;
if (s.useTime) if (s.useTime) {
{
QDateTime newLastMod = QFileInfo(file).lastModified(); QDateTime newLastMod = QFileInfo(file).lastModified();
if (s.lastMod == newLastMod) if (s.lastMod == newLastMod)
continue; continue;
s.lastMod = newLastMod; s.lastMod = newLastMod;
} }
if (s.useRegex) if (s.useRegex) {
{
QTextStream in(&file); QTextStream in(&file);
QRegExp rx(t); QRegExp rx(t);
equal = rx.exactMatch(in.readAll()); equal = rx.exactMatch(in.readAll());
} } else {
else
{
/*Im using QTextStream here so the conversion between different lineendings is done by QT. /*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, *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. *but the files selected by the user might use different line endings.
@@ -147,24 +139,21 @@ void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSo
*/ */
QTextStream in(&file); QTextStream in(&file);
QTextStream text(&t); QTextStream text(&t);
while (!in.atEnd() && !text.atEnd()) while (!in.atEnd() && !text.atEnd()) {
{
QString fileLine = in.readLine(); QString fileLine = in.readLine();
QString textLine = text.readLine(); QString textLine = text.readLine();
if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0) if (QString::compare(fileLine, textLine,
{ Qt::CaseSensitive) != 0) {
equal = false; equal = false;
break; break;
} } else {
else {
equal = true; equal = true;
} }
} }
} }
file.close(); file.close();
if (equal) if (equal) {
{
scene = s.scene; scene = s.scene;
transition = s.transition; transition = s.transition;
match = true; match = true;
@@ -177,7 +166,8 @@ void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSo
void SceneSwitcher::on_browseButton_3_clicked() void SceneSwitcher::on_browseButton_3_clicked()
{ {
QString path = QFileDialog::getOpenFileName( 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()) if (!path.isEmpty())
ui->filePathLineEdit->setText(path); ui->filePathLineEdit->setText(path);
} }
@@ -191,28 +181,31 @@ void SceneSwitcher::on_fileAdd_clicked()
bool useRegex = ui->fileContentRegExCheckBox->isChecked(); bool useRegex = ui->fileContentRegExCheckBox->isChecked();
bool useTime = ui->fileContentTimeCheckBox->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; return;
OBSWeakSource source = GetWeakSourceByQString(sceneName); OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); 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); QVariant v = QVariant::fromValue(switchText);
QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList); new QListWidgetItem(switchText, ui->fileScenesList);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back( switcher->fileSwitches.emplace_back(source, transition,
source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime); fileName.toUtf8().constData(),
text.toUtf8().constData(), useRegex,
useTime);
} }
void SceneSwitcher::on_fileRemove_clicked() void SceneSwitcher::on_fileRemove_clicked()
{ {
QListWidgetItem* item = ui->fileScenesList->currentItem(); QListWidgetItem *item = ui->fileScenesList->currentItem();
if (!item) if (!item)
return; return;
@@ -221,9 +214,9 @@ void SceneSwitcher::on_fileRemove_clicked()
return; 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); switches.erase(switches.begin() + idx);
} }
qDeleteAll(ui->fileScenesList->selectedItems()); qDeleteAll(ui->fileScenesList->selectedItems());
@@ -236,14 +229,14 @@ void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
if (switcher->fileSwitches.size() <= idx) if (switcher->fileSwitches.size() <= idx)
return; return;
FileSwitch s = switcher->fileSwitches[idx]; FileSwitch s = switcher->fileSwitches[idx];
string sceneName = GetWeakSourceName(s.scene); std::string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition); std::string transitionName = GetWeakSourceName(s.transition);
ui->fileScenes->setCurrentText(sceneName.c_str()); ui->fileScenes->setCurrentText(sceneName.c_str());
ui->fileTransitions->setCurrentText(transitionName.c_str()); ui->fileTransitions->setCurrentText(transitionName.c_str());

View File

@@ -11,14 +11,14 @@ void SceneSwitcher::on_startAtLaunch_toggled(bool value)
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->startAtLaunch = value; switcher->startAtLaunch = value;
} }
void SceneSwitcher::UpdateNonMatchingScene(const QString& name) void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
{ {
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws; switcher->nonMatchingScene = ws;
@@ -31,7 +31,7 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NO_SWITCH; switcher->switchIfNotMatching = NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false); ui->noMatchSwitchScene->setEnabled(false);
} }
@@ -41,7 +41,7 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = SWITCH; switcher->switchIfNotMatching = SWITCH;
ui->noMatchSwitchScene->setEnabled(true); ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText()); UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
@@ -52,17 +52,17 @@ void SceneSwitcher::on_noMatchRandomSwitch_clicked()
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = RANDOM_SWITCH; switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false); ui->noMatchSwitchScene->setEnabled(false);
} }
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text) void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
UpdateNonMatchingScene(text); UpdateNonMatchingScene(text);
} }
@@ -71,7 +71,7 @@ void SceneSwitcher::on_checkInterval_valueChanged(int value)
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->interval = value; switcher->interval = value;
} }
@@ -89,19 +89,16 @@ void SceneSwitcher::SetStopped()
void SceneSwitcher::on_toggleStartButton_clicked() void SceneSwitcher::on_toggleStartButton_clicked()
{ {
if (switcher->th.joinable()) if (switcher->th && switcher->th->isRunning()) {
{
switcher->Stop(); switcher->Stop();
SetStopped(); SetStopped();
} } else {
else
{
switcher->Start(); switcher->Start();
SetStarted(); SetStarted();
} }
} }
void SceneSwitcher::closeEvent(QCloseEvent*) void SceneSwitcher::closeEvent(QCloseEvent *)
{ {
obs_frontend_save(); obs_frontend_save();
} }

View File

@@ -51,6 +51,8 @@ public:
public slots: public slots:
void on_switches_currentRowChanged(int idx); void on_switches_currentRowChanged(int idx);
void on_up_clicked();
void on_down_clicked();
void on_add_clicked(); void on_add_clicked();
void on_remove_clicked(); void on_remove_clicked();
void on_noMatchDontSwitch_clicked(); void on_noMatchDontSwitch_clicked();
@@ -99,6 +101,8 @@ public slots:
void on_writePathLineEdit_textChanged(const QString &text); void on_writePathLineEdit_textChanged(const QString &text);
void on_browseButton_2_clicked(); void on_browseButton_2_clicked();
void on_executableUp_clicked();
void on_executableDown_clicked();
void on_executableAdd_clicked(); void on_executableAdd_clicked();
void on_executableRemove_clicked(); void on_executableRemove_clicked();
void on_executables_currentRowChanged(int idx); void on_executables_currentRowChanged(int idx);
@@ -120,6 +124,7 @@ public slots:
void on_fileScenesList_currentRowChanged(int idx); void on_fileScenesList_currentRowChanged(int idx);
void on_browseButton_3_clicked(); void on_browseButton_3_clicked();
void on_mediaSwitches_currentRowChanged(int idx);
void on_mediaAdd_clicked(); void on_mediaAdd_clicked();
void on_mediaRemove_clicked(); void on_mediaRemove_clicked();
@@ -129,6 +134,7 @@ public slots:
void on_priorityUp_clicked(); void on_priorityUp_clicked();
void on_priorityDown_clicked(); void on_priorityDown_clicked();
void on_threadPriority_currentTextChanged(const QString &text);
void updateScreenRegionCursorPos(); void updateScreenRegionCursorPos();
@@ -139,13 +145,14 @@ public slots:
* Windowtitle helper * Windowtitle helper
********************************************************************************/ ********************************************************************************/
void GetWindowList(std::vector<std::string> &windows); void GetWindowList(std::vector<std::string> &windows);
void GetWindowList(QStringList &windows); // Overloaded
void GetCurrentWindowTitle(std::string &title); void GetCurrentWindowTitle(std::string &title);
bool isFullscreen(); bool isFullscreen(std::string &title);
/******************************************************************************** /********************************************************************************
* Screenregion helper * Screenregion helper
********************************************************************************/ ********************************************************************************/
pair<int, int> getCursorPos(); std::pair<int, int> getCursorPos();
/******************************************************************************** /********************************************************************************
* Idle detection helper * Idle detection helper
@@ -156,7 +163,7 @@ int secondsSinceLastInput();
* Executable helper * Executable helper
********************************************************************************/ ********************************************************************************/
void GetProcessList(QStringList &processes); void GetProcessList(QStringList &processes);
bool isInFocus(const QString &exeToCheck); bool isInFocus(const QString &executable);
/******************************************************************************** /********************************************************************************
* Sceneswitch helper * Sceneswitch helper
@@ -167,7 +174,7 @@ typedef struct obs_weak_source obs_weak_source_t;
obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1, obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
obs_weak_source_t *scene2); obs_weak_source_t *scene2);
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition, void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
unique_lock<mutex> &lock); std::unique_lock<std::mutex> &lock);
/******************************************************************************** /********************************************************************************
* Hotkey helper * Hotkey helper
@@ -183,7 +190,7 @@ void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed); bool pressed);
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id, void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
obs_hotkey_t *hotkey, bool pressed); 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 * Main SwitcherData

View File

@@ -3,7 +3,6 @@
#include <chrono> #include <chrono>
#include <string> #include <string>
#include <vector> #include <vector>
#include <thread>
#include <regex> #include <regex>
#include <mutex> #include <mutex>
#include <fstream> #include <fstream>
@@ -35,23 +34,24 @@
#define DEFAULT_PRIORITY_6 MEDIA_FUNC #define DEFAULT_PRIORITY_6 MEDIA_FUNC
#define DEFAULT_PRIORITY_7 TIME_FUNC #define DEFAULT_PRIORITY_7 TIME_FUNC
using namespace std;
/******************************************************************************** /********************************************************************************
* Data structs for each scene switching method * Data structs for each scene switching method
********************************************************************************/ ********************************************************************************/
struct WindowSceneSwitch { struct WindowSceneSwitch {
OBSWeakSource scene; OBSWeakSource scene;
string window; std::string window;
OBSWeakSource transition; OBSWeakSource transition;
bool fullscreen; bool fullscreen;
bool focus;
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_, inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_,
OBSWeakSource transition_, bool fullscreen_) OBSWeakSource transition_, bool fullscreen_,
bool focus_)
: scene(scene_), : scene(scene_),
window(window_), window(window_),
transition(transition_), transition(transition_),
fullscreen(fullscreen_) fullscreen(fullscreen_),
focus(focus_)
{ {
} }
}; };
@@ -77,12 +77,12 @@ struct ScreenRegionSwitch {
OBSWeakSource scene; OBSWeakSource scene;
OBSWeakSource transition; OBSWeakSource transition;
int minX, minY, maxX, maxY; int minX, minY, maxX, maxY;
string regionStr; std::string regionStr;
inline ScreenRegionSwitch(OBSWeakSource scene_, inline ScreenRegionSwitch(OBSWeakSource scene_,
OBSWeakSource transition_, int minX_, OBSWeakSource transition_, int minX_,
int minY_, int maxX_, int maxY_, int minY_, int maxX_, int maxY_,
string regionStr_) std::string regionStr_)
: scene(scene_), : scene(scene_),
transition(transition_), transition(transition_),
minX(minX_), minX(minX_),
@@ -100,12 +100,12 @@ struct SceneRoundTripSwitch {
OBSWeakSource transition; OBSWeakSource transition;
int delay; int delay;
bool usePreviousScene; bool usePreviousScene;
string sceneRoundTripStr; std::string sceneRoundTripStr;
inline SceneRoundTripSwitch(OBSWeakSource scene1_, inline SceneRoundTripSwitch(OBSWeakSource scene1_,
OBSWeakSource scene2_, OBSWeakSource scene2_,
OBSWeakSource transition_, int delay_, OBSWeakSource transition_, int delay_,
bool usePreviousScene_, string str) bool usePreviousScene_, std::string str)
: scene1(scene1_), : scene1(scene1_),
scene2(scene2_), scene2(scene2_),
transition(transition_), transition(transition_),
@@ -120,10 +120,10 @@ struct RandomSwitch {
OBSWeakSource scene; OBSWeakSource scene;
OBSWeakSource transition; OBSWeakSource transition;
double delay; double delay;
string randomSwitchStr; std::string randomSwitchStr;
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_, inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
double delay_, string str) double delay_, std::string str)
: scene(scene_), : scene(scene_),
transition(transition_), transition(transition_),
delay(delay_), delay(delay_),
@@ -136,11 +136,11 @@ struct SceneTransition {
OBSWeakSource scene1; OBSWeakSource scene1;
OBSWeakSource scene2; OBSWeakSource scene2;
OBSWeakSource transition; OBSWeakSource transition;
string sceneTransitionStr; std::string sceneTransitionStr;
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_,
OBSWeakSource transition_, OBSWeakSource transition_,
string sceneTransitionStr_) std::string sceneTransitionStr_)
: scene1(scene1_), : scene1(scene1_),
scene2(scene2_), scene2(scene2_),
transition(transition_), transition(transition_),
@@ -152,11 +152,11 @@ struct SceneTransition {
struct DefaultSceneTransition { struct DefaultSceneTransition {
OBSWeakSource scene; OBSWeakSource scene;
OBSWeakSource transition; OBSWeakSource transition;
string sceneTransitionStr; std::string sceneTransitionStr;
inline DefaultSceneTransition(OBSWeakSource scene_, inline DefaultSceneTransition(OBSWeakSource scene_,
OBSWeakSource transition_, OBSWeakSource transition_,
string sceneTransitionStr_) std::string sceneTransitionStr_)
: scene(scene_), : scene(scene_),
transition(transition_), transition(transition_),
sceneTransitionStr(sceneTransitionStr_) sceneTransitionStr(sceneTransitionStr_)
@@ -167,8 +167,8 @@ struct DefaultSceneTransition {
struct FileSwitch { struct FileSwitch {
OBSWeakSource scene; OBSWeakSource scene;
OBSWeakSource transition; OBSWeakSource transition;
string file; std::string file;
string text; std::string text;
bool useRegex = false; bool useRegex = false;
bool useTime = false; bool useTime = false;
QDateTime lastMod; QDateTime lastMod;
@@ -189,9 +189,9 @@ struct FileSwitch {
struct FileIOData { struct FileIOData {
bool readEnabled = false; bool readEnabled = false;
string readPath; std::string readPath;
bool writeEnabled = false; bool writeEnabled = false;
string writePath; std::string writePath;
}; };
struct IdleData { struct IdleData {
@@ -212,18 +212,20 @@ struct MediaSwitch {
time_restriction restriction; time_restriction restriction;
bool matched; bool matched;
bool usePreviousScene; bool usePreviousScene;
std::string mediaSwitchStr;
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_, inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
OBSWeakSource transition_, obs_media_state state_, OBSWeakSource transition_, obs_media_state state_,
time_restriction restriction_, uint64_t time_, time_restriction restriction_, uint64_t time_,
bool usePreviousScene_) bool usePreviousScene_, std::string mediaSwitchStr_)
: scene(scene_), : scene(scene_),
source(source_), source(source_),
transition(transition_), transition(transition_),
state(state_), state(state_),
restriction(restriction_), restriction(restriction_),
time(time_), time(time_),
usePreviousScene(usePreviousScene_) usePreviousScene(usePreviousScene_),
mediaSwitchStr(mediaSwitchStr_)
{ {
} }
}; };
@@ -234,11 +236,11 @@ struct TimeSwitch {
QTime time; QTime time;
bool matched; bool matched;
bool usePreviousScene; bool usePreviousScene;
string timeSwitchStr; std::string timeSwitchStr;
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_, inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
QTime time_, bool usePreviousScene_, QTime time_, bool usePreviousScene_,
string timeSwitchStr_) std::string timeSwitchStr_)
: scene(scene_), : scene(scene_),
transition(transition_), transition(transition_),
time(time_), time(time_),
@@ -250,16 +252,19 @@ struct TimeSwitch {
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch; typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
class SwitcherThread;
/******************************************************************************** /********************************************************************************
* SwitcherData * SwitcherData
********************************************************************************/ ********************************************************************************/
struct SwitcherData { struct SwitcherData {
thread th; SwitcherThread *th = nullptr;
condition_variable cv;
mutex m; std::condition_variable cv;
std::mutex m;
bool transitionActive = false; bool transitionActive = false;
bool waitForTransition = false; bool waitForTransition = false;
condition_variable transitionCv; std::condition_variable transitionCv;
bool startAtLaunch = false; bool startAtLaunch = false;
bool stop = false; bool stop = false;
@@ -272,55 +277,70 @@ struct SwitcherData {
OBSWeakSource nonMatchingScene; OBSWeakSource nonMatchingScene;
NoMatch switchIfNotMatching = NO_SWITCH; NoMatch switchIfNotMatching = NO_SWITCH;
vector<WindowSceneSwitch> windowSwitches; std::vector<WindowSceneSwitch> windowSwitches;
vector<string> ignoreIdleWindows; std::vector<std::string> ignoreIdleWindows;
string lastTitle; 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;
vector<RandomSwitch> randomSwitches; std::vector<RandomSwitch> randomSwitches;
FileIOData fileIO; FileIOData fileIO;
IdleData idleData; IdleData idleData;
vector<FileSwitch> fileSwitches; std::vector<FileSwitch> fileSwitches;
vector<ExecutableSceneSwitch> executableSwitches; std::vector<ExecutableSceneSwitch> executableSwitches;
bool autoStopEnable = false; bool autoStopEnable = false;
OBSWeakSource autoStopScene; OBSWeakSource autoStopScene;
vector<SceneTransition> sceneTransitions; std::vector<SceneTransition> sceneTransitions;
vector<DefaultSceneTransition> defaultSceneTransitions; 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_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5, DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7}; DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
std::vector<std::string> threadPrioritiesNamesOrderdByPrio{ struct ThreadPrio {
"Lowest", "Low", "Normal", "High", "Highest", "Time critical", std::string name;
std::string description;
uint32_t value;
}; };
std::map<std::string, int> threadPriorities = {
{"Lowest", QThread::LowestPriority}, std::vector<ThreadPrio> threadPriorities{
{"Low", QThread::LowPriority}, {"Idle",
{"Normal", QThread::NormalPriority}, "scheduled only when no other threads are running (lowest CPU load)",
{"High", QThread::HighPriority}, QThread::IdlePriority},
{"Highest", QThread::HighestPriority}, {"Lowest", "scheduled less often than LowPriority",
{"Time critical", QThread::TimeCriticalPriority}, 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;
void Thread(); void Thread();
void Start(); void Start();
void Stop(); void Stop();
@@ -333,7 +353,7 @@ struct SwitcherData {
bool checkPause(); bool checkPause();
void checkSceneRoundTrip(bool &match, OBSWeakSource &scene, void checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, OBSWeakSource &transition,
unique_lock<mutex> &lock); std::unique_lock<std::mutex> &lock);
void checkIdleSwitch(bool &match, OBSWeakSource &scene, void checkIdleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition); OBSWeakSource &transition);
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene, void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
@@ -440,7 +460,8 @@ struct SwitcherData {
for (size_t i = 0; i < timeSwitches.size(); i++) { for (size_t i = 0; i < timeSwitches.size(); i++) {
TimeSwitch &s = timeSwitches[i]; TimeSwitch &s = timeSwitches[i];
if (!WeakSourceValid(s.scene) || if ((!s.usePreviousScene &&
!WeakSourceValid(s.scene)) ||
!WeakSourceValid(s.transition)) !WeakSourceValid(s.transition))
timeSwitches.erase(timeSwitches.begin() + i--); timeSwitches.erase(timeSwitches.begin() + i--);
} }
@@ -450,6 +471,23 @@ struct SwitcherData {
!WeakSourceValid(idleData.transition)) { !WeakSourceValid(idleData.transition)) {
idleData.idleEnable = false; 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(); } 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 <QString>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include "switcher-data-structs.hpp" #include "switcher-data-structs.hpp"
using namespace std;
static inline bool WeakSourceValid(obs_weak_source_t *ws) 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, static inline QString MakeSwitchName(const QString &scene, const QString &value,
const QString &transition, bool fullscreen) const QString &transition, bool fullscreen,
bool focus)
{ {
if (!fullscreen) QString name = QStringLiteral("[") + scene + QStringLiteral(", ") +
return QStringLiteral("[") + scene + QStringLiteral(", ") +
transition + QStringLiteral("]: ") + value; transition + QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
QStringLiteral("]: ") + value + if (fullscreen || focus) {
QStringLiteral(" (only if window is fullscreen)"); 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, static inline QString MakeSwitchNameExecutable(const QString &scene,
@@ -34,7 +45,7 @@ static inline QString MakeSwitchNameExecutable(const QString &scene,
transition + QStringLiteral("]: ") + value; transition + QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
QStringLiteral("]: ") + value + QStringLiteral("]: ") + value +
QStringLiteral(" (only if window is focused)"); QStringLiteral(" (only if focused)");
} }
static inline QString MakeScreenRegionSwitchName(const QString &scene, static inline QString MakeScreenRegionSwitchName(const QString &scene,
@@ -168,9 +179,9 @@ static inline QString MakeTimeSwitchName(const QString &scene,
return switchName; 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); obs_source_t *source = obs_weak_source_get_source(weak_source);
if (source) { if (source) {

View File

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

View File

@@ -1,54 +1,47 @@
#include "headers/advanced-scene-switcher.hpp" #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) if (!idleData.idleEnable)
return; return;
string title; std::string title;
bool ignoreIdle = false; bool ignoreIdle = false;
//lock.unlock(); //lock.unlock();
GetCurrentWindowTitle(title); GetCurrentWindowTitle(title);
//lock.lock(); //lock.lock();
for (string& window : ignoreIdleWindows) for (std::string &window : ignoreIdleWindows) {
{ if (window == title) {
if (window == title)
{
ignoreIdle = true; ignoreIdle = true;
break; break;
} }
} }
if (!ignoreIdle) if (!ignoreIdle) {
{ for (std::string &window : ignoreIdleWindows) {
for (string& window : ignoreIdleWindows) try {
{ bool matches = std::regex_match(
try title, std::regex(window));
{ if (matches) {
bool matches = regex_match(title, regex(window));
if (matches)
{
ignoreIdle = true; ignoreIdle = true;
break; break;
} }
} } catch (const std::regex_error &) {
catch (const regex_error&)
{
} }
} }
} }
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
{
if (idleData.alreadySwitched) if (idleData.alreadySwitched)
return; return;
scene = (idleData.usePreviousScene) ? previousScene : idleData.scene; scene = (idleData.usePreviousScene) ? previousScene
: idleData.scene;
transition = idleData.transition; transition = idleData.transition;
match = true; match = true;
idleData.alreadySwitched = true; idleData.alreadySwitched = true;
} } else
else
idleData.alreadySwitched = false; idleData.alreadySwitched = false;
} }
@@ -57,17 +50,14 @@ void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
if (!state) if (!state) {
{
ui->idleScenes->setDisabled(true); ui->idleScenes->setDisabled(true);
ui->idleSpinBox->setDisabled(true); ui->idleSpinBox->setDisabled(true);
ui->idleTransitions->setDisabled(true); ui->idleTransitions->setDisabled(true);
switcher->idleData.idleEnable = false; switcher->idleData.idleEnable = false;
} } else {
else
{
ui->idleScenes->setDisabled(false); ui->idleScenes->setDisabled(false);
ui->idleSpinBox->setDisabled(false); ui->idleSpinBox->setDisabled(false);
ui->idleTransitions->setDisabled(false); ui->idleTransitions->setDisabled(false);
@@ -79,18 +69,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; switcher->idleData.transition = transition;
} }
void SceneSwitcher::UpdateIdleDataScene(const QString& name) void SceneSwitcher::UpdateIdleDataScene(const QString &name)
{ {
switcher->idleData.usePreviousScene = (name == PREVIOUS_SCENE_NAME); switcher->idleData.usePreviousScene = (name == PREVIOUS_SCENE_NAME);
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->idleData.scene = ws; switcher->idleData.scene = ws;
@@ -98,21 +87,21 @@ void SceneSwitcher::UpdateIdleDataScene(const QString& name)
obs_source_release(scene); obs_source_release(scene);
} }
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text) void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
UpdateIdleDataTransition(text); UpdateIdleDataTransition(text);
} }
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text) void SceneSwitcher::on_idleScenes_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
UpdateIdleDataScene(text); UpdateIdleDataScene(text);
} }
@@ -120,7 +109,7 @@ void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->idleData.time = i; switcher->idleData.time = i;
} }
@@ -131,15 +120,13 @@ void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->ignoreIdleWindows->item(idx); QListWidgetItem *item = ui->ignoreIdleWindows->item(idx);
QString window = item->data(Qt::UserRole).toString(); QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& w : switcher->ignoreIdleWindows) for (auto &w : switcher->ignoreIdleWindows) {
{ if (window.compare(w.c_str()) == 0) {
if (window.compare(w.c_str()) == 0)
{
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str()); ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
break; break;
} }
@@ -155,37 +142,37 @@ void SceneSwitcher::on_ignoreIdleAdd_clicked()
QVariant v = QVariant::fromValue(windowName); 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) if (items.size() == 0) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows); new QListWidgetItem(windowName, ui->ignoreIdleWindows);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData()); switcher->ignoreIdleWindows.emplace_back(
windowName.toUtf8().constData());
ui->ignoreIdleWindows->sortItems(); ui->ignoreIdleWindows->sortItems();
} }
} }
void SceneSwitcher::on_ignoreIdleRemove_clicked() void SceneSwitcher::on_ignoreIdleRemove_clicked()
{ {
QListWidgetItem* item = ui->ignoreIdleWindows->currentItem(); QListWidgetItem *item = ui->ignoreIdleWindows->currentItem();
if (!item) if (!item)
return; return;
QString windowName = item->data(Qt::UserRole).toString(); QString windowName = item->data(Qt::UserRole).toString();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto& windows = switcher->ignoreIdleWindows; auto &windows = switcher->ignoreIdleWindows;
for (auto it = windows.begin(); it != windows.end(); ++it) for (auto it = windows.begin(); it != windows.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s == windowName.toUtf8().constData()) if (s == windowName.toUtf8().constData()) {
{
windows.erase(it); windows.erase(it);
break; break;
} }
@@ -195,18 +182,16 @@ void SceneSwitcher::on_ignoreIdleRemove_clicked()
delete item; delete item;
} }
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window) int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString &window)
{ {
int count = ui->ignoreIdleWindows->count(); int count = ui->ignoreIdleWindows->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->ignoreIdleWindows->item(i);
QListWidgetItem* item = ui->ignoreIdleWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString(); QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window) if (itemRegion == window) {
{
idx = i; idx = i;
break; break;
} }

View File

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

View File

@@ -1,6 +1,37 @@
#include <obs-module.h> #include <obs-module.h>
#include "headers/advanced-scene-switcher.hpp" #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() void SceneSwitcher::on_mediaAdd_clicked()
{ {
QString sourceName = ui->mediaSources->currentText(); QString sourceName = ui->mediaSources->currentText();
@@ -29,10 +60,11 @@ void SceneSwitcher::on_mediaAdd_clicked()
new QListWidgetItem(switchText, ui->mediaSwitches); new QListWidgetItem(switchText, ui->mediaSwitches);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->mediaSwitches.emplace_back( switcher->mediaSwitches.emplace_back(
scene, source, transition, state, restriction, time, scene, source, transition, state, restriction, time,
(sceneName == QString(PREVIOUS_SCENE_NAME))); (sceneName == QString(PREVIOUS_SCENE_NAME)),
switchText.toUtf8().constData());
} }
void SceneSwitcher::on_mediaRemove_clicked() void SceneSwitcher::on_mediaRemove_clicked()
@@ -41,17 +73,23 @@ void SceneSwitcher::on_mediaRemove_clicked()
if (!item) if (!item)
return; return;
int idx = ui->mediaSwitches->currentRow(); std::string mediaStr =
if (idx == -1) item->data(Qt::UserRole).toString().toUtf8().constData();
return;
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->mediaSwitches; auto &switches = switcher->mediaSwitches;
switches.erase(switches.begin() + idx);
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.mediaSwitchStr == mediaStr) {
switches.erase(it);
break;
}
}
} }
qDeleteAll(ui->mediaSwitches->selectedItems());
delete item;
} }
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
@@ -86,5 +124,6 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
transition = mediaSwitch.transition; transition = mediaSwitch.transition;
} }
mediaSwitch.matched = matched; mediaSwitch.matched = matched;
obs_source_release(source);
} }
} }

View File

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

View File

@@ -10,14 +10,15 @@ void SceneSwitcher::on_pauseScenesAdd_clicked()
OBSWeakSource source = GetWeakSourceByQString(sceneName); OBSWeakSource source = GetWeakSourceByQString(sceneName);
QVariant v = QVariant::fromValue(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) if (items.size() == 0) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes); new QListWidgetItem(sceneName, ui->pauseScenes);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseScenesSwitches.emplace_back(source); switcher->pauseScenesSwitches.emplace_back(source);
ui->pauseScenes->sortItems(); ui->pauseScenes->sortItems();
} }
@@ -25,22 +26,20 @@ void SceneSwitcher::on_pauseScenesAdd_clicked()
void SceneSwitcher::on_pauseScenesRemove_clicked() void SceneSwitcher::on_pauseScenesRemove_clicked()
{ {
QListWidgetItem* item = ui->pauseScenes->currentItem(); QListWidgetItem *item = ui->pauseScenes->currentItem();
if (!item) if (!item)
return; return;
QString pauseScene = item->data(Qt::UserRole).toString(); QString pauseScene = item->data(Qt::UserRole).toString();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->pauseScenesSwitches; auto &switches = switcher->pauseScenesSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s == GetWeakSourceByQString(pauseScene)) if (s == GetWeakSourceByQString(pauseScene)) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -59,37 +58,37 @@ void SceneSwitcher::on_pauseWindowsAdd_clicked()
QVariant v = QVariant::fromValue(windowName); 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) if (items.size() == 0) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows); new QListWidgetItem(windowName, ui->pauseWindows);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData()); switcher->pauseWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
ui->pauseWindows->sortItems(); ui->pauseWindows->sortItems();
} }
} }
void SceneSwitcher::on_pauseWindowsRemove_clicked() void SceneSwitcher::on_pauseWindowsRemove_clicked()
{ {
QListWidgetItem* item = ui->pauseWindows->currentItem(); QListWidgetItem *item = ui->pauseWindows->currentItem();
if (!item) if (!item)
return; return;
QString windowName = item->data(Qt::UserRole).toString(); QString windowName = item->data(Qt::UserRole).toString();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->pauseWindowsSwitches; auto &switches = switcher->pauseWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s == windowName.toUtf8().constData()) if (s == windowName.toUtf8().constData()) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -106,16 +105,14 @@ void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->pauseScenes->item(idx); QListWidgetItem *item = ui->pauseScenes->item(idx);
QString scene = item->data(Qt::UserRole).toString(); QString scene = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->pauseScenesSwitches) for (auto &s : switcher->pauseScenesSwitches) {
{ std::string name = GetWeakSourceName(s);
string name = GetWeakSourceName(s); if (scene.compare(name.c_str()) == 0) {
if (scene.compare(name.c_str()) == 0)
{
ui->pauseScenesScenes->setCurrentText(name.c_str()); ui->pauseScenesScenes->setCurrentText(name.c_str());
break; break;
} }
@@ -129,33 +126,29 @@ void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->pauseWindows->item(idx); QListWidgetItem *item = ui->pauseWindows->item(idx);
QString window = item->data(Qt::UserRole).toString(); QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->pauseWindowsSwitches) for (auto &s : switcher->pauseWindowsSwitches) {
{ if (window.compare(s.c_str()) == 0) {
if (window.compare(s.c_str()) == 0)
{
ui->pauseWindowsWindows->setCurrentText(s.c_str()); ui->pauseWindowsWindows->setCurrentText(s.c_str());
break; break;
} }
} }
} }
int SceneSwitcher::PauseScenesFindByData(const QString& scene) int SceneSwitcher::PauseScenesFindByData(const QString &scene)
{ {
int count = ui->pauseScenes->count(); int count = ui->pauseScenes->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->pauseScenes->item(i);
QListWidgetItem* item = ui->pauseScenes->item(i);
QString itemRegion = item->data(Qt::UserRole).toString(); QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == scene) if (itemRegion == scene) {
{
idx = i; idx = i;
break; break;
} }
@@ -164,18 +157,16 @@ int SceneSwitcher::PauseScenesFindByData(const QString& scene)
return idx; return idx;
} }
int SceneSwitcher::PauseWindowsFindByData(const QString& window) int SceneSwitcher::PauseWindowsFindByData(const QString &window)
{ {
int count = ui->pauseWindows->count(); int count = ui->pauseWindows->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->pauseWindows->item(i);
QListWidgetItem* item = ui->pauseWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString(); QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window) if (itemRegion == window) {
{
idx = i; idx = i;
break; break;
} }
@@ -187,13 +178,11 @@ int SceneSwitcher::PauseWindowsFindByData(const QString& window)
bool SwitcherData::checkPause() bool SwitcherData::checkPause()
{ {
bool pause = false; bool pause = false;
obs_source_t* currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (OBSWeakSource& s : pauseScenesSwitches) for (OBSWeakSource &s : pauseScenesSwitches) {
{ if (s == ws) {
if (s == ws)
{
pause = true; pause = true;
break; break;
} }
@@ -201,40 +190,32 @@ bool SwitcherData::checkPause()
obs_source_release(currentSource); obs_source_release(currentSource);
obs_weak_source_release(ws); obs_weak_source_release(ws);
string title; std::string title;
if (!pause) if (!pause) {
{
//lock.unlock(); //lock.unlock();
GetCurrentWindowTitle(title); GetCurrentWindowTitle(title);
//lock.lock(); //lock.lock();
for (string& window : pauseWindowsSwitches) for (std::string &window : pauseWindowsSwitches) {
{ if (window == title) {
if (window == title)
{
pause = true; pause = true;
break; break;
} }
} }
} }
if (!pause) if (!pause) {
{
//lock.unlock(); //lock.unlock();
GetCurrentWindowTitle(title); GetCurrentWindowTitle(title);
//lock.lock(); //lock.lock();
for (string& window : pauseWindowsSwitches) for (std::string &window : pauseWindowsSwitches) {
{ try {
try bool matches = std::regex_match(
{ title, std::regex(window));
bool matches = regex_match(title, regex(window)); if (matches) {
if (matches)
{
pause = true; pause = true;
break; break;
} }
} } catch (const std::regex_error &) {
catch (const regex_error&)
{
} }
} }
} }

View File

@@ -1,44 +1,68 @@
#include <algorithm> #include <algorithm>
#include "headers/advanced-scene-switcher.hpp" #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() void SceneSwitcher::on_priorityUp_clicked()
{ {
int currentIndex = ui->priorityList->currentRow(); int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != 0) if (currentIndex != -1 && currentIndex != 0) {
{ ui->priorityList->insertItem(
ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex)); currentIndex - 1,
ui->priorityList->setCurrentRow(currentIndex -1); ui->priorityList->takeItem(currentIndex));
lock_guard<mutex> lock(switcher->m); 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() void SceneSwitcher::on_priorityDown_clicked()
{ {
int currentIndex = ui->priorityList->currentRow(); int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1) if (currentIndex != -1 &&
{ currentIndex != ui->priorityList->count() - 1) {
ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex)); ui->priorityList->insertItem(
currentIndex + 1,
ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex + 1); 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() bool SwitcherData::prioFuncsValid()
{ {
auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end()); auto it = std::unique(functionNamesByPriority.begin(),
functionNamesByPriority.end());
bool wasUnique = (it == functionNamesByPriority.end()); bool wasUnique = (it == functionNamesByPriority.end());
if (!wasUnique) if (!wasUnique)
return false; return false;
for (int p : functionNamesByPriority) for (int p : functionNamesByPriority) {
{
if (p < 0 || p > 7) if (p < 0 || p > 7)
return false; return false;
} }
return true; return true;
} }

View File

@@ -8,17 +8,16 @@ void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->randomScenesList->item(idx); QListWidgetItem *item = ui->randomScenesList->item(idx);
QString randomSceneStr = item->data(Qt::UserRole).toString(); QString randomSceneStr = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches) for (auto &s : switcher->randomSwitches) {
{ if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0) {
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
{
QString sceneName = GetWeakSourceName(s.scene).c_str(); 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->randomScenes->setCurrentText(sceneName);
ui->randomSpinBox->setValue(s.delay); ui->randomSpinBox->setValue(s.delay);
ui->randomTransitions->setCurrentText(transitionName); 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(); int count = ui->randomScenesList->count();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->randomScenesList->item(i);
QListWidgetItem* item = ui->randomScenesList->item(i);
QString str = item->data(Qt::UserRole).toString(); QString str = item->data(Qt::UserRole).toString();
if (str == randomStr) if (str == randomStr)
@@ -49,42 +47,38 @@ void SceneSwitcher::on_randomAdd_clicked()
QString transitionName = ui->randomTransitions->currentText(); QString transitionName = ui->randomTransitions->currentText();
double delay = ui->randomSpinBox->value(); double delay = ui->randomSpinBox->value();
if (sceneName.isEmpty()) if (sceneName.isEmpty())
return; return;
OBSWeakSource source = GetWeakSourceByQString(sceneName); OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeRandomSwitchName(sceneName, transitionName, delay); QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
QVariant v = QVariant::fromValue(text); QVariant v = QVariant::fromValue(text);
int idx = randomFindByData(text); int idx = randomFindByData(text);
if (idx == -1) if (idx == -1) {
{ std::lock_guard<std::mutex> lock(switcher->m);
lock_guard<mutex> lock(switcher->m);
switcher->randomSwitches.emplace_back( switcher->randomSwitches.emplace_back(
source, transition, delay, text.toUtf8().constData()); 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); item->setData(Qt::UserRole, v);
} } else {
else QListWidgetItem *item = ui->randomScenesList->item(idx);
{
QListWidgetItem* item = ui->randomScenesList->item(idx);
item->setText(text); item->setText(text);
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches) for (auto &s : switcher->randomSwitches) {
{ if (s.scene == source) {
if (s.scene == source)
{
s.delay = delay; s.delay = delay;
s.transition = transition; s.transition = transition;
s.randomSwitchStr = text.toUtf8().constData();; s.randomSwitchStr =
text.toUtf8().constData();
;
break; break;
} }
} }
@@ -96,22 +90,21 @@ void SceneSwitcher::on_randomAdd_clicked()
void SceneSwitcher::on_randomRemove_clicked() void SceneSwitcher::on_randomRemove_clicked()
{ {
QListWidgetItem* item = ui->randomScenesList->currentItem(); QListWidgetItem *item = ui->randomScenesList->currentItem();
if (!item) if (!item)
return; 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->randomSwitches; auto &switches = switcher->randomSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.randomSwitchStr == text) if (s.randomSwitchStr == text) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -121,17 +114,17 @@ void SceneSwitcher::on_randomRemove_clicked()
delete item; 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) if (randomSwitches.size() == 0)
return; return;
vector<RandomSwitch> rs (randomSwitches); std::vector<RandomSwitch> rs(randomSwitches);
std::random_device rng; std::random_device rng;
std::mt19937 urng(rng()); std::mt19937 urng(rng());
std::shuffle(rs.begin(), rs.end(), urng); std::shuffle(rs.begin(), rs.end(), urng);
for (RandomSwitch& r : rs) for (RandomSwitch &r : rs) {
{
if (r.scene == lastRandomScene) if (r.scene == lastRandomScene)
continue; continue;
scene = r.scene; scene = r.scene;

View File

@@ -22,38 +22,38 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay); QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name,
transitionName, delay);
QVariant v = QVariant::fromValue(text); QVariant v = QVariant::fromValue(text);
int idx = SceneRoundTripFindByData(scene1Name); int idx = SceneRoundTripFindByData(scene1Name);
if (idx == -1) if (idx == -1) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips); new QListWidgetItem(text, ui->sceneRoundTrips);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneRoundTripSwitches.emplace_back( switcher->sceneRoundTripSwitches.emplace_back(
source1, source2, transition, int(delay * 1000), source1, source2, transition, int(delay * 1000),
(scene2Name == QString(PREVIOUS_SCENE_NAME)), (scene2Name == QString(PREVIOUS_SCENE_NAME)),
text.toUtf8().constData()); text.toUtf8().constData());
} } else {
else QListWidgetItem *item = ui->sceneRoundTrips->item(idx);
{
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
item->setText(text); item->setText(text);
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches) for (auto &s : switcher->sceneRoundTripSwitches) {
{ if (s.scene1 == source1) {
if (s.scene1 == source1)
{
s.scene2 = source2; s.scene2 = source2;
s.delay = int(delay * 1000); s.delay = int(delay * 1000);
s.transition = transition; s.transition = transition;
s.usePreviousScene = (scene2Name == QString(PREVIOUS_SCENE_NAME)); s.usePreviousScene =
s.sceneRoundTripStr = text.toUtf8().constData(); (scene2Name ==
QString(PREVIOUS_SCENE_NAME));
s.sceneRoundTripStr =
text.toUtf8().constData();
break; break;
} }
} }
@@ -65,22 +65,21 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
void SceneSwitcher::on_sceneRoundTripRemove_clicked() void SceneSwitcher::on_sceneRoundTripRemove_clicked()
{ {
QListWidgetItem* item = ui->sceneRoundTrips->currentItem(); QListWidgetItem *item = ui->sceneRoundTrips->currentItem();
if (!item) if (!item)
return; 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->sceneRoundTripSwitches; auto &switches = switcher->sceneRoundTripSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.sceneRoundTripStr == text) if (s.sceneRoundTripStr == text) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -95,23 +94,20 @@ void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
if (!state) if (!state) {
{
ui->autoStopScenes->setDisabled(true); ui->autoStopScenes->setDisabled(true);
switcher->autoStopEnable = false; switcher->autoStopEnable = false;
} } else {
else
{
ui->autoStopScenes->setDisabled(false); ui->autoStopScenes->setDisabled(false);
switcher->autoStopEnable = true; switcher->autoStopEnable = true;
} }
} }
void SceneSwitcher::UpdateAutoStopScene(const QString& name) void SceneSwitcher::UpdateAutoStopScene(const QString &name)
{ {
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData()); obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->autoStopScene = ws; switcher->autoStopScene = ws;
@@ -119,76 +115,91 @@ void SceneSwitcher::UpdateAutoStopScene(const QString& name)
obs_source_release(scene); obs_source_release(scene);
} }
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text) void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString &text)
{ {
if (loading) if (loading)
return; return;
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
UpdateAutoStopScene(text); UpdateAutoStopScene(text);
} }
void SceneSwitcher::on_sceneRoundTripSave_clicked() void SceneSwitcher::on_sceneRoundTripSave_clicked()
{ {
QString directory = QFileDialog::getSaveFileName( QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)")); this, tr("Save Scene Round Trip to file ..."),
if (!directory.isEmpty()) QDir::currentPath(), tr("Text files (*.txt)"));
{ if (!directory.isEmpty()) {
QFile file(directory); QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return; return;
QTextStream out(&file); QTextStream out(&file);
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches) for (SceneRoundTripSwitch s :
{ switcher->sceneRoundTripSwitches) {
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n"; out << QString::fromStdString(
GetWeakSourceName(s.scene1))
<< "\n";
if (s.usePreviousScene) if (s.usePreviousScene)
out << (PREVIOUS_SCENE_NAME) << "\n"; out << (PREVIOUS_SCENE_NAME) << "\n";
else else
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n"; out << QString::fromStdString(
GetWeakSourceName(s.scene2))
<< "\n";
out << s.delay << "\n"; out << s.delay << "\n";
out << QString::fromStdString(s.sceneRoundTripStr) << "\n"; out << QString::fromStdString(s.sceneRoundTripStr)
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n"; << "\n";
out << QString::fromStdString(
GetWeakSourceName(s.transition))
<< "\n";
} }
} }
} }
void SceneSwitcher::on_sceneRoundTripLoad_clicked() void SceneSwitcher::on_sceneRoundTripLoad_clicked()
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
QString directory = QFileDialog::getOpenFileName( QString directory = QFileDialog::getOpenFileName(
this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)")); this, tr("Select a file to read Scene Round Trip from ..."),
if (!directory.isEmpty()) QDir::currentPath(), tr("Text files (*.txt)"));
{ if (!directory.isEmpty()) {
QFile file(directory); QFile file(directory);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return; return;
QTextStream in(&file); QTextStream in(&file);
vector<QString> lines; std::vector<QString> lines;
vector<SceneRoundTripSwitch> newSceneRoundTripSwitch; std::vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
while (!in.atEnd()) while (!in.atEnd()) {
{
QString line = in.readLine(); QString line = in.readLine();
lines.push_back(line); lines.push_back(line);
if (lines.size() == 5) if (lines.size() == 5) {
{ OBSWeakSource scene1 =
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]); GetWeakSourceByQString(lines[0]);
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]); OBSWeakSource scene2 =
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]); GetWeakSourceByQString(lines[1]);
OBSWeakSource transition =
GetWeakTransitionByQString(lines[4]);
if (WeakSourceValid(scene1) && ((lines[1] == QString(PREVIOUS_SCENE_NAME)) || (WeakSourceValid(scene2))) if (WeakSourceValid(scene1) &&
&& WeakSourceValid(transition)) ((lines[1] ==
{ QString(PREVIOUS_SCENE_NAME)) ||
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch( (WeakSourceValid(scene2))) &&
GetWeakSourceByQString(lines[0]), WeakSourceValid(transition)) {
GetWeakSourceByQString(lines[1]), newSceneRoundTripSwitch.emplace_back(
GetWeakTransitionByQString(lines[4]), SceneRoundTripSwitch(
lines[2].toInt(), GetWeakSourceByQString(
(lines[1] == QString(PREVIOUS_SCENE_NAME)), lines[0]),
lines[3].toStdString())); GetWeakSourceByQString(
lines[1]),
GetWeakTransitionByQString(
lines[4]),
lines[2].toInt(),
(lines[1] ==
QString(PREVIOUS_SCENE_NAME)),
lines[3].toStdString()));
} }
lines.clear(); lines.clear();
} }
@@ -200,39 +211,43 @@ void SceneSwitcher::on_sceneRoundTripLoad_clicked()
switcher->sceneRoundTripSwitches.clear(); switcher->sceneRoundTripSwitches.clear();
ui->sceneRoundTrips->clear(); ui->sceneRoundTrips->clear();
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch; switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches) for (SceneRoundTripSwitch s :
{ switcher->sceneRoundTripSwitches) {
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips); QListWidgetItem *item = new QListWidgetItem(
item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr)); QString::fromStdString(s.sceneRoundTripStr),
ui->sceneRoundTrips);
item->setData(
Qt::UserRole,
QString::fromStdString(s.sceneRoundTripStr));
} }
} }
} }
void SwitcherData::checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock) OBSWeakSource &transition,
std::unique_lock<std::mutex> &lock)
{ {
bool sceneRoundTripActive = false; bool sceneRoundTripActive = false;
obs_source_t* currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (SceneRoundTripSwitch& s : sceneRoundTripSwitches) for (SceneRoundTripSwitch &s : sceneRoundTripSwitches) {
{ if (s.scene1 == ws) {
if (s.scene1 == ws)
{
sceneRoundTripActive = true; sceneRoundTripActive = true;
int dur = s.delay - interval; int dur = s.delay - interval;
if (dur > 0) if (dur > 0) {
{
waitScene = currentSource; waitScene = currentSource;
cv.wait_for(lock, chrono::milliseconds(dur)); cv.wait_for(lock,
std::chrono::milliseconds(dur));
} }
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 // only switch if user hasn't changed scene manually
if (currentSource == currentSource2) if (currentSource == currentSource2) {
{
match = true; match = true;
scene = (s.usePreviousScene) ? previousScene : s.scene2; scene = (s.usePreviousScene) ? previousScene
: s.scene2;
transition = s.transition; transition = s.transition;
} }
obs_source_release(currentSource2); obs_source_release(currentSource2);
@@ -250,42 +265,42 @@ void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->sceneRoundTrips->item(idx); QListWidgetItem *item = ui->sceneRoundTrips->item(idx);
QString sceneRoundTrip = item->text(); QString sceneRoundTrip = item->text();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches) for (auto &s : switcher->sceneRoundTripSwitches) {
{ if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0) {
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0) std::string scene1 = GetWeakSourceName(s.scene1);
{ std::string scene2 = GetWeakSourceName(s.scene2);
string scene1 = GetWeakSourceName(s.scene1); std::string transitionName =
string scene2 = GetWeakSourceName(s.scene2); GetWeakSourceName(s.transition);
string transitionName = GetWeakSourceName(s.transition);
int delay = s.delay; int delay = s.delay;
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str()); ui->sceneRoundTripScenes1->setCurrentText(
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str()); scene1.c_str());
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str()); ui->sceneRoundTripScenes2->setCurrentText(
ui->sceneRoundTripSpinBox->setValue((double)delay/1000); scene2.c_str());
ui->sceneRoundTripTransitions->setCurrentText(
transitionName.c_str());
ui->sceneRoundTripSpinBox->setValue((double)delay /
1000);
break; break;
} }
} }
} }
int SceneSwitcher::SceneRoundTripFindByData(const QString &scene1)
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
{ {
QRegExp rx(scene1 + " ->.*"); QRegExp rx(scene1 + " ->.*");
int count = ui->sceneRoundTrips->count(); int count = ui->sceneRoundTrips->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->sceneRoundTrips->item(i);
QListWidgetItem* item = ui->sceneRoundTrips->item(i);
QString itemString = item->data(Qt::UserRole).toString(); QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString)) if (rx.exactMatch(itemString)) {
{
idx = i; idx = i;
break; break;
} }
@@ -294,14 +309,12 @@ int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
return idx; return idx;
} }
void SwitcherData::autoStopStreamAndRecording() void SwitcherData::autoStopStreamAndRecording()
{ {
obs_source_t* currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
if (ws && autoStopScene == ws) if (ws && autoStopScene == ws) {
{
if (obs_frontend_streaming_active()) if (obs_frontend_streaming_active())
obs_frontend_streaming_stop(); obs_frontend_streaming_stop();
if (obs_frontend_recording_active()) if (obs_frontend_recording_active())

View File

@@ -16,33 +16,33 @@ void SceneSwitcher::on_transitionsAdd_clicked()
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name); OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName); QString text =
MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
QVariant v = QVariant::fromValue(text); QVariant v = QVariant::fromValue(text);
int idx = SceneTransitionsFindByData(scene1Name, scene2Name); int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
if (idx == -1) if (idx == -1) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions); new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneTransitions.emplace_back( switcher->sceneTransitions.emplace_back(
source1, source2, transition, text.toUtf8().constData()); source1, source2, transition,
} text.toUtf8().constData());
else } else {
{ QListWidgetItem *item = ui->sceneTransitions->item(idx);
QListWidgetItem* item = ui->sceneTransitions->item(idx);
item->setText(text); item->setText(text);
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions) for (auto &s : switcher->sceneTransitions) {
{ if (s.scene1 == source1 &&
if (s.scene1 == source1 && s.scene2 == source2) s.scene2 == source2) {
{
s.transition = transition; s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData(); s.sceneTransitionStr =
text.toUtf8().constData();
break; break;
} }
} }
@@ -54,22 +54,21 @@ void SceneSwitcher::on_transitionsAdd_clicked()
void SceneSwitcher::on_transitionsRemove_clicked() void SceneSwitcher::on_transitionsRemove_clicked()
{ {
QListWidgetItem* item = ui->sceneTransitions->currentItem(); QListWidgetItem *item = ui->sceneTransitions->currentItem();
if (!item) if (!item)
return; 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->sceneTransitions; auto &switches = switcher->sceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.sceneTransitionStr == text) if (s.sceneTransitionStr == text) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -82,7 +81,8 @@ void SceneSwitcher::on_transitionsRemove_clicked()
void SceneSwitcher::on_defaultTransitionsAdd_clicked() void SceneSwitcher::on_defaultTransitionsAdd_clicked()
{ {
QString sceneName = ui->defaultTransitionsScene->currentText(); QString sceneName = ui->defaultTransitionsScene->currentText();
QString transitionName = ui->defaultTransitionsTransitions->currentText(); QString transitionName =
ui->defaultTransitionsTransitions->currentText();
if (sceneName.isEmpty() || transitionName.isEmpty()) if (sceneName.isEmpty() || transitionName.isEmpty())
return; return;
@@ -90,33 +90,31 @@ void SceneSwitcher::on_defaultTransitionsAdd_clicked()
OBSWeakSource source = GetWeakSourceByQString(sceneName); OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeDefaultSceneTransitionName(sceneName, transitionName); QString text =
MakeDefaultSceneTransitionName(sceneName, transitionName);
QVariant v = QVariant::fromValue(text); QVariant v = QVariant::fromValue(text);
int idx = DefaultTransitionsFindByData(sceneName); int idx = DefaultTransitionsFindByData(sceneName);
if (idx == -1) if (idx == -1) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions); new QListWidgetItem(text, ui->defaultTransitions);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back( switcher->defaultSceneTransitions.emplace_back(
source, transition, text.toUtf8().constData()); source, transition, text.toUtf8().constData());
} } else {
else QListWidgetItem *item = ui->defaultTransitions->item(idx);
{
QListWidgetItem* item = ui->defaultTransitions->item(idx);
item->setText(text); item->setText(text);
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions) for (auto &s : switcher->defaultSceneTransitions) {
{ if (s.scene == source) {
if (s.scene == source)
{
s.transition = transition; s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData(); s.sceneTransitionStr =
text.toUtf8().constData();
break; break;
} }
} }
@@ -128,22 +126,21 @@ void SceneSwitcher::on_defaultTransitionsAdd_clicked()
void SceneSwitcher::on_defaultTransitionsRemove_clicked() void SceneSwitcher::on_defaultTransitionsRemove_clicked()
{ {
QListWidgetItem* item = ui->defaultTransitions->currentItem(); QListWidgetItem *item = ui->defaultTransitions->currentItem();
if (!item) if (!item)
return; 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->defaultSceneTransitions; auto &switches = switcher->defaultSceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.sceneTransitionStr == text) if (s.sceneTransitionStr == text) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -155,14 +152,13 @@ void SceneSwitcher::on_defaultTransitionsRemove_clicked()
void SwitcherData::setDefaultSceneTransitions() void SwitcherData::setDefaultSceneTransitions()
{ {
obs_source_t* currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource); obs_weak_source_t *ws = obs_source_get_weak_source(currentSource);
for (DefaultSceneTransition& s : defaultSceneTransitions) for (DefaultSceneTransition &s : defaultSceneTransitions) {
{ if (s.scene == ws) {
if (s.scene == ws) obs_source_t *transition =
{ obs_weak_source_get_source(s.transition);
obs_source_t* transition = obs_weak_source_get_source(s.transition);
//This might cancel the current transition //This might cancel the current transition
//There is no way to be sure when the previous transition finished //There is no way to be sure when the previous transition finished
obs_frontend_set_current_transition(transition); obs_frontend_set_current_transition(transition);
@@ -174,19 +170,18 @@ void SwitcherData::setDefaultSceneTransitions()
obs_weak_source_release(ws); 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); QRegExp rx(scene1 + " --- .* --> " + scene2);
int count = ui->sceneTransitions->count(); int count = ui->sceneTransitions->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->sceneTransitions->item(i);
QListWidgetItem* item = ui->sceneTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString(); QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString)) if (rx.exactMatch(itemString)) {
{
idx = i; idx = i;
break; break;
} }
@@ -195,19 +190,17 @@ int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QStri
return idx; return idx;
} }
int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene) int SceneSwitcher::DefaultTransitionsFindByData(const QString &scene)
{ {
QRegExp rx(scene + " --> .*"); QRegExp rx(scene + " --> .*");
int count = ui->defaultTransitions->count(); int count = ui->defaultTransitions->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->defaultTransitions->item(i);
QListWidgetItem* item = ui->defaultTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString(); QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString)) if (rx.exactMatch(itemString)) {
{
idx = i; idx = i;
break; break;
} }
@@ -223,21 +216,22 @@ void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->sceneTransitions->item(idx); QListWidgetItem *item = ui->sceneTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString(); QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions) for (auto &s : switcher->sceneTransitions) {
{ if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) 0) {
{ std::string scene1 = GetWeakSourceName(s.scene1);
string scene1 = GetWeakSourceName(s.scene1); std::string scene2 = GetWeakSourceName(s.scene2);
string scene2 = GetWeakSourceName(s.scene2); std::string transitionName =
string transitionName = GetWeakSourceName(s.transition); GetWeakSourceName(s.transition);
ui->transitionsScene1->setCurrentText(scene1.c_str()); ui->transitionsScene1->setCurrentText(scene1.c_str());
ui->transitionsScene2->setCurrentText(scene2.c_str()); ui->transitionsScene2->setCurrentText(scene2.c_str());
ui->transitionsTransitions->setCurrentText(transitionName.c_str()); ui->transitionsTransitions->setCurrentText(
transitionName.c_str());
break; break;
} }
} }
@@ -250,31 +244,32 @@ void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->defaultTransitions->item(idx); QListWidgetItem *item = ui->defaultTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString(); QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions) for (auto &s : switcher->defaultSceneTransitions) {
{ if (sceneTransition.compare(s.sceneTransitionStr.c_str()) ==
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0) 0) {
{ std::string scene = GetWeakSourceName(s.scene);
string scene = GetWeakSourceName(s.scene); std::string transitionName =
string transitionName = GetWeakSourceName(s.transition); GetWeakSourceName(s.transition);
ui->defaultTransitionsScene->setCurrentText(scene.c_str()); ui->defaultTransitionsScene->setCurrentText(
ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str()); scene.c_str());
ui->defaultTransitionsTransitions->setCurrentText(
transitionName.c_str());
break; break;
} }
} }
} }
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2) obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
obs_weak_source_t *scene2)
{ {
obs_weak_source_t* ws = nullptr; obs_weak_source_t *ws = nullptr;
if (scene1 && scene2) if (scene1 && scene2) {
{ for (SceneTransition &t : switcher->sceneTransitions) {
for (SceneTransition& t : switcher->sceneTransitions)
{
if (t.scene1 == scene1 && t.scene2 == scene2) if (t.scene1 == scene1 && t.scene2 == scene2)
ws = t.transition; ws = t.transition;
} }

View File

@@ -1,18 +1,16 @@
#include "headers/advanced-scene-switcher.hpp" #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; int minRegionSize = 99999;
for (auto& s : screenRegionSwitches) for (auto &s : screenRegionSwitches) {
{ if (cursorPos.first >= s.minX && cursorPos.second >= s.minY &&
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) {
&& cursorPos.first <= s.maxX && cursorPos.second <= s.maxY)
{
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY); int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
if (regionSize < minRegionSize) if (regionSize < minRegionSize) {
{
match = true; match = true;
scene = s.scene; scene = s.scene;
transition = s.transition; transition = s.transition;
@@ -24,9 +22,8 @@ void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OB
void SceneSwitcher::updateScreenRegionCursorPos() void SceneSwitcher::updateScreenRegionCursorPos()
{ {
pair<int, int> position = getCursorPos(); std::pair<int, int> position = getCursorPos();
ui->cursorXPosition->setText(QString::number(position.first)); ui->cursorXPosition->setText(QString::number(position.first));
;
ui->cursorYPosition->setText(QString::number(position.second)); ui->cursorYPosition->setText(QString::number(position.second));
} }
@@ -43,40 +40,38 @@ void SceneSwitcher::on_screenRegionAdd_clicked()
int maxX = ui->screenRegionMaxX->value(); int maxX = ui->screenRegionMaxX->value();
int maxY = ui->screenRegionMaxY->value(); int maxY = ui->screenRegionMaxY->value();
string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", " std::string regionStr =
+ to_string(maxY); std::to_string(minX) + ", " + std::to_string(minY) + " x " +
std::to_string(maxX) + ", " + std::to_string(maxY);
QString region = QString::fromStdString(regionStr); QString region = QString::fromStdString(regionStr);
OBSWeakSource source = GetWeakSourceByQString(sceneName); OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(region); 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); int idx = ScreenRegionFindByData(region);
if (idx == -1) if (idx == -1) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions); new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back( switcher->screenRegionSwitches.emplace_back(
source, transition, minX, minY, maxX, maxY, regionStr); source, transition, minX, minY, maxX, maxY, regionStr);
} } else {
else QListWidgetItem *item = ui->screenRegions->item(idx);
{
QListWidgetItem* item = ui->screenRegions->item(idx);
item->setText(text); item->setText(text);
string curRegion = region.toUtf8().constData(); std::string curRegion = region.toUtf8().constData();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches) for (auto &s : switcher->screenRegionSwitches) {
{ if (s.regionStr == curRegion) {
if (s.regionStr == curRegion)
{
s.scene = source; s.scene = source;
s.transition = transition; s.transition = transition;
break; break;
@@ -90,22 +85,21 @@ void SceneSwitcher::on_screenRegionAdd_clicked()
void SceneSwitcher::on_screenRegionRemove_clicked() void SceneSwitcher::on_screenRegionRemove_clicked()
{ {
QListWidgetItem* item = ui->screenRegions->currentItem(); QListWidgetItem *item = ui->screenRegions->currentItem();
if (!item) if (!item)
return; 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); std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->screenRegionSwitches; auto &switches = switcher->screenRegionSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.regionStr == region) if (s.regionStr == region) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -122,19 +116,19 @@ void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->screenRegions->item(idx); QListWidgetItem *item = ui->screenRegions->item(idx);
QString region = item->data(Qt::UserRole).toString(); QString region = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches) for (auto &s : switcher->screenRegionSwitches) {
{ if (region.compare(s.regionStr.c_str()) == 0) {
if (region.compare(s.regionStr.c_str()) == 0) std::string name = GetWeakSourceName(s.scene);
{ std::string transitionName =
string name = GetWeakSourceName(s.scene); GetWeakSourceName(s.transition);
string transitionName = GetWeakSourceName(s.transition);
ui->screenRegionScenes->setCurrentText(name.c_str()); ui->screenRegionScenes->setCurrentText(name.c_str());
ui->screenRegionsTransitions->setCurrentText(transitionName.c_str()); ui->screenRegionsTransitions->setCurrentText(
transitionName.c_str());
ui->screenRegionMinX->setValue(s.minX); ui->screenRegionMinX->setValue(s.minX);
ui->screenRegionMinY->setValue(s.minY); ui->screenRegionMinY->setValue(s.minY);
ui->screenRegionMaxX->setValue(s.maxX); ui->screenRegionMaxX->setValue(s.maxX);
@@ -144,18 +138,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 count = ui->screenRegions->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->screenRegions->item(i);
QListWidgetItem* item = ui->screenRegions->item(i);
QString itemRegion = item->data(Qt::UserRole).toString(); QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == region) if (itemRegion == region) {
{
idx = i; idx = i;
break; break;
} }

View File

@@ -11,7 +11,7 @@ void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
QString timeScenestr = item->data(Qt::UserRole).toString(); 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) { for (auto &s : switcher->timeSwitches) {
if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) { if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
QString sceneName = GetWeakSourceName(s.scene).c_str(); QString sceneName = GetWeakSourceName(s.scene).c_str();
@@ -59,7 +59,7 @@ void SceneSwitcher::on_timeAdd_clicked()
int idx = timeFindByData(time.toString()); int idx = timeFindByData(time.toString());
if (idx == -1) { if (idx == -1) {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->timeSwitches.emplace_back( switcher->timeSwitches.emplace_back(
source, transition, time, source, transition, time,
(sceneName == QString(PREVIOUS_SCENE_NAME)), (sceneName == QString(PREVIOUS_SCENE_NAME)),
@@ -73,7 +73,7 @@ void SceneSwitcher::on_timeAdd_clicked()
item->setText(text); item->setText(text);
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->timeSwitches) { for (auto &s : switcher->timeSwitches) {
if (s.time == time) { if (s.time == time) {
s.scene = source; s.scene = source;
@@ -99,10 +99,11 @@ void SceneSwitcher::on_timeRemove_clicked()
if (!item) if (!item)
return; 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; auto &switches = switcher->timeSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) { for (auto it = switches.begin(); it != switches.end(); ++it) {

View File

@@ -6,7 +6,7 @@
using namespace std; using namespace std;
static bool GetWindowTitle(HWND window, string& title) static bool GetWindowTitle(HWND window, string &title)
{ {
size_t len = (size_t)GetWindowTextLengthW(window); size_t len = (size_t)GetWindowTextLengthW(window);
wstring wtitle; wstring wtitle;
@@ -45,12 +45,13 @@ static bool WindowValid(HWND window)
return true; return true;
} }
void GetWindowList(vector<string>& windows) void GetWindowList(vector<string> &windows)
{ {
windows.resize(0);
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
while (window) while (window) {
{
string title; string title;
if (WindowValid(window) && GetWindowTitle(window, title)) if (WindowValid(window) && GetWindowTitle(window, title))
windows.emplace_back(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(); HWND window = GetForegroundWindow();
DWORD pid; DWORD pid;
@@ -75,43 +91,63 @@ void GetCurrentWindowTitle(string& title)
GetWindowTitle(window, 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; POINT cursorPos;
if (GetPhysicalCursorPos(&cursorPos)) if (GetPhysicalCursorPos(&cursorPos)) {
{
pos.first = cursorPos.x; pos.first = cursorPos.x;
pos.second = cursorPos.y; pos.second = cursorPos.y;
} }
return pos; return pos;
} }
bool isFullscreen() bool isFullscreen(std::string &title)
{ {
RECT appBounds; RECT appBounds;
RECT rc; MONITORINFO monitorInfo = {0};
GetWindowRect(GetDesktopWindow(), &rc);
HWND hwnd = GetForegroundWindow(); HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) 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); GetWindowRect(hwnd, &appBounds);
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left if (monitorInfo.rcMonitor.bottom == appBounds.bottom &&
&& rc.right == appBounds.right) monitorInfo.rcMonitor.top == appBounds.top &&
{ monitorInfo.rcMonitor.left == appBounds.left &&
monitorInfo.rcMonitor.right == appBounds.right) {
return true; return true;
} }
} }
return false; return false;
} }
void GetProcessList(QStringList &processes) { void GetProcessList(QStringList &processes)
{
HANDLE procSnapshot; HANDLE procSnapshot;
PROCESSENTRY32 procEntry; PROCESSENTRY32 procEntry;
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (procSnapshot == INVALID_HANDLE_VALUE) return; if (procSnapshot == INVALID_HANDLE_VALUE)
return;
procEntry.dwSize = sizeof(PROCESSENTRY32); procEntry.dwSize = sizeof(PROCESSENTRY32);
@@ -122,30 +158,45 @@ void GetProcessList(QStringList &processes) {
do { do {
QString tempexe = QString::fromWCharArray(procEntry.szExeFile); QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
if (tempexe == "System") continue; if (tempexe == "System")
if (tempexe == "[System Process]") continue; continue;
if (processes.contains(tempexe)) continue; if (tempexe == "[System Process]")
continue;
if (processes.contains(tempexe))
continue;
processes.append(tempexe); processes.append(tempexe);
} while (Process32Next(procSnapshot, &procEntry)); } while (Process32Next(procSnapshot, &procEntry));
CloseHandle(procSnapshot); CloseHandle(procSnapshot);
} }
bool isInFocus(const QString &exeToCheck) { bool isInFocus(const QString &executable)
{
// only checks if the current foreground window is from the same 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(); HWND foregroundWindow = GetForegroundWindow();
DWORD processId = 0; DWORD processId = 0;
GetWindowThreadProcessId(foregroundWindow, &processId); GetWindowThreadProcessId(foregroundWindow, &processId);
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); HANDLE process = OpenProcess(
if (process == NULL) return false; PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (process == NULL)
return false;
WCHAR executablePath[600]; WCHAR executablePath[600];
GetModuleFileNameEx(process, 0, executablePath, 600); GetModuleFileNameEx(process, 0, executablePath, 600);
CloseHandle(process); 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() int getLastInputTime()

View File

@@ -1,12 +1,71 @@
#include <obs-module.h> #include <obs-module.h>
#include "headers/advanced-scene-switcher.hpp" #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() void SceneSwitcher::on_add_clicked()
{ {
QString sceneName = ui->scenes->currentText(); QString sceneName = ui->scenes->currentText();
QString windowName = ui->windows->currentText(); QString windowName = ui->windows->currentText();
QString transitionName = ui->transitions->currentText(); QString transitionName = ui->transitions->currentText();
bool fullscreen = ui->fullscreenCheckBox->isChecked(); bool fullscreen = ui->fullscreenCheckBox->isChecked();
bool focus = ui->focusCheckBox->isChecked();
if (windowName.isEmpty() || sceneName.isEmpty()) if (windowName.isEmpty() || sceneName.isEmpty())
return; return;
@@ -15,62 +74,57 @@ void SceneSwitcher::on_add_clicked()
OBSWeakSource transition = GetWeakTransitionByQString(transitionName); OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(windowName); QVariant v = QVariant::fromValue(windowName);
QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen); QString text = MakeSwitchName(sceneName, windowName, transitionName,
fullscreen, focus);
int idx = FindByData(windowName); int idx = FindByData(windowName);
if (idx == -1) if (idx == -1) {
{ std::lock_guard<std::mutex> lock(switcher->m);
lock_guard<mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back( 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); item->setData(Qt::UserRole, v);
} } else {
else QListWidgetItem *item = ui->switches->item(idx);
{
QListWidgetItem* item = ui->switches->item(idx);
item->setText(text); item->setText(text);
string window = windowName.toUtf8().constData(); std::string window = windowName.toUtf8().constData();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->windowSwitches) for (auto &s : switcher->windowSwitches) {
{ if (s.window == window) {
if (s.window == window)
{
s.scene = source; s.scene = source;
s.transition = transition; s.transition = transition;
s.fullscreen = fullscreen; s.fullscreen = fullscreen;
s.focus = focus;
break; break;
} }
} }
} }
ui->switches->sortItems();
} }
} }
void SceneSwitcher::on_remove_clicked() void SceneSwitcher::on_remove_clicked()
{ {
QListWidgetItem* item = ui->switches->currentItem(); QListWidgetItem *item = ui->switches->currentItem();
if (!item) if (!item)
return; 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); std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->windowSwitches; auto &switches = switcher->windowSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s.window == window) if (s.window == window) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -80,9 +134,6 @@ void SceneSwitcher::on_remove_clicked()
delete item; delete item;
} }
void SceneSwitcher::on_ignoreWindowsAdd_clicked() void SceneSwitcher::on_ignoreWindowsAdd_clicked()
{ {
QString windowName = ui->ignoreWindowsWindows->currentText(); QString windowName = ui->ignoreWindowsWindows->currentText();
@@ -92,37 +143,36 @@ void SceneSwitcher::on_ignoreWindowsAdd_clicked()
QVariant v = QVariant::fromValue(windowName); 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) if (items.size() == 0) {
{ QListWidgetItem *item =
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows); new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData()); switcher->ignoreWindowsSwitches.emplace_back(
ui->ignoreWindows->sortItems(); windowName.toUtf8().constData());
} }
} }
void SceneSwitcher::on_ignoreWindowsRemove_clicked() void SceneSwitcher::on_ignoreWindowsRemove_clicked()
{ {
QListWidgetItem* item = ui->ignoreWindows->currentItem(); QListWidgetItem *item = ui->ignoreWindows->currentItem();
if (!item) if (!item)
return; return;
QString windowName = item->data(Qt::UserRole).toString(); QString windowName = item->data(Qt::UserRole).toString();
{ {
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto& switches = switcher->ignoreWindowsSwitches; auto &switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) for (auto it = switches.begin(); it != switches.end(); ++it) {
{ auto &s = *it;
auto& s = *it;
if (s == windowName.toUtf8().constData()) if (s == windowName.toUtf8().constData()) {
{
switches.erase(it); switches.erase(it);
break; break;
} }
@@ -132,18 +182,16 @@ void SceneSwitcher::on_ignoreWindowsRemove_clicked()
delete item; delete item;
} }
int SceneSwitcher::FindByData(const QString& window) int SceneSwitcher::FindByData(const QString &window)
{ {
int count = ui->switches->count(); int count = ui->switches->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->switches->item(i);
QListWidgetItem* item = ui->switches->item(i);
QString itemWindow = item->data(Qt::UserRole).toString(); QString itemWindow = item->data(Qt::UserRole).toString();
if (itemWindow == window) if (itemWindow == window) {
{
idx = i; idx = i;
break; break;
} }
@@ -152,21 +200,16 @@ int SceneSwitcher::FindByData(const QString& window)
return idx; return idx;
} }
int SceneSwitcher::IgnoreWindowsFindByData(const QString &window)
int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
{ {
int count = ui->ignoreWindows->count(); int count = ui->ignoreWindows->count();
int idx = -1; int idx = -1;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{ QListWidgetItem *item = ui->ignoreWindows->item(i);
QListWidgetItem* item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString(); QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window) if (itemRegion == window) {
{
idx = i; idx = i;
break; break;
} }
@@ -175,7 +218,6 @@ int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
return idx; return idx;
} }
void SceneSwitcher::on_switches_currentRowChanged(int idx) void SceneSwitcher::on_switches_currentRowChanged(int idx)
{ {
if (loading) if (loading)
@@ -183,27 +225,26 @@ void SceneSwitcher::on_switches_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->switches->item(idx); QListWidgetItem *item = ui->switches->item(idx);
QString window = item->data(Qt::UserRole).toString(); QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->windowSwitches) for (auto &s : switcher->windowSwitches) {
{ if (window.compare(s.window.c_str()) == 0) {
if (window.compare(s.window.c_str()) == 0) std::string name = GetWeakSourceName(s.scene);
{ std::string transitionName =
string name = GetWeakSourceName(s.scene); GetWeakSourceName(s.transition);
string transitionName = GetWeakSourceName(s.transition);
ui->scenes->setCurrentText(name.c_str()); ui->scenes->setCurrentText(name.c_str());
ui->windows->setCurrentText(window); ui->windows->setCurrentText(window);
ui->transitions->setCurrentText(transitionName.c_str()); ui->transitions->setCurrentText(transitionName.c_str());
ui->fullscreenCheckBox->setChecked(s.fullscreen); ui->fullscreenCheckBox->setChecked(s.fullscreen);
ui->focusCheckBox->setChecked(s.focus);
break; break;
} }
} }
} }
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx) void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{ {
if (loading) if (loading)
@@ -211,70 +252,63 @@ void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
if (idx == -1) if (idx == -1)
return; return;
QListWidgetItem* item = ui->ignoreWindows->item(idx); QListWidgetItem *item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString(); QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto& s : switcher->ignoreWindowsSwitches) for (auto &s : switcher->ignoreWindowsSwitches) {
{ if (window.compare(s.c_str()) == 0) {
if (window.compare(s.c_str()) == 0)
{
ui->ignoreWindowsWindows->setCurrentText(s.c_str()); ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break; 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 std::string title;
string title; bool ignored = false;
// Check if current window is ignored
GetCurrentWindowTitle(title); GetCurrentWindowTitle(title);
for (auto& window : ignoreWindowsSwitches) for (auto &window : ignoreWindowsSwitches) {
{ // True if ignored switch equals current window
try bool equals = (title == window);
{ // True if ignored switch matches current window
bool matches = regex_match(title, regex(window)); bool matches = QString::fromStdString(title).contains(
if (matches) QRegularExpression(QString::fromStdString(window)));
{
title = lastTitle; if (equals || matches) {
break; ignored = true;
} title = lastTitle;
}
catch (const regex_error&) break;
{
} }
} }
lastTitle = title; lastTitle = title;
//direct match // Check for match
for (WindowSceneSwitch& s : windowSwitches) for (WindowSceneSwitch &s : windowSwitches) {
{ // True if fullscreen is disabled OR current window is fullscreen
if (s.window == title) bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
{ // True if focus is disabled OR switch is focused
match = !s.fullscreen || (s.fullscreen && isFullscreen()); 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; scene = s.scene;
transition = s.transition; transition = s.transition;
return;
}
}
//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&)
{
}
}
break;
}
}
} }