New upstream version 0.16.2+dfsg1

This commit is contained in:
Sebastian Ramacher 2016-10-10 21:01:40 +02:00
parent 67704ac59c
commit 6efda2859e
377 changed files with 7938 additions and 696 deletions

View file

@ -0,0 +1,3 @@
if(WIN32 OR APPLE)
add_subdirectory(frontend-tools)
endif()

View file

@ -0,0 +1,46 @@
project(frontend-tools)
if(APPLE)
find_library(COCOA Cocoa)
include_directories(${COCOA})
endif()
set(frontend-tools_HEADERS
auto-scene-switcher.hpp
)
set(frontend-tools_SOURCES
frontend-tools.c
auto-scene-switcher.cpp
)
set(frontend-tools_UI
forms/auto-scene-switcher.ui
)
if(WIN32)
set(frontend-tools_PLATFORM_SOURCES
auto-scene-switcher-win.cpp)
elseif(APPLE)
set(frontend-tools_PLATFORM_SOURCES
auto-scene-switcher-osx.mm)
set_source_files_properties(auto-scene-switcher-osx.mm
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
set(frontend-tools_PLATFORM_LIBS
${COCOA})
endif()
qt5_wrap_ui(frontend-tools_UI_HEADERS ${frontend-tools_UI})
add_library(frontend-tools MODULE
${frontend-tools_HEADERS}
${frontend-tools_SOURCES}
${frontend-tools_PLATFORM_SOURCES}
${frontend-tools_UI_HEADERS}
)
target_link_libraries(frontend-tools
${frontend-tools_PLATFORM_LIBS}
obs-frontend-api
Qt5::Widgets
libobs)
install_obs_plugin_with_data(frontend-tools data)

View file

@ -0,0 +1,43 @@
#import <AppKit/AppKit.h>
#include <util/platform.h>
#include "auto-scene-switcher.hpp"
using namespace std;
void GetWindowList(vector<string> &windows)
{
windows.resize(0);
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSArray *array = [ws runningApplications];
for (NSRunningApplication *app in array) {
NSString *name = app.localizedName;
if (!name)
continue;
const char *str = name.UTF8String;
if (str && *str)
windows.emplace_back(str);
}
}
}
void GetCurrentWindowTitle(string &title)
{
title.resize(0);
@autoreleasepool {
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSRunningApplication *app = [ws frontmostApplication];
if (app) {
NSString *name = app.localizedName;
if (!name)
return;
const char *str = name.UTF8String;
if (str && *str)
title = str;
}
}
}

View file

@ -0,0 +1,69 @@
#include <windows.h>
#include <util/platform.h>
#include "auto-scene-switcher.hpp"
using namespace std;
static bool GetWindowTitle(HWND window, string &title)
{
size_t len = (size_t)GetWindowTextLengthW(window);
wstring wtitle;
wtitle.resize(len);
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
return false;
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
title.resize(len);
os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1);
return true;
}
static bool WindowValid(HWND window)
{
LONG_PTR styles, ex_styles;
RECT rect;
DWORD id;
if (!IsWindowVisible(window))
return false;
GetWindowThreadProcessId(window, &id);
if (id == GetCurrentProcessId())
return false;
GetClientRect(window, &rect);
styles = GetWindowLongPtr(window, GWL_STYLE);
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
if (ex_styles & WS_EX_TOOLWINDOW)
return false;
if (styles & WS_CHILD)
return false;
return true;
}
void GetWindowList(vector<string> &windows)
{
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
while (window) {
string title;
if (WindowValid(window) && GetWindowTitle(window, title))
windows.emplace_back(title);
window = GetNextWindow(window, GW_HWNDNEXT);
}
}
void GetCurrentWindowTitle(string &title)
{
HWND window = GetForegroundWindow();
DWORD id;
GetWindowThreadProcessId(window, &id);
if (id == GetCurrentProcessId()) {
title = "";
return;
}
GetWindowTitle(window, title);
}

View file

