mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
1 Commits
nested-que
...
lock
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8174004eda |
90
.github/scripts/Package-Windows.ps1
vendored
90
.github/scripts/Package-Windows.ps1
vendored
@@ -68,53 +68,44 @@ function Package {
|
|||||||
|
|
||||||
Remove-Item @RemoveArgs
|
Remove-Item @RemoveArgs
|
||||||
|
|
||||||
$ReleasePath = "${ProjectRoot}/release/${Configuration}"
|
# Build a staging directory with two subfolders:
|
||||||
$NewBinPath = "${ReleasePath}/${ProductName}/bin/64bit"
|
# recommended/ - new layout, extract to %ProgramData%\obs-studio\
|
||||||
$NewDataPath = "${ReleasePath}/${ProductName}/data"
|
# legacy/ - old layout, extract to the OBS install directory
|
||||||
$CIWindowsDir = "${ProjectRoot}/build-aux/CI/windows"
|
$ReleasePath = "${ProjectRoot}/release/${Configuration}"
|
||||||
|
$StagingPath = "${ProjectRoot}/release/zip-staging"
|
||||||
|
$NewBinPath = "${ReleasePath}/${ProductName}/bin/64bit"
|
||||||
|
$NewDataPath = "${ReleasePath}/${ProductName}/data"
|
||||||
|
|
||||||
|
Remove-Item -Path $StagingPath -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
New-Item -ItemType Directory -Force -Path $StagingPath | Out-Null
|
||||||
|
Copy-Item -Path "${ProjectRoot}/build-aux/CI/windows/README.txt" -Destination "${StagingPath}/README.txt"
|
||||||
|
|
||||||
# --- Recommended zip (new layout, extract to %ProgramData%\obs-studio\) ---
|
|
||||||
Log-Group "Archiving ${ProductName} (recommended)..."
|
|
||||||
$RecStaging = "${ProjectRoot}/release/zip-staging-rec"
|
|
||||||
Remove-Item -Path $RecStaging -Recurse -Force -ErrorAction SilentlyContinue
|
|
||||||
New-Item -ItemType Directory -Force -Path $RecStaging | Out-Null
|
|
||||||
Copy-Item -Path "${CIWindowsDir}/README.txt" -Destination "${RecStaging}/README.txt"
|
|
||||||
if ( Test-Path -Path $NewBinPath ) {
|
if ( Test-Path -Path $NewBinPath ) {
|
||||||
$RecBinPath = "${RecStaging}/${ProductName}/bin/64bit"
|
$RecBinPath = "${StagingPath}/recommended/${ProductName}/bin/64bit"
|
||||||
New-Item -ItemType Directory -Force -Path $RecBinPath | Out-Null
|
$LegacyBinPath = "${StagingPath}/legacy/obs-plugins/64bit"
|
||||||
Copy-Item -Path "${NewBinPath}/*" -Destination $RecBinPath -Recurse -Force
|
New-Item -ItemType Directory -Force -Path $RecBinPath | Out-Null
|
||||||
|
New-Item -ItemType Directory -Force -Path $LegacyBinPath | Out-Null
|
||||||
|
Copy-Item -Path "${NewBinPath}/*" -Destination $RecBinPath -Recurse -Force
|
||||||
|
Copy-Item -Path "${NewBinPath}/*" -Destination $LegacyBinPath -Recurse -Force
|
||||||
}
|
}
|
||||||
if ( Test-Path -Path $NewDataPath ) {
|
if ( Test-Path -Path $NewDataPath ) {
|
||||||
$RecDataPath = "${RecStaging}/${ProductName}/data"
|
$RecDataPath = "${StagingPath}/recommended/${ProductName}/data"
|
||||||
New-Item -ItemType Directory -Force -Path $RecDataPath | Out-Null
|
$LegacyDataPath = "${StagingPath}/legacy/data/obs-plugins/${ProductName}"
|
||||||
Copy-Item -Path "${NewDataPath}/*" -Destination $RecDataPath -Recurse -Force
|
New-Item -ItemType Directory -Force -Path $RecDataPath | Out-Null
|
||||||
|
New-Item -ItemType Directory -Force -Path $LegacyDataPath | Out-Null
|
||||||
|
Copy-Item -Path "${NewDataPath}/*" -Destination $RecDataPath -Recurse -Force
|
||||||
|
Copy-Item -Path "${NewDataPath}/*" -Destination $LegacyDataPath -Recurse -Force
|
||||||
}
|
}
|
||||||
Compress-Archive -Force -Path (Get-ChildItem -Path $RecStaging) `
|
|
||||||
-CompressionLevel Optimal `
|
|
||||||
-DestinationPath "${ProjectRoot}/release/${OutputName}.zip"
|
|
||||||
Remove-Item -Path $RecStaging -Recurse -Force
|
|
||||||
Log-Group
|
|
||||||
|
|
||||||
# --- Legacy zip (old layout, extract to OBS install directory) ---
|
Log-Group "Archiving ${ProductName}..."
|
||||||
Log-Group "Archiving ${ProductName} (legacy)..."
|
$CompressArgs = @{
|
||||||
$LegStaging = "${ProjectRoot}/release/zip-staging-leg"
|
Path = (Get-ChildItem -Path $StagingPath)
|
||||||
Remove-Item -Path $LegStaging -Recurse -Force -ErrorAction SilentlyContinue
|
CompressionLevel = 'Optimal'
|
||||||
New-Item -ItemType Directory -Force -Path $LegStaging | Out-Null
|
DestinationPath = "${ProjectRoot}/release/${OutputName}.zip"
|
||||||
Copy-Item -Path "${CIWindowsDir}/README-legacy.txt" -Destination "${LegStaging}/README.txt"
|
Verbose = ($null -ne $Env:CI)
|
||||||
if ( Test-Path -Path $NewBinPath ) {
|
|
||||||
$LegBinPath = "${LegStaging}/obs-plugins/64bit"
|
|
||||||
New-Item -ItemType Directory -Force -Path $LegBinPath | Out-Null
|
|
||||||
Copy-Item -Path "${NewBinPath}/*" -Destination $LegBinPath -Recurse -Force
|
|
||||||
}
|
}
|
||||||
if ( Test-Path -Path $NewDataPath ) {
|
Compress-Archive -Force @CompressArgs
|
||||||
$LegDataPath = "${LegStaging}/data/obs-plugins/${ProductName}"
|
Remove-Item -Path $StagingPath -Recurse -Force
|
||||||
New-Item -ItemType Directory -Force -Path $LegDataPath | Out-Null
|
|
||||||
Copy-Item -Path "${NewDataPath}/*" -Destination $LegDataPath -Recurse -Force
|
|
||||||
}
|
|
||||||
Compress-Archive -Force -Path (Get-ChildItem -Path $LegStaging) `
|
|
||||||
-CompressionLevel Optimal `
|
|
||||||
-DestinationPath "${ProjectRoot}/release/${OutputName}-legacy.zip"
|
|
||||||
Remove-Item -Path $LegStaging -Recurse -Force
|
|
||||||
Log-Group
|
Log-Group
|
||||||
|
|
||||||
if ( ( $BuildInstaller ) ) {
|
if ( ( $BuildInstaller ) ) {
|
||||||
@@ -129,24 +120,7 @@ function Package {
|
|||||||
Push-Location -Stack BuildTemp
|
Push-Location -Stack BuildTemp
|
||||||
Ensure-Location -Path "${ProjectRoot}/release"
|
Ensure-Location -Path "${ProjectRoot}/release"
|
||||||
Remove-Item -Path Package -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path Package -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Copy-Item -Path ${Configuration} -Destination Package -Recurse
|
||||||
# Recommended layout (for %ProgramData%\obs-studio\plugins\)
|
|
||||||
$PkgRec = "Package/recommended"
|
|
||||||
New-Item -ItemType Directory -Force -Path $PkgRec | Out-Null
|
|
||||||
Copy-Item -Path "${Configuration}/*" -Destination $PkgRec -Recurse -Force
|
|
||||||
|
|
||||||
# Legacy layout (for OBS installation directory)
|
|
||||||
if ( Test-Path "${Configuration}/${ProductName}/bin/64bit" ) {
|
|
||||||
$PkgLegBin = "Package/legacy/obs-plugins/64bit"
|
|
||||||
New-Item -ItemType Directory -Force -Path $PkgLegBin | Out-Null
|
|
||||||
Copy-Item -Path "${Configuration}/${ProductName}/bin/64bit/*" -Destination $PkgLegBin -Recurse -Force
|
|
||||||
}
|
|
||||||
if ( Test-Path "${Configuration}/${ProductName}/data" ) {
|
|
||||||
$PkgLegData = "Package/legacy/data/obs-plugins/${ProductName}"
|
|
||||||
New-Item -ItemType Directory -Force -Path $PkgLegData | Out-Null
|
|
||||||
Copy-Item -Path "${Configuration}/${ProductName}/data/*" -Destination $PkgLegData -Recurse -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer"
|
Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer"
|
||||||
Remove-Item -Path Package -Recurse
|
Remove-Item -Path Package -Recurse
|
||||||
Pop-Location -Stack BuildTemp
|
Pop-Location -Stack BuildTemp
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
Advanced Scene Switcher - Windows Installation (Legacy)
|
|
||||||
========================================================
|
|
||||||
|
|
||||||
For full installation instructions visit:
|
|
||||||
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
|
||||||
|
|
||||||
|
|
||||||
This archive uses the legacy plugin layout for older OBS versions,
|
|
||||||
portable OBS installs, and Steam.
|
|
||||||
|
|
||||||
Extract the CONTENTS of this archive into your OBS installation directory,
|
|
||||||
typically:
|
|
||||||
|
|
||||||
C:\Program Files\obs-studio\
|
|
||||||
|
|
||||||
Merge the data\ and obs-plugins\ folders with the existing ones when prompted.
|
|
||||||
|
|
||||||
Steam users: right-click OBS in your library -> Manage -> Browse local files,
|
|
||||||
then extract the contents of this archive into that directory.
|
|
||||||
|
|
||||||
|
|
||||||
For OBS 28 and newer the recommended archive is preferred:
|
|
||||||
advanced-scene-switcher-<version>-windows-x64.zip
|
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
Advanced Scene Switcher - Windows Installation
|
Advanced Scene Switcher - Windows Installation
|
||||||
===============================================
|
==============================================
|
||||||
|
|
||||||
For full installation instructions visit:
|
For full installation instructions visit:
|
||||||
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
||||||
|
|
||||||
|
|
||||||
This archive uses the recommended plugin layout for OBS 28 and newer.
|
Quick guide
|
||||||
|
-----------
|
||||||
|
|
||||||
Extract the CONTENTS of this archive into:
|
This archive contains two installation methods.
|
||||||
|
Choose ONE depending on your OBS version.
|
||||||
|
|
||||||
C:\ProgramData\obs-studio\plugins\
|
|
||||||
|
recommended\ (preferred)
|
||||||
|
---------------------------------------------
|
||||||
|
Extract the CONTENTS of this folder into:
|
||||||
|
|
||||||
|
C:\ProgramData\obs-studio\
|
||||||
|
|
||||||
Tip: press Win+R and type %ProgramData%\obs-studio\plugins to open that folder.
|
Tip: press Win+R and type %ProgramData%\obs-studio\plugins to open that folder.
|
||||||
|
|
||||||
@@ -17,5 +24,14 @@ After extracting, the path should look like:
|
|||||||
C:\ProgramData\obs-studio\plugins\advanced-scene-switcher\bin\64bit\advanced-scene-switcher.dll
|
C:\ProgramData\obs-studio\plugins\advanced-scene-switcher\bin\64bit\advanced-scene-switcher.dll
|
||||||
|
|
||||||
|
|
||||||
If the plugin does not appear in OBS, try the legacy archive instead:
|
legacy\ (older OBS versions, portable OBS installs, or if the recommended method does not work)
|
||||||
advanced-scene-switcher-<version>-windows-x64-legacy.zip
|
---------------------------------------------------------------------------
|
||||||
|
Extract the CONTENTS of this folder into your OBS installation directory,
|
||||||
|
typically:
|
||||||
|
|
||||||
|
C:\Program Files\obs-studio\
|
||||||
|
|
||||||
|
Merge the data\ and obs-plugins\ folders with the existing ones when prompted.
|
||||||
|
|
||||||
|
Steam users: right-click OBS in your library -> Manage -> Browse local files,
|
||||||
|
then extract the contents of legacy\ into that directory.
|
||||||
@@ -157,9 +157,7 @@ else()
|
|||||||
set_target_properties(${target} PROPERTIES INSTALL_RPATH
|
set_target_properties(${target} PROPERTIES INSTALL_RPATH
|
||||||
"$ORIGIN:$ORIGIN/..")
|
"$ORIGIN:$ORIGIN/..")
|
||||||
endif()
|
endif()
|
||||||
get_filename_component(_plugin_dir_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
|
message(STATUS "ADVSS: ENABLED PLUGIN ${target}")
|
||||||
set_property(GLOBAL APPEND PROPERTY ADVSS_PLUGINS_ENABLED
|
|
||||||
${_plugin_dir_name})
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(install_advss_plugin_dependency_target target dep)
|
function(install_advss_plugin_dependency_target target dep)
|
||||||
|
|||||||
@@ -6,11 +6,7 @@ include(buildspec_common)
|
|||||||
|
|
||||||
# _check_dependencies_windows: Set up Windows slice for _check_dependencies
|
# _check_dependencies_windows: Set up Windows slice for _check_dependencies
|
||||||
function(_check_dependencies_windows)
|
function(_check_dependencies_windows)
|
||||||
if(CMAKE_GENERATOR_PLATFORM)
|
set(arch ${CMAKE_GENERATOR_PLATFORM})
|
||||||
set(arch ${CMAKE_GENERATOR_PLATFORM})
|
|
||||||
else()
|
|
||||||
set(arch x64)
|
|
||||||
endif()
|
|
||||||
set(platform windows-${arch})
|
set(platform windows-${arch})
|
||||||
|
|
||||||
set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps")
|
set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps")
|
||||||
|
|||||||
@@ -23,17 +23,14 @@ SolidCompression=yes
|
|||||||
DirExistsWarning=no
|
DirExistsWarning=no
|
||||||
UsePreviousAppDir=no
|
UsePreviousAppDir=no
|
||||||
SetupIconFile=installer.ico
|
SetupIconFile=installer.ico
|
||||||
UninstallDisplayIcon={code:GetUninstallIconPath}
|
UninstallDisplayIcon={app}\advanced-scene-switcher\data\res\images\logo.ico
|
||||||
DisableDirPage=no
|
DisableDirPage=no
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; Recommended layout - used when installing to %ProgramData%\obs-studio\plugins\
|
Source: "..\release\Package\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
Source: "..\release\Package\recommended\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsRecommendedLayout
|
|
||||||
; Legacy layout - used when installing to the OBS installation directory
|
|
||||||
Source: "..\release\Package\legacy\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsLegacyLayout
|
|
||||||
Source: "..\LICENSE"; Flags: dontcopy
|
Source: "..\LICENSE"; Flags: dontcopy
|
||||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||||
|
|
||||||
@@ -56,54 +53,23 @@ begin
|
|||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Returns true when the selected install directory is under %ProgramData%,
|
|
||||||
// meaning the recommended plugin layout should be used.
|
|
||||||
function IsRecommendedLayout(): Boolean;
|
|
||||||
begin
|
|
||||||
Result := Pos(LowerCase(ExpandConstant('{commonappdata}')),
|
|
||||||
LowerCase(WizardDirValue())) = 1;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function IsLegacyLayout(): Boolean;
|
|
||||||
begin
|
|
||||||
Result := not IsRecommendedLayout();
|
|
||||||
end;
|
|
||||||
|
|
||||||
function GetUninstallIconPath(Param: string): string;
|
|
||||||
begin
|
|
||||||
if IsRecommendedLayout() then
|
|
||||||
Result := ExpandConstant('{app}\advanced-scene-switcher\data\res\images\logo.ico')
|
|
||||||
else
|
|
||||||
Result := ExpandConstant('{app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico');
|
|
||||||
end;
|
|
||||||
|
|
||||||
function GetDirName(Value: string): string;
|
function GetDirName(Value: string): string;
|
||||||
var
|
|
||||||
PrevPath: string;
|
|
||||||
UninstallKey: string;
|
|
||||||
begin
|
begin
|
||||||
Result := ExpandConstant('{commonappdata}\obs-studio\plugins');
|
Result := ExpandConstant('{commonappdata}\obs-studio\plugins');
|
||||||
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
|
||||||
if RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', PrevPath) and (PrevPath <> '') then
|
|
||||||
Result := PrevPath;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Remove files placed by the legacy installer (obs-plugins/64bit and
|
// Remove files placed by the legacy installer (obs-plugins/64bit and
|
||||||
// data/obs-plugins layout) so the plugin is not loaded twice by OBS.
|
// data/obs-plugins layout) so the plugin is not loaded twice by OBS.
|
||||||
// Only runs when upgrading from a legacy location to the recommended one.
|
// We read InstallLocation from our own previous uninstall entry, which is
|
||||||
|
// the exact directory the old installer used regardless of OBS install path.
|
||||||
procedure RemoveLegacyFiles();
|
procedure RemoveLegacyFiles();
|
||||||
var
|
var
|
||||||
OldInstallPath: string;
|
OldInstallPath: string;
|
||||||
UninstallKey: string;
|
UninstallKey: string;
|
||||||
begin
|
begin
|
||||||
if not IsRecommendedLayout() then
|
|
||||||
Exit;
|
|
||||||
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
||||||
if not RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', OldInstallPath) then
|
if not RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', OldInstallPath) then
|
||||||
Exit;
|
Exit;
|
||||||
// Skip if the previous install was already in the recommended location
|
|
||||||
if Pos(LowerCase(ExpandConstant('{commonappdata}')), LowerCase(OldInstallPath)) = 1 then
|
|
||||||
Exit;
|
|
||||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.dll');
|
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.dll');
|
||||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.pdb');
|
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.pdb');
|
||||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.dll');
|
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.dll');
|
||||||
@@ -117,3 +83,4 @@ begin
|
|||||||
if CurStep = ssInstall then
|
if CurStep = ssInstall then
|
||||||
RemoveLegacyFiles();
|
RemoveLegacyFiles();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
2
deps/cpp-httplib
vendored
2
deps/cpp-httplib
vendored
Submodule deps/cpp-httplib updated: 008e107d0f...811dd0b6f2
@@ -461,13 +461,12 @@ void SwitcherData::Stop()
|
|||||||
SetMacroAbortWait(true);
|
SetMacroAbortWait(true);
|
||||||
GetMacroWaitCV().notify_all();
|
GetMacroWaitCV().notify_all();
|
||||||
GetMacroTransitionCV().notify_all();
|
GetMacroTransitionCV().notify_all();
|
||||||
SignalStopAllMacros();
|
StopAllMacros();
|
||||||
StopAndClearAllActionQueues();
|
StopAndClearAllActionQueues();
|
||||||
CloseAllInputDialogs();
|
CloseAllInputDialogs();
|
||||||
th->wait();
|
th->wait();
|
||||||
delete th;
|
delete th;
|
||||||
th = nullptr;
|
th = nullptr;
|
||||||
WaitForAllMacros();
|
|
||||||
RunStopSteps();
|
RunStopSteps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -294,30 +294,6 @@ std::vector<WindowInfo> GetWindows(const WindowQueryOptions &options)
|
|||||||
result.emplace_back(std::move(info));
|
result.emplace_back(std::move(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
// When KWin compat is active, native Wayland windows are not tracked by
|
|
||||||
// X11 and therefore do not appear in the list above. Merge in any window
|
|
||||||
// reported by KWin that is not already present (matched by title) so that
|
|
||||||
// title and focus conditions work for native Wayland windows.
|
|
||||||
if (KWin) {
|
|
||||||
for (const auto &[pid, title] :
|
|
||||||
FocusNotifier::getWindowList()) {
|
|
||||||
bool found = false;
|
|
||||||
for (const auto &info : result) {
|
|
||||||
if (info.title == title) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
WindowInfo waylandWindow;
|
|
||||||
waylandWindow.title = title;
|
|
||||||
waylandWindow.focused =
|
|
||||||
(title == foregroundTitle);
|
|
||||||
result.emplace_back(std::move(waylandWindow));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,82 +12,35 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
std::mutex FocusNotifier::_mutex;
|
|
||||||
int FocusNotifier::activePID = -1;
|
int FocusNotifier::activePID = -1;
|
||||||
std::string FocusNotifier::activeTitle = {};
|
std::string FocusNotifier::activeTitle = {};
|
||||||
std::map<std::string, std::pair<int, std::string>> FocusNotifier::_windows;
|
|
||||||
|
|
||||||
int FocusNotifier::getActiveWindowPID()
|
int FocusNotifier::getActiveWindowPID()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
return activePID;
|
return activePID;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FocusNotifier::getActiveWindowTitle()
|
std::string FocusNotifier::getActiveWindowTitle()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
return activeTitle;
|
return activeTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<int, std::string>> FocusNotifier::getWindowList()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
std::vector<std::pair<int, std::string>> result;
|
|
||||||
result.reserve(_windows.size());
|
|
||||||
for (const auto &entry : _windows) {
|
|
||||||
result.emplace_back(entry.second);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FocusNotifier::focusChanged(const int pid)
|
void FocusNotifier::focusChanged(const int pid)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
activePID = pid;
|
activePID = pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FocusNotifier::focusTitle(const QString &title)
|
void FocusNotifier::focusTitle(const QString &title)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
activeTitle = title.toStdString();
|
activeTitle = title.toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FocusNotifier::focusUpdate(const int pid, const QString &title)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
activePID = pid;
|
|
||||||
activeTitle = title.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FocusNotifier::windowAdded(const QString &id, const int pid,
|
|
||||||
const QString &title)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
_windows[id.toStdString()] = {pid, title.toStdString()};
|
|
||||||
}
|
|
||||||
|
|
||||||
void FocusNotifier::windowRemoved(const QString &id)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
_windows.erase(id.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FocusNotifier::windowTitleChanged(const QString &id, const QString &title)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
|
||||||
auto it = _windows.find(id.toStdString());
|
|
||||||
if (it != _windows.end()) {
|
|
||||||
it->second.second = title.toStdString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isKWinAvailable()
|
bool isKWinAvailable()
|
||||||
{
|
{
|
||||||
const QDBusConnectionInterface *interface =
|
const QDBusConnectionInterface *interface =
|
||||||
QDBusConnection::sessionBus().interface();
|
QDBusConnection::sessionBus().interface();
|
||||||
if (!interface) {
|
if (!interface)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
const QStringList services =
|
const QStringList services =
|
||||||
interface->registeredServiceNames().value();
|
interface->registeredServiceNames().value();
|
||||||
@@ -100,32 +53,25 @@ bool startKWinScript(QString &scriptObjectPath)
|
|||||||
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
||||||
|
|
||||||
const QString script =
|
const QString script =
|
||||||
R"(var adss = "com.github.AdvancedSceneSwitcher";
|
R"(workspace.windowActivated.connect(function(client) {
|
||||||
var adssPath = "/com/github/AdvancedSceneSwitcher";
|
if (!client) return;
|
||||||
|
if (!client.pid) return;
|
||||||
|
if (!client.caption) return;
|
||||||
|
|
||||||
function trackWindow(window) {
|
callDBus(
|
||||||
var id = window.internalId.toString();
|
"com.github.AdvancedSceneSwitcher",
|
||||||
callDBus(adss, adssPath, adss, "windowAdded", id, window.pid, window.caption);
|
"/com/github/AdvancedSceneSwitcher",
|
||||||
window.captionChanged.connect(function() {
|
"com.github.AdvancedSceneSwitcher",
|
||||||
callDBus(adss, adssPath, adss, "windowTitleChanged", id, window.caption);
|
"focusChanged",
|
||||||
});
|
client.pid
|
||||||
}
|
);
|
||||||
|
callDBus(
|
||||||
var windows = workspace.windowList();
|
"com.github.AdvancedSceneSwitcher",
|
||||||
for (var i = 0; i < windows.length; i++) {
|
"/com/github/AdvancedSceneSwitcher",
|
||||||
trackWindow(windows[i]);
|
"com.github.AdvancedSceneSwitcher",
|
||||||
}
|
"focusTitle",
|
||||||
|
client.caption
|
||||||
workspace.windowAdded.connect(trackWindow);
|
);
|
||||||
|
|
||||||
workspace.windowRemoved.connect(function(window) {
|
|
||||||
callDBus(adss, adssPath, adss, "windowRemoved", window.internalId.toString());
|
|
||||||
});
|
|
||||||
|
|
||||||
workspace.windowActivated.connect(function(client) {
|
|
||||||
callDBus(adss, adssPath, adss, "focusUpdate",
|
|
||||||
client ? client.pid : 0,
|
|
||||||
client ? client.caption : "");
|
|
||||||
}))";
|
}))";
|
||||||
|
|
||||||
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
||||||
|
|||||||
@@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -14,27 +10,18 @@ class FocusNotifier final : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
|
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
|
||||||
|
|
||||||
static std::mutex _mutex;
|
|
||||||
static int activePID;
|
static int activePID;
|
||||||
static std::string activeTitle;
|
static std::string activeTitle;
|
||||||
// Maps KWin internal window ID to {pid, title}
|
|
||||||
static std::map<std::string, std::pair<int, std::string>> _windows;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using QObject::QObject;
|
using QObject::QObject;
|
||||||
|
|
||||||
static int getActiveWindowPID();
|
static int getActiveWindowPID();
|
||||||
static std::string getActiveWindowTitle();
|
static std::string getActiveWindowTitle();
|
||||||
static std::vector<std::pair<int, std::string>> getWindowList();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void focusChanged(const int pid);
|
void focusChanged(const int pid);
|
||||||
void focusTitle(const QString &title);
|
void focusTitle(const QString &title);
|
||||||
void focusUpdate(const int pid, const QString &title);
|
|
||||||
void windowAdded(const QString &id, const int pid,
|
|
||||||
const QString &title);
|
|
||||||
void windowRemoved(const QString &id);
|
|
||||||
void windowTitleChanged(const QString &id, const QString &title);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isKWinAvailable();
|
bool isKWinAvailable();
|
||||||
|
|||||||
@@ -164,9 +164,4 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
|||||||
return *_entryData;
|
return *_entryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionEdit::FocusTypeSelection()
|
|
||||||
{
|
|
||||||
_actionSelection->setFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ public:
|
|||||||
std::shared_ptr<MacroAction> * = nullptr);
|
std::shared_ptr<MacroAction> * = nullptr);
|
||||||
void SetupWidgets(bool basicSetup = false);
|
void SetupWidgets(bool basicSetup = false);
|
||||||
void SetEntryData(std::shared_ptr<MacroAction> *);
|
void SetEntryData(std::shared_ptr<MacroAction> *);
|
||||||
void FocusTypeSelection() override;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ActionSelectionChanged(const QString &text);
|
void ActionSelectionChanged(const QString &text);
|
||||||
|
|||||||
@@ -263,7 +263,6 @@ bool MacroActionMacro::Load(obs_data_t *obj)
|
|||||||
if (obs_data_has_user_value(obj, "nestedMacro")) {
|
if (obs_data_has_user_value(obj, "nestedMacro")) {
|
||||||
OBSDataAutoRelease nestedMacroData =
|
OBSDataAutoRelease nestedMacroData =
|
||||||
obs_data_get_obj(obj, "nestedMacro");
|
obs_data_get_obj(obj, "nestedMacro");
|
||||||
_nestedMacro = std::make_shared<Macro>();
|
|
||||||
_nestedMacro->Load(nestedMacroData);
|
_nestedMacro->Load(nestedMacroData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,15 +309,6 @@ void MacroActionMacro::ResolveVariablesToFixedValues()
|
|||||||
{
|
{
|
||||||
_actionIndex.ResolveVariables();
|
_actionIndex.ResolveVariables();
|
||||||
_label.ResolveVariables();
|
_label.ResolveVariables();
|
||||||
|
|
||||||
if (_action == Action::NESTED_MACRO) {
|
|
||||||
for (auto &action : _nestedMacro->Actions()) {
|
|
||||||
action->ResolveVariablesToFixedValues();
|
|
||||||
}
|
|
||||||
for (auto &action : _nestedMacro->ElseActions()) {
|
|
||||||
action->ResolveVariablesToFixedValues();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
|
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
|
||||||
|
|||||||
@@ -305,9 +305,4 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
|||||||
return *_entryData;
|
return *_entryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::FocusTypeSelection()
|
|
||||||
{
|
|
||||||
_conditionSelection->setFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ public:
|
|||||||
void SetRootNode(bool);
|
void SetRootNode(bool);
|
||||||
void SetupWidgets(bool basicSetup = false);
|
void SetupWidgets(bool basicSetup = false);
|
||||||
void SetEntryData(std::shared_ptr<MacroCondition> *);
|
void SetEntryData(std::shared_ptr<MacroCondition> *);
|
||||||
void FocusTypeSelection() override;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void LogicSelectionChanged(int idx);
|
void LogicSelectionChanged(int idx);
|
||||||
|
|||||||
@@ -650,18 +650,6 @@ void MacroEdit::HighlightCondition(int idx, QColor color) const
|
|||||||
ui->conditionsList->Highlight(idx, color);
|
ui->conditionsList->Highlight(idx, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::ScrollAndFocusNewSegment(MacroSegmentList *list, int newIdx,
|
|
||||||
int *currentIdx)
|
|
||||||
{
|
|
||||||
QTimer::singleShot(0, this, [this, list, newIdx, currentIdx]() {
|
|
||||||
list->ensureWidgetVisible(list->WidgetAt(*currentIdx));
|
|
||||||
auto *widget = list->WidgetAt(newIdx);
|
|
||||||
if (widget) {
|
|
||||||
widget->FocusTypeSelection();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resetSegmentHighlights(MacroSegmentList *list)
|
static void resetSegmentHighlights(MacroSegmentList *list)
|
||||||
{
|
{
|
||||||
MacroSegmentEdit *widget = nullptr;
|
MacroSegmentEdit *widget = nullptr;
|
||||||
@@ -1099,7 +1087,10 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
|||||||
ui->actionsList->SetHelpMsgVisible(false);
|
ui->actionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
|
|
||||||
ScrollAndFocusNewSegment(ui->actionsList, idx, ¤tActionIdx);
|
QTimer::singleShot(0, this, [this]() {
|
||||||
|
ui->actionsList->ensureWidgetVisible(
|
||||||
|
ui->actionsList->WidgetAt(currentActionIdx));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::AddMacroAction(int idx)
|
void MacroEdit::AddMacroAction(int idx)
|
||||||
@@ -1407,8 +1398,10 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
|||||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
|
|
||||||
ScrollAndFocusNewSegment(ui->elseActionsList, idx,
|
QTimer::singleShot(0, this, [this]() {
|
||||||
¤tElseActionIdx);
|
ui->elseActionsList->ensureWidgetVisible(
|
||||||
|
ui->elseActionsList->WidgetAt(currentElseActionIdx));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::AddMacroElseAction(int idx)
|
void MacroEdit::AddMacroElseAction(int idx)
|
||||||
@@ -1618,7 +1611,10 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
|||||||
ui->conditionsList->SetHelpMsgVisible(false);
|
ui->conditionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
|
|
||||||
ScrollAndFocusNewSegment(ui->conditionsList, idx, ¤tConditionIdx);
|
QTimer::singleShot(0, this, [this]() {
|
||||||
|
ui->conditionsList->ensureWidgetVisible(
|
||||||
|
ui->conditionsList->WidgetAt(currentConditionIdx));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::on_conditionAdd_clicked()
|
void MacroEdit::on_conditionAdd_clicked()
|
||||||
|
|||||||
@@ -116,8 +116,6 @@ private:
|
|||||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||||
void ScrollAndFocusNewSegment(MacroSegmentList *list, int newIdx,
|
|
||||||
int *currentIdx);
|
|
||||||
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||||
void
|
void
|
||||||
SetupContextMenu(const QPoint &pos,
|
SetupContextMenu(const QPoint &pos,
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
#include "macro-export-import-dialog.hpp"
|
#include "macro-export-import-dialog.hpp"
|
||||||
#include "macro-export-extensions.hpp"
|
#include "macro-export-extensions.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
#include "section.hpp"
|
|
||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QScrollArea>
|
|
||||||
#include <QSplitter>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
@@ -47,14 +44,10 @@ static bool isValidData(const QString &json)
|
|||||||
// Extension section
|
// Extension section
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
QWidget *MacroExportImportDialog::BuildExtensionWidget()
|
Section *MacroExportImportDialog::BuildExtensionSection()
|
||||||
{
|
{
|
||||||
auto wrapper = new QWidget(this);
|
auto outerSection = new Section(300, this);
|
||||||
auto wrapperLayout = new QVBoxLayout(wrapper);
|
outerSection->AddHeaderWidget(new QLabel(obs_module_text(
|
||||||
wrapperLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
wrapperLayout->setSpacing(4);
|
|
||||||
|
|
||||||
wrapperLayout->addWidget(new QLabel(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.macroTab.export.additionalContent")));
|
"AdvSceneSwitcher.macroTab.export.additionalContent")));
|
||||||
|
|
||||||
auto outerContent = new QWidget();
|
auto outerContent = new QWidget();
|
||||||
@@ -64,6 +57,7 @@ QWidget *MacroExportImportDialog::BuildExtensionWidget()
|
|||||||
|
|
||||||
const auto &extensions = GetMacroExportExtensions();
|
const auto &extensions = GetMacroExportExtensions();
|
||||||
|
|
||||||
|
// Build a sorted index list (alphabetical by translated display name).
|
||||||
std::vector<int> order(extensions.size());
|
std::vector<int> order(extensions.size());
|
||||||
std::iota(order.begin(), order.end(), 0);
|
std::iota(order.begin(), order.end(), 0);
|
||||||
std::sort(order.begin(), order.end(), [&](int a, int b) {
|
std::sort(order.begin(), order.end(), [&](int a, int b) {
|
||||||
@@ -87,7 +81,6 @@ QWidget *MacroExportImportDialog::BuildExtensionWidget()
|
|||||||
&MacroExportImportDialog::UpdateExportString);
|
&MacroExportImportDialog::UpdateExportString);
|
||||||
outerLayout->addWidget(ui.mainCheck);
|
outerLayout->addWidget(ui.mainCheck);
|
||||||
_extensionUIs.append(std::move(ui));
|
_extensionUIs.append(std::move(ui));
|
||||||
_extensionOrder.push_back(extIdx);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,18 +88,11 @@ QWidget *MacroExportImportDialog::BuildExtensionWidget()
|
|||||||
// Section: the main checkbox sits in the header (next to the
|
// Section: the main checkbox sits in the header (next to the
|
||||||
// toggle arrow) and the per-item checkboxes live in the
|
// toggle arrow) and the per-item checkboxes live in the
|
||||||
// collapsible content area.
|
// collapsible content area.
|
||||||
auto items = ext.getExportItems();
|
const auto items = ext.getExportItems();
|
||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(items.begin(), items.end(),
|
|
||||||
[](const QPair<QString, QString> &a,
|
|
||||||
const QPair<QString, QString> &b) {
|
|
||||||
return QString::localeAwareCompare(
|
|
||||||
a.second, b.second) < 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto innerSection = new Section(200, outerContent);
|
auto innerSection = new Section(200, outerContent);
|
||||||
|
|
||||||
ui.mainCheck =
|
ui.mainCheck =
|
||||||
@@ -146,22 +132,13 @@ QWidget *MacroExportImportDialog::BuildExtensionWidget()
|
|||||||
UpdateExportString();
|
UpdateExportString();
|
||||||
});
|
});
|
||||||
|
|
||||||
innerSection->SetContent(subWidget, true);
|
innerSection->SetContent(subWidget, false);
|
||||||
outerLayout->addWidget(innerSection);
|
outerLayout->addWidget(innerSection);
|
||||||
_extensionUIs.append(std::move(ui));
|
_extensionUIs.append(std::move(ui));
|
||||||
_extensionOrder.push_back(extIdx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outerLayout->addStretch();
|
outerSection->SetContent(outerContent, true);
|
||||||
|
return outerSection;
|
||||||
auto scrollArea = new QScrollArea(wrapper);
|
|
||||||
scrollArea->setWidget(outerContent);
|
|
||||||
scrollArea->setWidgetResizable(true);
|
|
||||||
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
scrollArea->setFrameShape(QFrame::NoFrame);
|
|
||||||
wrapperLayout->addWidget(scrollArea);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -203,25 +180,12 @@ MacroExportImportDialog::MacroExportImportDialog(Type type,
|
|||||||
auto layout = new QVBoxLayout(this);
|
auto layout = new QVBoxLayout(this);
|
||||||
|
|
||||||
if (type == Type::EXPORT_MACRO && !GetMacroExportExtensions().empty()) {
|
if (type == Type::EXPORT_MACRO && !GetMacroExportExtensions().empty()) {
|
||||||
auto splitter = new QSplitter(Qt::Vertical, this);
|
layout->addWidget(BuildExtensionSection());
|
||||||
splitter->setChildrenCollapsible(false);
|
|
||||||
splitter->addWidget(BuildExtensionWidget());
|
|
||||||
|
|
||||||
auto textWidget = new QWidget(splitter);
|
|
||||||
auto textLayout = new QVBoxLayout(textWidget);
|
|
||||||
textLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
textLayout->addWidget(label);
|
|
||||||
textLayout->addWidget(_importExportString);
|
|
||||||
textLayout->addWidget(_usePlainText);
|
|
||||||
splitter->addWidget(textWidget);
|
|
||||||
|
|
||||||
layout->addWidget(splitter);
|
|
||||||
} else {
|
|
||||||
layout->addWidget(label);
|
|
||||||
layout->addWidget(_importExportString);
|
|
||||||
layout->addWidget(_usePlainText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layout->addWidget(label);
|
||||||
|
layout->addWidget(_importExportString);
|
||||||
|
layout->addWidget(_usePlainText);
|
||||||
layout->addWidget(buttons);
|
layout->addWidget(buttons);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
@@ -245,26 +209,19 @@ QString MacroExportImportDialog::BuildExportJson() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto &extensions = GetMacroExportExtensions();
|
const auto &extensions = GetMacroExportExtensions();
|
||||||
for (int i = 0; i < (int)_extensionUIs.size(); ++i) {
|
for (int i = 0;
|
||||||
const auto &ui = _extensionUIs[i];
|
i < (int)extensions.size() && i < (int)_extensionUIs.size(); ++i) {
|
||||||
|
if (!_extensionUIs[i].mainCheck->isChecked()) {
|
||||||
QStringList selectedIds;
|
continue;
|
||||||
if (ui.itemChecks.isEmpty()) {
|
|
||||||
if (!ui.mainCheck->isChecked()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const auto &[id, cb] : ui.itemChecks) {
|
|
||||||
if (cb->isChecked()) {
|
|
||||||
selectedIds << id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selectedIds.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions[_extensionOrder[i]].save(data, selectedIds);
|
QStringList selectedIds;
|
||||||
|
for (const auto &[id, cb] : _extensionUIs[i].itemChecks) {
|
||||||
|
if (cb->isChecked()) {
|
||||||
|
selectedIds << id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extensions[i].save(data, selectedIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *json = obs_data_get_json(data);
|
const char *json = obs_data_get_json(data);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "section.hpp"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
#include <obs-data.h>
|
#include <obs-data.h>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ private:
|
|||||||
QList<QPair<QString, QCheckBox *>> itemChecks;
|
QList<QPair<QString, QCheckBox *>> itemChecks;
|
||||||
};
|
};
|
||||||
|
|
||||||
QWidget *BuildExtensionWidget();
|
Section *BuildExtensionSection();
|
||||||
QString BuildExportJson() const;
|
QString BuildExportJson() const;
|
||||||
void RefreshExportText();
|
void RefreshExportText();
|
||||||
|
|
||||||
@@ -41,7 +42,6 @@ private:
|
|||||||
QPlainTextEdit *_importExportString;
|
QPlainTextEdit *_importExportString;
|
||||||
QCheckBox *_usePlainText;
|
QCheckBox *_usePlainText;
|
||||||
QList<ExtensionUI> _extensionUIs;
|
QList<ExtensionUI> _extensionUIs;
|
||||||
std::vector<int> _extensionOrder;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -76,8 +76,7 @@ EXPORT bool RunMacroElseActions(Macro *, bool forceParallel = false,
|
|||||||
bool ignorePause = false);
|
bool ignorePause = false);
|
||||||
EXPORT bool RunMacros();
|
EXPORT bool RunMacros();
|
||||||
|
|
||||||
void SignalStopAllMacros();
|
void StopAllMacros();
|
||||||
void WaitForAllMacros();
|
|
||||||
|
|
||||||
EXPORT void LoadMacros(obs_data_t *obj);
|
EXPORT void LoadMacros(obs_data_t *obj);
|
||||||
EXPORT void SaveMacros(obs_data_t *obj);
|
EXPORT void SaveMacros(obs_data_t *obj);
|
||||||
|
|||||||
@@ -74,11 +74,11 @@ void LoadMacroList(obs_data_t *obj, std::vector<MacroRef> ¯os,
|
|||||||
{
|
{
|
||||||
obs_data_array_t *array = obs_data_get_array(obj, name.c_str());
|
obs_data_array_t *array = obs_data_get_array(obj, name.c_str());
|
||||||
size_t count = obs_data_array_count(array);
|
size_t count = obs_data_array_count(array);
|
||||||
macros.reserve(macros.size() + count);
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(array, i);
|
obs_data_t *array_obj = obs_data_array_item(array, i);
|
||||||
macros.emplace_back();
|
MacroRef ref;
|
||||||
macros.back().Load(array_obj);
|
ref.Load(array_obj);
|
||||||
|
macros.push_back(ref);
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(array);
|
obs_data_array_release(array);
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ public:
|
|||||||
void SetSelected(bool);
|
void SetSelected(bool);
|
||||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||||
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
||||||
virtual void FocusTypeSelection() {}
|
|
||||||
|
|
||||||
void SetupVarMappings(MacroSegment *segment);
|
void SetupVarMappings(MacroSegment *segment);
|
||||||
|
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
std::vector<std::shared_ptr<Macro>> importedMacros;
|
std::vector<std::shared_ptr<Macro>> importedMacros;
|
||||||
auto &tempMacros = GetTemporaryMacros();
|
auto &tempMacros = GetTemporaryMacros();
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
auto lock = LockContext();
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
tempMacros.clear();
|
tempMacros.clear();
|
||||||
|
|
||||||
@@ -405,14 +405,10 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
macro->Load(array_obj);
|
macro->Load(array_obj);
|
||||||
RunAndClearPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
|
|
||||||
if (macroNameExists(macro->Name())) {
|
if (macroNameExists(macro->Name()) &&
|
||||||
lock.unlock();
|
!ResolveMacroImportNameConflict(macro)) {
|
||||||
bool resolved = ResolveMacroImportNameConflict(macro);
|
groupSize--;
|
||||||
lock.lock();
|
continue;
|
||||||
if (!resolved) {
|
|
||||||
groupSize--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
importedMacros.emplace_back(macro);
|
importedMacros.emplace_back(macro);
|
||||||
|
|||||||
@@ -1316,14 +1316,7 @@ bool RunMacros()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SignalStopAllMacros()
|
void StopAllMacros()
|
||||||
{
|
|
||||||
for (const auto &m : GetAllMacros()) {
|
|
||||||
m->SignalStop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitForAllMacros()
|
|
||||||
{
|
{
|
||||||
for (const auto &m : GetAllMacros()) {
|
for (const auto &m : GetAllMacros()) {
|
||||||
m->Stop();
|
m->Stop();
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ public:
|
|||||||
PauseStateSaveBehavior GetPauseStateSaveBehavior() const;
|
PauseStateSaveBehavior GetPauseStateSaveBehavior() const;
|
||||||
|
|
||||||
void Stop();
|
void Stop();
|
||||||
void SignalStop() { _stop = true; }
|
|
||||||
bool GetStop() const { return _stop; }
|
bool GetStop() const { return _stop; }
|
||||||
void ResetTimers();
|
void ResetTimers();
|
||||||
|
|
||||||
@@ -229,7 +228,7 @@ void LoadMacros(obs_data_t *obj);
|
|||||||
void SaveMacros(obs_data_t *obj);
|
void SaveMacros(obs_data_t *obj);
|
||||||
bool CheckMacros();
|
bool CheckMacros();
|
||||||
bool RunMacros();
|
bool RunMacros();
|
||||||
void WaitForAllMacros();
|
void StopAllMacros();
|
||||||
void InvalidateMacroTempVarValues();
|
void InvalidateMacroTempVarValues();
|
||||||
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
|
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
macro(add_plugin plugin)
|
macro(add_plugin plugin)
|
||||||
option(ENABLE_${plugin}_PLUGIN "Enable the ${plugin} plugin" ON)
|
option(ENABLE_${plugin}_PLUGIN "Enable the ${plugin} plugin" ON)
|
||||||
if(ENABLE_${plugin}_PLUGIN)
|
if(ENABLE_${plugin}_PLUGIN)
|
||||||
set_property(GLOBAL APPEND PROPERTY ADVSS_PLUGINS_PENDING ${plugin})
|
|
||||||
add_subdirectory(${plugin})
|
add_subdirectory(${plugin})
|
||||||
else()
|
|
||||||
set_property(GLOBAL APPEND PROPERTY ADVSS_PLUGINS_DISABLED_BY_OPTION
|
|
||||||
${plugin})
|
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
@@ -41,32 +37,3 @@ add_plugin(stream-deck)
|
|||||||
add_plugin(twitch)
|
add_plugin(twitch)
|
||||||
add_plugin(usb)
|
add_plugin(usb)
|
||||||
add_plugin(video)
|
add_plugin(video)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------- #
|
|
||||||
|
|
||||||
# Print plugin summary
|
|
||||||
get_property(_advss_enabled GLOBAL PROPERTY ADVSS_PLUGINS_ENABLED)
|
|
||||||
get_property(_advss_pending GLOBAL PROPERTY ADVSS_PLUGINS_PENDING)
|
|
||||||
get_property(_advss_disabled_opt GLOBAL
|
|
||||||
PROPERTY ADVSS_PLUGINS_DISABLED_BY_OPTION)
|
|
||||||
|
|
||||||
set(_advss_disabled_deps)
|
|
||||||
foreach(_p ${_advss_pending})
|
|
||||||
if(NOT _p IN_LIST _advss_enabled)
|
|
||||||
list(APPEND _advss_disabled_deps ${_p})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
message(STATUS "")
|
|
||||||
message(STATUS "ADVSS Plugin Summary")
|
|
||||||
message(STATUS "====================")
|
|
||||||
foreach(_p ${_advss_enabled})
|
|
||||||
message(STATUS " ENABLED: ${_p}")
|
|
||||||
endforeach()
|
|
||||||
foreach(_p ${_advss_disabled_deps})
|
|
||||||
message(STATUS " DISABLED: ${_p} (missing dependencies)")
|
|
||||||
endforeach()
|
|
||||||
foreach(_p ${_advss_disabled_opt})
|
|
||||||
message(STATUS " DISABLED: ${_p} (ENABLE_${_p}_PLUGIN=OFF)")
|
|
||||||
endforeach()
|
|
||||||
message(STATUS "")
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ void MacroConditionTransition::TransitionStarted(void *data, calldata_t *cd)
|
|||||||
// Look up the original by name to get a comparable reference.
|
// Look up the original by name to get a comparable reference.
|
||||||
const bool studioModeActive =
|
const bool studioModeActive =
|
||||||
obs_frontend_preview_program_mode_active();
|
obs_frontend_preview_program_mode_active();
|
||||||
if (studioModeActive && startSource) {
|
if (studioModeActive) {
|
||||||
OBSSourceAutoRelease startSourceByName = obs_get_source_by_name(
|
OBSSourceAutoRelease startSourceByName = obs_get_source_by_name(
|
||||||
obs_source_get_name(startSource));
|
obs_source_get_name(startSource));
|
||||||
if (startSourceByName) {
|
if (startSourceByName) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ if(NOT OpenVR_DIR)
|
|||||||
set(OpenVR_DIR ${ADVSS_SOURCE_DIR}/deps/openvr)
|
set(OpenVR_DIR ${ADVSS_SOURCE_DIR}/deps/openvr)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(EXISTS "${OpenVR_DIR}/CMakeLists.txt")
|
if(EXISTS ${OpenVR_DIR})
|
||||||
set(SIZEOF_VOIDP ${CMAKE_SIZEOF_VOID_P})
|
set(SIZEOF_VOIDP ${CMAKE_SIZEOF_VOID_P})
|
||||||
if((NOT APPLE) AND (CMAKE_SIZEOF_VOID_P EQUAL 8))
|
if((NOT APPLE) AND (CMAKE_SIZEOF_VOID_P EQUAL 8))
|
||||||
set(PROCESSOR_ARCH "64")
|
set(PROCESSOR_ARCH "64")
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
|
|
||||||
#include <log-helper.hpp>
|
#include <log-helper.hpp>
|
||||||
#include <plugin-state-helpers.hpp>
|
|
||||||
|
|
||||||
#undef DispatchMessage
|
#undef DispatchMessage
|
||||||
|
|
||||||
@@ -340,24 +339,6 @@ static constexpr std::string_view defaultURL =
|
|||||||
std::map<TwitchChatConnection::ChatMapKey, std::weak_ptr<TwitchChatConnection>>
|
std::map<TwitchChatConnection::ChatMapKey, std::weak_ptr<TwitchChatConnection>>
|
||||||
TwitchChatConnection::_chatMap = {};
|
TwitchChatConnection::_chatMap = {};
|
||||||
|
|
||||||
void TwitchChatConnection::DisconnectAll()
|
|
||||||
{
|
|
||||||
for (auto &[key, weakConn] : _chatMap) {
|
|
||||||
auto conn = weakConn.lock();
|
|
||||||
if (conn) {
|
|
||||||
conn->Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool setupChatConnectionSupport()
|
|
||||||
{
|
|
||||||
AddStopStep(TwitchChatConnection::DisconnectAll);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _chatSetup = setupChatConnectionSupport();
|
|
||||||
|
|
||||||
TwitchChatConnection::TwitchChatConnection(const TwitchToken &token,
|
TwitchChatConnection::TwitchChatConnection(const TwitchToken &token,
|
||||||
const TwitchChannel &channel)
|
const TwitchChannel &channel)
|
||||||
: QObject(nullptr),
|
: QObject(nullptr),
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ public:
|
|||||||
static std::shared_ptr<TwitchChatConnection>
|
static std::shared_ptr<TwitchChatConnection>
|
||||||
GetChatConnection(const TwitchToken &token,
|
GetChatConnection(const TwitchToken &token,
|
||||||
const TwitchChannel &channel);
|
const TwitchChannel &channel);
|
||||||
static void DisconnectAll();
|
|
||||||
[[nodiscard]] ChatMessageBuffer RegisterForMessages();
|
[[nodiscard]] ChatMessageBuffer RegisterForMessages();
|
||||||
[[nodiscard]] ChatMessageBuffer RegisterForWhispers();
|
[[nodiscard]] ChatMessageBuffer RegisterForWhispers();
|
||||||
void SendChatMessage(const std::string &message);
|
void SendChatMessage(const std::string &message);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
|
|
||||||
#include <log-helper.hpp>
|
#include <log-helper.hpp>
|
||||||
#include <plugin-state-helpers.hpp>
|
|
||||||
|
|
||||||
#ifdef VERIFY_TIMESTAMPS
|
#ifdef VERIFY_TIMESTAMPS
|
||||||
#include "date/tz.h"
|
#include "date/tz.h"
|
||||||
@@ -72,22 +71,6 @@ void EventSub::UnregisterInstance()
|
|||||||
_instances.erase(it, _instances.end());
|
_instances.erase(it, _instances.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventSub::DisconnectAll()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_instancesMtx);
|
|
||||||
for (auto *instance : _instances) {
|
|
||||||
instance->Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool setupEventSubSupport()
|
|
||||||
{
|
|
||||||
AddStopStep(EventSub::DisconnectAll);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _eventSubSetup = setupEventSubSupport();
|
|
||||||
|
|
||||||
void EventSub::ConnectThread()
|
void EventSub::ConnectThread()
|
||||||
{
|
{
|
||||||
_client->reset();
|
_client->reset();
|
||||||
@@ -279,21 +262,12 @@ std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture the session ID and release the lock before making the HTTP
|
|
||||||
// request. Holding the mutex during a network call would block
|
|
||||||
// SubscriptionIsActive() on the condition-check thread for the entire
|
|
||||||
// duration of the request, causing visibly slow macro evaluations.
|
|
||||||
const std::string sessionID = eventSub->_sessionID;
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
OBSDataAutoRelease postData = copyData(subscription.data);
|
OBSDataAutoRelease postData = copyData(subscription.data);
|
||||||
setTransportData(postData.Get(), sessionID);
|
setTransportData(postData.Get(), eventSub->_sessionID);
|
||||||
auto result = SendPostRequest(*token, registerSubscriptionURL.data(),
|
auto result = SendPostRequest(*token, registerSubscriptionURL.data(),
|
||||||
registerSubscriptionPath.data(), {},
|
registerSubscriptionPath.data(), {},
|
||||||
postData.Get());
|
postData.Get());
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
if (result.status != 202) {
|
if (result.status != 202) {
|
||||||
const char *error = obs_data_get_string(result.data, "error");
|
const char *error = obs_data_get_string(result.data, "error");
|
||||||
const char *message =
|
const char *message =
|
||||||
@@ -306,24 +280,6 @@ std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the session has not been replaced while the HTTP request was
|
|
||||||
// in flight (e.g. a reconnect occurred). If it was, the subscription
|
|
||||||
// we just created belongs to a dead session and must be discarded so
|
|
||||||
// the caller will retry with the new session ID.
|
|
||||||
if (eventSub->_sessionID != sessionID) {
|
|
||||||
blog(LOG_INFO,
|
|
||||||
"discarding Twitch EventSub registration - session ID "
|
|
||||||
"changed during HTTP request");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Another thread may have registered the same subscription while the
|
|
||||||
// lock was released.
|
|
||||||
if (isAlreadySubscribed(eventSub->_activeSubscriptions, subscription)) {
|
|
||||||
eventSub->LogActiveSubscriptions();
|
|
||||||
return eventSub->_activeSubscriptions.find(subscription)->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
OBSDataArrayAutoRelease replyArray =
|
OBSDataArrayAutoRelease replyArray =
|
||||||
obs_data_get_array(result.data, "data");
|
obs_data_get_array(result.data, "data");
|
||||||
OBSDataAutoRelease replyData = obs_data_array_item(replyArray, 0);
|
OBSDataAutoRelease replyData = obs_data_array_item(replyArray, 0);
|
||||||
@@ -483,10 +439,9 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
|||||||
|
|
||||||
void EventSub::HandleWelcome(obs_data_t *data)
|
void EventSub::HandleWelcome(obs_data_t *data)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_subscriptionMtx);
|
|
||||||
OBSDataAutoRelease session = obs_data_get_obj(data, "session");
|
OBSDataAutoRelease session = obs_data_get_obj(data, "session");
|
||||||
_sessionID = obs_data_get_string(session, "id");
|
_sessionID = obs_data_get_string(session, "id");
|
||||||
_activeSubscriptions.clear();
|
ClearActiveSubscriptions();
|
||||||
blog(LOG_INFO, "Twitch EventSub connected");
|
blog(LOG_INFO, "Twitch EventSub connected");
|
||||||
vblog(LOG_INFO, "Twitch EventSub session id: %s", _sessionID.c_str());
|
vblog(LOG_INFO, "Twitch EventSub session id: %s", _sessionID.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ public:
|
|||||||
|
|
||||||
void Connect();
|
void Connect();
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
static void DisconnectAll();
|
|
||||||
[[nodiscard]] EventSubMessageBuffer RegisterForEvents();
|
[[nodiscard]] EventSubMessageBuffer RegisterForEvents();
|
||||||
bool SubscriptionIsActive(const std::string &id);
|
bool SubscriptionIsActive(const std::string &id);
|
||||||
static std::string AddEventSubscription(std::shared_ptr<TwitchToken>,
|
static std::string AddEventSubscription(std::shared_ptr<TwitchToken>,
|
||||||
|
|||||||
@@ -547,18 +547,16 @@ bool MacroConditionTwitch::CheckChatMessageRemove(TwitchToken &token)
|
|||||||
|
|
||||||
bool MacroConditionTwitch::ChatConnectionIsSetup(TwitchToken &token)
|
bool MacroConditionTwitch::ChatConnectionIsSetup(TwitchToken &token)
|
||||||
{
|
{
|
||||||
if (_chatConnection) {
|
|
||||||
_chatConnection->ConnectToChat();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_chatConnection =
|
|
||||||
TwitchChatConnection::GetChatConnection(token, _channel);
|
|
||||||
if (!_chatConnection) {
|
if (!_chatConnection) {
|
||||||
|
_chatConnection = TwitchChatConnection::GetChatConnection(
|
||||||
|
token, _channel);
|
||||||
|
if (!_chatConnection) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_chatBuffer = _chatConnection->RegisterForMessages();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_chatBuffer = _chatConnection->RegisterForMessages();
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionTwitch::HandleChatEvents(
|
bool MacroConditionTwitch::HandleChatEvents(
|
||||||
|
|||||||
@@ -403,12 +403,11 @@ bool MacroConditionVideo::CheckBrightnessThreshold()
|
|||||||
|
|
||||||
bool MacroConditionVideo::CheckOCR()
|
bool MacroConditionVideo::CheckOCR()
|
||||||
{
|
{
|
||||||
auto *ocr = _ocrParameters.GetOCR();
|
if (!_ocrParameters.Initialized()) {
|
||||||
if (!ocr) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto text = RunOCR(ocr, _screenshotData.GetImage(),
|
auto text = RunOCR(_ocrParameters.GetOCR(), _screenshotData.GetImage(),
|
||||||
_ocrParameters.color, _ocrParameters.colorThreshold);
|
_ocrParameters.color, _ocrParameters.colorThreshold);
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ bool ObjDetectParameters::Save(obs_data_t *obj) const
|
|||||||
minSize.Save(data, "minSize");
|
minSize.Save(data, "minSize");
|
||||||
maxSize.Save(data, "maxSize");
|
maxSize.Save(data, "maxSize");
|
||||||
obs_data_set_obj(obj, "objectMatchData", data);
|
obs_data_set_obj(obj, "objectMatchData", data);
|
||||||
obs_data_set_int(data, "version", 2);
|
obs_data_set_int(data, "version", 1);
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -121,21 +121,6 @@ bool ObjDetectParameters::Load(obs_data_t *obj)
|
|||||||
// TODO: Remove this fallback in a future version
|
// TODO: Remove this fallback in a future version
|
||||||
if (!obs_data_has_user_value(data, "version")) {
|
if (!obs_data_has_user_value(data, "version")) {
|
||||||
scaleFactor = obs_data_get_double(data, "scaleFactor");
|
scaleFactor = obs_data_get_double(data, "scaleFactor");
|
||||||
} else if (obs_data_get_int(data, "version") == 1) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
// On Windows the plugin directory moved from
|
|
||||||
// "Program Files/.../data/obs-plugins/advanced-scene-switcher"
|
|
||||||
// to "ProgramData/.../plugins/advanced-scene-switcher/data",
|
|
||||||
// which invalidates previously saved default model paths.
|
|
||||||
const std::string oldPrefix =
|
|
||||||
"../../data/obs-plugins/advanced-scene-switcher/res/cascadeClassifiers/";
|
|
||||||
if (modelPath.substr(0, oldPrefix.size()) == oldPrefix) {
|
|
||||||
modelPath = std::string(obs_get_module_data_path(
|
|
||||||
obs_current_module())) +
|
|
||||||
"/res/cascadeClassifiers/" +
|
|
||||||
modelPath.substr(oldPrefix.size());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (scaleFactor.IsFixedType() && !isScaleFactorValid(scaleFactor)) {
|
if (scaleFactor.IsFixedType() && !isScaleFactorValid(scaleFactor)) {
|
||||||
scaleFactor = 1.1;
|
scaleFactor = 1.1;
|
||||||
@@ -318,6 +303,9 @@ OCRParameters::OCRParameters(const OCRParameters &other)
|
|||||||
useConfig(other.useConfig),
|
useConfig(other.useConfig),
|
||||||
configFile(other.configFile)
|
configFile(other.configFile)
|
||||||
{
|
{
|
||||||
|
if (!initDone) {
|
||||||
|
Setup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OCRParameters &OCRParameters::operator=(const OCRParameters &other)
|
OCRParameters &OCRParameters::operator=(const OCRParameters &other)
|
||||||
@@ -331,7 +319,9 @@ OCRParameters &OCRParameters::operator=(const OCRParameters &other)
|
|||||||
languageCode = other.languageCode;
|
languageCode = other.languageCode;
|
||||||
useConfig = other.useConfig;
|
useConfig = other.useConfig;
|
||||||
configFile = other.configFile;
|
configFile = other.configFile;
|
||||||
initDone = false;
|
if (!initDone) {
|
||||||
|
Setup();
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +337,7 @@ bool OCRParameters::Save(obs_data_t *obj) const
|
|||||||
SaveColor(data, "textColor", color);
|
SaveColor(data, "textColor", color);
|
||||||
colorThreshold.Save(data, "colorThreshold");
|
colorThreshold.Save(data, "colorThreshold");
|
||||||
obs_data_set_int(data, "pageSegMode", static_cast<int>(pageSegMode));
|
obs_data_set_int(data, "pageSegMode", static_cast<int>(pageSegMode));
|
||||||
obs_data_set_int(data, "version", 3);
|
obs_data_set_int(data, "version", 2);
|
||||||
obs_data_set_obj(obj, "ocrData", data);
|
obs_data_set_obj(obj, "ocrData", data);
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
return true;
|
return true;
|
||||||
@@ -366,23 +356,6 @@ bool OCRParameters::Load(obs_data_t *obj)
|
|||||||
tesseractBasePath = std::string(obs_get_module_data_path(
|
tesseractBasePath = std::string(obs_get_module_data_path(
|
||||||
obs_current_module())) +
|
obs_current_module())) +
|
||||||
"/res/ocr/";
|
"/res/ocr/";
|
||||||
} else if (obs_data_get_int(data, "version") == 2) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
// On Windows the plugin directory moved from
|
|
||||||
// "Program Files/.../data/obs-plugins/advanced-scene-switcher"
|
|
||||||
// to "ProgramData/.../plugins/advanced-scene-switcher/data",
|
|
||||||
// which invalidates the previously saved default OCR path.
|
|
||||||
const std::string oldPath = tesseractBasePath;
|
|
||||||
if (oldPath ==
|
|
||||||
"../../data/obs-plugins/advanced-scene-switcher/res/ocr/" ||
|
|
||||||
oldPath ==
|
|
||||||
"../../data/obs-plugins/advanced-scene-switcher/res/ocr") {
|
|
||||||
tesseractBasePath =
|
|
||||||
std::string(obs_get_module_data_path(
|
|
||||||
obs_current_module())) +
|
|
||||||
"/res/ocr/";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
useConfig = obs_data_get_bool(data, "useConfig");
|
useConfig = obs_data_get_bool(data, "useConfig");
|
||||||
configFile = obs_data_get_string(data, "configFile");
|
configFile = obs_data_get_string(data, "configFile");
|
||||||
@@ -407,14 +380,6 @@ void OCRParameters::SetPageMode(tesseract::PageSegMode mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tesseract::TessBaseAPI *OCRParameters::GetOCR()
|
|
||||||
{
|
|
||||||
if (!initDone) {
|
|
||||||
Setup();
|
|
||||||
}
|
|
||||||
return initDone ? ocr.get() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OCRParameters::SetLanguageCode(const std::string &value)
|
bool OCRParameters::SetLanguageCode(const std::string &value)
|
||||||
{
|
{
|
||||||
const auto dataPath = QString::fromStdString(tesseractBasePath) + "/" +
|
const auto dataPath = QString::fromStdString(tesseractBasePath) + "/" +
|
||||||
@@ -424,7 +389,7 @@ bool OCRParameters::SetLanguageCode(const std::string &value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
languageCode = value;
|
languageCode = value;
|
||||||
initDone = false;
|
Setup();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +408,7 @@ bool OCRParameters::SetTesseractBasePath(const std::string &value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tesseractBasePath = value;
|
tesseractBasePath = value;
|
||||||
initDone = false;
|
Setup();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,13 +420,13 @@ std::string OCRParameters::GetTesseractBasePath() const
|
|||||||
void OCRParameters::EnableCustomConfig(bool enable)
|
void OCRParameters::EnableCustomConfig(bool enable)
|
||||||
{
|
{
|
||||||
useConfig = enable;
|
useConfig = enable;
|
||||||
initDone = false;
|
Setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OCRParameters::SetCustomConfigFile(const std::string &filename)
|
void OCRParameters::SetCustomConfigFile(const std::string &filename)
|
||||||
{
|
{
|
||||||
configFile = filename;
|
configFile = filename;
|
||||||
initDone = false;
|
Setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OCRParameters::Setup()
|
void OCRParameters::Setup()
|
||||||
|
|||||||
@@ -108,7 +108,10 @@ public:
|
|||||||
void SetCustomConfigFile(const std::string &);
|
void SetCustomConfigFile(const std::string &);
|
||||||
std::string GetCustomConfigFile() const { return configFile; }
|
std::string GetCustomConfigFile() const { return configFile; }
|
||||||
tesseract::PageSegMode GetPageMode() const { return pageSegMode; }
|
tesseract::PageSegMode GetPageMode() const { return pageSegMode; }
|
||||||
tesseract::TessBaseAPI *GetOCR();
|
tesseract::TessBaseAPI *GetOCR() const
|
||||||
|
{
|
||||||
|
return initDone ? ocr.get() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
StringVariable text = obs_module_text("AdvSceneSwitcher.enterText");
|
StringVariable text = obs_module_text("AdvSceneSwitcher.enterText");
|
||||||
RegexConfig regex = RegexConfig::PartialMatchRegexConfig();
|
RegexConfig regex = RegexConfig::PartialMatchRegexConfig();
|
||||||
|
|||||||
Reference in New Issue
Block a user