SceneSwitcher/src/switch-window.cpp
WarmUpTill bdd9d12257 Add setPreconditions()
The idea is to avoid repeated calls to the same functions which lead to
the same outcome, but just calling them once in the precondition checks.

For now move repeated calls of GetCurrentWindowTitle() and ignoreWindow
checks to this function.
2021-06-19 05:22:50 -07:00

485 lines
12 KiB
C++

#include <regex>
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
bool WindowSwitch::pause = false;
static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_windowAdd_clicked()
{
std::lock_guard<std::mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back();
listAddClicked(ui->windowSwitches,
new WindowSwitchWidget(this,
&switcher->windowSwitches.back()),
ui->windowAdd, &addPulse);
ui->windowHelp->setVisible(false);
}
void AdvSceneSwitcher::on_windowRemove_clicked()
{
QListWidgetItem *item = ui->windowSwitches->currentItem();
if (!item) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->windowSwitches->currentRow();
auto &switches = switcher->windowSwitches;
switches.erase(switches.begin() + idx);
}
delete item;
}
void AdvSceneSwitcher::on_windowUp_clicked()
{
int index = ui->windowSwitches->currentRow();
if (!listMoveUp(ui->windowSwitches)) {
return;
}
WindowSwitchWidget *s1 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index));
WindowSwitchWidget *s2 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index - 1));
WindowSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->windowSwitches[index],
switcher->windowSwitches[index - 1]);
}
void AdvSceneSwitcher::on_windowDown_clicked()
{
int index = ui->windowSwitches->currentRow();
if (!listMoveDown(ui->windowSwitches)) {
return;
}
WindowSwitchWidget *s1 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index));
WindowSwitchWidget *s2 =
(WindowSwitchWidget *)ui->windowSwitches->itemWidget(
ui->windowSwitches->item(index + 1));
WindowSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->windowSwitches[index],
switcher->windowSwitches[index + 1]);
}
void AdvSceneSwitcher::on_ignoreWindowsAdd_clicked()
{
QString windowName = ui->ignoreWindowsWindows->currentText();
if (windowName.isEmpty()) {
return;
}
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem *> items =
ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
}
ui->ignoreWindowHelp->setVisible(false);
}
void AdvSceneSwitcher::on_ignoreWindowsRemove_clicked()
{
QListWidgetItem *item = ui->ignoreWindows->currentItem();
if (!item) {
return;
}
QString windowName = item->data(Qt::UserRole).toString();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData()) {
switches.erase(it);
break;
}
}
}
delete item;
}
int AdvSceneSwitcher::IgnoreWindowsFindByData(const QString &window)
{
int count = ui->ignoreWindows->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window) {
idx = i;
break;
}
}
return idx;
}
void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{
if (loading) {
return;
}
if (idx == -1) {
return;
}
QListWidgetItem *item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->ignoreWindowsSwitches) {
if (window.compare(s.c_str()) == 0) {
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
void checkWindowTitleSwitchDirect(WindowSwitch &s,
std::string &currentWindowTitle, bool &match,
OBSWeakSource &scene,
OBSWeakSource &transition)
{
bool focus = (!s.focus || s.window == currentWindowTitle);
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
bool max = (!s.maximized || isMaximized(s.window));
if (focus && fullscreen && max) {
match = true;
scene = s.getScene();
transition = s.transition;
}
}
void checkWindowTitleSwitchRegex(WindowSwitch &s,
std::string &currentWindowTitle,
std::vector<std::string> windowList,
bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
for (auto &window : windowList) {
try {
std::regex expr(s.window);
if (!std::regex_match(window, expr)) {
continue;
}
} catch (const std::regex_error &) {
}
bool focus = (!s.focus || window == currentWindowTitle);
bool fullscreen = (!s.fullscreen || isFullscreen(window));
bool max = (!s.maximized || isMaximized(window));
if (focus && fullscreen && max) {
match = true;
scene = s.getScene();
transition = s.transition;
}
}
}
bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
OBSWeakSource &transition)
{
if (WindowSwitch::pause) {
return false;
}
std::string currentWindowTitle = switcher->currentTitle;
bool match = false;
std::vector<std::string> windowList;
GetWindowList(windowList);
for (WindowSwitch &s : windowSwitches) {
if (!s.initialized()) {
continue;
}
if (std::find(windowList.begin(), windowList.end(), s.window) !=
windowList.end()) {
checkWindowTitleSwitchDirect(s, currentWindowTitle,
match, scene, transition);
} else {
checkWindowTitleSwitchRegex(s, currentWindowTitle,
windowList, match, scene,
transition);
}
if (match) {
if (verbose) {
s.logMatch();
}
break;
}
}
return match;
}
void SwitcherData::saveWindowTitleSwitches(obs_data_t *obj)
{
obs_data_array_t *windowTitleArray = obs_data_array_create();
for (WindowSwitch &s : windowSwitches) {
obs_data_t *array_obj = obs_data_create();
s.save(array_obj);
obs_data_array_push_back(windowTitleArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "switches", windowTitleArray);
obs_data_array_release(windowTitleArray);
obs_data_array_t *ignoreWindowsArray = obs_data_array_create();
for (std::string &window : ignoreWindowsSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "ignoreWindow", window.c_str());
obs_data_array_push_back(ignoreWindowsArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "ignoreWindows", ignoreWindowsArray);
obs_data_array_release(ignoreWindowsArray);
}
void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
{
windowSwitches.clear();
obs_data_array_t *windowTitleArray =
obs_data_get_array(obj, "switches");
size_t count = obs_data_array_count(windowTitleArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(windowTitleArray, i);
windowSwitches.emplace_back();
windowSwitches.back().load(array_obj);
obs_data_release(array_obj);
}
obs_data_array_release(windowTitleArray);
ignoreWindowsSwitches.clear();
obs_data_array_t *ignoreWindowsArray =
obs_data_get_array(obj, "ignoreWindows");
count = obs_data_array_count(ignoreWindowsArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj =
obs_data_array_item(ignoreWindowsArray, i);
const char *window =
obs_data_get_string(array_obj, "ignoreWindow");
ignoreWindowsSwitches.emplace_back(window);
obs_data_release(array_obj);
}
obs_data_array_release(ignoreWindowsArray);
}
void AdvSceneSwitcher::setupTitleTab()
{
for (auto &s : switcher->windowSwitches) {
QListWidgetItem *item;
item = new QListWidgetItem(ui->windowSwitches);
ui->windowSwitches->addItem(item);
WindowSwitchWidget *sw = new WindowSwitchWidget(this, &s);
item->setSizeHint(sw->minimumSizeHint());
ui->windowSwitches->setItemWidget(item, sw);
}
if (switcher->windowSwitches.size() == 0) {
if (!switcher->disableHints) {
addPulse =
PulseWidget(ui->windowAdd, QColor(Qt::green));
}
ui->windowHelp->setVisible(true);
} else {
ui->windowHelp->setVisible(false);
}
populateWindowSelection(ui->ignoreWindowsWindows);
for (auto &window : switcher->ignoreWindowsSwitches) {
QString text = QString::fromStdString(window);
QListWidgetItem *item =
new QListWidgetItem(text, ui->ignoreWindows);
item->setData(Qt::UserRole, text);
}
if (switcher->ignoreWindowsSwitches.size() == 0) {
ui->ignoreWindowHelp->setVisible(true);
} else {
ui->ignoreWindowHelp->setVisible(false);
}
}
void WindowSwitch::save(obs_data_t *obj)
{
SceneSwitcherEntry::save(obj);
obs_data_set_string(obj, "windowTitle", window.c_str());
obs_data_set_bool(obj, "fullscreen", fullscreen);
obs_data_set_bool(obj, "maximized", maximized);
obs_data_set_bool(obj, "focus", focus);
}
void WindowSwitch::load(obs_data_t *obj)
{
SceneSwitcherEntry::load(obj);
window = obs_data_get_string(obj, "windowTitle");
fullscreen = obs_data_get_bool(obj, "fullscreen");
maximized = obs_data_get_bool(obj, "maximized");
focus = obs_data_get_bool(obj, "focus") ||
!obs_data_has_user_value(obj, "focus");
}
WindowSwitchWidget::WindowSwitchWidget(QWidget *parent, WindowSwitch *s)
: SwitchWidget(parent, s, true, true)
{
windows = new QComboBox();
fullscreen = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.fullscreen"));
maximized = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.maximized"));
focused = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.focused"));
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(WindowChanged(const QString &)));
QWidget::connect(fullscreen, SIGNAL(stateChanged(int)), this,
SLOT(FullscreenChanged(int)));
QWidget::connect(maximized, SIGNAL(stateChanged(int)), this,
SLOT(MaximizedChanged(int)));
QWidget::connect(focused, SIGNAL(stateChanged(int)), this,
SLOT(FocusChanged(int)));
populateWindowSelection(windows);
windows->setEditable(true);
windows->setMaxVisibleItems(20);
if (s) {
windows->setCurrentText(s->window.c_str());
fullscreen->setChecked(s->fullscreen);
maximized->setChecked(s->maximized);
focused->setChecked(s->focus);
}
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{windows}}", windows},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions},
{"{{fullscreen}}", fullscreen},
{"{{maximized}}", maximized},
{"{{focused}}", focused}};
placeWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;
loading = false;
}
WindowSwitch *WindowSwitchWidget::getSwitchData()
{
return switchData;
}
void WindowSwitchWidget::setSwitchData(WindowSwitch *s)
{
switchData = s;
}
void WindowSwitchWidget::swapSwitchData(WindowSwitchWidget *s1,
WindowSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
WindowSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void WindowSwitchWidget::WindowChanged(const QString &text)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->window = text.toStdString();
}
void WindowSwitchWidget::FullscreenChanged(int state)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->fullscreen = state;
}
void WindowSwitchWidget::MaximizedChanged(int state)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->maximized = state;
}
void WindowSwitchWidget::FocusChanged(int state)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->focus = state;
}