@ -0,0 +1,588 @@
#include <obs-frontend-api.h>
#include <obs-module.h>
#include <obs.hpp>
#include <util/util.hpp>
#include <QMainWindow>
#include <QAction>
#include "auto-scene-switcher.hpp"
#include <condition_variable>
#include <chrono>
#include <string>
#include <vector>
#include <thread>
#include <regex>
#include <mutex>
using namespace std;
#define DEFAULT_INTERVAL 300
struct SceneSwitch {
OBSWeakSource scene;
string window;
regex re;
inline SceneSwitch(OBSWeakSource scene_, const char *window_)
: scene(scene_), window(window_), re(window_)
{
}
};
static inline bool WeakSourceValid(obs_weak_source_t *ws)
{
obs_source_t *source = obs_weak_source_get_source(ws);
if (source)
obs_source_release(source);
return !!source;
}
struct SwitcherData {
thread th;
condition_variable cv;
mutex m;
bool stop = false;
vector<SceneSwitch> switches;
OBSWeakSource nonMatchingScene;
int interval = DEFAULT_INTERVAL;
bool switchIfNotMatching = false;
bool startAtLaunch = false;
void Thread();
void Start();
void Stop();
void Prune()
{
for (size_t i = 0; i < switches.size(); i++) {
SceneSwitch &s = switches[i];
if (!WeakSourceValid(s.scene))
switches.erase(switches.begin() + i--);
}
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
switchIfNotMatching = false;
nonMatchingScene = nullptr;
}
}
inline ~SwitcherData()
{
Stop();
}
};
static SwitcherData *switcher = nullptr;
static inline QString MakeSwitchName(const QString &scene,
const QString &window)
{
return QStringLiteral("[") + scene + QStringLiteral("]: ") + window;
}
static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
{
string name;
obs_source_t *source = obs_weak_source_get_source(weak_source);
if (source) {
name = obs_source_get_name(source);
obs_source_release(source);
}
return name;
}
static inline OBSWeakSource GetWeakSourceByName(const char *name)
{
OBSWeakSource weak;
obs_source_t *source = obs_get_source_by_name(name);
if (source) {
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
obs_source_release(source);
}
return weak;
}
static inline OBSWeakSource GetWeakSourceByQString(const QString &name)
{
return GetWeakSourceByName(name.toUtf8().constData());
}
SceneSwitcher::SceneSwitcher(QWidget *parent)
: QDialog(parent),
ui(new Ui_SceneSwitcher)
{
ui->setupUi(this);
lock_guard<mutex> lock(switcher->m);
switcher->Prune();
BPtr<char*> scenes = obs_frontend_get_scene_names();
char **temp = scenes;
while (*temp) {
const char *name = *temp;
ui->scenes->addItem(name);
ui->noMatchSwitchScene->addItem(name);
temp++;
}
if (switcher->switchIfNotMatching)
ui->noMatchSwitch->setChecked(true);
else
ui->noMatchDontSwitch->setChecked(true);
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->checkInterval->setValue(switcher->interval);
vector<string> windows;
GetWindowList(windows);
for (string &window : windows)
ui->windows->addItem(window.c_str());
for (auto &s : switcher->switches) {
string sceneName = GetWeakSourceName(s.scene);
QString text = MakeSwitchName(sceneName.c_str(),
s.window.c_str());
QListWidgetItem *item = new QListWidgetItem(text,
ui->switches);
item->setData(Qt::UserRole, s.window.c_str());
}
if (switcher->th.joinable())
SetStarted();
else
SetStopped();
loading = false;
}
void SceneSwitcher::closeEvent(QCloseEvent*)
{
obs_frontend_save();
}
int SceneSwitcher::FindByData(const QString &window)
{
int count = ui->switches->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->switches->item(i);
QString itemWindow =
item->data(Qt::UserRole).toString();
if (itemWindow == window) {
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_switches_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->switches->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto &s : switcher->switches) {
if (window.compare(s.window.c_str()) == 0) {
string name = GetWeakSourceName(s.scene);
ui->scenes->setCurrentText(name.c_str());
ui->windows->setCurrentText(window);
break;
}
}
}
void SceneSwitcher::on_close_clicked()
{
done(0);
}
void SceneSwitcher::on_add_clicked()
{
QString sceneName = ui->scenes->currentText();
QString windowName = ui->windows->currentText();
if (windowName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
QVariant v = QVariant::fromValue(windowName);
QString text = MakeSwitchName(sceneName, windowName);
int idx = FindByData(windowName);
if (idx == -1) {
QListWidgetItem *item = new QListWidgetItem(text,
ui->switches);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->switches.emplace_back(source,
windowName.toUtf8().constData());
} else {
QListWidgetItem *item = ui->switches->item(idx);
item->setText(text);
string window = windowName.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto &s : switcher->switches) {
if (s.window == window) {
s.scene = source;
break;
}
}
}
ui->switches->sortItems();
}
}
void SceneSwitcher::on_remove_clicked()
{
QListWidgetItem *item = ui->switches->currentItem();
if (!item)
return;
string window =
item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto &switches = switcher->switches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s.window == window) {
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->startAtLaunch = value;
}
void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
{
obs_source_t *scene = obs_get_source_by_name(
name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_noMatchDontSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = false;
}
void SceneSwitcher::on_noMatchSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = true;
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
}
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
const QString &text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateNonMatchingScene(text);
}
void SceneSwitcher::on_checkInterval_valueChanged(int value)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->interval = value;
}
void SceneSwitcher::SetStarted()
{
ui->toggleStartButton->setText(obs_module_text("Stop"));
ui->pluginRunningText->setText(obs_module_text("Active"));
}
void SceneSwitcher::SetStopped()
{
ui->toggleStartButton->setText(obs_module_text("Start"));
ui->pluginRunningText->setText(obs_module_text("Inactive"));
}
void SceneSwitcher::on_toggleStartButton_clicked()
{
if (switcher->th.joinable()) {
switcher->Stop();
SetStopped();
} else {
switcher->Start();
SetStarted();
}
}
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{
if (saving) {
lock_guard<mutex> lock(switcher->m);
obs_data_t *obj = obs_data_create();
obs_data_array_t *array = obs_data_array_create();
switcher->Prune();
for (SceneSwitch &s : switcher->switches) {
obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(
s.scene);
if (source) {
const char *n = obs_source_get_name(source);
obs_data_set_string(array_obj, "scene", n);
obs_data_set_string(array_obj, "window_title",
s.window.c_str());
obs_data_array_push_back(array, array_obj);
obs_source_release(source);
}
obs_data_release(array_obj);
}
string nonMatchingSceneName =
GetWeakSourceName(switcher->nonMatchingScene);
obs_data_set_int(obj, "interval", switcher->interval);
obs_data_set_string(obj, "non_matching_scene",
nonMatchingSceneName.c_str());
obs_data_set_bool(obj, "switch_if_not_matching",
switcher->switchIfNotMatching);
obs_data_set_bool(obj, "active", switcher->th.joinable());
obs_data_set_array(obj, "switches", array);
obs_data_set_obj(save_data, "auto-scene-switcher", obj);
obs_data_array_release(array);
obs_data_release(obj);
} else {
switcher->m.lock();
obs_data_t *obj = obs_data_get_obj(save_data,
"auto-scene-switcher");
obs_data_array_t *array = obs_data_get_array(obj, "switches");
size_t count = obs_data_array_count(array);
if (!obj)
obj = obs_data_create();
obs_data_set_default_int(obj, "interval", DEFAULT_INTERVAL);
switcher->interval = obs_data_get_int(obj, "interval");
switcher->switchIfNotMatching =
obs_data_get_bool(obj, "switch_if_not_matching");
string nonMatchingScene =
obs_data_get_string(obj, "non_matching_scene");
bool active = obs_data_get_bool(obj, "active");
switcher->nonMatchingScene =
GetWeakSourceByName(nonMatchingScene.c_str());
switcher->switches.clear();
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(array, i);
const char *scene =
obs_data_get_string(array_obj, "scene");
const char *window =
obs_data_get_string(array_obj, "window_title");
switcher->switches.emplace_back(
GetWeakSourceByName(scene),
window);
obs_data_release(array_obj);
}
obs_data_array_release(array);
obs_data_release(obj);
switcher->m.unlock();
if (active)
switcher->Start();
else
switcher->Stop();
}
}
void SwitcherData::Thread()
{
chrono::duration<long long, milli> duration =
chrono::milliseconds(interval);
string lastTitle;
string title;
for (;;) {
unique_lock<mutex> lock(m);
OBSWeakSource scene;
bool match = false;
cv.wait_for(lock, duration);
if (switcher->stop) {
switcher->stop = false;
break;
}
duration = chrono::milliseconds(interval);
GetCurrentWindowTitle(title);
if (lastTitle != title) {
switcher->Prune();
for (SceneSwitch &s : switches) {
if (s.window == title) {
match = true;
scene = s.scene;
break;
}
}
/* try regex */
if (!match) {
for (SceneSwitch &s : switches) {
try {
bool matches = regex_match(
title, s.re);
if (matches) {
match = true;
scene = s.scene;
break;
}
} catch (const regex_error &) {}
}
}
if (!match && switchIfNotMatching &&
nonMatchingScene) {
match = true;
scene = nonMatchingScene;
}
if (match) {
obs_source_t *source =
obs_weak_source_get_source(scene);
obs_source_t *currentSource =
obs_frontend_get_current_scene();
if (source && source != currentSource)
obs_frontend_set_current_scene(source);
obs_source_release(currentSource);
obs_source_release(source);
}
}
lastTitle = title;
}
}
void SwitcherData::Start()
{
if (!switcher->th.joinable())
switcher->th = thread([] () {switcher->Thread();});
}
void SwitcherData::Stop()
{
if (th.joinable()) {
{
lock_guard<mutex> lock(m);
stop = true;
}
cv.notify_one();
th.join();
}
}
extern "C" void FreeSceneSwitcher()
{
delete switcher;
switcher = nullptr;
}
static void OBSEvent(enum obs_frontend_event event, void *)
{
if (event == OBS_FRONTEND_EVENT_EXIT)
FreeSceneSwitcher();
}
extern "C" void InitSceneSwitcher()
{
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
obs_module_text("SceneSwitcher"));
switcher = new SwitcherData;
auto cb = [] ()
{
obs_frontend_push_ui_translation(obs_module_get_string);
QMainWindow *window =
(QMainWindow*)obs_frontend_get_main_window();
SceneSwitcher ss(window);
ss.exec();
obs_frontend_pop_ui_translation();
};
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
obs_frontend_add_event_callback(OBSEvent, nullptr);
action->connect(action, &QAction::triggered, cb);
}

