mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80cc8ba06c | ||
|
|
f1d5b110b8 | ||
|
|
2e475b8059 | ||
|
|
99b5c16406 | ||
|
|
9bedeedcb6 | ||
|
|
a88a5bb2da | ||
|
|
cfd6be2ba0 | ||
|
|
3658efff20 | ||
|
|
8331b50c5a | ||
|
|
7a343c2070 | ||
|
|
228a18eb77 | ||
|
|
4ed12db12b | ||
|
|
b20b894b2f | ||
|
|
7c052f2633 | ||
|
|
9305576789 | ||
|
|
38bd59c1fd | ||
|
|
7f84de64d8 | ||
|
|
5ae90fe913 | ||
|
|
115a90196c | ||
|
|
5e92a7bcdf | ||
|
|
922cf95119 | ||
|
|
05540b61a1 | ||
|
|
218ad13160 | ||
|
|
6e18eebb25 | ||
|
|
b7058f97a9 | ||
|
|
b0c00dfa98 | ||
|
|
7a074aa548 | ||
|
|
51c740bdc6 | ||
|
|
826a25926c | ||
|
|
e2cd39315f | ||
|
|
7665bf8872 | ||
|
|
14d78100c1 | ||
|
|
92d75bbddb | ||
|
|
14d6e6f5bf | ||
|
|
78fa18f22a | ||
|
|
bbf7d4acf5 | ||
|
|
299f7c00e0 | ||
|
|
70c0a8ed57 | ||
|
|
d41868c660 | ||
|
|
3381e6d62f | ||
|
|
6338aaa891 | ||
|
|
104f74bf39 | ||
|
|
9cc2875455 | ||
|
|
e466bf9750 | ||
|
|
42dcd9dec4 | ||
|
|
c934b5c7ff | ||
|
|
dd2d70bb9c | ||
|
|
ad052e9323 | ||
|
|
086d07f678 | ||
|
|
c606869d41 | ||
|
|
12512f7d0a | ||
|
|
1ed924a39c | ||
|
|
59ed240311 | ||
|
|
712767b824 | ||
|
|
bb4035824b | ||
|
|
a1d385f5dc | ||
|
|
3c9b1f7ad8 | ||
|
|
fc66509e50 | ||
|
|
62f1109256 | ||
|
|
25540aee2b | ||
|
|
53aa828c9e |
284
.github/workflows/build.yml
vendored
Normal file
284
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
name: build obs plugin
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
PLUGIN_NAME: SceneSwitcher
|
||||
LIB_NAME: advanced-scene-switcher
|
||||
|
||||
jobs:
|
||||
macos64:
|
||||
name: "macOS 64-bit"
|
||||
runs-on: [macos-latest]
|
||||
env:
|
||||
QT_VERSION: 5.14.1
|
||||
OSX_DEPS_VERSION: '2020-04-07'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: "Checkout plugin"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||
- name: Fetch Git Tags
|
||||
run: |
|
||||
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||
git fetch --prune --tags --unshallow
|
||||
- name: 'Install prerequisites (Homebrew)'
|
||||
shell: bash
|
||||
run: |
|
||||
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/CI/macos
|
||||
brew bundle
|
||||
cd -
|
||||
- name: 'Install prerequisite: Pre-built dependencies'
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.OSX_DEPS_VERSION }}/osx-deps-${{ env.OSX_DEPS_VERSION }}.tar.gz
|
||||
tar -xf ./osx-deps-${{ env.OSX_DEPS_VERSION }}.tar.gz -C "/tmp"
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: |
|
||||
echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
|
||||
mkdir ./build
|
||||
cd ./build
|
||||
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DDepsPath="/tmp/obsdeps" -DQTDIR="/usr/local/Cellar/qt/${{ env.QT_VERSION }}" ..
|
||||
cd -
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
cd ./build
|
||||
make -j4
|
||||
cd -
|
||||
- name: 'Install prerequisite: Packages app'
|
||||
if: success()
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L -O https://s3-us-west-2.amazonaws.com/obs-nightly/Packages.pkg
|
||||
sudo installer -pkg ./Packages.pkg -target /
|
||||
- name: Package
|
||||
if: success()
|
||||
shell: bash
|
||||
run: |
|
||||
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /usr/local/opt/qt5/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change /usr/local/opt/qt5/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
FILE_DATE=$(date +%Y-%m-%d)
|
||||
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
|
||||
echo "::set-env name=FILE_NAME::${FILE_NAME}"
|
||||
packagesbuild ./CI/macos/${{ env.PLUGIN_NAME }}.pkgproj
|
||||
cd -
|
||||
mkdir ./nightly
|
||||
mv UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.PLUGIN_NAME }}.pkg ./nightly/${FILE_NAME}
|
||||
- name: Publish
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: '${{ env.FILE_NAME }}'
|
||||
path: ./nightly/*.pkg
|
||||
ubuntu64:
|
||||
name: 'Linux/Ubuntu 64-bit'
|
||||
runs-on: [ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: "Checkout plugin"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||
- name: Add plugin to obs cmake
|
||||
shell: bash
|
||||
run: echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
|
||||
- name: Fetch Git Tags
|
||||
run: git fetch --prune --tags --unshallow
|
||||
- name: Install prerequisites (Apt)
|
||||
shell: bash
|
||||
run: |
|
||||
sudo dpkg --add-architecture amd64
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
checkinstall \
|
||||
cmake \
|
||||
libasound2-dev \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libavfilter-dev \
|
||||
libavformat-dev \
|
||||
libavutil-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libfdk-aac-dev \
|
||||
libfontconfig-dev \
|
||||
libfreetype6-dev \
|
||||
libgl1-mesa-dev \
|
||||
libjack-jackd2-dev \
|
||||
libjansson-dev \
|
||||
libluajit-5.1-dev \
|
||||
libpulse-dev \
|
||||
libqt5x11extras5-dev \
|
||||
libspeexdsp-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libudev-dev \
|
||||
libv4l-dev \
|
||||
libva-dev \
|
||||
libvlc-dev \
|
||||
libx11-dev \
|
||||
libx264-dev \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xinerama0-dev \
|
||||
libxcomposite-dev \
|
||||
libxinerama-dev \
|
||||
libmbedtls-dev \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
qtbase5-dev \
|
||||
libqt5svg5-dev \
|
||||
swig \
|
||||
libxss-dev
|
||||
- name: 'Configure'
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir ./build
|
||||
cd ./build
|
||||
cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DBUILD_CAPTIONS=OFF -DWITH_RTMPS=OFF -DBUILD_BROWSER=OFF ..
|
||||
- name: 'Build'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: make -j4
|
||||
- name: 'Package'
|
||||
shell: bash
|
||||
run: |
|
||||
FILE_DATE=$(date +%Y-%m-%d)
|
||||
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
|
||||
echo "::set-env name=FILE_NAME::${FILE_NAME}"
|
||||
mkdir -p ./${{ env.PLUGIN_NAME }}/bin/64bit/
|
||||
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.PLUGIN_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
|
||||
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }}
|
||||
- name: 'Publish'
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: '${{ env.FILE_NAME }}'
|
||||
path: '*.tar.gz'
|
||||
win64:
|
||||
name: Windows 64-bit
|
||||
runs-on: [windows-latest]
|
||||
env:
|
||||
QT_VERSION: 5.10.1
|
||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||
steps:
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.0
|
||||
- name: Checkout obs
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: Checkout plugin
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME}}
|
||||
- name: Add plugin to obs cmake
|
||||
shell: cmd
|
||||
run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> UI/frontend-plugins/CMakeLists.txt
|
||||
- name: Fetch Git Tags
|
||||
run: git fetch --prune --tags --unshallow
|
||||
- name: 'Install prerequisite: QT'
|
||||
run: |
|
||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
|
||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
|
||||
- name: 'Install prerequisite: Pre-built dependencies'
|
||||
run: |
|
||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
|
||||
7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps"
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir ./build
|
||||
mkdir ./build64
|
||||
cd ./build64
|
||||
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
|
||||
- name: Build
|
||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
|
||||
- name: Package
|
||||
if: success()
|
||||
run: |
|
||||
$env:FILE_DATE=(Get-Date -UFormat "%F")
|
||||
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win64.zip"
|
||||
echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
|
||||
robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\build\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
||||
7z a ${env:FILE_NAME} .\build\*
|
||||
- name: Publish
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: '${{ env.FILE_NAME }}'
|
||||
path: '*-win64.zip'
|
||||
win32:
|
||||
name: Windows 32-bit
|
||||
runs-on: [windows-latest]
|
||||
env:
|
||||
QT_VERSION: 5.10.1
|
||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||
steps:
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.0
|
||||
- name: Checkout obs
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: Checkout plugin
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
|
||||
- name: Add plugin to obs cmake
|
||||
shell: cmd
|
||||
run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> UI/frontend-plugins/CMakeLists.txt
|
||||
- name: Fetch Git Tags
|
||||
run: git fetch --prune --tags --unshallow
|
||||
- name: 'Install prerequisite: QT'
|
||||
run: |
|
||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
|
||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
|
||||
- name: 'Install prerequisite: Pre-built dependencies'
|
||||
run: |
|
||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
|
||||
7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps"
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir ./build
|
||||
mkdir ./build32
|
||||
cd ./build32
|
||||
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
|
||||
- name: Build
|
||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
|
||||
- name: Package
|
||||
if: success()
|
||||
run: |
|
||||
$env:FILE_DATE=(Get-Date -UFormat "%F")
|
||||
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win32.zip"
|
||||
echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
|
||||
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
|
||||
7z a ${env:FILE_NAME} .\build\*
|
||||
- name: Publish
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: '${{ env.FILE_NAME }}'
|
||||
path: '*-win32.zip'
|
||||
98
.gitignore
vendored
Normal file
98
.gitignore
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
# Prerequisites #
|
||||
#################
|
||||
*.d
|
||||
|
||||
# Object files #
|
||||
################
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
*.slo
|
||||
*.lo
|
||||
*.obj
|
||||
|
||||
# Linker output #
|
||||
#################
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers #
|
||||
#######################
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries #
|
||||
#############
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
*.lai
|
||||
|
||||
# Shared objects (inc. Windows DLLs) #
|
||||
######################################
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables #
|
||||
###############
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files #
|
||||
###############
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# CMake temp files #
|
||||
####################
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake_install
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
*.directory
|
||||
|
||||
# backup text files generated by an editor #
|
||||
############################################
|
||||
**/*~
|
||||
|
||||
# Various IDE Files #
|
||||
#####################
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
.idea
|
||||
.metadata
|
||||
*.iml
|
||||
*.ipr
|
||||
*.sublime*
|
||||
|
||||
# Directories #
|
||||
###############
|
||||
build/
|
||||
6
CI/macos/Brewfile
Normal file
6
CI/macos/Brewfile
Normal file
@@ -0,0 +1,6 @@
|
||||
brew "jack"
|
||||
brew "speexdsp"
|
||||
brew "cmake"
|
||||
brew "freetype"
|
||||
brew "fdk-aac"
|
||||
brew "https://gist.githubusercontent.com/DDRBoxman/9c7a2b08933166f4b61ed9a44b242609/raw/ef4de6c587c6bd7f50210eccd5bd51ff08e6de13/qt.rb"
|
||||
760
CI/macos/SceneSwitcher.pkgproj
Normal file
760
CI/macos/SceneSwitcher.pkgproj
Normal file
@@ -0,0 +1,760 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PROJECT</key>
|
||||
<dict>
|
||||
<key>PACKAGE_FILES</key>
|
||||
<dict>
|
||||
<key>DEFAULT_INSTALL_LOCATION</key>
|
||||
<string>/</string>
|
||||
<key>HIERARCHY</key>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>../../../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>bin</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>advanced-scene-switcher</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>plugins</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>obs-studio</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Application Support</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Automator</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Documentation</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Extensions</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Filesystems</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Frameworks</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Input Methods</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Internet Plug-Ins</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>LaunchAgents</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>LaunchDaemons</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>PreferencePanes</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Preferences</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Printers</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>PrivilegedHelperTools</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>1005</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>QuickLook</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>QuickTime</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Screen Savers</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Scripts</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Services</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Widgets</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Library</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Shared</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>1023</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Users</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Applications</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>509</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>/</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>PAYLOAD_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PRESERVE_EXTENDED_ATTRIBUTES</key>
|
||||
<false/>
|
||||
<key>SHOW_INVISIBLE</key>
|
||||
<false/>
|
||||
<key>SPLIT_FORKS</key>
|
||||
<true/>
|
||||
<key>TREAT_MISSING_FILES_AS_WARNING</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<integer>5</integer>
|
||||
</dict>
|
||||
<key>PACKAGE_SCRIPTS</key>
|
||||
<dict>
|
||||
<key>POSTINSTALL_PATH</key>
|
||||
<dict>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>PREINSTALL_PATH</key>
|
||||
<dict>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>RESOURCES</key>
|
||||
<array/>
|
||||
</dict>
|
||||
<key>PACKAGE_SETTINGS</key>
|
||||
<dict>
|
||||
<key>AUTHENTICATION</key>
|
||||
<integer>1</integer>
|
||||
<key>CONCLUSION_ACTION</key>
|
||||
<integer>0</integer>
|
||||
<key>FOLLOW_SYMBOLIC_LINKS</key>
|
||||
<false/>
|
||||
<key>IDENTIFIER</key>
|
||||
<string>com.warmuptill.SceneSwitcher</string>
|
||||
<key>LOCATION</key>
|
||||
<integer>0</integer>
|
||||
<key>NAME</key>
|
||||
<string></string>
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>PAYLOAD_SIZE</key>
|
||||
<integer>-1</integer>
|
||||
<key>REFERENCE_PATH</key>
|
||||
<string></string>
|
||||
<key>RELOCATABLE</key>
|
||||
<false/>
|
||||
<key>USE_HFS+_COMPRESSION</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>0.0.2</string>
|
||||
</dict>
|
||||
<key>PROJECT_COMMENTS</key>
|
||||
<dict>
|
||||
<key>NOTES</key>
|
||||
<data>
|
||||
PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M
|
||||
IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv
|
||||
c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l
|
||||
cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7
|
||||
IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250
|
||||
ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp
|
||||
dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u
|
||||
dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD
|
||||
b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE0MDQuMTMiPgo8c3R5bGUg
|
||||
dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5
|
||||
Pgo8L2JvZHk+CjwvaHRtbD4K
|
||||
</data>
|
||||
</dict>
|
||||
<key>PROJECT_SETTINGS</key>
|
||||
<dict>
|
||||
<key>BUILD_PATH</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>../..</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>EXCLUDED_FILES</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>PATTERNS_ARRAY</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.DS_Store</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PROTECTED</key>
|
||||
<true/>
|
||||
<key>PROXY_NAME</key>
|
||||
<string>Remove .DS_Store files</string>
|
||||
<key>PROXY_TOOLTIP</key>
|
||||
<string>Remove ".DS_Store" files created by the Finder.</string>
|
||||
<key>STATE</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>PATTERNS_ARRAY</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.pbdevelopment</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PROTECTED</key>
|
||||
<true/>
|
||||
<key>PROXY_NAME</key>
|
||||
<string>Remove .pbdevelopment files</string>
|
||||
<key>PROXY_TOOLTIP</key>
|
||||
<string>Remove ".pbdevelopment" files created by ProjectBuilder or Xcode.</string>
|
||||
<key>STATE</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>PATTERNS_ARRAY</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>CVS</string>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.cvsignore</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.cvspass</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.svn</string>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.git</string>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>.gitignore</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PROTECTED</key>
|
||||
<true/>
|
||||
<key>PROXY_NAME</key>
|
||||
<string>Remove SCM metadata</string>
|
||||
<key>PROXY_TOOLTIP</key>
|
||||
<string>Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems.</string>
|
||||
<key>STATE</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>PATTERNS_ARRAY</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>classes.nib</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>designable.db</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>info.nib</string>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PROTECTED</key>
|
||||
<true/>
|
||||
<key>PROXY_NAME</key>
|
||||
<string>Optimize nib files</string>
|
||||
<key>PROXY_TOOLTIP</key>
|
||||
<string>Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles.</string>
|
||||
<key>STATE</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>PATTERNS_ARRAY</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>REGULAR_EXPRESSION</key>
|
||||
<false/>
|
||||
<key>STRING</key>
|
||||
<string>Resources Disabled</string>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PROTECTED</key>
|
||||
<true/>
|
||||
<key>PROXY_NAME</key>
|
||||
<string>Remove Resources Disabled folders</string>
|
||||
<key>PROXY_TOOLTIP</key>
|
||||
<string>Remove "Resources Disabled" folders.</string>
|
||||
<key>STATE</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SEPARATOR</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NAME</key>
|
||||
<string>SceneSwitcher</string>
|
||||
<key>PAYLOAD_ONLY</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>VERSION</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
307
CMakeLists.txt
307
CMakeLists.txt
@@ -1,77 +1,230 @@
|
||||
project(advanced-scene-switcher)
|
||||
|
||||
if(APPLE)
|
||||
find_library(COCOA Cocoa)
|
||||
include_directories(${COCOA})
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
find_package(X11 REQUIRED)
|
||||
link_libraries(${X11_LIBRARIES})
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(advanced-scene-switcher_HEADERS
|
||||
${advanced-scene-switcher_HEADERS}
|
||||
advanced-scene-switcher.hpp
|
||||
switcher-data-structs.hpp
|
||||
utility.hpp
|
||||
)
|
||||
set(advanced-scene-switcher_SOURCES
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
advanced-scene-switcher.cpp
|
||||
advanced-scene-switcher-module.c
|
||||
scene-transitions.cpp
|
||||
screen-region-switch.cpp
|
||||
priority.cpp
|
||||
executable-switch.cpp
|
||||
idle-switch.cpp
|
||||
scene-round-trip.cpp
|
||||
file-switch.cpp
|
||||
window-title-switch.cpp
|
||||
hotkey.cpp
|
||||
general.cpp
|
||||
pause-switch.cpp
|
||||
)
|
||||
set(advanced-scene-switcher_UI
|
||||
${advanced-scene-switcher_UI}
|
||||
forms/advanced-scene-switcher.ui
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
advanced-scene-switcher-win.cpp)
|
||||
|
||||
elseif(APPLE)
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
advanced-scene-switcher-osx.mm)
|
||||
set_source_files_properties(advanced-scene-switcher-osx.mm
|
||||
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
||||
|
||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||
${COCOA})
|
||||
else()
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
advanced-scene-switcher-nix.cpp)
|
||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||
Xss)
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
||||
${advanced-scene-switcher_UI}
|
||||
${advanced-scene-switcher_PLATFORM_UI})
|
||||
|
||||
add_library(advanced-scene-switcher MODULE
|
||||
${advanced-scene-switcher_HEADERS}
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
${advanced-scene-switcher_UI_HEADERS}
|
||||
${advanced-scene-switcher_PLATFORM_SOURCES}
|
||||
${advanced-scene-switcher_PLATFORM_HEADERS}
|
||||
)
|
||||
target_link_libraries(advanced-scene-switcher
|
||||
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||
obs-frontend-api
|
||||
Qt5::Widgets
|
||||
libobs)
|
||||
|
||||
install_obs_plugin_with_data(advanced-scene-switcher data)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(advanced-scene-switcher)
|
||||
|
||||
if(BUILD_OUT_OF_TREE)
|
||||
# out of tree builds
|
||||
# credits to c3r1c3
|
||||
set(CMAKE_PREFIX_PATH "${QTDIR}")
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external")
|
||||
|
||||
include(external/FindLibObs.cmake)
|
||||
find_package(LibObs REQUIRED)
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
|
||||
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
|
||||
|
||||
if(APPLE)
|
||||
find_library(COCOA Cocoa)
|
||||
find_package(Qt5MacExtras REQUIRED)
|
||||
include_directories(${COCOA})
|
||||
add_link_options("-v")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(X11 REQUIRED)
|
||||
link_libraries(${X11_LIBRARIES})
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(advanced-scene-switcher_HEADERS
|
||||
${advanced-scene-switcher_HEADERS}
|
||||
src/headers/advanced-scene-switcher.hpp
|
||||
src/headers/switcher-data-structs.hpp
|
||||
src/headers/utility.hpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_SOURCES
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
src/advanced-scene-switcher.cpp
|
||||
src/advanced-scene-switcher-module.c
|
||||
src/scene-transitions.cpp
|
||||
src/screen-region-switch.cpp
|
||||
src/priority.cpp
|
||||
src/executable-switch.cpp
|
||||
src/idle-switch.cpp
|
||||
src/scene-round-trip.cpp
|
||||
src/file-switch.cpp
|
||||
src/window-title-switch.cpp
|
||||
src/media-switch.cpp
|
||||
src/hotkey.cpp
|
||||
src/general.cpp
|
||||
src/pause-switch.cpp
|
||||
src/random.cpp
|
||||
src/time-switch.cpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_UI
|
||||
${advanced-scene-switcher_UI}
|
||||
forms/advanced-scene-switcher.ui
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
src/win/advanced-scene-switcher-win.cpp)
|
||||
|
||||
elseif(APPLE)
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
src/osx/advanced-scene-switcher-osx.mm)
|
||||
set_source_files_properties(advanced-scene-switcher-osx.mm
|
||||
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||
${COCOA})
|
||||
|
||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
src/linux/advanced-scene-switcher-nix.cpp)
|
||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||
Xss)
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
||||
${advanced-scene-switcher_UI}
|
||||
${advanced-scene-switcher_PLATFORM_UI})
|
||||
|
||||
add_library(advanced-scene-switcher MODULE
|
||||
${advanced-scene-switcher_HEADERS}
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
${advanced-scene-switcher_UI_HEADERS}
|
||||
${advanced-scene-switcher_PLATFORM_SOURCES}
|
||||
${advanced-scene-switcher_PLATFORM_HEADERS}
|
||||
)
|
||||
|
||||
include_directories(
|
||||
"${LIBOBS_INCLUDE_DIRS}"
|
||||
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
|
||||
${Qt5Core_INCLUDES}
|
||||
${Qt5Widgets_INCLUDES})
|
||||
|
||||
target_link_libraries(advanced-scene-switcher
|
||||
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||
${LIBOBS_LIB}
|
||||
${LIBOBS_FRONTEND_API_LIB}
|
||||
Qt5::Core
|
||||
Qt5::Widgets)
|
||||
|
||||
# Additional commands to install the module in the correct place.
|
||||
# Find all the translation files so we can copy them to the correct
|
||||
# place later on.
|
||||
file(GLOB ASS_TRANSLATION_FILES
|
||||
"data/locale/*.ini"
|
||||
)
|
||||
|
||||
# Windows
|
||||
if(WIN32)
|
||||
string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
message("${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
|
||||
find_package(w32-pthreads REQUIRED)
|
||||
|
||||
target_link_libraries(advanced-scene-switcher
|
||||
w32-pthreads)
|
||||
endif()
|
||||
|
||||
# OSX
|
||||
if(APPLE)
|
||||
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
|
||||
|
||||
endif()
|
||||
|
||||
# Linux
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(CMAKE_C_FLAGS "-Wall -Wextra -Wvla -Wno-unused-function -Werror-implicit-function-declaration -Wno-missing-braces -Wno-missing-field-initializers ${CMAKE_C_FLAGS} -std=c99 -fno-strict-aliasing")
|
||||
|
||||
if(ARCH EQUAL 64)
|
||||
set(ARCH_NAME "x86_64")
|
||||
else()
|
||||
set(ARCH_NAME "i686")
|
||||
endif()
|
||||
|
||||
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
|
||||
|
||||
install(TARGETS advanced-scene-switcher
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/obs-plugins)
|
||||
install(FILES ${ASS_TRANSLATION_FILES}
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale")
|
||||
endif()
|
||||
else ()
|
||||
# in-tree build
|
||||
if(APPLE)
|
||||
find_library(COCOA Cocoa)
|
||||
include_directories(${COCOA})
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(X11 REQUIRED)
|
||||
link_libraries(${X11_LIBRARIES})
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(advanced-scene-switcher_HEADERS
|
||||
${advanced-scene-switcher_HEADERS}
|
||||
src/headers/advanced-scene-switcher.hpp
|
||||
src/headers/switcher-data-structs.hpp
|
||||
src/headers/utility.hpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_SOURCES
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
src/advanced-scene-switcher.cpp
|
||||
src/advanced-scene-switcher-module.c
|
||||
src/scene-transitions.cpp
|
||||
src/screen-region-switch.cpp
|
||||
src/priority.cpp
|
||||
src/executable-switch.cpp
|
||||
src/idle-switch.cpp
|
||||
src/scene-round-trip.cpp
|
||||
src/file-switch.cpp
|
||||
src/window-title-switch.cpp
|
||||
src/media-switch.cpp
|
||||
src/hotkey.cpp
|
||||
src/general.cpp
|
||||
src/pause-switch.cpp
|
||||
src/random.cpp
|
||||
src/time-switch.cpp
|
||||
)
|
||||
|
||||
set(advanced-scene-switcher_UI
|
||||
${advanced-scene-switcher_UI}
|
||||
forms/advanced-scene-switcher.ui
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
src/win/advanced-scene-switcher-win.cpp)
|
||||
elseif(APPLE)
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
src/osx/advanced-scene-switcher-osx.mm)
|
||||
set_source_files_properties(advanced-scene-switcher-osx.mm
|
||||
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||
${COCOA})
|
||||
else()
|
||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||
src/linux/advanced-scene-switcher-nix.cpp)
|
||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||
Xss)
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
||||
${advanced-scene-switcher_UI}
|
||||
${advanced-scene-switcher_PLATFORM_UI})
|
||||
|
||||
add_library(advanced-scene-switcher MODULE
|
||||
${advanced-scene-switcher_HEADERS}
|
||||
${advanced-scene-switcher_SOURCES}
|
||||
${advanced-scene-switcher_UI_HEADERS}
|
||||
${advanced-scene-switcher_PLATFORM_SOURCES}
|
||||
${advanced-scene-switcher_PLATFORM_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries(advanced-scene-switcher
|
||||
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||
obs-frontend-api
|
||||
Qt5::Widgets
|
||||
libobs)
|
||||
|
||||
install_obs_plugin(advanced-scene-switcher data)
|
||||
endif()
|
||||
|
||||
114
README.md
114
README.md
@@ -2,3 +2,117 @@
|
||||
An automated scene switcher for OBS Studio
|
||||
|
||||
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/
|
||||
|
||||
## Compiling in tree
|
||||
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
|
||||
```
|
||||
cd obs-studio/UI/frontend-plugins/
|
||||
git clone https://github.com/WarmUpTill/SceneSwitcher.git
|
||||
```
|
||||
|
||||
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt file and add an entry for the scene switcher:
|
||||
add_subdirectory(SceneSwitcher)
|
||||
|
||||
## Compiling out of tree
|
||||
### Prerequisites
|
||||
You'll need CMake and a working development environment for OBS Studio installed
|
||||
on your computer. Once you've done that, do the following:
|
||||
```
|
||||
git clone https://github.com/WarmUpTill/SceneSwitcher.git
|
||||
cd SceneSwitcher
|
||||
mkdir build && cd build
|
||||
```
|
||||
|
||||
### Windows
|
||||
In cmake-gui, you'll have to set these CMake variables :
|
||||
- **BUILD_OUT_OF_TREE** (bool) : true
|
||||
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
|
||||
code of OBS Studio, located at [source_directory]/libobs/.
|
||||
- **LIBOBS_LIB** (filepath) : location of the obs.dll file (usually set to
|
||||
C:\Program Files\obs-studio\bin\64bit\obs.dll)
|
||||
|
||||
Assuming that you installed Qt via the regular Qt App way:
|
||||
- **Qt5Core_DIR** (path) : C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Core
|
||||
- **Qt5Gui_DIR** (path): C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Gui
|
||||
- **Qt5Widgets_DIR** (path) : C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Widgets
|
||||
|
||||
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.dll
|
||||
file, usually C:/Program Files/obs-studio/bin/64bit/obs-frontend-api.dll
|
||||
(usually in the same place as LIBOBS_LIB)
|
||||
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
|
||||
subfolder in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
|
||||
|
||||
Just keep hitting configure until all the vars are filled out. Then hit generate.
|
||||
|
||||
### Linux
|
||||
Most versions of Linux you can use cmake-gui or the command line.
|
||||
|
||||
**For the command line:**
|
||||
```
|
||||
cmake -DBUILD_OUT_OF_TREE=1 -DLIBOBS_INCLUDE_DIR="<path to the libobs/ sub-folder in obs-studio's source code>"
|
||||
-DLIBOBS_FRONTEND_INCLUDE_DIR="<path to the UI/obs-frontend-api/ sub-folder in obs-studio's source code>"
|
||||
-DLIBOBS_FRONTEND_API_LIB="< path to the libobs-frontend-api.so file (usually in the same place as LIBOBS_LIB)>"
|
||||
-DCMAKE_INSTALL_PREFIX=/usr ..
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
|
||||
For cmake-gui you'll have to set the following variables:
|
||||
- **BUILD_OUT_OF_TREE** (bool) : true
|
||||
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
|
||||
code of OBS Studio, located at [source_directory]/libobs/.
|
||||
- **LIBOBS_LIB** (filepath) : location of the libobs.so file (usually CMake finds
|
||||
this, but if not it'll usually be in /usr/lib/libobs.so)
|
||||
|
||||
Assuming that you installed Qt via your system package manager, it should be
|
||||
found automatically. If not, then usually you'll find it in something like:
|
||||
- **Qt5Core_DIR** (path) : /usr/lib64/cmake/Qt5Core
|
||||
- **Qt5Gui_DIR** (path): /usr/lib64/cmake/Qt5Gui
|
||||
- **Qt5Widgets_DIR** (path) : /usr/lib64/cmake/Qt5Widgets
|
||||
|
||||
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.so
|
||||
file (usually in the same place as LIBOBS_LIB)
|
||||
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
|
||||
subfolder in the source code of OBS Studio, located at
|
||||
[source_directory]/UI/obs-frontend-api.
|
||||
|
||||
Just keep hitting configure until all the vars are filled out. Then hit generate.
|
||||
|
||||
Then open a terminal in the build folder and type:
|
||||
```
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
NOTE: The Linux version of this plugin is dependent on libXScrnSaver.
|
||||
|
||||
### OS X
|
||||
In cmake-gui, you'll have to set these CMake variables :
|
||||
- **BUILD_OUT_OF_TREE** (bool) : true
|
||||
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
|
||||
code of OBS Studio, located at [source_directory]/libobs/.
|
||||
- **LIBOBS_LIB** (filepath) : location of the libobs.0.dylib file (usually
|
||||
in /Applications/OBS.app/Contents/Resources/bin/libobs.0.dylib)
|
||||
|
||||
Assuming that you installed Qt via the regular Qt App way:
|
||||
- **Qt5Core_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Core
|
||||
- **Qt5Widgets_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Widgets
|
||||
- **Qt5MacExtras_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5MacExtras
|
||||
|
||||
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.0.dylib
|
||||
file (usually in usually in /Applications/OBS.app/Contents/Resources/bin/libobs-frontend-api.0.dylib)
|
||||
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api subfolder
|
||||
in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
|
||||
|
||||
Just keep hitting configure until all the vars are filled out. Then hit generate.
|
||||
|
||||
Open xcode (or a terminal, depending on the build type you chose), build and copy
|
||||
the advanced-scene-switcher.so file to /Applications/OBS.app/Contents/PlugIns
|
||||
|
||||
Note that you might have to adjust the library search paths using the install_name_tool if you want the plugin to run on machines other than your build machine:
|
||||
```
|
||||
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib 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 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 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 UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
|
||||
```
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
107
external/FindLibObs.cmake
vendored
Normal file
107
external/FindLibObs.cmake
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
# This module can be copied and used by external plugins for OBS
|
||||
#
|
||||
# Once done these will be defined:
|
||||
#
|
||||
# LIBOBS_FOUND
|
||||
# LIBOBS_INCLUDE_DIRS
|
||||
# LIBOBS_LIBRARIES
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(_OBS QUIET obs libobs)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_lib_suffix 64)
|
||||
else()
|
||||
set(_lib_suffix 32)
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_BUILD_TYPE)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(_build_type_base "debug")
|
||||
else()
|
||||
set(_build_type_base "release")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_path(LIBOBS_INCLUDE_DIR
|
||||
NAMES obs.h
|
||||
HINTS
|
||||
ENV obsPath${_lib_suffix}
|
||||
ENV obsPath
|
||||
${obsPath}
|
||||
PATHS
|
||||
/usr/include /usr/local/include /opt/local/include /sw/include
|
||||
PATH_SUFFIXES
|
||||
libobs
|
||||
)
|
||||
|
||||
function(find_obs_lib base_name repo_build_path lib_name)
|
||||
string(TOUPPER "${base_name}" base_name_u)
|
||||
|
||||
if(DEFINED _build_type_base)
|
||||
set(_build_type_${repo_build_path} "${_build_type_base}/${repo_build_path}")
|
||||
set(_build_type_${repo_build_path}${_lib_suffix} "${_build_type_base}${_lib_suffix}/${repo_build_path}")
|
||||
endif()
|
||||
|
||||
find_library(${base_name_u}_LIB
|
||||
NAMES ${_${base_name_u}_LIBRARIES} ${lib_name} lib${lib_name}
|
||||
HINTS
|
||||
ENV obsPath${_lib_suffix}
|
||||
ENV obsPath
|
||||
${obsPath}
|
||||
${_${base_name_u}_LIBRARY_DIRS}
|
||||
PATHS
|
||||
/usr/lib /usr/local/lib /opt/local/lib /sw/lib
|
||||
PATH_SUFFIXES
|
||||
lib${_lib_suffix} lib
|
||||
libs${_lib_suffix} libs
|
||||
bin${_lib_suffix} bin
|
||||
../lib${_lib_suffix} ../lib
|
||||
../libs${_lib_suffix} ../libs
|
||||
../bin${_lib_suffix} ../bin
|
||||
# base repo non-msvc-specific search paths
|
||||
${_build_type_${repo_build_path}}
|
||||
${_build_type_${repo_build_path}${_lib_suffix}}
|
||||
build/${repo_build_path}
|
||||
build${_lib_suffix}/${repo_build_path}
|
||||
# base repo msvc-specific search paths on windows
|
||||
build${_lib_suffix}/${repo_build_path}/Debug
|
||||
build${_lib_suffix}/${repo_build_path}/RelWithDebInfo
|
||||
build/${repo_build_path}/Debug
|
||||
build/${repo_build_path}/RelWithDebInfo
|
||||
)
|
||||
endfunction()
|
||||
|
||||
find_obs_lib(LIBOBS libobs obs)
|
||||
|
||||
if(MSVC)
|
||||
find_obs_lib(W32_PTHREADS deps/w32-pthreads w32-pthreads)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Libobs DEFAULT_MSG LIBOBS_LIB LIBOBS_INCLUDE_DIR)
|
||||
mark_as_advanced(LIBOBS_INCLUDE_DIR LIBOBS_LIB)
|
||||
|
||||
if(LIBOBS_FOUND)
|
||||
if(MSVC)
|
||||
if (NOT DEFINED W32_PTHREADS_LIB)
|
||||
message(FATAL_ERROR "Could not find the w32-pthreads library" )
|
||||
endif()
|
||||
|
||||
set(W32_PTHREADS_INCLUDE_DIR ${LIBOBS_INCLUDE_DIR}/../deps/w32-pthreads)
|
||||
endif()
|
||||
|
||||
set(LIBOBS_INCLUDE_DIRS ${LIBOBS_INCLUDE_DIR} ${W32_PTHREADS_INCLUDE_DIR})
|
||||
set(LIBOBS_LIBRARIES ${LIBOBS_LIB} ${W32_PTHREADS_LIB})
|
||||
include(${LIBOBS_INCLUDE_DIR}/../cmake/external/ObsPluginHelpers.cmake)
|
||||
|
||||
# allows external plugins to easily use/share common dependencies that are often included with libobs (such as FFmpeg)
|
||||
if(NOT DEFINED INCLUDED_LIBOBS_CMAKE_MODULES)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LIBOBS_INCLUDE_DIR}/../cmake/Modules/")
|
||||
set(INCLUDED_LIBOBS_CMAKE_MODULES true)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find the libobs library" )
|
||||
endif()
|
||||
163
external/ObsPluginHelpers.cmake
vendored
Normal file
163
external/ObsPluginHelpers.cmake
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
# Functions for generating external plugins
|
||||
|
||||
set(EXTERNAL_PLUGIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/rundir")
|
||||
|
||||
# Fix XCode includes to ignore warnings on system includes
|
||||
function(target_include_directories_system _target)
|
||||
if(XCODE)
|
||||
foreach(_arg ${ARGN})
|
||||
if("${_arg}" STREQUAL "PRIVATE" OR "${_arg}" STREQUAL "PUBLIC" OR "${_arg}" STREQUAL "INTERFACE")
|
||||
set(_scope ${_arg})
|
||||
else()
|
||||
target_compile_options(${_target} ${_scope} -isystem${_arg})
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
target_include_directories(${_target} SYSTEM ${_scope} ${ARGN})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(install_external_plugin_data_internal target source_dir target_dir)
|
||||
install(DIRECTORY ${source_dir}/
|
||||
DESTINATION "${target}/${target_dir}"
|
||||
USE_SOURCE_PERMISSIONS)
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${source_dir}" "${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/${target_dir}"
|
||||
VERBATIM)
|
||||
endfunction()
|
||||
|
||||
# Installs data
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'data_loc' specifies the directory of the data
|
||||
function(install_external_plugin_data target data_loc)
|
||||
install_external_plugin_data_internal(${target} ${data_loc} "data")
|
||||
endfunction()
|
||||
|
||||
# Installs data in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'data_loc' specifies the directory of the data being installed
|
||||
function(install_external_plugin_arch_data target data_loc)
|
||||
if(APPLE)
|
||||
set(_bit_suffix "")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_bit_suffix "/64bit")
|
||||
else()
|
||||
set(_bit_suffix "/32bit")
|
||||
endif()
|
||||
|
||||
install_external_plugin_data_internal(${target} ${data_loc} "data${_bit_suffix}")
|
||||
endfunction()
|
||||
|
||||
# Installs data in the target's bin directory
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'data_loc' specifies the directory of the data being installed
|
||||
function(install_external_plugin_data_to_bin target data_loc)
|
||||
if(APPLE)
|
||||
set(_bit_suffix "")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_bit_suffix "/64bit")
|
||||
else()
|
||||
set(_bit_suffix "/32bit")
|
||||
endif()
|
||||
|
||||
install_external_plugin_data_internal(${target} ${data_loc} "bin${_bit_suffix}")
|
||||
endfunction()
|
||||
|
||||
# Installs an additional binary to a target
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'additional_target' specifies the additional binary
|
||||
function(install_external_plugin_additional target additional_target)
|
||||
if(APPLE)
|
||||
set(_bit_suffix "")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_bit_suffix "64bit/")
|
||||
else()
|
||||
set(_bit_suffix "32bit/")
|
||||
endif()
|
||||
|
||||
set_target_properties(${additional_target} PROPERTIES
|
||||
PREFIX "")
|
||||
|
||||
install(TARGETS ${additional_target}
|
||||
LIBRARY DESTINATION "bin"
|
||||
RUNTIME DESTINATION "bin")
|
||||
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:${additional_target}>"
|
||||
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/bin/${_bit_suffix}$<TARGET_FILE_NAME:${additional_target}>"
|
||||
VERBATIM)
|
||||
endfunction()
|
||||
|
||||
# Installs the binary of the target
|
||||
# 'target' is the target project being installed
|
||||
function(install_external_plugin target)
|
||||
install_external_plugin_additional(${target} ${target})
|
||||
endfunction()
|
||||
|
||||
# Installs the binary and data of the target
|
||||
# 'target' is the destination target project being installed to
|
||||
function(install_external_plugin_with_data target data_loc)
|
||||
install_external_plugin(${target})
|
||||
install_external_plugin_data(${target} ${data_loc})
|
||||
endfunction()
|
||||
|
||||
# Installs an additional binary to the data of a target
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'additional_target' specifies the additional binary
|
||||
function(install_external_plugin_bin_to_data target additional_target)
|
||||
install(TARGETS ${additional_target}
|
||||
LIBRARY DESTINATION "data"
|
||||
RUNTIME DESTINATION "data")
|
||||
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:${additional_target}>"
|
||||
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data/$<TARGET_FILE_NAME:${additional_target}>"
|
||||
VERBATIM)
|
||||
endfunction()
|
||||
|
||||
# Installs an additional binary in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'additional_target' specifies the additional binary
|
||||
function(install_external_plugin_bin_to_arch_data target additional_target)
|
||||
if(APPLE)
|
||||
set(_bit_suffix "")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_bit_suffix "/64bit")
|
||||
else()
|
||||
set(_bit_suffix "/32bit")
|
||||
endif()
|
||||
|
||||
install(TARGETS ${additional_target}
|
||||
LIBRARY DESTINATION "data${_bit_suffix}"
|
||||
RUNTIME DESTINATION "data${_bit_suffix}")
|
||||
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:${additional_target}>"
|
||||
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data${_bit_suffix}/$<TARGET_FILE_NAME:${additional_target}>"
|
||||
VERBATIM)
|
||||
endfunction()
|
||||
|
||||
# Installs an additional file in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
|
||||
# 'target' is the destination target project being installed to
|
||||
# 'additional_target' specifies the additional binary
|
||||
function(install_external_plugin_data_file_to_arch_data target additional_target file_target)
|
||||
if(APPLE)
|
||||
set(_bit_suffix "")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_bit_suffix "/64bit")
|
||||
else()
|
||||
set(_bit_suffix "/32bit")
|
||||
endif()
|
||||
|
||||
get_filename_component(file_target_name ${file_target} NAME)
|
||||
|
||||
install(TARGETS ${additional_target}
|
||||
LIBRARY DESTINATION "data${_bit_suffix}"
|
||||
RUNTIME DESTINATION "data${_bit_suffix}")
|
||||
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"${file_target}"
|
||||
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data${_bit_suffix}/${file_target_name}"
|
||||
VERBATIM)
|
||||
endfunction()
|
||||
113
file-switch.cpp
113
file-switch.cpp
@@ -1,113 +0,0 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <obs.hpp>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
|
||||
|
||||
void SceneSwitcher::on_browseButton_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!directory.isEmpty())
|
||||
ui->writePathLineEdit->setText(directory);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (!state)
|
||||
{
|
||||
ui->browseButton_2->setDisabled(true);
|
||||
ui->readPathLineEdit->setDisabled(true);
|
||||
switcher->fileIO.readEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->browseButton_2->setDisabled(false);
|
||||
ui->readPathLineEdit->setDisabled(false);
|
||||
switcher->fileIO.readEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (text.isEmpty())
|
||||
{
|
||||
switcher->fileIO.readEnabled = false;
|
||||
return;
|
||||
}
|
||||
switcher->fileIO.readEnabled = true;
|
||||
switcher->fileIO.readPath = text.toUtf8().constData();
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (text.isEmpty())
|
||||
{
|
||||
switcher->fileIO.writeEnabled = false;
|
||||
return;
|
||||
}
|
||||
switcher->fileIO.writeEnabled = true;
|
||||
switcher->fileIO.writePath = text.toUtf8().constData();
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_browseButton_2_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!directory.isEmpty())
|
||||
ui->readPathLineEdit->setText(directory);
|
||||
}
|
||||
|
||||
void SwitcherData::writeSceneInfoToFile()
|
||||
{
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.writePath));
|
||||
if (file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
const char* msg = obs_source_get_name(currentSource);
|
||||
file.write(msg, qstrlen(msg));
|
||||
file.close();
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
}
|
||||
|
||||
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
|
||||
|
||||
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
if (!fileIO.readEnabled)
|
||||
return;
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.readPath));
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QString sceneStr = in.readLine();
|
||||
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
|
||||
if (sceneRead){
|
||||
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
|
||||
|
||||
match = true;
|
||||
scene = sceneReadWs;
|
||||
transition = nullptr;
|
||||
|
||||
obs_weak_source_release(sceneReadWs);
|
||||
obs_source_release(sceneRead);
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
72
hotkey.cpp
72
hotkey.cpp
@@ -1,72 +0,0 @@
|
||||
#include <obs-module.h>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
switcher->Stop();
|
||||
else
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||
|
||||
if (hotkeyData != NULL)
|
||||
{
|
||||
char* path = obs_module_config_path("");
|
||||
ofstream file;
|
||||
file.open(string(path).append("hotkey.txt"), ofstream::trunc);
|
||||
if (file.is_open())
|
||||
{
|
||||
size_t num = obs_data_array_count(hotkeyData);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
{
|
||||
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||
string temp = obs_data_get_json(data);
|
||||
obs_data_release(data);
|
||||
file << temp;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
bfree(path);
|
||||
}
|
||||
obs_data_array_release(hotkeyData);
|
||||
}
|
||||
|
||||
string loadConfigFile(string filename)
|
||||
{
|
||||
ifstream settingsFile;
|
||||
char* path = obs_module_config_path("");
|
||||
string value;
|
||||
|
||||
settingsFile.open(string(path).append(filename));
|
||||
if (settingsFile.is_open())
|
||||
{
|
||||
settingsFile.seekg(0, ios::end);
|
||||
value.reserve(settingsFile.tellg());
|
||||
settingsFile.seekg(0, ios::beg);
|
||||
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
|
||||
settingsFile.close();
|
||||
}
|
||||
bfree(path);
|
||||
return value;
|
||||
}
|
||||
|
||||
void loadKeybinding(obs_hotkey_id hotkeyId)
|
||||
{
|
||||
string bindings = loadConfigFile("hotkey.txt");
|
||||
if (!bindings.empty())
|
||||
{
|
||||
obs_data_array_t* hotkeyData = obs_data_array_create();
|
||||
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
|
||||
obs_data_array_insert(hotkeyData, 0, data);
|
||||
obs_data_release(data);
|
||||
obs_hotkey_load(hotkeyId, hotkeyData);
|
||||
obs_data_array_release(hotkeyData);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
#include <obs-module.h>
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
|
||||
|
||||
void InitSceneSwitcher();
|
||||
void FreeSceneSwitcher();
|
||||
|
||||
bool obs_module_load(void)
|
||||
{
|
||||
InitSceneSwitcher();
|
||||
return true;
|
||||
}
|
||||
|
||||
void obs_module_unload(void)
|
||||
{
|
||||
FreeSceneSwitcher();
|
||||
}
|
||||
#include <obs-module.h>
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
|
||||
void InitSceneSwitcher();
|
||||
void FreeSceneSwitcher();
|
||||
|
||||
bool obs_module_load(void)
|
||||
{
|
||||
InitSceneSwitcher();
|
||||
return true;
|
||||
}
|
||||
|
||||
void obs_module_unload(void)
|
||||
{
|
||||
FreeSceneSwitcher();
|
||||
}
|
||||
1635
src/advanced-scene-switcher.cpp
Normal file
1635
src/advanced-scene-switcher.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,140 +1,140 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
int SceneSwitcher::executableFindByData(const QString& exe)
|
||||
{
|
||||
int count = ui->executables->count();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->executables->item(i);
|
||||
QString itemExe = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemExe == exe)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_executables_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->executables->item(idx);
|
||||
|
||||
QString exec = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->executableSwitches)
|
||||
{
|
||||
if (exec.compare(s.mExe) == 0)
|
||||
{
|
||||
QString sceneName = GetWeakSourceName(s.mScene).c_str();
|
||||
QString transitionName = GetWeakSourceName(s.mTransition).c_str();
|
||||
ui->executableScenes->setCurrentText(sceneName);
|
||||
ui->executable->setCurrentText(exec);
|
||||
ui->executableTransitions->setCurrentText(transitionName);
|
||||
ui->requiresFocusCheckBox->setChecked(s.mInFocus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_executableAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->executableScenes->currentText();
|
||||
QString exeName = ui->executable->currentText();
|
||||
QString transitionName = ui->executableTransitions->currentText();
|
||||
bool inFocus = ui->requiresFocusCheckBox->isChecked();
|
||||
|
||||
if (exeName.isEmpty() || sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
QVariant v = QVariant::fromValue(exeName);
|
||||
|
||||
QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus);
|
||||
|
||||
int idx = executableFindByData(exeName);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->executableSwitches.emplace_back(
|
||||
source, transition, exeName.toUtf8().constData(), inFocus);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->executables);
|
||||
item->setData(Qt::UserRole, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->executables->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->executableSwitches)
|
||||
{
|
||||
if (s.mExe == exeName)
|
||||
{
|
||||
s.mScene = source;
|
||||
s.mTransition = transition;
|
||||
s.mInFocus = inFocus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->executables->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_executableRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->executables->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString exe = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->executableSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.mExe == exe)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
QStringList runningProcesses;
|
||||
GetProcessList(runningProcesses);
|
||||
for (ExecutableSceneSwitch& s : executableSwitches)
|
||||
{
|
||||
if (runningProcesses.contains(s.mExe))
|
||||
{
|
||||
scene = s.mScene;
|
||||
transition = s.mTransition;
|
||||
match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
int SceneSwitcher::executableFindByData(const QString& exe)
|
||||
{
|
||||
int count = ui->executables->count();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->executables->item(i);
|
||||
QString itemExe = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemExe == exe)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_executables_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->executables->item(idx);
|
||||
|
||||
QString exec = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->executableSwitches)
|
||||
{
|
||||
if (exec.compare(s.mExe) == 0)
|
||||
{
|
||||
QString sceneName = GetWeakSourceName(s.mScene).c_str();
|
||||
QString transitionName = GetWeakSourceName(s.mTransition).c_str();
|
||||
ui->executableScenes->setCurrentText(sceneName);
|
||||
ui->executable->setCurrentText(exec);
|
||||
ui->executableTransitions->setCurrentText(transitionName);
|
||||
ui->requiresFocusCheckBox->setChecked(s.mInFocus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_executableAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->executableScenes->currentText();
|
||||
QString exeName = ui->executable->currentText();
|
||||
QString transitionName = ui->executableTransitions->currentText();
|
||||
bool inFocus = ui->requiresFocusCheckBox->isChecked();
|
||||
|
||||
if (exeName.isEmpty() || sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
QVariant v = QVariant::fromValue(exeName);
|
||||
|
||||
QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus);
|
||||
|
||||
int idx = executableFindByData(exeName);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->executableSwitches.emplace_back(
|
||||
source, transition, exeName.toUtf8().constData(), inFocus);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->executables);
|
||||
item->setData(Qt::UserRole, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->executables->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->executableSwitches)
|
||||
{
|
||||
if (s.mExe == exeName)
|
||||
{
|
||||
s.mScene = source;
|
||||
s.mTransition = transition;
|
||||
s.mInFocus = inFocus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->executables->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_executableRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->executables->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString exe = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->executableSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.mExe == exe)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
QStringList runningProcesses;
|
||||
GetProcessList(runningProcesses);
|
||||
for (ExecutableSceneSwitch& s : executableSwitches)
|
||||
{
|
||||
if (runningProcesses.contains(s.mExe))
|
||||
{
|
||||
scene = s.mScene;
|
||||
transition = s.mTransition;
|
||||
match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
254
src/file-switch.cpp
Normal file
254
src/file-switch.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <obs.hpp>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
|
||||
|
||||
void SceneSwitcher::on_browseButton_clicked()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!path.isEmpty())
|
||||
ui->writePathLineEdit->setText(path);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (!state)
|
||||
{
|
||||
ui->browseButton_2->setDisabled(true);
|
||||
ui->readPathLineEdit->setDisabled(true);
|
||||
switcher->fileIO.readEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->browseButton_2->setDisabled(false);
|
||||
ui->readPathLineEdit->setDisabled(false);
|
||||
switcher->fileIO.readEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (text.isEmpty())
|
||||
{
|
||||
switcher->fileIO.readEnabled = false;
|
||||
return;
|
||||
}
|
||||
switcher->fileIO.readEnabled = true;
|
||||
switcher->fileIO.readPath = text.toUtf8().constData();
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (text.isEmpty())
|
||||
{
|
||||
switcher->fileIO.writeEnabled = false;
|
||||
return;
|
||||
}
|
||||
switcher->fileIO.writeEnabled = true;
|
||||
switcher->fileIO.writePath = text.toUtf8().constData();
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_browseButton_2_clicked()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
|
||||
if (!path.isEmpty())
|
||||
ui->readPathLineEdit->setText(path);
|
||||
}
|
||||
|
||||
void SwitcherData::writeSceneInfoToFile()
|
||||
{
|
||||
if (!fileIO.writeEnabled || fileIO.writePath.empty())
|
||||
return;
|
||||
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.writePath));
|
||||
if (file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
const char* msg = obs_source_get_name(currentSource);
|
||||
file.write(msg, qstrlen(msg));
|
||||
file.close();
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
}
|
||||
|
||||
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
if (!fileIO.readEnabled || fileIO.readPath.empty())
|
||||
return;
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.readPath));
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QString sceneStr = in.readLine();
|
||||
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
|
||||
if (sceneRead){
|
||||
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
|
||||
|
||||
match = true;
|
||||
scene = sceneReadWs;
|
||||
transition = nullptr;
|
||||
|
||||
obs_weak_source_release(sceneReadWs);
|
||||
obs_source_release(sceneRead);
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
for (FileSwitch& s : fileSwitches)
|
||||
{
|
||||
bool equal = false;
|
||||
QString t = QString::fromStdString(s.text);
|
||||
QFile file(QString::fromStdString(s.file));
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
continue;
|
||||
|
||||
if (s.useTime)
|
||||
{
|
||||
QDateTime newLastMod = QFileInfo(file).lastModified();
|
||||
if (s.lastMod == newLastMod)
|
||||
continue;
|
||||
s.lastMod = newLastMod;
|
||||
}
|
||||
|
||||
if (s.useRegex)
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QRegExp rx(t);
|
||||
equal = rx.exactMatch(in.readAll());
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Im using QTextStream here so the conversion between different lineendings is done by QT.
|
||||
*QT itself uses only the linefeed internally so the input by the user is always using that,
|
||||
*but the files selected by the user might use different line endings.
|
||||
*If you are reading this and know of a cleaner way to do this, please let me know :)
|
||||
*/
|
||||
QTextStream in(&file);
|
||||
QTextStream text(&t);
|
||||
while (!in.atEnd() && !text.atEnd())
|
||||
{
|
||||
QString fileLine = in.readLine();
|
||||
QString textLine = text.readLine();
|
||||
if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0)
|
||||
{
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
equal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
|
||||
if (equal)
|
||||
{
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
match = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_browseButton_3_clicked()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
|
||||
if (!path.isEmpty())
|
||||
ui->filePathLineEdit->setText(path);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_fileAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->fileScenes->currentText();
|
||||
QString transitionName = ui->fileTransitions->currentText();
|
||||
QString fileName = ui->filePathLineEdit->text();
|
||||
QString text = ui->fileTextEdit->toPlainText();
|
||||
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
|
||||
bool useTime = ui->fileContentTimeCheckBox->isChecked();
|
||||
|
||||
if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime);
|
||||
QVariant v = QVariant::fromValue(switchText);
|
||||
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->fileSwitches.emplace_back(
|
||||
source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime);
|
||||
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_fileRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->fileScenesList->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
int idx = ui->fileScenesList->currentRow();
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
auto& switches = switcher->fileSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
qDeleteAll(ui->fileScenesList->selectedItems());
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
if (switcher->fileSwitches.size() <= idx)
|
||||
return;
|
||||
FileSwitch s = switcher->fileSwitches[idx];
|
||||
|
||||
string sceneName = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
|
||||
ui->fileScenes->setCurrentText(sceneName.c_str());
|
||||
ui->fileTransitions->setCurrentText(transitionName.c_str());
|
||||
ui->fileTextEdit->setPlainText(s.text.c_str());
|
||||
ui->filePathLineEdit->setText(s.file.c_str());
|
||||
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
|
||||
ui->fileContentTimeCheckBox->setChecked(s.useTime);
|
||||
}
|
||||
@@ -1,95 +1,107 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include <obs-module.h>
|
||||
|
||||
void SceneSwitcher::on_close_clicked()
|
||||
{
|
||||
done(0);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->startAtLaunch = value;
|
||||
}
|
||||
|
||||
void SceneSwitcher::UpdateNonMatchingScene(const QString& name)
|
||||
{
|
||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = false;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = true;
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateNonMatchingScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->interval = value;
|
||||
}
|
||||
|
||||
void SceneSwitcher::SetStarted()
|
||||
{
|
||||
ui->toggleStartButton->setText(obs_module_text("Stop"));
|
||||
ui->pluginRunningText->setText(obs_module_text("Active"));
|
||||
}
|
||||
|
||||
void SceneSwitcher::SetStopped()
|
||||
{
|
||||
ui->toggleStartButton->setText(obs_module_text("Start"));
|
||||
ui->pluginRunningText->setText(obs_module_text("Inactive"));
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_toggleStartButton_clicked()
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
{
|
||||
switcher->Stop();
|
||||
SetStopped();
|
||||
}
|
||||
else
|
||||
{
|
||||
switcher->Start();
|
||||
SetStarted();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::closeEvent(QCloseEvent*)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include <obs-module.h>
|
||||
|
||||
void SceneSwitcher::on_close_clicked()
|
||||
{
|
||||
done(0);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->startAtLaunch = value;
|
||||
}
|
||||
|
||||
void SceneSwitcher::UpdateNonMatchingScene(const QString& name)
|
||||
{
|
||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = NO_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateNonMatchingScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->interval = value;
|
||||
}
|
||||
|
||||
void SceneSwitcher::SetStarted()
|
||||
{
|
||||
ui->toggleStartButton->setText("Stop");
|
||||
ui->pluginRunningText->setText("Active");
|
||||
}
|
||||
|
||||
void SceneSwitcher::SetStopped()
|
||||
{
|
||||
ui->toggleStartButton->setText("Start");
|
||||
ui->pluginRunningText->setText("Inactive");
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_toggleStartButton_clicked()
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
{
|
||||
switcher->Stop();
|
||||
SetStopped();
|
||||
}
|
||||
else
|
||||
{
|
||||
switcher->Start();
|
||||
SetStarted();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::closeEvent(QCloseEvent*)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
@@ -1,123 +1,192 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "ui_advanced-scene-switcher.h"
|
||||
#include "switcher-data-structs.hpp"
|
||||
|
||||
struct obs_weak_source;
|
||||
typedef struct obs_weak_source obs_weak_source_t;
|
||||
|
||||
class QCloseEvent;
|
||||
|
||||
class SceneSwitcher : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
std::unique_ptr<Ui_SceneSwitcher> ui;
|
||||
bool loading = true;
|
||||
|
||||
SceneSwitcher(QWidget *parent);
|
||||
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
void SetStarted();
|
||||
void SetStopped();
|
||||
|
||||
int FindByData(const QString &window);
|
||||
int ScreenRegionFindByData(const QString ®ion);
|
||||
int PauseScenesFindByData(const QString &scene);
|
||||
int PauseWindowsFindByData(const QString &window);
|
||||
int IgnoreWindowsFindByData(const QString &window);
|
||||
int SceneRoundTripFindByData(const QString &scene1);
|
||||
int SceneTransitionsFindByData(const QString &scene1, const QString &scene2);
|
||||
int DefaultTransitionsFindByData(const QString &scene);
|
||||
int executableFindByData(const QString &exe);
|
||||
int IgnoreIdleWindowsFindByData(const QString& window);
|
||||
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void UpdateAutoStopScene(const QString &name);
|
||||
void UpdateIdleDataTransition(const QString& name);
|
||||
void UpdateIdleDataScene(const QString& name);
|
||||
|
||||
public slots:
|
||||
void on_switches_currentRowChanged(int idx);
|
||||
void on_add_clicked();
|
||||
void on_remove_clicked();
|
||||
void on_noMatchDontSwitch_clicked();
|
||||
void on_noMatchSwitch_clicked();
|
||||
void on_startAtLaunch_toggled(bool value);
|
||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_toggleStartButton_clicked();
|
||||
|
||||
void on_screenRegions_currentRowChanged(int idx);
|
||||
void on_screenRegionAdd_clicked();
|
||||
void on_screenRegionRemove_clicked();
|
||||
|
||||
void on_pauseScenes_currentRowChanged(int idx);
|
||||
void on_pauseScenesAdd_clicked();
|
||||
void on_pauseScenesRemove_clicked();
|
||||
|
||||
void on_pauseWindows_currentRowChanged(int idx);
|
||||
void on_pauseWindowsAdd_clicked();
|
||||
void on_pauseWindowsRemove_clicked();
|
||||
|
||||
void on_ignoreWindows_currentRowChanged(int idx);
|
||||
void on_ignoreWindowsAdd_clicked();
|
||||
void on_ignoreWindowsRemove_clicked();
|
||||
|
||||
void on_sceneRoundTrips_currentRowChanged(int idx);
|
||||
void on_sceneRoundTripAdd_clicked();
|
||||
void on_sceneRoundTripRemove_clicked();
|
||||
void on_sceneRoundTripSave_clicked();
|
||||
void on_sceneRoundTripLoad_clicked();
|
||||
|
||||
void on_autoStopSceneCheckBox_stateChanged(int state);
|
||||
void on_autoStopScenes_currentTextChanged(const QString &text);
|
||||
|
||||
void on_sceneTransitions_currentRowChanged(int idx);
|
||||
void on_transitionsAdd_clicked();
|
||||
void on_transitionsRemove_clicked();
|
||||
void on_defaultTransitions_currentRowChanged(int idx);
|
||||
void on_defaultTransitionsAdd_clicked();
|
||||
void on_defaultTransitionsRemove_clicked();
|
||||
|
||||
void on_browseButton_clicked();
|
||||
void on_readFileCheckBox_stateChanged(int state);
|
||||
void on_readPathLineEdit_textChanged(const QString & text);
|
||||
void on_writePathLineEdit_textChanged(const QString & text);
|
||||
void on_browseButton_2_clicked();
|
||||
|
||||
void on_executableAdd_clicked();
|
||||
void on_executableRemove_clicked();
|
||||
void on_executables_currentRowChanged(int idx);
|
||||
|
||||
void on_idleCheckBox_stateChanged(int state);
|
||||
void on_idleTransitions_currentTextChanged(const QString& text);
|
||||
void on_idleScenes_currentTextChanged(const QString& text);
|
||||
void on_idleSpinBox_valueChanged(int i);
|
||||
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
||||
void on_ignoreIdleAdd_clicked();
|
||||
void on_ignoreIdleRemove_clicked();
|
||||
|
||||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
|
||||
void updateScreenRegionCursorPos();
|
||||
|
||||
void on_close_clicked();
|
||||
};
|
||||
|
||||
void GetWindowList(std::vector<std::string> &windows);
|
||||
void GetCurrentWindowTitle(std::string &title);
|
||||
pair<int, int> getCursorPos();
|
||||
bool isFullscreen();
|
||||
int secondsSinceLastInput();
|
||||
bool isInFocus(const QString &exeToCheck);
|
||||
void GetProcessList(QStringList &processes);
|
||||
|
||||
struct SwitcherData;
|
||||
extern SwitcherData* switcher;
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#ifdef BUILD_OUT_OF_TREE
|
||||
#include "../../forms/ui_advanced-scene-switcher.h"
|
||||
#else
|
||||
#include "ui_advanced-scene-switcher.h"
|
||||
#endif
|
||||
#include "switcher-data-structs.hpp"
|
||||
|
||||
class QCloseEvent;
|
||||
|
||||
/*******************************************************************************
|
||||
* Advanced Scene Switcher window
|
||||
*******************************************************************************/
|
||||
class SceneSwitcher : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
std::unique_ptr<Ui_SceneSwitcher> ui;
|
||||
bool loading = true;
|
||||
|
||||
SceneSwitcher(QWidget *parent);
|
||||
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
void SetStarted();
|
||||
void SetStopped();
|
||||
|
||||
int FindByData(const QString &window);
|
||||
int ScreenRegionFindByData(const QString ®ion);
|
||||
int PauseScenesFindByData(const QString &scene);
|
||||
int PauseWindowsFindByData(const QString &window);
|
||||
int IgnoreWindowsFindByData(const QString &window);
|
||||
int SceneRoundTripFindByData(const QString &scene1);
|
||||
int SceneTransitionsFindByData(const QString &scene1,
|
||||
const QString &scene2);
|
||||
int DefaultTransitionsFindByData(const QString &scene);
|
||||
int executableFindByData(const QString &exe);
|
||||
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||
int randomFindByData(const QString &scene);
|
||||
int timeFindByData(const QString &timeStr);
|
||||
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void UpdateAutoStopScene(const QString &name);
|
||||
void UpdateIdleDataTransition(const QString &name);
|
||||
void UpdateIdleDataScene(const QString &name);
|
||||
|
||||
public slots:
|
||||
void on_switches_currentRowChanged(int idx);
|
||||
void on_add_clicked();
|
||||
void on_remove_clicked();
|
||||
void on_noMatchDontSwitch_clicked();
|
||||
void on_noMatchSwitch_clicked();
|
||||
void on_noMatchRandomSwitch_clicked();
|
||||
void on_startAtLaunch_toggled(bool value);
|
||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_toggleStartButton_clicked();
|
||||
|
||||
void on_screenRegions_currentRowChanged(int idx);
|
||||
void on_screenRegionAdd_clicked();
|
||||
void on_screenRegionRemove_clicked();
|
||||
|
||||
void on_pauseScenes_currentRowChanged(int idx);
|
||||
void on_pauseScenesAdd_clicked();
|
||||
void on_pauseScenesRemove_clicked();
|
||||
|
||||
void on_pauseWindows_currentRowChanged(int idx);
|
||||
void on_pauseWindowsAdd_clicked();
|
||||
void on_pauseWindowsRemove_clicked();
|
||||
|
||||
void on_ignoreWindows_currentRowChanged(int idx);
|
||||
void on_ignoreWindowsAdd_clicked();
|
||||
void on_ignoreWindowsRemove_clicked();
|
||||
|
||||
void on_sceneRoundTrips_currentRowChanged(int idx);
|
||||
void on_sceneRoundTripAdd_clicked();
|
||||
void on_sceneRoundTripRemove_clicked();
|
||||
void on_sceneRoundTripSave_clicked();
|
||||
void on_sceneRoundTripLoad_clicked();
|
||||
|
||||
void on_autoStopSceneCheckBox_stateChanged(int state);
|
||||
void on_autoStopScenes_currentTextChanged(const QString &text);
|
||||
|
||||
void on_sceneTransitions_currentRowChanged(int idx);
|
||||
void on_transitionsAdd_clicked();
|
||||
void on_transitionsRemove_clicked();
|
||||
void on_defaultTransitions_currentRowChanged(int idx);
|
||||
void on_defaultTransitionsAdd_clicked();
|
||||
void on_defaultTransitionsRemove_clicked();
|
||||
|
||||
void on_browseButton_clicked();
|
||||
void on_readFileCheckBox_stateChanged(int state);
|
||||
void on_readPathLineEdit_textChanged(const QString &text);
|
||||
void on_writePathLineEdit_textChanged(const QString &text);
|
||||
void on_browseButton_2_clicked();
|
||||
|
||||
void on_executableAdd_clicked();
|
||||
void on_executableRemove_clicked();
|
||||
void on_executables_currentRowChanged(int idx);
|
||||
|
||||
void on_idleCheckBox_stateChanged(int state);
|
||||
void on_idleTransitions_currentTextChanged(const QString &text);
|
||||
void on_idleScenes_currentTextChanged(const QString &text);
|
||||
void on_idleSpinBox_valueChanged(int i);
|
||||
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
||||
void on_ignoreIdleAdd_clicked();
|
||||
void on_ignoreIdleRemove_clicked();
|
||||
|
||||
void on_randomAdd_clicked();
|
||||
void on_randomRemove_clicked();
|
||||
void on_randomScenesList_currentRowChanged(int idx);
|
||||
|
||||
void on_fileAdd_clicked();
|
||||
void on_fileRemove_clicked();
|
||||
void on_fileScenesList_currentRowChanged(int idx);
|
||||
void on_browseButton_3_clicked();
|
||||
|
||||
void on_mediaAdd_clicked();
|
||||
void on_mediaRemove_clicked();
|
||||
|
||||
void on_timeSwitches_currentRowChanged(int idx);
|
||||
void on_timeAdd_clicked();
|
||||
void on_timeRemove_clicked();
|
||||
|
||||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
|
||||
void updateScreenRegionCursorPos();
|
||||
|
||||
void on_close_clicked();
|
||||
};
|
||||
|
||||
/********************************************************************************
|
||||
* Windowtitle helper
|
||||
********************************************************************************/
|
||||
void GetWindowList(std::vector<std::string> &windows);
|
||||
void GetCurrentWindowTitle(std::string &title);
|
||||
bool isFullscreen();
|
||||
|
||||
/********************************************************************************
|
||||
* Screenregion helper
|
||||
********************************************************************************/
|
||||
pair<int, int> getCursorPos();
|
||||
|
||||
/********************************************************************************
|
||||
* Idle detection helper
|
||||
********************************************************************************/
|
||||
int secondsSinceLastInput();
|
||||
|
||||
/********************************************************************************
|
||||
* Executable helper
|
||||
********************************************************************************/
|
||||
void GetProcessList(QStringList &processes);
|
||||
bool isInFocus(const QString &exeToCheck);
|
||||
|
||||
/********************************************************************************
|
||||
* Sceneswitch helper
|
||||
********************************************************************************/
|
||||
struct obs_weak_source;
|
||||
typedef struct obs_weak_source obs_weak_source_t;
|
||||
|
||||
obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
|
||||
obs_weak_source_t *scene2);
|
||||
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
unique_lock<mutex> &lock);
|
||||
|
||||
/********************************************************************************
|
||||
* Hotkey helper
|
||||
********************************************************************************/
|
||||
|
||||
#define TOGGLE_HOTKEY_PATH "hotkey_toggle.txt"
|
||||
#define STOP_HOTKEY_PATH "hotkey_stop.txt"
|
||||
#define START_HOTKEY_PATH "hotkey_start.txt"
|
||||
|
||||
void stopHotkeyFunc(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);
|
||||
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed);
|
||||
void loadKeybinding(obs_hotkey_id hotkeyId, string path);
|
||||
|
||||
/********************************************************************************
|
||||
* Main SwitcherData
|
||||
********************************************************************************/
|
||||
struct SwitcherData;
|
||||
extern SwitcherData *switcher;
|
||||
455
src/headers/switcher-data-structs.hpp
Normal file
455
src/headers/switcher-data-structs.hpp
Normal file
@@ -0,0 +1,455 @@
|
||||
#pragma once
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <regex>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
#include "utility.hpp"
|
||||
|
||||
#define DEFAULT_INTERVAL 300
|
||||
|
||||
#define DEFAULT_IDLE_TIME 60
|
||||
|
||||
#define PREVIOUS_SCENE_NAME "Previous Scene"
|
||||
|
||||
#define READ_FILE_FUNC 0
|
||||
#define ROUND_TRIP_FUNC 1
|
||||
#define IDLE_FUNC 2
|
||||
#define EXE_FUNC 3
|
||||
#define SCREEN_REGION_FUNC 4
|
||||
#define WINDOW_TITLE_FUNC 5
|
||||
#define MEDIA_FUNC 6
|
||||
#define TIME_FUNC 7
|
||||
|
||||
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
|
||||
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
|
||||
#define DEFAULT_PRIORITY_2 IDLE_FUNC
|
||||
#define DEFAULT_PRIORITY_3 EXE_FUNC
|
||||
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
|
||||
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
|
||||
#define DEFAULT_PRIORITY_6 MEDIA_FUNC
|
||||
#define DEFAULT_PRIORITY_7 TIME_FUNC
|
||||
|
||||
using namespace std;
|
||||
|
||||
/********************************************************************************
|
||||
* Data structs for each scene switching method
|
||||
********************************************************************************/
|
||||
struct WindowSceneSwitch {
|
||||
OBSWeakSource scene;
|
||||
string window;
|
||||
OBSWeakSource transition;
|
||||
bool fullscreen;
|
||||
|
||||
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_,
|
||||
OBSWeakSource transition_, bool fullscreen_)
|
||||
: scene(scene_),
|
||||
window(window_),
|
||||
transition(transition_),
|
||||
fullscreen(fullscreen_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ExecutableSceneSwitch {
|
||||
OBSWeakSource mScene;
|
||||
OBSWeakSource mTransition;
|
||||
QString mExe;
|
||||
bool mInFocus;
|
||||
|
||||
inline ExecutableSceneSwitch(OBSWeakSource scene,
|
||||
OBSWeakSource transition,
|
||||
const QString &exe, bool inFocus)
|
||||
: mScene(scene),
|
||||
mTransition(transition),
|
||||
mExe(exe),
|
||||
mInFocus(inFocus)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ScreenRegionSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
int minX, minY, maxX, maxY;
|
||||
string regionStr;
|
||||
|
||||
inline ScreenRegionSwitch(OBSWeakSource scene_,
|
||||
OBSWeakSource transition_, int minX_,
|
||||
int minY_, int maxX_, int maxY_,
|
||||
string regionStr_)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
minX(minX_),
|
||||
minY(minY_),
|
||||
maxX(maxX_),
|
||||
maxY(maxY_),
|
||||
regionStr(regionStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct SceneRoundTripSwitch {
|
||||
OBSWeakSource scene1;
|
||||
OBSWeakSource scene2;
|
||||
OBSWeakSource transition;
|
||||
int delay;
|
||||
bool usePreviousScene;
|
||||
string sceneRoundTripStr;
|
||||
|
||||
inline SceneRoundTripSwitch(OBSWeakSource scene1_,
|
||||
OBSWeakSource scene2_,
|
||||
OBSWeakSource transition_, int delay_,
|
||||
bool usePreviousScene_, string str)
|
||||
: scene1(scene1_),
|
||||
scene2(scene2_),
|
||||
transition(transition_),
|
||||
delay(delay_),
|
||||
usePreviousScene(usePreviousScene_),
|
||||
sceneRoundTripStr(str)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct RandomSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
double delay;
|
||||
string randomSwitchStr;
|
||||
|
||||
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
double delay_, string str)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
delay(delay_),
|
||||
randomSwitchStr(str)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct SceneTransition {
|
||||
OBSWeakSource scene1;
|
||||
OBSWeakSource scene2;
|
||||
OBSWeakSource transition;
|
||||
string sceneTransitionStr;
|
||||
|
||||
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_,
|
||||
OBSWeakSource transition_,
|
||||
string sceneTransitionStr_)
|
||||
: scene1(scene1_),
|
||||
scene2(scene2_),
|
||||
transition(transition_),
|
||||
sceneTransitionStr(sceneTransitionStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DefaultSceneTransition {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
string sceneTransitionStr;
|
||||
|
||||
inline DefaultSceneTransition(OBSWeakSource scene_,
|
||||
OBSWeakSource transition_,
|
||||
string sceneTransitionStr_)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
sceneTransitionStr(sceneTransitionStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct FileSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
string file;
|
||||
string text;
|
||||
bool useRegex = false;
|
||||
bool useTime = false;
|
||||
QDateTime lastMod;
|
||||
|
||||
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
const char *file_, const char *text_, bool useRegex_,
|
||||
bool useTime_)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
file(file_),
|
||||
text(text_),
|
||||
useRegex(useRegex_),
|
||||
useTime(useTime_),
|
||||
lastMod()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct FileIOData {
|
||||
bool readEnabled = false;
|
||||
string readPath;
|
||||
bool writeEnabled = false;
|
||||
string writePath;
|
||||
};
|
||||
|
||||
struct IdleData {
|
||||
bool idleEnable = false;
|
||||
int time = DEFAULT_IDLE_TIME;
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
bool usePreviousScene;
|
||||
bool alreadySwitched = false;
|
||||
};
|
||||
|
||||
struct MediaSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource source;
|
||||
OBSWeakSource transition;
|
||||
obs_media_state state;
|
||||
uint64_t time;
|
||||
time_restriction restriction;
|
||||
bool matched;
|
||||
bool usePreviousScene;
|
||||
|
||||
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||
OBSWeakSource transition_, obs_media_state state_,
|
||||
time_restriction restriction_, uint64_t time_,
|
||||
bool usePreviousScene_)
|
||||
: scene(scene_),
|
||||
source(source_),
|
||||
transition(transition_),
|
||||
state(state_),
|
||||
restriction(restriction_),
|
||||
time(time_),
|
||||
usePreviousScene(usePreviousScene_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct TimeSwitch {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
QTime time;
|
||||
bool matched;
|
||||
bool usePreviousScene;
|
||||
string timeSwitchStr;
|
||||
|
||||
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
QTime time_, bool usePreviousScene_,
|
||||
string timeSwitchStr_)
|
||||
: scene(scene_),
|
||||
transition(transition_),
|
||||
time(time_),
|
||||
usePreviousScene(usePreviousScene_),
|
||||
timeSwitchStr(timeSwitchStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
||||
|
||||
/********************************************************************************
|
||||
* SwitcherData
|
||||
********************************************************************************/
|
||||
struct SwitcherData {
|
||||
thread th;
|
||||
condition_variable cv;
|
||||
mutex m;
|
||||
bool transitionActive = false;
|
||||
bool waitForTransition = false;
|
||||
condition_variable transitionCv;
|
||||
bool startAtLaunch = false;
|
||||
bool stop = false;
|
||||
|
||||
int interval = DEFAULT_INTERVAL;
|
||||
|
||||
obs_source_t *waitScene = NULL; //scene during which wait started
|
||||
OBSWeakSource previousScene = NULL;
|
||||
OBSWeakSource PreviousScene2 = NULL;
|
||||
OBSWeakSource lastRandomScene;
|
||||
OBSWeakSource nonMatchingScene;
|
||||
NoMatch switchIfNotMatching = NO_SWITCH;
|
||||
|
||||
vector<WindowSceneSwitch> windowSwitches;
|
||||
vector<string> ignoreIdleWindows;
|
||||
string lastTitle;
|
||||
|
||||
vector<ScreenRegionSwitch> screenRegionSwitches;
|
||||
|
||||
vector<OBSWeakSource> pauseScenesSwitches;
|
||||
|
||||
vector<string> pauseWindowsSwitches;
|
||||
|
||||
vector<string> ignoreWindowsSwitches;
|
||||
|
||||
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
|
||||
|
||||
vector<RandomSwitch> randomSwitches;
|
||||
|
||||
FileIOData fileIO;
|
||||
IdleData idleData;
|
||||
vector<FileSwitch> fileSwitches;
|
||||
|
||||
vector<ExecutableSceneSwitch> executableSwitches;
|
||||
|
||||
bool autoStopEnable = false;
|
||||
OBSWeakSource autoStopScene;
|
||||
|
||||
vector<SceneTransition> sceneTransitions;
|
||||
vector<DefaultSceneTransition> defaultSceneTransitions;
|
||||
|
||||
vector<MediaSwitch> mediaSwitches;
|
||||
|
||||
vector<TimeSwitch> timeSwitches;
|
||||
|
||||
vector<int> functionNamesByPriority = vector<int>{
|
||||
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
|
||||
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
|
||||
DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
|
||||
|
||||
std::vector<std::string> threadPrioritiesNamesOrderdByPrio{
|
||||
"Lowest", "Low", "Normal", "High", "Highest", "Time critical",
|
||||
};
|
||||
std::map<std::string, int> threadPriorities = {
|
||||
{"Lowest", QThread::LowestPriority},
|
||||
{"Low", QThread::LowPriority},
|
||||
{"Normal", QThread::NormalPriority},
|
||||
{"High", QThread::HighPriority},
|
||||
{"Highest", QThread::HighestPriority},
|
||||
{"Time critical", QThread::TimeCriticalPriority},
|
||||
};
|
||||
|
||||
void Thread();
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
bool sceneChangedDuringWait();
|
||||
bool prioFuncsValid();
|
||||
void writeSceneInfoToFile();
|
||||
void setDefaultSceneTransitions();
|
||||
void autoStopStreamAndRecording();
|
||||
bool checkPause();
|
||||
void checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition,
|
||||
unique_lock<mutex> &lock);
|
||||
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkExeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkFileContent(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkRandom(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &delay);
|
||||
void checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
void checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition);
|
||||
|
||||
void Prune()
|
||||
{
|
||||
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
||||
WindowSceneSwitch &s = windowSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
windowSwitches.erase(windowSwitches.begin() +
|
||||
i--);
|
||||
}
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||
switchIfNotMatching = NO_SWITCH;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||
RandomSwitch &s = randomSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
randomSwitches.erase(randomSwitches.begin() +
|
||||
i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
||||
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
screenRegionSwitches.erase(
|
||||
screenRegionSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) {
|
||||
OBSWeakSource &scene = pauseScenesSwitches[i];
|
||||
if (!WeakSourceValid(scene))
|
||||
pauseScenesSwitches.erase(
|
||||
pauseScenesSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++) {
|
||||
SceneRoundTripSwitch &s = sceneRoundTripSwitches[i];
|
||||
if (!WeakSourceValid(s.scene1) ||
|
||||
(!s.usePreviousScene &&
|
||||
!WeakSourceValid(s.scene2)) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
sceneRoundTripSwitches.erase(
|
||||
sceneRoundTripSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!WeakSourceValid(autoStopScene)) {
|
||||
autoStopScene = nullptr;
|
||||
autoStopEnable = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
||||
SceneTransition &s = sceneTransitions[i];
|
||||
if (!WeakSourceValid(s.scene1) ||
|
||||
!WeakSourceValid(s.scene2) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
sceneTransitions.erase(
|
||||
sceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
||||
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
defaultSceneTransitions.erase(
|
||||
defaultSceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
||||
ExecutableSceneSwitch &s = executableSwitches[i];
|
||||
if (!WeakSourceValid(s.mScene) ||
|
||||
!WeakSourceValid(s.mTransition))
|
||||
executableSwitches.erase(
|
||||
executableSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
||||
FileSwitch &s = fileSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
fileSwitches.erase(fileSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < timeSwitches.size(); i++) {
|
||||
TimeSwitch &s = timeSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) ||
|
||||
!WeakSourceValid(s.transition))
|
||||
timeSwitches.erase(timeSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!idleData.usePreviousScene &&
|
||||
!WeakSourceValid(idleData.scene) ||
|
||||
!WeakSourceValid(idleData.transition)) {
|
||||
idleData.idleEnable = false;
|
||||
}
|
||||
}
|
||||
inline ~SwitcherData() { Stop(); }
|
||||
};
|
||||
241
src/headers/utility.hpp
Normal file
241
src/headers/utility.hpp
Normal file
@@ -0,0 +1,241 @@
|
||||
#pragma once
|
||||
#include <obs.hpp>
|
||||
#include <QString>
|
||||
#include <obs-frontend-api.h>
|
||||
#include "switcher-data-structs.hpp"
|
||||
using namespace std;
|
||||
|
||||
static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
||||
{
|
||||
obs_source_t *source = obs_weak_source_get_source(ws);
|
||||
if (source)
|
||||
obs_source_release(source);
|
||||
return !!source;
|
||||
}
|
||||
|
||||
static inline QString MakeSwitchName(const QString &scene, const QString &value,
|
||||
const QString &transition, bool fullscreen)
|
||||
{
|
||||
if (!fullscreen)
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") +
|
||||
transition + QStringLiteral("]: ") + value;
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||
QStringLiteral("]: ") + value +
|
||||
QStringLiteral(" (only if window is fullscreen)");
|
||||
}
|
||||
|
||||
static inline QString MakeSwitchNameExecutable(const QString &scene,
|
||||
const QString &value,
|
||||
const QString &transition,
|
||||
bool inFocus)
|
||||
{
|
||||
if (!inFocus)
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") +
|
||||
transition + QStringLiteral("]: ") + value;
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||
QStringLiteral("]: ") + value +
|
||||
QStringLiteral(" (only if window is focused)");
|
||||
}
|
||||
|
||||
static inline QString MakeScreenRegionSwitchName(const QString &scene,
|
||||
const QString &transition,
|
||||
int minX, int minY, int maxX,
|
||||
int maxY)
|
||||
{
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||
QStringLiteral("]: ") + QString::number(minX) +
|
||||
QStringLiteral(", ") + QString::number(minY) +
|
||||
QStringLiteral(" x ") + QString::number(maxX) +
|
||||
QStringLiteral(", ") + QString::number(maxY);
|
||||
}
|
||||
|
||||
static inline QString MakeSceneRoundTripSwitchName(const QString &scene1,
|
||||
const QString &scene2,
|
||||
const QString &transition,
|
||||
double delay)
|
||||
{
|
||||
return scene1 + QStringLiteral(" -> wait for ") +
|
||||
QString::number(delay) + QStringLiteral(" seconds -> ") +
|
||||
scene2 + QStringLiteral(" (using ") + transition +
|
||||
QStringLiteral(" transition)");
|
||||
}
|
||||
|
||||
static inline QString MakeSceneTransitionName(const QString &scene1,
|
||||
const QString &scene2,
|
||||
const QString &transition)
|
||||
{
|
||||
return scene1 + QStringLiteral(" --- ") + transition +
|
||||
QStringLiteral(" --> ") + scene2;
|
||||
}
|
||||
|
||||
static inline QString MakeDefaultSceneTransitionName(const QString &scene,
|
||||
const QString &transition)
|
||||
{
|
||||
return scene + QStringLiteral(" --> ") + transition;
|
||||
}
|
||||
|
||||
static inline QString MakeRandomSwitchName(const QString &scene,
|
||||
const QString &transition,
|
||||
double &delay)
|
||||
{
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||
QStringLiteral("]: ") + QString::number(delay) +
|
||||
QStringLiteral(" seconds");
|
||||
}
|
||||
|
||||
static inline QString MakeFileSwitchName(const QString &scene,
|
||||
const QString &transition,
|
||||
const QString &fileName,
|
||||
const QString &text, bool useRegex,
|
||||
bool useTime)
|
||||
{
|
||||
QString switchName = QStringLiteral("Switch to ") + scene +
|
||||
QStringLiteral(" using ") + transition +
|
||||
QStringLiteral(" if ") + fileName;
|
||||
if (useTime)
|
||||
switchName += QStringLiteral(" was modified and");
|
||||
switchName += QStringLiteral(" contains");
|
||||
if (useRegex)
|
||||
switchName += QStringLiteral(" (RegEx): \n\"");
|
||||
else
|
||||
switchName += QStringLiteral(": \n\"");
|
||||
if (text.length() > 30)
|
||||
switchName += text.left(27) + QStringLiteral("...\"");
|
||||
else
|
||||
switchName += text + QStringLiteral("\"");
|
||||
|
||||
return switchName;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
TIME_RESTRICTION_NONE,
|
||||
TIME_RESTRICTION_SHORTER,
|
||||
TIME_RESTRICTION_LONGER,
|
||||
TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
TIME_RESTRICTION_REMAINING_LONGER,
|
||||
} time_restriction;
|
||||
|
||||
static inline QString
|
||||
MakeMediaSwitchName(const QString &source, const QString &scene,
|
||||
const QString &transition, obs_media_state state,
|
||||
time_restriction restriction, uint64_t time)
|
||||
{
|
||||
QString switchName = QStringLiteral("Switch to ") + scene +
|
||||
QStringLiteral(" using ") + transition +
|
||||
QStringLiteral(" if ") + source +
|
||||
QStringLiteral(" state is ");
|
||||
if (state == OBS_MEDIA_STATE_NONE) {
|
||||
switchName += QStringLiteral("none");
|
||||
} else if (state == OBS_MEDIA_STATE_PLAYING) {
|
||||
switchName += QStringLiteral("playing");
|
||||
} else if (state == OBS_MEDIA_STATE_OPENING) {
|
||||
switchName += QStringLiteral("opening");
|
||||
} else if (state == OBS_MEDIA_STATE_BUFFERING) {
|
||||
switchName += QStringLiteral("buffering");
|
||||
} else if (state == OBS_MEDIA_STATE_PAUSED) {
|
||||
switchName += QStringLiteral("paused");
|
||||
} else if (state == OBS_MEDIA_STATE_STOPPED) {
|
||||
switchName += QStringLiteral("stopped");
|
||||
} else if (state == OBS_MEDIA_STATE_ENDED) {
|
||||
switchName += QStringLiteral("ended");
|
||||
} else if (state == OBS_MEDIA_STATE_ERROR) {
|
||||
switchName += QStringLiteral("error");
|
||||
}
|
||||
if (restriction == TIME_RESTRICTION_SHORTER) {
|
||||
switchName += QStringLiteral(" and time shorter than ");
|
||||
} else if (restriction == TIME_RESTRICTION_LONGER) {
|
||||
switchName += QStringLiteral(" and time longer than ");
|
||||
} else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) {
|
||||
switchName +=
|
||||
QStringLiteral(" and time remaining shorter than ");
|
||||
} else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) {
|
||||
switchName +=
|
||||
QStringLiteral(" and time remaining longer than ");
|
||||
}
|
||||
if (restriction != TIME_RESTRICTION_NONE) {
|
||||
switchName += std::to_string(time).c_str();
|
||||
switchName += QStringLiteral(" ms");
|
||||
}
|
||||
return switchName;
|
||||
}
|
||||
|
||||
static inline QString MakeTimeSwitchName(const QString &scene,
|
||||
const QString &transition, QTime &time)
|
||||
{
|
||||
QString switchName = QStringLiteral("At ") + time.toString() +
|
||||
QStringLiteral(" switch to ") + scene +
|
||||
QStringLiteral(" using ") + transition;
|
||||
return switchName;
|
||||
}
|
||||
|
||||
static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
|
||||
{
|
||||
string name;
|
||||
|
||||
obs_source_t *source = obs_weak_source_get_source(weak_source);
|
||||
if (source) {
|
||||
name = obs_source_get_name(source);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakSourceByName(const char *name)
|
||||
{
|
||||
OBSWeakSource weak;
|
||||
obs_source_t *source = obs_get_source_by_name(name);
|
||||
if (source) {
|
||||
weak = obs_source_get_weak_source(source);
|
||||
obs_weak_source_release(weak);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
return weak;
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakSourceByQString(const QString &name)
|
||||
{
|
||||
return GetWeakSourceByName(name.toUtf8().constData());
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakTransitionByName(const char *transitionName)
|
||||
{
|
||||
OBSWeakSource weak;
|
||||
obs_source_t *source = nullptr;
|
||||
|
||||
if (strcmp(transitionName, "Default") == 0) {
|
||||
source = obs_frontend_get_current_transition();
|
||||
weak = obs_source_get_weak_source(source);
|
||||
obs_source_release(source);
|
||||
obs_weak_source_release(weak);
|
||||
return weak;
|
||||
}
|
||||
|
||||
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
||||
obs_frontend_get_transitions(transitions);
|
||||
bool match = false;
|
||||
|
||||
for (size_t i = 0; i < transitions->sources.num; i++) {
|
||||
const char *name =
|
||||
obs_source_get_name(transitions->sources.array[i]);
|
||||
if (strcmp(transitionName, name) == 0) {
|
||||
match = true;
|
||||
source = transitions->sources.array[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
weak = obs_source_get_weak_source(source);
|
||||
obs_weak_source_release(weak);
|
||||
}
|
||||
obs_frontend_source_list_free(transitions);
|
||||
|
||||
return weak;
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakTransitionByQString(const QString &name)
|
||||
{
|
||||
return GetWeakTransitionByName(name.toUtf8().constData());
|
||||
}
|
||||
142
src/hotkey.cpp
Normal file
142
src/hotkey.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include <obs-module.h>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (!switcher->th.joinable())
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||
|
||||
if (hotkeyData != NULL)
|
||||
{
|
||||
char* path = obs_module_config_path("");
|
||||
ofstream file;
|
||||
file.open(string(path).append(START_HOTKEY_PATH), ofstream::trunc);
|
||||
if (file.is_open())
|
||||
{
|
||||
size_t num = obs_data_array_count(hotkeyData);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
{
|
||||
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||
string temp = obs_data_get_json(data);
|
||||
obs_data_release(data);
|
||||
file << temp;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
bfree(path);
|
||||
}
|
||||
obs_data_array_release(hotkeyData);
|
||||
}
|
||||
|
||||
void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
switcher->Stop();
|
||||
}
|
||||
|
||||
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||
|
||||
if (hotkeyData != NULL)
|
||||
{
|
||||
char* path = obs_module_config_path("");
|
||||
ofstream file;
|
||||
file.open(string(path).append(STOP_HOTKEY_PATH), ofstream::trunc);
|
||||
if (file.is_open())
|
||||
{
|
||||
size_t num = obs_data_array_count(hotkeyData);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
{
|
||||
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||
string temp = obs_data_get_json(data);
|
||||
obs_data_release(data);
|
||||
file << temp;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
bfree(path);
|
||||
}
|
||||
obs_data_array_release(hotkeyData);
|
||||
}
|
||||
|
||||
void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (switcher->th.joinable())
|
||||
switcher->Stop();
|
||||
else
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||
|
||||
if (hotkeyData != NULL)
|
||||
{
|
||||
char* path = obs_module_config_path("");
|
||||
ofstream file;
|
||||
file.open(string(path).append(TOGGLE_HOTKEY_PATH), ofstream::trunc);
|
||||
if (file.is_open())
|
||||
{
|
||||
size_t num = obs_data_array_count(hotkeyData);
|
||||
for (size_t i = 0; i < num; i++)
|
||||
{
|
||||
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||
string temp = obs_data_get_json(data);
|
||||
obs_data_release(data);
|
||||
file << temp;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
bfree(path);
|
||||
}
|
||||
obs_data_array_release(hotkeyData);
|
||||
}
|
||||
|
||||
string loadConfigFile(string filename)
|
||||
{
|
||||
ifstream settingsFile;
|
||||
char* path = obs_module_config_path("");
|
||||
string value;
|
||||
|
||||
settingsFile.open(string(path).append(filename));
|
||||
if (settingsFile.is_open())
|
||||
{
|
||||
settingsFile.seekg(0, ios::end);
|
||||
value.reserve(settingsFile.tellg());
|
||||
settingsFile.seekg(0, ios::beg);
|
||||
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
|
||||
settingsFile.close();
|
||||
}
|
||||
bfree(path);
|
||||
return value;
|
||||
}
|
||||
|
||||
void loadKeybinding(obs_hotkey_id hotkeyId, string path)
|
||||
{
|
||||
string bindings = loadConfigFile(path);
|
||||
if (!bindings.empty())
|
||||
{
|
||||
obs_data_array_t* hotkeyData = obs_data_array_create();
|
||||
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
|
||||
obs_data_array_insert(hotkeyData, 0, data);
|
||||
obs_data_release(data);
|
||||
obs_hotkey_load(hotkeyId, hotkeyData);
|
||||
obs_data_array_release(hotkeyData);
|
||||
}
|
||||
}
|
||||
@@ -1,210 +1,216 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
if (!idleData.idleEnable)
|
||||
return;
|
||||
|
||||
string title;
|
||||
bool ignoreIdle = false;
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
|
||||
for (string& window : ignoreIdleWindows)
|
||||
{
|
||||
if (window == title)
|
||||
{
|
||||
ignoreIdle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle)
|
||||
{
|
||||
for (string& window : ignoreIdleWindows)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool matches = regex_match(title, regex(window));
|
||||
if (matches)
|
||||
{
|
||||
ignoreIdle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const regex_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
|
||||
{
|
||||
scene = idleData.scene;
|
||||
transition = idleData.transition;
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (!state)
|
||||
{
|
||||
ui->idleScenes->setDisabled(true);
|
||||
ui->idleSpinBox->setDisabled(true);
|
||||
ui->idleTransitions->setDisabled(true);
|
||||
|
||||
switcher->idleData.idleEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->idleScenes->setDisabled(false);
|
||||
ui->idleSpinBox->setDisabled(false);
|
||||
ui->idleTransitions->setDisabled(false);
|
||||
|
||||
switcher->idleData.idleEnable = true;
|
||||
|
||||
UpdateIdleDataTransition(ui->idleTransitions->currentText());
|
||||
UpdateIdleDataScene(ui->idleScenes->currentText());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::UpdateIdleDataTransition(const QString& name)
|
||||
{
|
||||
obs_weak_source_t* transition = GetWeakTransitionByQString(name);
|
||||
switcher->idleData.transition = transition;
|
||||
}
|
||||
|
||||
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
|
||||
{
|
||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->idleData.scene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateIdleDataTransition(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateIdleDataScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->idleData.time = i;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->ignoreIdleWindows->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& w : switcher->ignoreIdleWindows)
|
||||
{
|
||||
if (window.compare(w.c_str()) == 0)
|
||||
{
|
||||
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreIdleAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData());
|
||||
ui->ignoreIdleWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreIdleRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreIdleWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& windows = switcher->ignoreIdleWindows;
|
||||
|
||||
for (auto it = windows.begin(); it != windows.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == windowName.toUtf8().constData())
|
||||
{
|
||||
windows.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window)
|
||||
{
|
||||
int count = ui->ignoreIdleWindows->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreIdleWindows->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
if (!idleData.idleEnable)
|
||||
return;
|
||||
|
||||
string title;
|
||||
bool ignoreIdle = false;
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
|
||||
for (string& window : ignoreIdleWindows)
|
||||
{
|
||||
if (window == title)
|
||||
{
|
||||
ignoreIdle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle)
|
||||
{
|
||||
for (string& window : ignoreIdleWindows)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool matches = regex_match(title, regex(window));
|
||||
if (matches)
|
||||
{
|
||||
ignoreIdle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const regex_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
|
||||
{
|
||||
if (idleData.alreadySwitched)
|
||||
return;
|
||||
scene = (idleData.usePreviousScene) ? previousScene : idleData.scene;
|
||||
transition = idleData.transition;
|
||||
match = true;
|
||||
idleData.alreadySwitched = true;
|
||||
}
|
||||
else
|
||||
idleData.alreadySwitched = false;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (!state)
|
||||
{
|
||||
ui->idleScenes->setDisabled(true);
|
||||
ui->idleSpinBox->setDisabled(true);
|
||||
ui->idleTransitions->setDisabled(true);
|
||||
|
||||
switcher->idleData.idleEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->idleScenes->setDisabled(false);
|
||||
ui->idleSpinBox->setDisabled(false);
|
||||
ui->idleTransitions->setDisabled(false);
|
||||
|
||||
switcher->idleData.idleEnable = true;
|
||||
|
||||
UpdateIdleDataTransition(ui->idleTransitions->currentText());
|
||||
UpdateIdleDataScene(ui->idleScenes->currentText());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::UpdateIdleDataTransition(const QString& name)
|
||||
{
|
||||
obs_weak_source_t* transition = GetWeakTransitionByQString(name);
|
||||
switcher->idleData.transition = transition;
|
||||
}
|
||||
|
||||
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
|
||||
{
|
||||
switcher->idleData.usePreviousScene = (name == PREVIOUS_SCENE_NAME);
|
||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->idleData.scene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateIdleDataTransition(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateIdleDataScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->idleData.time = i;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->ignoreIdleWindows->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& w : switcher->ignoreIdleWindows)
|
||||
{
|
||||
if (window.compare(w.c_str()) == 0)
|
||||
{
|
||||
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreIdleAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData());
|
||||
ui->ignoreIdleWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreIdleRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreIdleWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& windows = switcher->ignoreIdleWindows;
|
||||
|
||||
for (auto it = windows.begin(); it != windows.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == windowName.toUtf8().constData())
|
||||
{
|
||||
windows.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window)
|
||||
{
|
||||
int count = ui->ignoreIdleWindows->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreIdleWindows->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
@@ -1,322 +1,325 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/scrnsaver.h>
|
||||
#undef Bool
|
||||
#undef CursorShape
|
||||
#undef Expose
|
||||
#undef KeyPress
|
||||
#undef KeyRelease
|
||||
#undef FocusIn
|
||||
#undef FocusOut
|
||||
#undef FontChange
|
||||
#undef None
|
||||
#undef Status
|
||||
#undef Unsorted
|
||||
#include <util/platform.h>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static Display* xdisplay = 0;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
if (!xdisplay)
|
||||
xdisplay = XOpenDisplay(NULL);
|
||||
|
||||
return xdisplay;
|
||||
}
|
||||
|
||||
void cleanupDisplay()
|
||||
{
|
||||
if (!xdisplay)
|
||||
return;
|
||||
|
||||
XCloseDisplay(xdisplay);
|
||||
xdisplay = 0;
|
||||
}
|
||||
|
||||
static bool ewmhIsSupported()
|
||||
{
|
||||
Display *display = disp();
|
||||
Atom netSupportingWmCheck = XInternAtom(display,
|
||||
"_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom actualType;
|
||||
int format = 0;
|
||||
unsigned long num = 0, bytes = 0;
|
||||
unsigned char *data = NULL;
|
||||
Window ewmh_window = 0;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
display,
|
||||
DefaultRootWindow(display),
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
|
||||
if (status == Success) {
|
||||
if (num > 0) {
|
||||
ewmh_window = ((Window*)data)[0];
|
||||
}
|
||||
if (data) {
|
||||
XFree(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ewmh_window) {
|
||||
status = XGetWindowProperty(
|
||||
display,
|
||||
ewmh_window,
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
if (status != Success || num == 0 ||
|
||||
ewmh_window != ((Window*)data)[0]) {
|
||||
ewmh_window = 0;
|
||||
}
|
||||
if (status == Success && data) {
|
||||
XFree(data);
|
||||
}
|
||||
}
|
||||
|
||||
return ewmh_window != 0;
|
||||
}
|
||||
|
||||
static std::vector<Window> getTopLevelWindows()
|
||||
{
|
||||
std::vector<Window> res;
|
||||
|
||||
res.resize(0);
|
||||
|
||||
if (!ewmhIsSupported()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Atom netClList = XInternAtom(disp(), "_NET_CLIENT_LIST", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
|
||||
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
||||
Window rootWin = RootWindow(disp(), i);
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
netClList,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
|
||||
if (status != Success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned long i = 0; i < num; ++i)
|
||||
res.emplace_back(data[i]);
|
||||
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string GetWindowTitle(size_t i)
|
||||
{
|
||||
Window w = getTopLevelWindows().at(i);
|
||||
std::string windowTitle;
|
||||
char* name;
|
||||
|
||||
int status = XFetchName(disp(), w, &name);
|
||||
if (status >= Success && name != nullptr)
|
||||
{
|
||||
std::string str(name);
|
||||
windowTitle = str;
|
||||
}
|
||||
|
||||
XFree(name);
|
||||
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
void GetWindowList(vector<string> &windows)
|
||||
{
|
||||
windows.resize(0);
|
||||
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
if (GetWindowTitle(i) != "")
|
||||
windows.emplace_back(GetWindowTitle(i));
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string &title)
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
char* name;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
|
||||
int status = XFetchName(disp(), data[0], &name);
|
||||
|
||||
if (status >= Success && name != nullptr) {
|
||||
std::string str(name);
|
||||
title = str;
|
||||
}
|
||||
|
||||
XFree(name);
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos()
|
||||
{
|
||||
pair<int, int> pos(0, 0);
|
||||
Display *dpy;
|
||||
Window root;
|
||||
Window ret_root;
|
||||
Window ret_child;
|
||||
int root_x;
|
||||
int root_y;
|
||||
int win_x;
|
||||
int win_y;
|
||||
unsigned int mask;
|
||||
|
||||
dpy = XOpenDisplay(NULL);
|
||||
root = XDefaultRootWindow(dpy);
|
||||
|
||||
if(XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
|
||||
&win_x, &win_y, &mask))
|
||||
{
|
||||
pos = pair<int, int> (root_x,root_y);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool isFullscreen()
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
|
||||
|
||||
XWindowAttributes window_attributes_return;
|
||||
XWindowAttributes screen_attributes_return;
|
||||
|
||||
XGetWindowAttributes(disp(), rootWin, &screen_attributes_return);
|
||||
XGetWindowAttributes(disp(), data[0], &window_attributes_return);
|
||||
|
||||
//menu bar is always 24 pixels in height
|
||||
return (window_attributes_return.width >= screen_attributes_return.width &&
|
||||
window_attributes_return.height + 24 >= screen_attributes_return.height) ? true : false;
|
||||
}
|
||||
|
||||
//exe switch is not quite what is expected but it works for now
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
string s = GetWindowTitle(i);
|
||||
if (s != "")
|
||||
processes << QString::fromStdString(s);
|
||||
}
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &exeToCheck)
|
||||
{
|
||||
string curWindow;
|
||||
GetCurrentWindowTitle(curWindow);
|
||||
|
||||
return (QString::compare(
|
||||
QString::fromStdString(curWindow),
|
||||
exeToCheck,
|
||||
Qt::CaseInsensitive) == 0) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
int secondsSinceLastInput()
|
||||
{
|
||||
time_t idle_time;
|
||||
static XScreenSaverInfo *mit_info;
|
||||
Display *display;
|
||||
int screen;
|
||||
|
||||
mit_info = XScreenSaverAllocInfo();
|
||||
|
||||
if((display=XOpenDisplay(NULL)) == NULL)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
screen = DefaultScreen(display);
|
||||
XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info);
|
||||
idle_time = (mit_info->idle) / 1000;
|
||||
XFree(mit_info);
|
||||
XCloseDisplay(display);
|
||||
|
||||
return idle_time;
|
||||
}
|
||||
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/scrnsaver.h>
|
||||
#undef Bool
|
||||
#undef CursorShape
|
||||
#undef Expose
|
||||
#undef KeyPress
|
||||
#undef KeyRelease
|
||||
#undef FocusIn
|
||||
#undef FocusOut
|
||||
#undef FontChange
|
||||
#undef None
|
||||
#undef Status
|
||||
#undef Unsorted
|
||||
#include <util/platform.h>
|
||||
#include "../headers/advanced-scene-switcher.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static Display* xdisplay = 0;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
if (!xdisplay)
|
||||
xdisplay = XOpenDisplay(NULL);
|
||||
|
||||
return xdisplay;
|
||||
}
|
||||
|
||||
void cleanupDisplay()
|
||||
{
|
||||
if (!xdisplay)
|
||||
return;
|
||||
|
||||
XCloseDisplay(xdisplay);
|
||||
xdisplay = 0;
|
||||
}
|
||||
|
||||
static bool ewmhIsSupported()
|
||||
{
|
||||
Display *display = disp();
|
||||
Atom netSupportingWmCheck = XInternAtom(display,
|
||||
"_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom actualType;
|
||||
int format = 0;
|
||||
unsigned long num = 0, bytes = 0;
|
||||
unsigned char *data = NULL;
|
||||
Window ewmh_window = 0;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
display,
|
||||
DefaultRootWindow(display),
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
|
||||
if (status == Success) {
|
||||
if (num > 0) {
|
||||
ewmh_window = ((Window*)data)[0];
|
||||
}
|
||||
if (data) {
|
||||
XFree(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ewmh_window) {
|
||||
status = XGetWindowProperty(
|
||||
display,
|
||||
ewmh_window,
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
if (status != Success || num == 0 ||
|
||||
ewmh_window != ((Window*)data)[0]) {
|
||||
ewmh_window = 0;
|
||||
}
|
||||
if (status == Success && data) {
|
||||
XFree(data);
|
||||
}
|
||||
}
|
||||
|
||||
return ewmh_window != 0;
|
||||
}
|
||||
|
||||
static std::vector<Window> getTopLevelWindows()
|
||||
{
|
||||
std::vector<Window> res;
|
||||
|
||||
res.resize(0);
|
||||
|
||||
if (!ewmhIsSupported()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Atom netClList = XInternAtom(disp(), "_NET_CLIENT_LIST", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
|
||||
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
||||
Window rootWin = RootWindow(disp(), i);
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
netClList,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
|
||||
if (status != Success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned long i = 0; i < num; ++i)
|
||||
res.emplace_back(data[i]);
|
||||
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string GetWindowTitle(size_t i)
|
||||
{
|
||||
Window w = getTopLevelWindows().at(i);
|
||||
std::string windowTitle;
|
||||
char* name;
|
||||
|
||||
XTextProperty text;
|
||||
int status = XGetWMName(disp(), w, &text);
|
||||
name = reinterpret_cast<char*>(text.value);
|
||||
if (status >= Success && name != nullptr)
|
||||
{
|
||||
std::string str(name);
|
||||
windowTitle = str;
|
||||
}
|
||||
|
||||
XFree(name);
|
||||
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
void GetWindowList(vector<string> &windows)
|
||||
{
|
||||
windows.resize(0);
|
||||
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
if (GetWindowTitle(i) != "")
|
||||
windows.emplace_back(GetWindowTitle(i));
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string &title)
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
char* name;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
|
||||
XTextProperty text;
|
||||
int status = XGetWMName(disp(), data[0], &text);
|
||||
name = reinterpret_cast<char*>(text.value);
|
||||
|
||||
if (status >= Success && name != nullptr) {
|
||||
std::string str(name);
|
||||
title = str;
|
||||
}
|
||||
|
||||
XFree(name);
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos()
|
||||
{
|
||||
pair<int, int> pos(0, 0);
|
||||
Display *dpy;
|
||||
Window root;
|
||||
Window ret_root;
|
||||
Window ret_child;
|
||||
int root_x;
|
||||
int root_y;
|
||||
int win_x;
|
||||
int win_y;
|
||||
unsigned int mask;
|
||||
|
||||
dpy = XOpenDisplay(NULL);
|
||||
root = XDefaultRootWindow(dpy);
|
||||
|
||||
if(XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
|
||||
&win_x, &win_y, &mask))
|
||||
{
|
||||
pos = pair<int, int> (root_x,root_y);
|
||||
}
|
||||
XCloseDisplay(dpy);
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool isFullscreen()
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
|
||||
|
||||
XWindowAttributes window_attributes_return;
|
||||
XWindowAttributes screen_attributes_return;
|
||||
|
||||
XGetWindowAttributes(disp(), rootWin, &screen_attributes_return);
|
||||
XGetWindowAttributes(disp(), data[0], &window_attributes_return);
|
||||
|
||||
//menu bar is always 24 pixels in height
|
||||
return (window_attributes_return.width >= screen_attributes_return.width &&
|
||||
window_attributes_return.height + 24 >= screen_attributes_return.height) ? true : false;
|
||||
}
|
||||
|
||||
//exe switch is not quite what is expected but it works for now
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
string s = GetWindowTitle(i);
|
||||
if (s != "")
|
||||
processes << QString::fromStdString(s);
|
||||
}
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &exeToCheck)
|
||||
{
|
||||
string curWindow;
|
||||
GetCurrentWindowTitle(curWindow);
|
||||
|
||||
return (QString::compare(
|
||||
QString::fromStdString(curWindow),
|
||||
exeToCheck,
|
||||
Qt::CaseInsensitive) == 0) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
int secondsSinceLastInput()
|
||||
{
|
||||
time_t idle_time;
|
||||
static XScreenSaverInfo *mit_info;
|
||||
Display *display;
|
||||
int screen;
|
||||
|
||||
mit_info = XScreenSaverAllocInfo();
|
||||
|
||||
if((display=XOpenDisplay(NULL)) == NULL)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
screen = DefaultScreen(display);
|
||||
XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info);
|
||||
idle_time = (mit_info->idle) / 1000;
|
||||
XFree(mit_info);
|
||||
XCloseDisplay(display);
|
||||
|
||||
return idle_time;
|
||||
}
|
||||
90
src/media-switch.cpp
Normal file
90
src/media-switch.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <obs-module.h>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_mediaAdd_clicked()
|
||||
{
|
||||
QString sourceName = ui->mediaSources->currentText();
|
||||
QString sceneName = ui->mediaScenes->currentText();
|
||||
QString transitionName = ui->mediaTransitions->currentText();
|
||||
obs_media_state state =
|
||||
(obs_media_state)ui->mediaStates->currentIndex();
|
||||
time_restriction restriction =
|
||||
(time_restriction)ui->mediaTimeRestrictions->currentIndex();
|
||||
uint64_t time = ui->mediaTime->value();
|
||||
|
||||
if (sceneName.isEmpty() || transitionName.isEmpty() ||
|
||||
sourceName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sourceName);
|
||||
OBSWeakSource scene = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString switchText = MakeMediaSwitchName(sourceName, sceneName,
|
||||
transitionName, state,
|
||||
restriction, time);
|
||||
QVariant v = QVariant::fromValue(switchText);
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(switchText, ui->mediaSwitches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->mediaSwitches.emplace_back(
|
||||
scene, source, transition, state, restriction, time,
|
||||
(sceneName == QString(PREVIOUS_SCENE_NAME)));
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_mediaRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
int idx = ui->mediaSwitches->currentRow();
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
auto &switches = switcher->mediaSwitches;
|
||||
switches.erase(switches.begin() + idx);
|
||||
}
|
||||
qDeleteAll(ui->mediaSwitches->selectedItems());
|
||||
}
|
||||
|
||||
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
||||
obs_source_t *source =
|
||||
obs_weak_source_get_source(mediaSwitch.source);
|
||||
auto duration = obs_source_media_get_duration(source);
|
||||
auto time = obs_source_media_get_time(source);
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
bool matched =
|
||||
state == mediaSwitch.state &&
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_NONE ||
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER &&
|
||||
time > mediaSwitch.time) ||
|
||||
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER &&
|
||||
time < mediaSwitch.time) ||
|
||||
(mediaSwitch.restriction ==
|
||||
TIME_RESTRICTION_REMAINING_SHORTER &&
|
||||
duration > time &&
|
||||
duration - time < mediaSwitch.time) ||
|
||||
(mediaSwitch.restriction ==
|
||||
TIME_RESTRICTION_REMAINING_LONGER &&
|
||||
duration > time &&
|
||||
duration - time > mediaSwitch.time));
|
||||
if (matched && !mediaSwitch.matched) {
|
||||
match = true;
|
||||
scene = (mediaSwitch.usePreviousScene)
|
||||
? previousScene
|
||||
: mediaSwitch.scene;
|
||||
transition = mediaSwitch.transition;
|
||||
}
|
||||
mediaSwitch.matched = matched;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
#import <Carbon/Carbon.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <util/platform.h>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "../headers/advanced-scene-switcher.hpp"
|
||||
|
||||
|
||||
void GetWindowList(vector<string> &windows)
|
||||
@@ -1,242 +1,242 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_pauseScenesAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->pauseScenesScenes->currentText();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
QVariant v = QVariant::fromValue(sceneName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->pauseScenesSwitches.emplace_back(source);
|
||||
ui->pauseScenes->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseScenesRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseScenes->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString pauseScene = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->pauseScenesSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == GetWeakSourceByQString(pauseScene))
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseWindowsAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->pauseWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData());
|
||||
ui->pauseWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseWindowsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->pauseWindowsSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == windowName.toUtf8().constData())
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->pauseScenes->item(idx);
|
||||
|
||||
QString scene = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->pauseScenesSwitches)
|
||||
{
|
||||
string name = GetWeakSourceName(s);
|
||||
if (scene.compare(name.c_str()) == 0)
|
||||
{
|
||||
ui->pauseScenesScenes->setCurrentText(name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->pauseWindows->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->pauseWindowsSwitches)
|
||||
{
|
||||
if (window.compare(s.c_str()) == 0)
|
||||
{
|
||||
ui->pauseWindowsWindows->setCurrentText(s.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::PauseScenesFindByData(const QString& scene)
|
||||
{
|
||||
int count = ui->pauseScenes->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseScenes->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == scene)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int SceneSwitcher::PauseWindowsFindByData(const QString& window)
|
||||
{
|
||||
int count = ui->pauseWindows->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseWindows->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool SwitcherData::checkPause()
|
||||
{
|
||||
bool pause = false;
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (OBSWeakSource& s : pauseScenesSwitches)
|
||||
{
|
||||
if (s == ws)
|
||||
{
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
|
||||
string title;
|
||||
if (!pause)
|
||||
{
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
for (string& window : pauseWindowsSwitches)
|
||||
{
|
||||
if (window == title)
|
||||
{
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pause)
|
||||
{
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
for (string& window : pauseWindowsSwitches)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool matches = regex_match(title, regex(window));
|
||||
if (matches)
|
||||
{
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const regex_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
return pause;
|
||||
}
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_pauseScenesAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->pauseScenesScenes->currentText();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
QVariant v = QVariant::fromValue(sceneName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->pauseScenesSwitches.emplace_back(source);
|
||||
ui->pauseScenes->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseScenesRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseScenes->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString pauseScene = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->pauseScenesSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == GetWeakSourceByQString(pauseScene))
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseWindowsAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->pauseWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData());
|
||||
ui->pauseWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseWindowsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->pauseWindowsSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == windowName.toUtf8().constData())
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->pauseScenes->item(idx);
|
||||
|
||||
QString scene = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->pauseScenesSwitches)
|
||||
{
|
||||
string name = GetWeakSourceName(s);
|
||||
if (scene.compare(name.c_str()) == 0)
|
||||
{
|
||||
ui->pauseScenesScenes->setCurrentText(name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->pauseWindows->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->pauseWindowsSwitches)
|
||||
{
|
||||
if (window.compare(s.c_str()) == 0)
|
||||
{
|
||||
ui->pauseWindowsWindows->setCurrentText(s.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::PauseScenesFindByData(const QString& scene)
|
||||
{
|
||||
int count = ui->pauseScenes->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseScenes->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == scene)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int SceneSwitcher::PauseWindowsFindByData(const QString& window)
|
||||
{
|
||||
int count = ui->pauseWindows->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->pauseWindows->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool SwitcherData::checkPause()
|
||||
{
|
||||
bool pause = false;
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (OBSWeakSource& s : pauseScenesSwitches)
|
||||
{
|
||||
if (s == ws)
|
||||
{
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
|
||||
string title;
|
||||
if (!pause)
|
||||
{
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
for (string& window : pauseWindowsSwitches)
|
||||
{
|
||||
if (window == title)
|
||||
{
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pause)
|
||||
{
|
||||
//lock.unlock();
|
||||
GetCurrentWindowTitle(title);
|
||||
//lock.lock();
|
||||
for (string& window : pauseWindowsSwitches)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool matches = regex_match(title, regex(window));
|
||||
if (matches)
|
||||
{
|
||||
pause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const regex_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
return pause;
|
||||
}
|
||||
@@ -1,57 +1,44 @@
|
||||
#include <algorithm>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_priorityUp_clicked()
|
||||
{
|
||||
int currentIndex = ui->priorityList->currentRow();
|
||||
if (currentIndex != -1 && currentIndex != 0)
|
||||
{
|
||||
ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex));
|
||||
ui->priorityList->setCurrentRow(currentIndex -1);
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_priorityDown_clicked()
|
||||
{
|
||||
int currentIndex = ui->priorityList->currentRow();
|
||||
if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1)
|
||||
{
|
||||
ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex));
|
||||
ui->priorityList->setCurrentRow(currentIndex + 1);
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool prioStrValid(string s)
|
||||
{
|
||||
if (s == WINDOW_TITLE_FUNC)
|
||||
return true;
|
||||
if (s == SCREEN_REGION_FUNC)
|
||||
return true;
|
||||
if (s == ROUND_TRIP_FUNC)
|
||||
return true;
|
||||
if (s == (IDLE_FUNC))
|
||||
return true;
|
||||
if (s == EXE_FUNC)
|
||||
return true;
|
||||
if (s == READ_FILE_FUNC)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SwitcherData::prioFuncsValid()
|
||||
{
|
||||
for (string f : functionNamesByPriority)
|
||||
{
|
||||
if (!prioStrValid(f))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_priorityUp_clicked()
|
||||
{
|
||||
int currentIndex = ui->priorityList->currentRow();
|
||||
if (currentIndex != -1 && currentIndex != 0)
|
||||
{
|
||||
ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex));
|
||||
ui->priorityList->setCurrentRow(currentIndex -1);
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_priorityDown_clicked()
|
||||
{
|
||||
int currentIndex = ui->priorityList->currentRow();
|
||||
if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1)
|
||||
{
|
||||
ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex));
|
||||
ui->priorityList->setCurrentRow(currentIndex + 1);
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool SwitcherData::prioFuncsValid()
|
||||
{
|
||||
auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end());
|
||||
bool wasUnique = (it == functionNamesByPriority.end());
|
||||
if (!wasUnique)
|
||||
return false;
|
||||
|
||||
for (int p : functionNamesByPriority)
|
||||
{
|
||||
if (p < 0 || p > 7)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
144
src/random.cpp
Normal file
144
src/random.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include <random>
|
||||
|
||||
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->randomScenesList->item(idx);
|
||||
|
||||
QString randomSceneStr = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->randomSwitches)
|
||||
{
|
||||
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
|
||||
{
|
||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
||||
QString transitionName = GetWeakSourceName(s.transition).c_str();
|
||||
ui->randomScenes->setCurrentText(sceneName);
|
||||
ui->randomSpinBox->setValue(s.delay);
|
||||
ui->randomTransitions->setCurrentText(transitionName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::randomFindByData(const QString& randomStr)
|
||||
{
|
||||
int count = ui->randomScenesList->count();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->randomScenesList->item(i);
|
||||
QString str = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (str == randomStr)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_randomAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->randomScenes->currentText();
|
||||
QString transitionName = ui->randomTransitions->currentText();
|
||||
double delay = ui->randomSpinBox->value();
|
||||
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
|
||||
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = randomFindByData(text);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->randomSwitches.emplace_back(
|
||||
source, transition, delay, text.toUtf8().constData());
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
|
||||
item->setData(Qt::UserRole, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->randomScenesList->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->randomSwitches)
|
||||
{
|
||||
if (s.scene == source)
|
||||
{
|
||||
s.delay = delay;
|
||||
s.transition = transition;
|
||||
s.randomSwitchStr = text.toUtf8().constData();;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->randomScenesList->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_randomRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->randomScenesList->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->randomSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.randomSwitchStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
|
||||
{
|
||||
if (randomSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
vector<RandomSwitch> rs (randomSwitches);
|
||||
std::random_device rng;
|
||||
std::mt19937 urng(rng());
|
||||
std::shuffle(rs.begin(), rs.end(), urng);
|
||||
for (RandomSwitch& r : rs)
|
||||
{
|
||||
if (r.scene == lastRandomScene)
|
||||
continue;
|
||||
scene = r.scene;
|
||||
transition = r.transition;
|
||||
delay = (int)r.delay * 1000;
|
||||
match = true;
|
||||
lastRandomScene = r.scene;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,308 +1,312 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <obs.hpp>
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
||||
{
|
||||
QString scene1Name = ui->sceneRoundTripScenes1->currentText();
|
||||
QString scene2Name = ui->sceneRoundTripScenes2->currentText();
|
||||
QString transitionName = ui->sceneRoundTripTransitions->currentText();
|
||||
|
||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
||||
return;
|
||||
|
||||
int delay = ui->sceneRoundTripSpinBox->value();
|
||||
|
||||
if (scene1Name == scene2Name)
|
||||
return;
|
||||
|
||||
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
|
||||
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = SceneRoundTripFindByData(scene1Name);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->sceneRoundTripSwitches.emplace_back(
|
||||
source1, source2, transition, delay, text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
if (s.scene1 == source1 && s.scene2 == source2)
|
||||
{
|
||||
s.delay = delay;
|
||||
s.transition = transition;
|
||||
s.sceneRoundTripStr = text.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->sceneRoundTrips->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->sceneRoundTripSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.sceneRoundTripStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (!state)
|
||||
{
|
||||
ui->autoStopScenes->setDisabled(true);
|
||||
switcher->autoStopEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->autoStopScenes->setDisabled(false);
|
||||
switcher->autoStopEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::UpdateAutoStopScene(const QString& name)
|
||||
{
|
||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->autoStopScene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateAutoStopScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripSave_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return;
|
||||
QTextStream out(&file);
|
||||
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
|
||||
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
|
||||
out << s.delay << "\n";
|
||||
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
|
||||
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripLoad_clicked()
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
QTextStream in(&file);
|
||||
vector<QString> lines;
|
||||
|
||||
vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
|
||||
|
||||
while (!in.atEnd())
|
||||
{
|
||||
QString line = in.readLine();
|
||||
lines.push_back(line);
|
||||
if (lines.size() == 5)
|
||||
{
|
||||
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
|
||||
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
|
||||
|
||||
if (WeakSourceValid(scene1) && WeakSourceValid(scene2)
|
||||
&& WeakSourceValid(transition))
|
||||
{
|
||||
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
|
||||
GetWeakSourceByQString(lines[0]),
|
||||
GetWeakSourceByQString(lines[1]),
|
||||
GetWeakTransitionByQString(lines[4]),
|
||||
lines[2].toInt(),
|
||||
lines[3].toStdString()));
|
||||
}
|
||||
lines.clear();
|
||||
}
|
||||
}
|
||||
//unvalid amount of lines in file or nothing valid read
|
||||
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
|
||||
return;
|
||||
|
||||
switcher->sceneRoundTripSwitches.clear();
|
||||
ui->sceneRoundTrips->clear();
|
||||
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
|
||||
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips);
|
||||
item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock)
|
||||
{
|
||||
bool sceneRoundTripActive = false;
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (SceneRoundTripSwitch& s : sceneRoundTripSwitches)
|
||||
{
|
||||
if (s.scene1 == ws)
|
||||
{
|
||||
sceneRoundTripActive = true;
|
||||
int dur = s.delay * 1000 - interval;
|
||||
if (dur > 0)
|
||||
{
|
||||
string s = obs_source_get_name(currentSource);
|
||||
waitSceneName = s;
|
||||
cv.wait_for(lock, chrono::milliseconds(dur));
|
||||
}
|
||||
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
|
||||
|
||||
// only switch if user hasn't changed scene manually
|
||||
if (currentSource == currentSource2)
|
||||
{
|
||||
match = true;
|
||||
scene = s.scene2;
|
||||
transition = s.transition;
|
||||
}
|
||||
obs_source_release(currentSource2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
||||
|
||||
QString sceneRoundTrip = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0)
|
||||
{
|
||||
string scene1 = GetWeakSourceName(s.scene1);
|
||||
string scene2 = GetWeakSourceName(s.scene2);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
int delay = s.delay;
|
||||
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
|
||||
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
|
||||
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
|
||||
ui->sceneRoundTripSpinBox->setValue(delay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
|
||||
{
|
||||
QRegExp rx(scene1 + " -> wait for [0-9]* seconds -> .*");
|
||||
int count = ui->sceneRoundTrips->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(i);
|
||||
QString itemString = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(itemString))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
void SwitcherData::autoStopStreamAndRecording()
|
||||
{
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
if (ws && autoStopScene == ws)
|
||||
{
|
||||
if (obs_frontend_streaming_active())
|
||||
obs_frontend_streaming_stop();
|
||||
if (obs_frontend_recording_active())
|
||||
obs_frontend_recording_stop();
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <obs.hpp>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
||||
{
|
||||
QString scene1Name = ui->sceneRoundTripScenes1->currentText();
|
||||
QString scene2Name = ui->sceneRoundTripScenes2->currentText();
|
||||
QString transitionName = ui->sceneRoundTripTransitions->currentText();
|
||||
|
||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
||||
return;
|
||||
|
||||
double delay = ui->sceneRoundTripSpinBox->value();
|
||||
|
||||
if (scene1Name == scene2Name)
|
||||
return;
|
||||
|
||||
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
|
||||
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = SceneRoundTripFindByData(scene1Name);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->sceneRoundTripSwitches.emplace_back(
|
||||
source1, source2, transition, int(delay * 1000),
|
||||
(scene2Name == QString(PREVIOUS_SCENE_NAME)),
|
||||
text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
if (s.scene1 == source1)
|
||||
{
|
||||
s.scene2 = source2;
|
||||
s.delay = int(delay * 1000);
|
||||
s.transition = transition;
|
||||
s.usePreviousScene = (scene2Name == QString(PREVIOUS_SCENE_NAME));
|
||||
s.sceneRoundTripStr = text.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->sceneRoundTrips->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->sceneRoundTripSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.sceneRoundTripStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
if (!state)
|
||||
{
|
||||
ui->autoStopScenes->setDisabled(true);
|
||||
switcher->autoStopEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->autoStopScenes->setDisabled(false);
|
||||
switcher->autoStopEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::UpdateAutoStopScene(const QString& name)
|
||||
{
|
||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->autoStopScene = ws;
|
||||
|
||||
obs_weak_source_release(ws);
|
||||
obs_source_release(scene);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
UpdateAutoStopScene(text);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripSave_clicked()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return;
|
||||
QTextStream out(&file);
|
||||
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
|
||||
if (s.usePreviousScene)
|
||||
out << (PREVIOUS_SCENE_NAME) << "\n";
|
||||
else
|
||||
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
|
||||
out << s.delay << "\n";
|
||||
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
|
||||
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTripLoad_clicked()
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
|
||||
QString directory = QFileDialog::getOpenFileName(
|
||||
this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
QTextStream in(&file);
|
||||
vector<QString> lines;
|
||||
|
||||
vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
|
||||
|
||||
while (!in.atEnd())
|
||||
{
|
||||
QString line = in.readLine();
|
||||
lines.push_back(line);
|
||||
if (lines.size() == 5)
|
||||
{
|
||||
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
|
||||
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
|
||||
|
||||
if (WeakSourceValid(scene1) && ((lines[1] == QString(PREVIOUS_SCENE_NAME)) || (WeakSourceValid(scene2)))
|
||||
&& WeakSourceValid(transition))
|
||||
{
|
||||
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
|
||||
GetWeakSourceByQString(lines[0]),
|
||||
GetWeakSourceByQString(lines[1]),
|
||||
GetWeakTransitionByQString(lines[4]),
|
||||
lines[2].toInt(),
|
||||
(lines[1] == QString(PREVIOUS_SCENE_NAME)),
|
||||
lines[3].toStdString()));
|
||||
}
|
||||
lines.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
|
||||
return;
|
||||
|
||||
switcher->sceneRoundTripSwitches.clear();
|
||||
ui->sceneRoundTrips->clear();
|
||||
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
|
||||
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips);
|
||||
item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock)
|
||||
{
|
||||
bool sceneRoundTripActive = false;
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (SceneRoundTripSwitch& s : sceneRoundTripSwitches)
|
||||
{
|
||||
if (s.scene1 == ws)
|
||||
{
|
||||
sceneRoundTripActive = true;
|
||||
int dur = s.delay - interval;
|
||||
if (dur > 0)
|
||||
{
|
||||
waitScene = currentSource;
|
||||
cv.wait_for(lock, chrono::milliseconds(dur));
|
||||
}
|
||||
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
|
||||
|
||||
// only switch if user hasn't changed scene manually
|
||||
if (currentSource == currentSource2)
|
||||
{
|
||||
match = true;
|
||||
scene = (s.usePreviousScene) ? previousScene : s.scene2;
|
||||
transition = s.transition;
|
||||
}
|
||||
obs_source_release(currentSource2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
||||
|
||||
QString sceneRoundTrip = item->text();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||
{
|
||||
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0)
|
||||
{
|
||||
string scene1 = GetWeakSourceName(s.scene1);
|
||||
string scene2 = GetWeakSourceName(s.scene2);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
int delay = s.delay;
|
||||
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
|
||||
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
|
||||
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
|
||||
ui->sceneRoundTripSpinBox->setValue((double)delay/1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
|
||||
{
|
||||
QRegExp rx(scene1 + " ->.*");
|
||||
int count = ui->sceneRoundTrips->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneRoundTrips->item(i);
|
||||
QString itemString = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(itemString))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
void SwitcherData::autoStopStreamAndRecording()
|
||||
{
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
if (ws && autoStopScene == ws)
|
||||
{
|
||||
if (obs_frontend_streaming_active())
|
||||
obs_frontend_streaming_stop();
|
||||
if (obs_frontend_recording_active())
|
||||
obs_frontend_recording_stop();
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
@@ -1,283 +1,284 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_transitionsAdd_clicked()
|
||||
{
|
||||
QString scene1Name = ui->transitionsScene1->currentText();
|
||||
QString scene2Name = ui->transitionsScene2->currentText();
|
||||
QString transitionName = ui->transitionsTransitions->currentText();
|
||||
|
||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
||||
return;
|
||||
|
||||
if (scene1Name == scene2Name)
|
||||
return;
|
||||
|
||||
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
|
||||
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->sceneTransitions.emplace_back(
|
||||
source1, source2, transition, text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneTransitions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneTransitions)
|
||||
{
|
||||
if (s.scene1 == source1 && s.scene2 == source2)
|
||||
{
|
||||
s.transition = transition;
|
||||
s.sceneTransitionStr = text.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->sceneTransitions->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_transitionsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneTransitions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->sceneTransitions;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.sceneTransitionStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_defaultTransitionsAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->defaultTransitionsScene->currentText();
|
||||
QString transitionName = ui->defaultTransitionsTransitions->currentText();
|
||||
|
||||
if (sceneName.isEmpty() || transitionName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeDefaultSceneTransitionName(sceneName, transitionName);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = DefaultTransitionsFindByData(sceneName);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->defaultSceneTransitions.emplace_back(
|
||||
source, transition, text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->defaultSceneTransitions)
|
||||
{
|
||||
if (s.scene == source)
|
||||
{
|
||||
s.transition = transition;
|
||||
s.sceneTransitionStr = text.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->defaultTransitions->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_defaultTransitionsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->defaultSceneTransitions;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.sceneTransitionStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::setDefaultSceneTransitions(unique_lock<mutex>& lock)
|
||||
{
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (DefaultSceneTransition& s : defaultSceneTransitions)
|
||||
{
|
||||
if (s.scene == ws)
|
||||
{
|
||||
obs_source_t* transition = obs_weak_source_get_source(s.transition);
|
||||
//sleep planned but no fitting OBS event to measure transition time
|
||||
obs_frontend_set_current_transition(transition);
|
||||
obs_source_release(transition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
|
||||
int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2)
|
||||
{
|
||||
QRegExp rx(scene1 + " --- .* --> " + scene2);
|
||||
int count = ui->sceneTransitions->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneTransitions->item(i);
|
||||
QString itemString = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(itemString))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene)
|
||||
{
|
||||
QRegExp rx(scene + " --> .*");
|
||||
int count = ui->defaultTransitions->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(i);
|
||||
QString itemString = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(itemString))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->sceneTransitions->item(idx);
|
||||
|
||||
QString sceneTransition = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneTransitions)
|
||||
{
|
||||
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
|
||||
{
|
||||
string scene1 = GetWeakSourceName(s.scene1);
|
||||
string scene2 = GetWeakSourceName(s.scene2);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->transitionsScene1->setCurrentText(scene1.c_str());
|
||||
ui->transitionsScene2->setCurrentText(scene2.c_str());
|
||||
ui->transitionsTransitions->setCurrentText(transitionName.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(idx);
|
||||
|
||||
QString sceneTransition = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->defaultSceneTransitions)
|
||||
{
|
||||
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
|
||||
{
|
||||
string scene = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->defaultTransitionsScene->setCurrentText(scene.c_str());
|
||||
ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2)
|
||||
{
|
||||
obs_weak_source_t* ws = nullptr;
|
||||
if (scene1 && scene2)
|
||||
{
|
||||
for (SceneTransition& t : switcher->sceneTransitions)
|
||||
{
|
||||
if (t.scene1 == scene1 && t.scene2 == scene2)
|
||||
ws = t.transition;
|
||||
}
|
||||
obs_weak_source_addref(ws);
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_transitionsAdd_clicked()
|
||||
{
|
||||
QString scene1Name = ui->transitionsScene1->currentText();
|
||||
QString scene2Name = ui->transitionsScene2->currentText();
|
||||
QString transitionName = ui->transitionsTransitions->currentText();
|
||||
|
||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
||||
return;
|
||||
|
||||
if (scene1Name == scene2Name)
|
||||
return;
|
||||
|
||||
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
|
||||
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->sceneTransitions.emplace_back(
|
||||
source1, source2, transition, text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneTransitions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneTransitions)
|
||||
{
|
||||
if (s.scene1 == source1 && s.scene2 == source2)
|
||||
{
|
||||
s.transition = transition;
|
||||
s.sceneTransitionStr = text.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->sceneTransitions->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_transitionsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneTransitions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->sceneTransitions;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.sceneTransitionStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_defaultTransitionsAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->defaultTransitionsScene->currentText();
|
||||
QString transitionName = ui->defaultTransitionsTransitions->currentText();
|
||||
|
||||
if (sceneName.isEmpty() || transitionName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeDefaultSceneTransitionName(sceneName, transitionName);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = DefaultTransitionsFindByData(sceneName);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->defaultSceneTransitions.emplace_back(
|
||||
source, transition, text.toUtf8().constData());
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->defaultSceneTransitions)
|
||||
{
|
||||
if (s.scene == source)
|
||||
{
|
||||
s.transition = transition;
|
||||
s.sceneTransitionStr = text.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->defaultTransitions->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_defaultTransitionsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->defaultSceneTransitions;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.sceneTransitionStr == text)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::setDefaultSceneTransitions()
|
||||
{
|
||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||
|
||||
for (DefaultSceneTransition& s : defaultSceneTransitions)
|
||||
{
|
||||
if (s.scene == ws)
|
||||
{
|
||||
obs_source_t* transition = obs_weak_source_get_source(s.transition);
|
||||
//This might cancel the current transition
|
||||
//There is no way to be sure when the previous transition finished
|
||||
obs_frontend_set_current_transition(transition);
|
||||
obs_source_release(transition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
obs_source_release(currentSource);
|
||||
obs_weak_source_release(ws);
|
||||
}
|
||||
|
||||
int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2)
|
||||
{
|
||||
QRegExp rx(scene1 + " --- .* --> " + scene2);
|
||||
int count = ui->sceneTransitions->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->sceneTransitions->item(i);
|
||||
QString itemString = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(itemString))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene)
|
||||
{
|
||||
QRegExp rx(scene + " --> .*");
|
||||
int count = ui->defaultTransitions->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(i);
|
||||
QString itemString = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(itemString))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->sceneTransitions->item(idx);
|
||||
|
||||
QString sceneTransition = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->sceneTransitions)
|
||||
{
|
||||
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
|
||||
{
|
||||
string scene1 = GetWeakSourceName(s.scene1);
|
||||
string scene2 = GetWeakSourceName(s.scene2);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->transitionsScene1->setCurrentText(scene1.c_str());
|
||||
ui->transitionsScene2->setCurrentText(scene2.c_str());
|
||||
ui->transitionsTransitions->setCurrentText(transitionName.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->defaultTransitions->item(idx);
|
||||
|
||||
QString sceneTransition = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->defaultSceneTransitions)
|
||||
{
|
||||
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
|
||||
{
|
||||
string scene = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->defaultTransitionsScene->setCurrentText(scene.c_str());
|
||||
ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2)
|
||||
{
|
||||
obs_weak_source_t* ws = nullptr;
|
||||
if (scene1 && scene2)
|
||||
{
|
||||
for (SceneTransition& t : switcher->sceneTransitions)
|
||||
{
|
||||
if (t.scene1 == scene1 && t.scene2 == scene2)
|
||||
ws = t.transition;
|
||||
}
|
||||
obs_weak_source_addref(ws);
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
@@ -1,165 +1,165 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
pair<int, int> cursorPos = getCursorPos();
|
||||
int minRegionSize = 99999;
|
||||
|
||||
for (auto& s : screenRegionSwitches)
|
||||
{
|
||||
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY
|
||||
&& cursorPos.first <= s.maxX && cursorPos.second <= s.maxY)
|
||||
{
|
||||
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
|
||||
if (regionSize < minRegionSize)
|
||||
{
|
||||
match = true;
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
minRegionSize = regionSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::updateScreenRegionCursorPos()
|
||||
{
|
||||
pair<int, int> position = getCursorPos();
|
||||
ui->cursorXPosition->setText(QString::number(position.first));
|
||||
;
|
||||
ui->cursorYPosition->setText(QString::number(position.second));
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_screenRegionAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->screenRegionScenes->currentText();
|
||||
QString transitionName = ui->screenRegionsTransitions->currentText();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
int minX = ui->screenRegionMinX->value();
|
||||
int minY = ui->screenRegionMinY->value();
|
||||
int maxX = ui->screenRegionMaxX->value();
|
||||
int maxY = ui->screenRegionMaxY->value();
|
||||
|
||||
string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", "
|
||||
+ to_string(maxY);
|
||||
QString region = QString::fromStdString(regionStr);
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
QVariant v = QVariant::fromValue(region);
|
||||
|
||||
QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY);
|
||||
|
||||
int idx = ScreenRegionFindByData(region);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->screenRegionSwitches.emplace_back(
|
||||
source, transition, minX, minY, maxX, maxY, regionStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->screenRegions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
string curRegion = region.toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->screenRegionSwitches)
|
||||
{
|
||||
if (s.regionStr == curRegion)
|
||||
{
|
||||
s.scene = source;
|
||||
s.transition = transition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->screenRegions->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_screenRegionRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->screenRegions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string region = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->screenRegionSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.regionStr == region)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->screenRegions->item(idx);
|
||||
|
||||
QString region = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->screenRegionSwitches)
|
||||
{
|
||||
if (region.compare(s.regionStr.c_str()) == 0)
|
||||
{
|
||||
string name = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->screenRegionScenes->setCurrentText(name.c_str());
|
||||
ui->screenRegionsTransitions->setCurrentText(transitionName.c_str());
|
||||
ui->screenRegionMinX->setValue(s.minX);
|
||||
ui->screenRegionMinY->setValue(s.minY);
|
||||
ui->screenRegionMaxX->setValue(s.maxX);
|
||||
ui->screenRegionMaxY->setValue(s.maxY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::ScreenRegionFindByData(const QString& region)
|
||||
{
|
||||
int count = ui->screenRegions->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->screenRegions->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == region)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
pair<int, int> cursorPos = getCursorPos();
|
||||
int minRegionSize = 99999;
|
||||
|
||||
for (auto& s : screenRegionSwitches)
|
||||
{
|
||||
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY
|
||||
&& cursorPos.first <= s.maxX && cursorPos.second <= s.maxY)
|
||||
{
|
||||
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
|
||||
if (regionSize < minRegionSize)
|
||||
{
|
||||
match = true;
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
minRegionSize = regionSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::updateScreenRegionCursorPos()
|
||||
{
|
||||
pair<int, int> position = getCursorPos();
|
||||
ui->cursorXPosition->setText(QString::number(position.first));
|
||||
;
|
||||
ui->cursorYPosition->setText(QString::number(position.second));
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_screenRegionAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->screenRegionScenes->currentText();
|
||||
QString transitionName = ui->screenRegionsTransitions->currentText();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
int minX = ui->screenRegionMinX->value();
|
||||
int minY = ui->screenRegionMinY->value();
|
||||
int maxX = ui->screenRegionMaxX->value();
|
||||
int maxY = ui->screenRegionMaxY->value();
|
||||
|
||||
string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", "
|
||||
+ to_string(maxY);
|
||||
QString region = QString::fromStdString(regionStr);
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
QVariant v = QVariant::fromValue(region);
|
||||
|
||||
QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY);
|
||||
|
||||
int idx = ScreenRegionFindByData(region);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->screenRegionSwitches.emplace_back(
|
||||
source, transition, minX, minY, maxX, maxY, regionStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->screenRegions->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
string curRegion = region.toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->screenRegionSwitches)
|
||||
{
|
||||
if (s.regionStr == curRegion)
|
||||
{
|
||||
s.scene = source;
|
||||
s.transition = transition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->screenRegions->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_screenRegionRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->screenRegions->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string region = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->screenRegionSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.regionStr == region)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->screenRegions->item(idx);
|
||||
|
||||
QString region = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->screenRegionSwitches)
|
||||
{
|
||||
if (region.compare(s.regionStr.c_str()) == 0)
|
||||
{
|
||||
string name = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->screenRegionScenes->setCurrentText(name.c_str());
|
||||
ui->screenRegionsTransitions->setCurrentText(transitionName.c_str());
|
||||
ui->screenRegionMinX->setValue(s.minX);
|
||||
ui->screenRegionMinY->setValue(s.minY);
|
||||
ui->screenRegionMaxX->setValue(s.maxX);
|
||||
ui->screenRegionMaxY->setValue(s.maxY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::ScreenRegionFindByData(const QString& region)
|
||||
{
|
||||
int count = ui->screenRegions->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->screenRegions->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == region)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
147
src/time-switch.cpp
Normal file
147
src/time-switch.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem *item = ui->timeSwitches->item(idx);
|
||||
|
||||
QString timeScenestr = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->timeSwitches) {
|
||||
if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
|
||||
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
||||
QString transitionName =
|
||||
GetWeakSourceName(s.transition).c_str();
|
||||
ui->timeScenes->setCurrentText(sceneName);
|
||||
ui->timeEdit->setTime(s.time);
|
||||
ui->timeTransitions->setCurrentText(transitionName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneSwitcher::timeFindByData(const QString &timeStr)
|
||||
{
|
||||
QRegExp rx("At " + timeStr + " switch to .*");
|
||||
int count = ui->timeSwitches->count();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
QListWidgetItem *item = ui->timeSwitches->item(i);
|
||||
QString str = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (rx.exactMatch(str))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_timeAdd_clicked()
|
||||
{
|
||||
QString sceneName = ui->timeScenes->currentText();
|
||||
QString transitionName = ui->timeTransitions->currentText();
|
||||
QTime time = ui->timeEdit->time();
|
||||
|
||||
if (sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
|
||||
QString text = MakeTimeSwitchName(sceneName, transitionName, time);
|
||||
QVariant v = QVariant::fromValue(text);
|
||||
|
||||
int idx = timeFindByData(time.toString());
|
||||
|
||||
if (idx == -1) {
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->timeSwitches.emplace_back(
|
||||
source, transition, time,
|
||||
(sceneName == QString(PREVIOUS_SCENE_NAME)),
|
||||
text.toUtf8().constData());
|
||||
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->timeSwitches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
} else {
|
||||
QListWidgetItem *item = ui->timeSwitches->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto &s : switcher->timeSwitches) {
|
||||
if (s.time == time) {
|
||||
s.scene = source;
|
||||
s.transition = transition;
|
||||
s.usePreviousScene =
|
||||
(sceneName ==
|
||||
QString(PREVIOUS_SCENE_NAME));
|
||||
s.timeSwitchStr =
|
||||
text.toUtf8().constData();
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->timeSwitches->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_timeRemove_clicked()
|
||||
{
|
||||
QListWidgetItem *item = ui->timeSwitches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto &switches = switcher->timeSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it) {
|
||||
auto &s = *it;
|
||||
|
||||
if (s.timeSwitchStr == text) {
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
if (timeSwitches.size() == 0)
|
||||
return;
|
||||
|
||||
QTime now = QTime::currentTime();
|
||||
|
||||
for (TimeSwitch &s : timeSwitches) {
|
||||
|
||||
QTime validSwitchTimeWindow = s.time.addMSecs(interval);
|
||||
|
||||
match = s.time <= now && now <= validSwitchTimeWindow;
|
||||
if (!match &&
|
||||
validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
|
||||
// check for overflow
|
||||
match = now >= s.time || now <= validSwitchTimeWindow;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
scene = (s.usePreviousScene) ? previousScene : s.scene;
|
||||
transition = s.transition;
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,167 +1,168 @@
|
||||
#include <windows.h>
|
||||
#include <util/platform.h>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include <TlHelp32.h>
|
||||
#include <Psapi.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool GetWindowTitle(HWND window, string& title)
|
||||
{
|
||||
size_t len = (size_t)GetWindowTextLengthW(window);
|
||||
wstring wtitle;
|
||||
|
||||
wtitle.resize(len);
|
||||
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
|
||||
return false;
|
||||
|
||||
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
|
||||
title.resize(len);
|
||||
os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WindowValid(HWND window)
|
||||
{
|
||||
LONG_PTR styles, ex_styles;
|
||||
RECT rect;
|
||||
DWORD id;
|
||||
|
||||
if (!IsWindowVisible(window))
|
||||
return false;
|
||||
GetWindowThreadProcessId(window, &id);
|
||||
if (id == GetCurrentProcessId())
|
||||
return false;
|
||||
|
||||
GetClientRect(window, &rect);
|
||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
|
||||
|
||||
if (ex_styles & WS_EX_TOOLWINDOW)
|
||||
return false;
|
||||
if (styles & WS_CHILD)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetWindowList(vector<string>& windows)
|
||||
{
|
||||
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
|
||||
|
||||
while (window)
|
||||
{
|
||||
string title;
|
||||
if (WindowValid(window) && GetWindowTitle(window, title))
|
||||
windows.emplace_back(title);
|
||||
window = GetNextWindow(window, GW_HWNDNEXT);
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string& title)
|
||||
{
|
||||
HWND window = GetForegroundWindow();
|
||||
DWORD id;
|
||||
GetWindowThreadProcessId(window, &id);
|
||||
/*GetWindowText will freeze if the control it is reading was created in another thread.
|
||||
It does not directly read the control.Instead,
|
||||
it waits for the thread that created the control to process a WM_GETTEXT message.
|
||||
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
|
||||
if (id == GetCurrentProcessId()) {
|
||||
title = "";
|
||||
return;
|
||||
}
|
||||
GetWindowTitle(window, title);
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos()
|
||||
{
|
||||
pair<int, int> pos(0, 0);
|
||||
POINT cursorPos;
|
||||
if (GetPhysicalCursorPos(&cursorPos))
|
||||
{
|
||||
pos.first = cursorPos.x;
|
||||
pos.second = cursorPos.y;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool isFullscreen()
|
||||
{
|
||||
RECT appBounds;
|
||||
RECT rc;
|
||||
GetWindowRect(GetDesktopWindow(), &rc);
|
||||
HWND hwnd = GetForegroundWindow();
|
||||
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow())
|
||||
{
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left
|
||||
&& rc.right == appBounds.right)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes) {
|
||||
|
||||
HANDLE procSnapshot;
|
||||
PROCESSENTRY32 procEntry;
|
||||
|
||||
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (procSnapshot == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(procSnapshot, &procEntry)) {
|
||||
CloseHandle(procSnapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
|
||||
if (tempexe == "System") continue;
|
||||
if (tempexe == "[System Process]") continue;
|
||||
if (processes.contains(tempexe)) continue;
|
||||
processes.append(tempexe);
|
||||
} while (Process32Next(procSnapshot, &procEntry));
|
||||
|
||||
CloseHandle(procSnapshot);
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &exeToCheck) {
|
||||
// only checks if the current foreground window is from the same executable,
|
||||
// may return true for incorrent not meant windows from a program
|
||||
HWND foregroundWindow = GetForegroundWindow();
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(foregroundWindow, &processId);
|
||||
|
||||
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||
if (process == NULL) return false;
|
||||
|
||||
WCHAR executablePath[600];
|
||||
GetModuleFileNameEx(process, 0, executablePath, 600);
|
||||
CloseHandle(process);
|
||||
|
||||
return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back();
|
||||
}
|
||||
|
||||
int getLastInputTime()
|
||||
{
|
||||
LASTINPUTINFO lastInputInfo;
|
||||
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
|
||||
if (GetLastInputInfo(&lastInputInfo))
|
||||
return lastInputInfo.dwTime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getTime()
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
int secondsSinceLastInput()
|
||||
{
|
||||
return (getTime() - getLastInputTime()) / 1000;
|
||||
}
|
||||
#include <windows.h>
|
||||
#include <util/platform.h>
|
||||
#include "../headers/advanced-scene-switcher.hpp"
|
||||
#include <TlHelp32.h>
|
||||
#include <Psapi.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool GetWindowTitle(HWND window, string& title)
|
||||
{
|
||||
size_t len = (size_t)GetWindowTextLengthW(window);
|
||||
wstring wtitle;
|
||||
|
||||
wtitle.resize(len);
|
||||
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
|
||||
return false;
|
||||
|
||||
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
|
||||
title.resize(len);
|
||||
os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WindowValid(HWND window)
|
||||
{
|
||||
LONG_PTR styles, ex_styles;
|
||||
RECT rect;
|
||||
DWORD id;
|
||||
|
||||
if (!IsWindowVisible(window))
|
||||
return false;
|
||||
GetWindowThreadProcessId(window, &id);
|
||||
if (id == GetCurrentProcessId())
|
||||
return false;
|
||||
|
||||
GetClientRect(window, &rect);
|
||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
|
||||
|
||||
if (ex_styles & WS_EX_TOOLWINDOW)
|
||||
return false;
|
||||
if (styles & WS_CHILD)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetWindowList(vector<string>& windows)
|
||||
{
|
||||
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
|
||||
|
||||
while (window)
|
||||
{
|
||||
string title;
|
||||
if (WindowValid(window) && GetWindowTitle(window, title))
|
||||
windows.emplace_back(title);
|
||||
window = GetNextWindow(window, GW_HWNDNEXT);
|
||||
}
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(string& title)
|
||||
{
|
||||
HWND window = GetForegroundWindow();
|
||||
DWORD pid;
|
||||
DWORD thid;
|
||||
thid = GetWindowThreadProcessId(window, &pid);
|
||||
/*GetWindowText will freeze if the control it is reading was created in another thread.
|
||||
It does not directly read the control.Instead,
|
||||
it waits for the thread that created the control to process a WM_GETTEXT message.
|
||||
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
|
||||
if (GetCurrentProcessId() == pid) {
|
||||
title = "OBS";
|
||||
return;
|
||||
}
|
||||
GetWindowTitle(window, title);
|
||||
}
|
||||
|
||||
pair<int, int> getCursorPos()
|
||||
{
|
||||
pair<int, int> pos(0, 0);
|
||||
POINT cursorPos;
|
||||
if (GetPhysicalCursorPos(&cursorPos))
|
||||
{
|
||||
pos.first = cursorPos.x;
|
||||
pos.second = cursorPos.y;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool isFullscreen()
|
||||
{
|
||||
RECT appBounds;
|
||||
RECT rc;
|
||||
GetWindowRect(GetDesktopWindow(), &rc);
|
||||
HWND hwnd = GetForegroundWindow();
|
||||
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow())
|
||||
{
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left
|
||||
&& rc.right == appBounds.right)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes) {
|
||||
|
||||
HANDLE procSnapshot;
|
||||
PROCESSENTRY32 procEntry;
|
||||
|
||||
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (procSnapshot == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(procSnapshot, &procEntry)) {
|
||||
CloseHandle(procSnapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
|
||||
if (tempexe == "System") continue;
|
||||
if (tempexe == "[System Process]") continue;
|
||||
if (processes.contains(tempexe)) continue;
|
||||
processes.append(tempexe);
|
||||
} while (Process32Next(procSnapshot, &procEntry));
|
||||
|
||||
CloseHandle(procSnapshot);
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &exeToCheck) {
|
||||
// only checks if the current foreground window is from the same executable,
|
||||
// may return true for incorrent not meant windows from a program
|
||||
HWND foregroundWindow = GetForegroundWindow();
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(foregroundWindow, &processId);
|
||||
|
||||
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||
if (process == NULL) return false;
|
||||
|
||||
WCHAR executablePath[600];
|
||||
GetModuleFileNameEx(process, 0, executablePath, 600);
|
||||
CloseHandle(process);
|
||||
|
||||
return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back();
|
||||
}
|
||||
|
||||
int getLastInputTime()
|
||||
{
|
||||
LASTINPUTINFO lastInputInfo;
|
||||
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
|
||||
if (GetLastInputInfo(&lastInputInfo))
|
||||
return lastInputInfo.dwTime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getTime()
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
int secondsSinceLastInput()
|
||||
{
|
||||
return (getTime() - getLastInputTime()) / 1000;
|
||||
}
|
||||
@@ -1,276 +1,280 @@
|
||||
#include <obs-module.h>
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_add_clicked()
|
||||
{
|
||||
QString sceneName = ui->scenes->currentText();
|
||||
QString windowName = ui->windows->currentText();
|
||||
QString transitionName = ui->transitions->currentText();
|
||||
bool fullscreen = ui->fullscreenCheckBox->isChecked();
|
||||
|
||||
if (windowName.isEmpty() || sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen);
|
||||
|
||||
int idx = FindByData(windowName);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switches.emplace_back(
|
||||
source, windowName.toUtf8().constData(), transition, fullscreen);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->switches->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
string window = windowName.toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->switches)
|
||||
{
|
||||
if (s.window == window)
|
||||
{
|
||||
s.scene = source;
|
||||
s.transition = transition;
|
||||
s.fullscreen = fullscreen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->switches->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_remove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->switches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string window = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->switches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.window == window)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->ignoreWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData());
|
||||
ui->ignoreWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->ignoreWindowsSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == windowName.toUtf8().constData())
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
int SceneSwitcher::FindByData(const QString& window)
|
||||
{
|
||||
int count = ui->switches->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->switches->item(i);
|
||||
QString itemWindow = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemWindow == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
|
||||
{
|
||||
int count = ui->ignoreWindows->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreWindows->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_switches_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->switches->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->switches)
|
||||
{
|
||||
if (window.compare(s.window.c_str()) == 0)
|
||||
{
|
||||
string name = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->scenes->setCurrentText(name.c_str());
|
||||
ui->windows->setCurrentText(window);
|
||||
ui->transitions->setCurrentText(transitionName.c_str());
|
||||
ui->fullscreenCheckBox->setChecked(s.fullscreen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->ignoreWindows->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->ignoreWindowsSwitches)
|
||||
{
|
||||
if (window.compare(s.c_str()) == 0)
|
||||
{
|
||||
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
//check if title should be ignored
|
||||
string title;
|
||||
GetCurrentWindowTitle(title);
|
||||
for (auto& window : ignoreWindowsSwitches)
|
||||
{
|
||||
if (window == title)
|
||||
{
|
||||
title = lastTitle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastTitle = title;
|
||||
|
||||
//direct match
|
||||
for (SceneSwitch& s : switches)
|
||||
{
|
||||
if (s.window == title)
|
||||
{
|
||||
match = !s.fullscreen || (s.fullscreen && isFullscreen());
|
||||
scene = s.scene;
|
||||
transition = s.transition;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//regex match
|
||||
for (SceneSwitch& s : switches)
|
||||
{
|
||||
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&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <obs-module.h>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void SceneSwitcher::on_add_clicked()
|
||||
{
|
||||
QString sceneName = ui->scenes->currentText();
|
||||
QString windowName = ui->windows->currentText();
|
||||
QString transitionName = ui->transitions->currentText();
|
||||
bool fullscreen = ui->fullscreenCheckBox->isChecked();
|
||||
|
||||
if (windowName.isEmpty() || sceneName.isEmpty())
|
||||
return;
|
||||
|
||||
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen);
|
||||
|
||||
int idx = FindByData(windowName);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->windowSwitches.emplace_back(
|
||||
source, windowName.toUtf8().constData(), transition, fullscreen);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
QListWidgetItem* item = ui->switches->item(idx);
|
||||
item->setText(text);
|
||||
|
||||
string window = windowName.toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->windowSwitches)
|
||||
{
|
||||
if (s.window == window)
|
||||
{
|
||||
s.scene = source;
|
||||
s.transition = transition;
|
||||
s.fullscreen = fullscreen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->switches->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_remove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->switches->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
string window = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->windowSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s.window == window)
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
|
||||
{
|
||||
QString windowName = ui->ignoreWindowsWindows->currentText();
|
||||
|
||||
if (windowName.isEmpty())
|
||||
return;
|
||||
|
||||
QVariant v = QVariant::fromValue(windowName);
|
||||
|
||||
QList<QListWidgetItem*> items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
|
||||
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows);
|
||||
item->setData(Qt::UserRole, v);
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData());
|
||||
ui->ignoreWindows->sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreWindows->currentItem();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString windowName = item->data(Qt::UserRole).toString();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
auto& switches = switcher->ignoreWindowsSwitches;
|
||||
|
||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||
{
|
||||
auto& s = *it;
|
||||
|
||||
if (s == windowName.toUtf8().constData())
|
||||
{
|
||||
switches.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
int SceneSwitcher::FindByData(const QString& window)
|
||||
{
|
||||
int count = ui->switches->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->switches->item(i);
|
||||
QString itemWindow = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemWindow == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
|
||||
{
|
||||
int count = ui->ignoreWindows->count();
|
||||
int idx = -1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QListWidgetItem* item = ui->ignoreWindows->item(i);
|
||||
QString itemRegion = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemRegion == window)
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_switches_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->switches->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->windowSwitches)
|
||||
{
|
||||
if (window.compare(s.window.c_str()) == 0)
|
||||
{
|
||||
string name = GetWeakSourceName(s.scene);
|
||||
string transitionName = GetWeakSourceName(s.transition);
|
||||
ui->scenes->setCurrentText(name.c_str());
|
||||
ui->windows->setCurrentText(window);
|
||||
ui->transitions->setCurrentText(transitionName.c_str());
|
||||
ui->fullscreenCheckBox->setChecked(s.fullscreen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = ui->ignoreWindows->item(idx);
|
||||
|
||||
QString window = item->data(Qt::UserRole).toString();
|
||||
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
for (auto& s : switcher->ignoreWindowsSwitches)
|
||||
{
|
||||
if (window.compare(s.c_str()) == 0)
|
||||
{
|
||||
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||
{
|
||||
//check if title should be ignored
|
||||
string title;
|
||||
GetCurrentWindowTitle(title);
|
||||
for (auto& window : ignoreWindowsSwitches)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool matches = regex_match(title, regex(window));
|
||||
if (matches)
|
||||
{
|
||||
title = lastTitle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const regex_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
lastTitle = title;
|
||||
|
||||
//direct match
|
||||
for (WindowSceneSwitch& s : windowSwitches)
|
||||
{
|
||||
if (s.window == title)
|
||||
{
|
||||
match = !s.fullscreen || (s.fullscreen && isFullscreen());
|
||||
scene = s.scene;
|
||||
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&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,288 +0,0 @@
|
||||
#pragma once
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <regex>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
#include "utility.hpp"
|
||||
|
||||
#define DEFAULT_INTERVAL 300
|
||||
|
||||
#define READ_FILE_FUNC "File based"
|
||||
#define ROUND_TRIP_FUNC "Scene Sequence"
|
||||
#define IDLE_FUNC "Idle detection"
|
||||
#define EXE_FUNC "Executable"
|
||||
#define SCREEN_REGION_FUNC "Screen region"
|
||||
#define WINDOW_TITLE_FUNC "Window title"
|
||||
|
||||
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
|
||||
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
|
||||
#define DEFAULT_PRIORITY_2 IDLE_FUNC
|
||||
#define DEFAULT_PRIORITY_3 EXE_FUNC
|
||||
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
|
||||
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct SceneSwitch
|
||||
{
|
||||
OBSWeakSource scene;
|
||||
string window;
|
||||
OBSWeakSource transition;
|
||||
bool fullscreen;
|
||||
|
||||
inline SceneSwitch(
|
||||
OBSWeakSource scene_, const char* window_, OBSWeakSource transition_, bool fullscreen_)
|
||||
: scene(scene_)
|
||||
, window(window_)
|
||||
, transition(transition_)
|
||||
, fullscreen(fullscreen_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ExecutableSceneSwitch
|
||||
{
|
||||
OBSWeakSource mScene;
|
||||
OBSWeakSource mTransition;
|
||||
QString mExe;
|
||||
bool mInFocus;
|
||||
|
||||
inline ExecutableSceneSwitch(
|
||||
OBSWeakSource scene, OBSWeakSource transition, const QString& exe, bool inFocus)
|
||||
: mScene(scene)
|
||||
, mTransition(transition)
|
||||
, mExe(exe)
|
||||
, mInFocus(inFocus)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ScreenRegionSwitch
|
||||
{
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
int minX, minY, maxX, maxY;
|
||||
string regionStr;
|
||||
|
||||
inline ScreenRegionSwitch(OBSWeakSource scene_, OBSWeakSource transition_, int minX_, int minY_,
|
||||
int maxX_, int maxY_, string regionStr_)
|
||||
: scene(scene_)
|
||||
, transition(transition_)
|
||||
, minX(minX_)
|
||||
, minY(minY_)
|
||||
, maxX(maxX_)
|
||||
, maxY(maxY_)
|
||||
, regionStr(regionStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct SceneRoundTripSwitch
|
||||
{
|
||||
OBSWeakSource scene1;
|
||||
OBSWeakSource scene2;
|
||||
OBSWeakSource transition;
|
||||
int delay;
|
||||
string sceneRoundTripStr;
|
||||
|
||||
inline SceneRoundTripSwitch(OBSWeakSource scene1_, OBSWeakSource scene2_,
|
||||
OBSWeakSource transition_, int delay_, string str)
|
||||
: scene1(scene1_)
|
||||
, scene2(scene2_)
|
||||
, transition(transition_)
|
||||
, delay(delay_)
|
||||
, sceneRoundTripStr(str)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct SceneTransition
|
||||
{
|
||||
OBSWeakSource scene1;
|
||||
OBSWeakSource scene2;
|
||||
OBSWeakSource transition;
|
||||
string sceneTransitionStr;
|
||||
|
||||
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, OBSWeakSource transition_,
|
||||
string sceneTransitionStr_)
|
||||
: scene1(scene1_)
|
||||
, scene2(scene2_)
|
||||
, transition(transition_)
|
||||
, sceneTransitionStr(sceneTransitionStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DefaultSceneTransition
|
||||
{
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
string sceneTransitionStr;
|
||||
|
||||
inline DefaultSceneTransition(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||
string sceneTransitionStr_)
|
||||
: scene(scene_)
|
||||
, transition(transition_)
|
||||
, sceneTransitionStr(sceneTransitionStr_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct FileIOData
|
||||
{
|
||||
bool readEnabled;
|
||||
string readPath;
|
||||
bool writeEnabled;
|
||||
string writePath;
|
||||
};
|
||||
|
||||
struct IdleData
|
||||
{
|
||||
bool idleEnable;
|
||||
int time;
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct SwitcherData
|
||||
{
|
||||
thread th;
|
||||
condition_variable cv;
|
||||
mutex m;
|
||||
mutex transitionMutex;
|
||||
bool transitionActive = false;
|
||||
bool waitForTransition = false;
|
||||
condition_variable transitionCv;
|
||||
bool stop = false;
|
||||
|
||||
vector<SceneSwitch> switches;
|
||||
string lastTitle;
|
||||
OBSWeakSource nonMatchingScene;
|
||||
int interval = DEFAULT_INTERVAL;
|
||||
bool switchIfNotMatching = false;
|
||||
bool startAtLaunch = false;
|
||||
vector<ScreenRegionSwitch> screenRegionSwitches;
|
||||
vector<OBSWeakSource> pauseScenesSwitches;
|
||||
vector<string> pauseWindowsSwitches;
|
||||
vector<string> ignoreWindowsSwitches;
|
||||
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
|
||||
bool autoStopEnable = false;
|
||||
OBSWeakSource autoStopScene;
|
||||
string waitSceneName; //indicates which scene was active when we startet waiting on something
|
||||
vector<SceneTransition> sceneTransitions;
|
||||
vector<DefaultSceneTransition> defaultSceneTransitions;
|
||||
vector<ExecutableSceneSwitch> executableSwitches;
|
||||
FileIOData fileIO;
|
||||
IdleData idleData;
|
||||
vector<string> ignoreIdleWindows;
|
||||
vector<string> functionNamesByPriority = vector<string>{
|
||||
string(DEFAULT_PRIORITY_0),
|
||||
string(DEFAULT_PRIORITY_1),
|
||||
string(DEFAULT_PRIORITY_2),
|
||||
string(DEFAULT_PRIORITY_3),
|
||||
string(DEFAULT_PRIORITY_4),
|
||||
string(DEFAULT_PRIORITY_5),
|
||||
};
|
||||
|
||||
void Thread();
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
bool sceneChangedDuringWait();
|
||||
bool prioFuncsValid();
|
||||
void writeSceneInfoToFile();
|
||||
void setDefaultSceneTransitions(unique_lock<mutex>& lock);
|
||||
void autoStopStreamAndRecording();
|
||||
bool checkPause();
|
||||
void checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock);
|
||||
void checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
||||
void checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
||||
void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
||||
void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
||||
void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
||||
|
||||
|
||||
|
||||
void Prune()
|
||||
{
|
||||
for (size_t i = 0; i < switches.size(); i++)
|
||||
{
|
||||
SceneSwitch& s = switches[i];
|
||||
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
|
||||
switches.erase(switches.begin() + i--);
|
||||
}
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene))
|
||||
{
|
||||
switchIfNotMatching = false;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < screenRegionSwitches.size(); i++)
|
||||
{
|
||||
ScreenRegionSwitch& s = screenRegionSwitches[i];
|
||||
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
|
||||
screenRegionSwitches.erase(screenRegionSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pauseScenesSwitches.size(); i++)
|
||||
{
|
||||
OBSWeakSource& scene = pauseScenesSwitches[i];
|
||||
if (!WeakSourceValid(scene))
|
||||
pauseScenesSwitches.erase(pauseScenesSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++)
|
||||
{
|
||||
SceneRoundTripSwitch& s = sceneRoundTripSwitches[i];
|
||||
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|
||||
|| !WeakSourceValid(s.transition))
|
||||
sceneRoundTripSwitches.erase(sceneRoundTripSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!WeakSourceValid(autoStopScene))
|
||||
{
|
||||
autoStopScene = nullptr;
|
||||
autoStopEnable = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sceneTransitions.size(); i++)
|
||||
{
|
||||
SceneTransition& s = sceneTransitions[i];
|
||||
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|
||||
|| !WeakSourceValid(s.transition))
|
||||
sceneTransitions.erase(sceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < defaultSceneTransitions.size(); i++)
|
||||
{
|
||||
DefaultSceneTransition& s = defaultSceneTransitions[i];
|
||||
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
|
||||
defaultSceneTransitions.erase(defaultSceneTransitions.begin() + i--);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < executableSwitches.size(); i++)
|
||||
{
|
||||
ExecutableSceneSwitch& s = executableSwitches[i];
|
||||
if (!WeakSourceValid(s.mScene) || !WeakSourceValid(s.mTransition))
|
||||
executableSwitches.erase(executableSwitches.begin() + i--);
|
||||
}
|
||||
|
||||
if (!WeakSourceValid(idleData.scene) || !WeakSourceValid(idleData.transition))
|
||||
{
|
||||
idleData.idleEnable = false;
|
||||
}
|
||||
}
|
||||
inline ~SwitcherData()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
};
|
||||
|
||||
140
utility.hpp
140
utility.hpp
@@ -1,140 +0,0 @@
|
||||
#pragma once
|
||||
#include <obs.hpp>
|
||||
#include <QString>
|
||||
#include <obs-frontend-api.h>
|
||||
#include "switcher-data-structs.hpp"
|
||||
using namespace std;
|
||||
|
||||
static inline bool WeakSourceValid(obs_weak_source_t* ws)
|
||||
{
|
||||
obs_source_t* source = obs_weak_source_get_source(ws);
|
||||
if (source)
|
||||
obs_source_release(source);
|
||||
return !!source;
|
||||
}
|
||||
|
||||
static inline QString MakeSwitchName(
|
||||
const QString& scene, const QString& value, const QString& transition, bool fullscreen)
|
||||
{
|
||||
if (!fullscreen)
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
|
||||
+ QStringLiteral("]: ") + value;
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
|
||||
+ value + QStringLiteral(" (only if window is fullscreen)");
|
||||
}
|
||||
|
||||
static inline QString MakeSwitchNameExecutable(
|
||||
const QString& scene, const QString& value, const QString& transition, bool inFocus)
|
||||
{
|
||||
if (!inFocus)
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
|
||||
+ QStringLiteral("]: ") + value;
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
|
||||
+ value + QStringLiteral(" (only if window is focused)");
|
||||
}
|
||||
|
||||
static inline QString MakeScreenRegionSwitchName(
|
||||
const QString& scene, const QString& transition, int minX, int minY, int maxX, int maxY)
|
||||
{
|
||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
|
||||
+ QString::number(minX) + QStringLiteral(", ") + QString::number(minY)
|
||||
+ QStringLiteral(" x ") + QString::number(maxX) + QStringLiteral(", ")
|
||||
+ QString::number(maxY);
|
||||
}
|
||||
|
||||
static inline QString MakeSceneRoundTripSwitchName(
|
||||
const QString& scene1, const QString& scene2, const QString& transition, int delay)
|
||||
{
|
||||
return scene1 + QStringLiteral(" -> wait for ") + QString::number(delay)
|
||||
+ QStringLiteral(" seconds -> ") + scene2 + QStringLiteral(" (using ") + transition
|
||||
+ QStringLiteral(" transition)");
|
||||
}
|
||||
|
||||
static inline QString MakeSceneTransitionName(
|
||||
const QString& scene1, const QString& scene2, const QString& transition)
|
||||
{
|
||||
return scene1 + QStringLiteral(" --- ") + transition + QStringLiteral(" --> ") + scene2;
|
||||
}
|
||||
|
||||
static inline QString MakeDefaultSceneTransitionName(
|
||||
const QString& scene, const QString& transition)
|
||||
{
|
||||
return scene + QStringLiteral(" --> ") + transition;
|
||||
}
|
||||
|
||||
static inline string GetWeakSourceName(obs_weak_source_t* weak_source)
|
||||
{
|
||||
string name;
|
||||
|
||||
obs_source_t* source = obs_weak_source_get_source(weak_source);
|
||||
if (source)
|
||||
{
|
||||
name = obs_source_get_name(source);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakSourceByName(const char* name)
|
||||
{
|
||||
OBSWeakSource weak;
|
||||
obs_source_t* source = obs_get_source_by_name(name);
|
||||
if (source)
|
||||
{
|
||||
weak = obs_source_get_weak_source(source);
|
||||
obs_weak_source_release(weak);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
return weak;
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakSourceByQString(const QString& name)
|
||||
{
|
||||
return GetWeakSourceByName(name.toUtf8().constData());
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakTransitionByName(const char* transitionName)
|
||||
{
|
||||
OBSWeakSource weak;
|
||||
obs_source_t* source = nullptr;
|
||||
|
||||
if (strcmp(transitionName, "Default") == 0)
|
||||
{
|
||||
source = obs_frontend_get_current_transition();
|
||||
weak = obs_source_get_weak_source(source);
|
||||
obs_source_release(source);
|
||||
obs_weak_source_release(weak);
|
||||
return weak;
|
||||
}
|
||||
|
||||
obs_frontend_source_list* transitions = new obs_frontend_source_list();
|
||||
obs_frontend_get_transitions(transitions);
|
||||
bool match = false;
|
||||
|
||||
for (size_t i = 0; i < transitions->sources.num; i++)
|
||||
{
|
||||
const char* name = obs_source_get_name(transitions->sources.array[i]);
|
||||
if (strcmp(transitionName, name) == 0)
|
||||
{
|
||||
match = true;
|
||||
source = transitions->sources.array[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match){
|
||||
weak = obs_source_get_weak_source(source);
|
||||
obs_weak_source_release(weak);
|
||||
}
|
||||
obs_frontend_source_list_free(transitions);
|
||||
|
||||
return weak;
|
||||
}
|
||||
|
||||
static inline OBSWeakSource GetWeakTransitionByQString(const QString& name)
|
||||
{
|
||||
return GetWeakTransitionByName(name.toUtf8().constData());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user