mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
11 Commits
1.34.2
...
nested-que
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba7886c8c1 | ||
|
|
801268d08b | ||
|
|
7dfd9ddcb5 | ||
|
|
6215c39024 | ||
|
|
1c856911e8 | ||
|
|
ed17c2ac6d | ||
|
|
1ce332a91d | ||
|
|
2aa27fc051 | ||
|
|
31b239d5dc | ||
|
|
7c3779e287 | ||
|
|
3f13c33b10 |
@@ -157,7 +157,9 @@ else()
|
|||||||
set_target_properties(${target} PROPERTIES INSTALL_RPATH
|
set_target_properties(${target} PROPERTIES INSTALL_RPATH
|
||||||
"$ORIGIN:$ORIGIN/..")
|
"$ORIGIN:$ORIGIN/..")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "ADVSS: ENABLED PLUGIN ${target}")
|
get_filename_component(_plugin_dir_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
|
||||||
|
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,7 +6,11 @@ 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)
|
||||||
set(arch ${CMAKE_GENERATOR_PLATFORM})
|
if(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")
|
||||||
|
|||||||
@@ -294,6 +294,30 @@ 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,35 +12,82 @@
|
|||||||
|
|
||||||
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();
|
||||||
@@ -53,25 +100,32 @@ bool startKWinScript(QString &scriptObjectPath)
|
|||||||
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
||||||
|
|
||||||
const QString script =
|
const QString script =
|
||||||
R"(workspace.windowActivated.connect(function(client) {
|
R"(var adss = "com.github.AdvancedSceneSwitcher";
|
||||||
if (!client) return;
|
var adssPath = "/com/github/AdvancedSceneSwitcher";
|
||||||
if (!client.pid) return;
|
|
||||||
if (!client.caption) return;
|
|
||||||
|
|
||||||
callDBus(
|
function trackWindow(window) {
|
||||||
"com.github.AdvancedSceneSwitcher",
|
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() {
|
||||||
"focusChanged",
|
callDBus(adss, adssPath, adss, "windowTitleChanged", id, window.caption);
|
||||||
client.pid
|
});
|
||||||
);
|
}
|
||||||
callDBus(
|
|
||||||
"com.github.AdvancedSceneSwitcher",
|
var windows = workspace.windowList();
|
||||||
"/com/github/AdvancedSceneSwitcher",
|
for (var i = 0; i < windows.length; i++) {
|
||||||
"com.github.AdvancedSceneSwitcher",
|
trackWindow(windows[i]);
|
||||||
"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,7 +2,11 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -10,18 +14,27 @@ 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,4 +164,9 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
|||||||
return *_entryData;
|
return *_entryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionEdit::FocusTypeSelection()
|
||||||
|
{
|
||||||
|
_actionSelection->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ 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,6 +263,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +310,15 @@ 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,4 +305,9 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
|||||||
return *_entryData;
|
return *_entryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionEdit::FocusTypeSelection()
|
||||||
|
{
|
||||||
|
_conditionSelection->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ 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,6 +650,18 @@ 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;
|
||||||
@@ -1087,10 +1099,7 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
|||||||
ui->actionsList->SetHelpMsgVisible(false);
|
ui->actionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
|
|
||||||
QTimer::singleShot(0, this, [this]() {
|
ScrollAndFocusNewSegment(ui->actionsList, idx, ¤tActionIdx);
|
||||||
ui->actionsList->ensureWidgetVisible(
|
|
||||||
ui->actionsList->WidgetAt(currentActionIdx));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::AddMacroAction(int idx)
|
void MacroEdit::AddMacroAction(int idx)
|
||||||
@@ -1398,10 +1407,8 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
|||||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
|
|
||||||
QTimer::singleShot(0, this, [this]() {
|
ScrollAndFocusNewSegment(ui->elseActionsList, idx,
|
||||||
ui->elseActionsList->ensureWidgetVisible(
|
¤tElseActionIdx);
|
||||||
ui->elseActionsList->WidgetAt(currentElseActionIdx));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::AddMacroElseAction(int idx)
|
void MacroEdit::AddMacroElseAction(int idx)
|
||||||
@@ -1611,10 +1618,7 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
|||||||
ui->conditionsList->SetHelpMsgVisible(false);
|
ui->conditionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
|
|
||||||
QTimer::singleShot(0, this, [this]() {
|
ScrollAndFocusNewSegment(ui->conditionsList, idx, ¤tConditionIdx);
|
||||||
ui->conditionsList->ensureWidgetVisible(
|
|
||||||
ui->conditionsList->WidgetAt(currentConditionIdx));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::on_conditionAdd_clicked()
|
void MacroEdit::on_conditionAdd_clicked()
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ 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,11 +1,14 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@@ -44,10 +47,14 @@ static bool isValidData(const QString &json)
|
|||||||
// Extension section
|
// Extension section
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
Section *MacroExportImportDialog::BuildExtensionSection()
|
QWidget *MacroExportImportDialog::BuildExtensionWidget()
|
||||||
{
|
{
|
||||||
auto outerSection = new Section(300, this);
|
auto wrapper = new QWidget(this);
|
||||||
outerSection->AddHeaderWidget(new QLabel(obs_module_text(
|
auto wrapperLayout = new QVBoxLayout(wrapper);
|
||||||
|
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();
|
||||||
@@ -57,7 +64,6 @@ Section *MacroExportImportDialog::BuildExtensionSection()
|
|||||||
|
|
||||||
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) {
|
||||||
@@ -81,6 +87,7 @@ Section *MacroExportImportDialog::BuildExtensionSection()
|
|||||||
&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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,11 +95,18 @@ Section *MacroExportImportDialog::BuildExtensionSection()
|
|||||||
// 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.
|
||||||
const auto items = ext.getExportItems();
|
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 =
|
||||||
@@ -132,13 +146,22 @@ Section *MacroExportImportDialog::BuildExtensionSection()
|
|||||||
UpdateExportString();
|
UpdateExportString();
|
||||||
});
|
});
|
||||||
|
|
||||||
innerSection->SetContent(subWidget, false);
|
innerSection->SetContent(subWidget, true);
|
||||||
outerLayout->addWidget(innerSection);
|
outerLayout->addWidget(innerSection);
|
||||||
_extensionUIs.append(std::move(ui));
|
_extensionUIs.append(std::move(ui));
|
||||||
|
_extensionOrder.push_back(extIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
outerSection->SetContent(outerContent, true);
|
outerLayout->addStretch();
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -180,12 +203,25 @@ 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()) {
|
||||||
layout->addWidget(BuildExtensionSection());
|
auto splitter = new QSplitter(Qt::Vertical, this);
|
||||||
|
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);
|
||||||
|
|
||||||
@@ -209,19 +245,26 @@ QString MacroExportImportDialog::BuildExportJson() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto &extensions = GetMacroExportExtensions();
|
const auto &extensions = GetMacroExportExtensions();
|
||||||
for (int i = 0;
|
for (int i = 0; i < (int)_extensionUIs.size(); ++i) {
|
||||||
i < (int)extensions.size() && i < (int)_extensionUIs.size(); ++i) {
|
const auto &ui = _extensionUIs[i];
|
||||||
if (!_extensionUIs[i].mainCheck->isChecked()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList selectedIds;
|
QStringList selectedIds;
|
||||||
for (const auto &[id, cb] : _extensionUIs[i].itemChecks) {
|
if (ui.itemChecks.isEmpty()) {
|
||||||
if (cb->isChecked()) {
|
if (!ui.mainCheck->isChecked()) {
|
||||||
selectedIds << id;
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const auto &[id, cb] : ui.itemChecks) {
|
||||||
|
if (cb->isChecked()) {
|
||||||
|
selectedIds << id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedIds.isEmpty()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extensions[i].save(data, selectedIds);
|
|
||||||
|
extensions[_extensionOrder[i]].save(data, selectedIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *json = obs_data_get_json(data);
|
const char *json = obs_data_get_json(data);
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
#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 {
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ private:
|
|||||||
QList<QPair<QString, QCheckBox *>> itemChecks;
|
QList<QPair<QString, QCheckBox *>> itemChecks;
|
||||||
};
|
};
|
||||||
|
|
||||||
Section *BuildExtensionSection();
|
QWidget *BuildExtensionWidget();
|
||||||
QString BuildExportJson() const;
|
QString BuildExportJson() const;
|
||||||
void RefreshExportText();
|
void RefreshExportText();
|
||||||
|
|
||||||
@@ -42,6 +41,7 @@ private:
|
|||||||
QPlainTextEdit *_importExportString;
|
QPlainTextEdit *_importExportString;
|
||||||
QCheckBox *_usePlainText;
|
QCheckBox *_usePlainText;
|
||||||
QList<ExtensionUI> _extensionUIs;
|
QList<ExtensionUI> _extensionUIs;
|
||||||
|
std::vector<int> _extensionOrder;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
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()
|
||||||
|
|
||||||
@@ -37,3 +41,32 @@ 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) {
|
if (studioModeActive && startSource) {
|
||||||
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})
|
if(EXISTS "${OpenVR_DIR}/CMakeLists.txt")
|
||||||
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,6 +3,7 @@
|
|||||||
#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
|
||||||
|
|
||||||
@@ -339,6 +340,24 @@ 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,6 +84,7 @@ 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,6 +3,7 @@
|
|||||||
#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"
|
||||||
@@ -71,6 +72,22 @@ 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();
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ 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,16 +547,18 @@ 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;
|
||||||
}
|
}
|
||||||
return true;
|
_chatBuffer = _chatConnection->RegisterForMessages();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionTwitch::HandleChatEvents(
|
bool MacroConditionTwitch::HandleChatEvents(
|
||||||
|
|||||||
Reference in New Issue
Block a user