View file

@ -0,0 +1,47 @@
#pragma once
#include <QDialog>
#include <memory>
#include <vector>
#include <string>
#include "ui_auto-scene-switcher.h"
struct obs_weak_source;
typedef struct obs_weak_source obs_weak_source_t;
class QCloseEvent;
class SceneSwitcher : public QDialog {
Q_OBJECT
public:
std::unique_ptr<Ui_SceneSwitcher> ui;
bool loading = true;
SceneSwitcher(QWidget *parent);
void closeEvent(QCloseEvent *event) override;
void SetStarted();
void SetStopped();
int FindByData(const QString &window);
void UpdateNonMatchingScene(const QString &name);
public slots:
void on_switches_currentRowChanged(int idx);
void on_close_clicked();
void on_add_clicked();
void on_remove_clicked();
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
void on_startAtLaunch_toggled(bool value);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_toggleStartButton_clicked();
};
void GetWindowList(std::vector<std::string> &windows);
void GetCurrentWindowTitle(std::string &title);

View file

@ -0,0 +1,11 @@
SceneSwitcher="Canviador d'escena automàtica"
SceneSwitcher.OnNoMatch="Quan no coincideixi amb cap finestra:"
SceneSwitcher.OnNoMatch.DontSwitch="No canviar"
SceneSwitcher.OnNoMatch.SwitchTo="Canvia a:"
SceneSwitcher.CheckInterval="Comprova el títol de la finestra activa cada:"
SceneSwitcher.ActiveOrNotActive="El canviador de escena està:"
Active="Actiu"
Inactive="Inactiu"
Start="Inicia"
Stop="Atura"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatický přepínač scén"
SceneSwitcher.OnNoMatch="Výchozí chování u nesouhlasící:"
SceneSwitcher.OnNoMatch.DontSwitch="Nepřepínat"
SceneSwitcher.OnNoMatch.SwitchTo="Přepnout na:"
SceneSwitcher.CheckInterval="Kontrolovat titulek aktivního okna každých:"
SceneSwitcher.ActiveOrNotActive="Přepínač scén je:"
Active="Aktivní"
Inactive="Neaktivní"
Start="Spustit"
Stop="Zastavit"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatisk sceneskifter"
SceneSwitcher.OnNoMatch="Når intet vindue svarer til:"
SceneSwitcher.OnNoMatch.DontSwitch="Skift ikke"
SceneSwitcher.OnNoMatch.SwitchTo="Skift til:"
SceneSwitcher.CheckInterval="Kontroller aktivt vinduestitel hvert:"
SceneSwitcher.ActiveOrNotActive="Sceneskifter er:"
Active="Aktiv"
Inactive="Inaktiv"
Start="Start"
Stop="Stop"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatischer Szenenwechsler"
SceneSwitcher.OnNoMatch="Wenn kein Fenster passt:"
SceneSwitcher.OnNoMatch.DontSwitch="Nicht wechseln"
SceneSwitcher.OnNoMatch.SwitchTo="Wechseln zu:"
SceneSwitcher.CheckInterval="Titel des aktiven Fensters überprüfen alle:"
SceneSwitcher.ActiveOrNotActive="Szenenwechsler ist:"
Active="Aktiv"
Inactive="Inaktiv"
Start="Start"
Stop="Stop"

View file

@ -0,0 +1,10 @@
SceneSwitcher="Automatic Scene Switcher"
SceneSwitcher.OnNoMatch="When no window matches:"
SceneSwitcher.OnNoMatch.DontSwitch="Don't switch"
SceneSwitcher.OnNoMatch.SwitchTo="Switch to:"
SceneSwitcher.CheckInterval="Check active window title every:"
SceneSwitcher.ActiveOrNotActive="Scene Switcher is:"
Active="Active"
Inactive="Inactive"
Start="Start"
Stop="Stop"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Cambiador de escena automática"
SceneSwitcher.OnNoMatch="Cuando no coincida con ninguna ventana:"
SceneSwitcher.OnNoMatch.DontSwitch="No cambiar"
SceneSwitcher.OnNoMatch.SwitchTo="Cambiar a:"
SceneSwitcher.CheckInterval="Comprobar el título de la ventana activa cada:"
SceneSwitcher.ActiveOrNotActive="El cambiador de escena está:"
Active="Activo"
Inactive="Inactivo"
Start="Iniciar"
Stop="Detener"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Eszena-aldatzaile automatikoa"
SceneSwitcher.OnNoMatch="Leihoa bat etortzen ez denean:"
SceneSwitcher.OnNoMatch.DontSwitch="Ez aldatu"
SceneSwitcher.OnNoMatch.SwitchTo="Aldatu hona:"
SceneSwitcher.CheckInterval="Leiho aktiboaren titulua egiaztatzeko maiztasuna:"
SceneSwitcher.ActiveOrNotActive="Eszena aldatzailea dago:"
Active="Aktiboa"
Inactive="Inaktiboa"
Start="Hasi"
Stop="Gelditu"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automaattinen skenen vaihtaja"
SceneSwitcher.OnNoMatch="Kun ikkunaa ei löydy:"
SceneSwitcher.OnNoMatch.DontSwitch="Älä vaihda"
SceneSwitcher.OnNoMatch.SwitchTo="Vaihda:"
SceneSwitcher.CheckInterval="Tarkista aktiivisen ikkunan otsikko:"
SceneSwitcher.ActiveOrNotActive="Skenen vaihtaja:"
Active="Aktiivinen"
Inactive="Ei käytössä"
Start="Käynnistä"
Stop="Pysäytä"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Sélecteur automatique de scène"
SceneSwitcher.OnNoMatch="Si aucune fenêtre ne correspond :"
SceneSwitcher.OnNoMatch.DontSwitch="Ne rien faire"
SceneSwitcher.OnNoMatch.SwitchTo="Basculer vers :"
SceneSwitcher.CheckInterval="Détecter le titre de la fenêtre active toutes les :"
SceneSwitcher.ActiveOrNotActive="Etat du sélecteur automatique :"
Active="Actif"
Inactive="Inactif"
Start="Démarrer"
Stop="Arrêter"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatski menjač scena"
SceneSwitcher.OnNoMatch="Kada se nijedan naslov prozora ne poklapa:"
SceneSwitcher.OnNoMatch.DontSwitch="Ne menjaj"
SceneSwitcher.OnNoMatch.SwitchTo="Promeni na:"
SceneSwitcher.CheckInterval="Proveravaj naziv aktivnog prozora svakih:"
SceneSwitcher.ActiveOrNotActive="Menjač scena je:"
Active="Aktivan"
Inactive="Neaktivan"
Start="Pokreni"
Stop="Zaustavi"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatikus jelenetváltó"
SceneSwitcher.OnNoMatch="Ha nem található megfelelő ablak:"
SceneSwitcher.OnNoMatch.DontSwitch="Ne váltson"
SceneSwitcher.OnNoMatch.SwitchTo="Váltson:"
SceneSwitcher.CheckInterval="Aktív ablak ellenőrzése ennyi időközönként:"
SceneSwitcher.ActiveOrNotActive="Jelenet váltó:"
Active="Aktív"
Inactive="Inaktiv"
Start="Start"
Stop="Stop"

View file

@ -0,0 +1,11 @@
SceneSwitcher="自動シーンスイッチャー"
SceneSwitcher.OnNoMatch="どのウィンドウにも一致しない場合:"
SceneSwitcher.OnNoMatch.DontSwitch="切り替えない"
SceneSwitcher.OnNoMatch.SwitchTo="切り替える:"
SceneSwitcher.CheckInterval="アクティブウィンドウタイトルを確認する間隔:"
SceneSwitcher.ActiveOrNotActive="シーンスイッチャーは:"
Active="アクティブ"
Inactive="非アクティブ"
Start="開始"
Stop="停止"

View file

@ -0,0 +1,11 @@
SceneSwitcher="자동 장면 전환기"
SceneSwitcher.OnNoMatch="일치하는 윈도우가 없는 경우:"
SceneSwitcher.OnNoMatch.DontSwitch="전환하지 않음"
SceneSwitcher.OnNoMatch.SwitchTo="여기로 전환:"
SceneSwitcher.CheckInterval="활성화된 윈도우 제목을 확인:"
SceneSwitcher.ActiveOrNotActive="장면 전환기:"
Active="활성화"
Inactive="비활성화"
Start="시작"
Stop="중단"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatische Scènewisselaar"
SceneSwitcher.OnNoMatch="Als geen venster overeenkomt:"
SceneSwitcher.OnNoMatch.DontSwitch="Wissel niet"
SceneSwitcher.OnNoMatch.SwitchTo="Wissel naar:"
SceneSwitcher.CheckInterval="Controleer actieve venstertitel elke:"
SceneSwitcher.ActiveOrNotActive="Scènewisselaar is:"
Active="Actief"
Inactive="Inactief"
Start="Start"
Stop="Stop"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatyczne Przełączanie Scen"
SceneSwitcher.OnNoMatch="Gdy nie pasuje żadne okno:"
SceneSwitcher.OnNoMatch.DontSwitch="Nie przełączaj"
SceneSwitcher.OnNoMatch.SwitchTo="Przełącz na:"
SceneSwitcher.CheckInterval="Sprawdź tytuł aktywnego okna co:"
SceneSwitcher.ActiveOrNotActive="Przełączanie scen jest:"
Active="Aktywne"
Inactive="Nieaktywne"
Start="Start"
Stop="Stop"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Alternador automático de cena"
SceneSwitcher.OnNoMatch="Quando nenhuma janela corresponde:"
SceneSwitcher.OnNoMatch.DontSwitch="Não alternar"
SceneSwitcher.OnNoMatch.SwitchTo="Alternar para:"
SceneSwitcher.CheckInterval="Checar o título da janela ativa a cada:"
SceneSwitcher.ActiveOrNotActive="O alternador de cenas está:"
Active="Ligado"
Inactive="Desligado"
Start="Iniciar"
Stop="Parar"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Автоматический переключатель сцен"
SceneSwitcher.OnNoMatch="Когда ни одно окно не подходит:"
SceneSwitcher.OnNoMatch.DontSwitch="Не переключать"
SceneSwitcher.OnNoMatch.SwitchTo="Переключать на:"
SceneSwitcher.CheckInterval="Проверять имя активного окна каждые:"
SceneSwitcher.ActiveOrNotActive="Переключатель сцен:"
Active="Активен"
Inactive="Неактивен"
Start="Запустить"
Stop="Остановить"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatski menjač scena"
SceneSwitcher.OnNoMatch="Kada se nijedan naslov prozora ne poklapa:"
SceneSwitcher.OnNoMatch.DontSwitch="Ne menjaj"
SceneSwitcher.OnNoMatch.SwitchTo="Promeni na:"
SceneSwitcher.CheckInterval="Proveravaj naziv aktivnog prozora svakih:"
SceneSwitcher.ActiveOrNotActive="Menjač scena je:"
Active="Aktivan"
Inactive="Neaktivan"
Start="Pokreni"
Stop="Zaustavi"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Аутоматски мењач сцена"
SceneSwitcher.OnNoMatch="Када се ниједан наслов прозора не поклапа:"
SceneSwitcher.OnNoMatch.DontSwitch="Не мењај"
SceneSwitcher.OnNoMatch.SwitchTo="Промени на:"
SceneSwitcher.CheckInterval="Проверавај назив активног прозора сваких:"
SceneSwitcher.ActiveOrNotActive="Мењач сцена је:"
Active="Активан"
Inactive="Неактиван"
Start="Покрени"
Stop="Заустави"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Automatisk scenbytare"
SceneSwitcher.OnNoMatch="När inget fönster matchar:"
SceneSwitcher.OnNoMatch.DontSwitch="Byt inte"
SceneSwitcher.OnNoMatch.SwitchTo="Byt till:"
SceneSwitcher.CheckInterval="Kontrollera aktiv fönstertitel varje:"
SceneSwitcher.ActiveOrNotActive="Scenbytaren är:"
Active="Aktiv"
Inactive="Inaktiv"
Start="Starta"
Stop="Stoppa"

View file

@ -0,0 +1,11 @@
SceneSwitcher="Автоматичний перехід між Сценами"
SceneSwitcher.OnNoMatch="Якщо нема відповідних вікон:"
SceneSwitcher.OnNoMatch.DontSwitch="Нічого не робити"
SceneSwitcher.OnNoMatch.SwitchTo="Перейти до:"
SceneSwitcher.CheckInterval="Перевіряти заголовок активного вікна кожні:"
SceneSwitcher.ActiveOrNotActive="Автоматичний перехід між Сценами:"
Active="Активний"
Inactive="Неактивний"
Start="Запустити"
Stop="Зупинити"

View file

@ -0,0 +1,11 @@
SceneSwitcher="自动场景切换器"
SceneSwitcher.OnNoMatch="当没有窗口匹配的时候:"
SceneSwitcher.OnNoMatch.DontSwitch="不切换"
SceneSwitcher.OnNoMatch.SwitchTo="切换到:"
SceneSwitcher.CheckInterval="检查活动窗口的标题,每:"
SceneSwitcher.ActiveOrNotActive="场景切换器是:"
Active="已激活"
Inactive="未激活"
Start="开始"
Stop="停止"

View file

@ -0,0 +1,11 @@
SceneSwitcher="自動場景切換器"
SceneSwitcher.OnNoMatch="當沒有視窗相符時︰"
SceneSwitcher.OnNoMatch.DontSwitch="不切換"
SceneSwitcher.OnNoMatch.SwitchTo="切換到︰"
SceneSwitcher.CheckInterval="檢查使用中視窗標題的頻率︰"
SceneSwitcher.ActiveOrNotActive="場景切換器︰"
Active="啟動中"
Inactive="未啟動"
Start="開始"
Stop="停止"

View file

@ -0,0 +1,310 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SceneSwitcher</class>
<widget class="QDialog" name="SceneSwitcher">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>743</width>
<height>563</height>
</rect>
</property>
<property name="windowTitle">
<string>SceneSwitcher</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="windows">
<property name="editable">
<bool>true</bool>
</property>
<property name="maxVisibleItems">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="scenes">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="switches">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>4</number>
</property>
<item>
<widget class="QPushButton" name="add">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="themeID" stdset="0">
<string notr="true">addIconSmall</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="themeID" stdset="0">
<string notr="true">removeIconSmall</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>SceneSwitcher.OnNoMatch</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="noMatchDontSwitch">
<property name="text">
<string>SceneSwitcher.OnNoMatch.DontSwitch</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="noMatchSwitch">
<property name="text">
<string>SceneSwitcher.OnNoMatch.SwitchTo</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="noMatchSwitchScene">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>SceneSwitcher.CheckInterval</string>
</property>
<property name="buddy">
<cstring>checkInterval</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="checkInterval">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="suffix">
<string notr="true">ms</string>
</property>
<property name="minimum">
<number>50</number>
</property>
<property name="maximum">
<number>20000</number>
</property>
<property name="value">
<number>300</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>SceneSwitcher.ActiveOrNotActive</string>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>200</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="toggleStartButton">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QLabel" name="pluginRunningText">
<property name="text">
<string notr="true">Not Active</string>
</property>
</widget>
</item>
</layout>
</item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>noMatchSwitch</sender>
<signal>toggled(bool)</signal>
<receiver>noMatchSwitchScene</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>286</x>
<y>347</y>
</hint>
<hint type="destinationlabel">
<x>483</x>
<y>352</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,18 @@
#include <obs-module.h>
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
void InitSceneSwitcher();
void FreeSceneSwitcher();
bool obs_module_load(void)
{
InitSceneSwitcher();
return true;
}
void obs_module_unload(void)
{
FreeSceneSwitcher();
}