Merge pull request #900 from cg2121/linux-scene-switcher
frontend-tools: Add automatic scene switcher for Linuxmaster
commit
965e2eea9a
|
@ -5,16 +5,10 @@ if(APPLE)
|
||||||
include_directories(${COCOA})
|
include_directories(${COCOA})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32 OR APPLE)
|
if(UNIX)
|
||||||
set(frontend-tools_HEADERS
|
find_package(X11 REQUIRED)
|
||||||
auto-scene-switcher.hpp
|
link_libraries(${X11_LIBRARIES})
|
||||||
)
|
include_directories(${X11_INCLUDE_DIR})
|
||||||
set(frontend-tools_SOURCES
|
|
||||||
auto-scene-switcher.cpp
|
|
||||||
)
|
|
||||||
set(frontend-tools_UI
|
|
||||||
forms/auto-scene-switcher.ui
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
|
@ -24,16 +18,19 @@ configure_file(
|
||||||
set(frontend-tools_HEADERS
|
set(frontend-tools_HEADERS
|
||||||
${frontend-tools_HEADERS}
|
${frontend-tools_HEADERS}
|
||||||
"${CMAKE_BINARY_DIR}/config/frontend-tools-config.h"
|
"${CMAKE_BINARY_DIR}/config/frontend-tools-config.h"
|
||||||
|
auto-scene-switcher.hpp
|
||||||
output-timer.hpp
|
output-timer.hpp
|
||||||
tool-helpers.hpp
|
tool-helpers.hpp
|
||||||
)
|
)
|
||||||
set(frontend-tools_SOURCES
|
set(frontend-tools_SOURCES
|
||||||
${frontend-tools_SOURCES}
|
${frontend-tools_SOURCES}
|
||||||
|
auto-scene-switcher.cpp
|
||||||
frontend-tools.c
|
frontend-tools.c
|
||||||
output-timer.cpp
|
output-timer.cpp
|
||||||
)
|
)
|
||||||
set(frontend-tools_UI
|
set(frontend-tools_UI
|
||||||
${frontend-tools_UI}
|
${frontend-tools_UI}
|
||||||
|
forms/auto-scene-switcher.ui
|
||||||
forms/output-timer.ui
|
forms/output-timer.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,6 +61,9 @@ elseif(APPLE)
|
||||||
|
|
||||||
set(frontend-tools_PLATFORM_LIBS
|
set(frontend-tools_PLATFORM_LIBS
|
||||||
${COCOA})
|
${COCOA})
|
||||||
|
else()
|
||||||
|
set(frontend-tools_PLATFORM_SOURCES
|
||||||
|
auto-scene-switcher-nix.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt5_wrap_ui(frontend-tools_UI_HEADERS
|
qt5_wrap_ui(frontend-tools_UI_HEADERS
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#undef Bool
|
||||||
|
#undef CursorShape
|
||||||
|
#undef Expose
|
||||||
|
#undef KeyPress
|
||||||
|
#undef KeyRelease
|
||||||
|
#undef FocusIn
|
||||||
|
#undef FocusOut
|
||||||
|
#undef FontChange
|
||||||
|
#undef None
|
||||||
|
#undef Status
|
||||||
|
#undef Unsorted
|
||||||
|
#include <util/platform.h>
|
||||||
|
#include "auto-scene-switcher.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static Display* xdisplay = 0;
|
||||||
|
|
||||||
|
Display *disp()
|
||||||
|
{
|
||||||
|
if (!xdisplay)
|
||||||
|
xdisplay = XOpenDisplay(NULL);
|
||||||
|
|
||||||
|
return xdisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupDisplay()
|
||||||
|
{
|
||||||
|
if (!xdisplay)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XCloseDisplay(xdisplay);
|
||||||
|
xdisplay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ewmhIsSupported()
|
||||||
|
{
|
||||||
|
Display *display = disp();
|
||||||
|
Atom netSupportingWmCheck = XInternAtom(display,
|
||||||
|
"_NET_SUPPORTING_WM_CHECK", true);
|
||||||
|
Atom actualType;
|
||||||
|
int format = 0;
|
||||||
|
unsigned long num = 0, bytes = 0;
|
||||||
|
unsigned char *data = NULL;
|
||||||
|
Window ewmh_window = 0;
|
||||||
|
|
||||||
|
int status = XGetWindowProperty(
|
||||||
|
display,
|
||||||
|
DefaultRootWindow(display),
|
||||||
|
netSupportingWmCheck,
|
||||||
|
0L,
|
||||||
|
1L,
|
||||||
|
false,
|
||||||
|
XA_WINDOW,
|
||||||
|
&actualType,
|
||||||
|
&format,
|
||||||
|
&num,
|
||||||
|
&bytes,
|
||||||
|
&data);
|
||||||
|
|
||||||
|
if (status == Success) {
|
||||||
|
if (num > 0) {
|
||||||
|
ewmh_window = ((Window*)data)[0];
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
XFree(data);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ewmh_window) {
|
||||||
|
status = XGetWindowProperty(
|
||||||
|
display,
|
||||||
|
ewmh_window,
|
||||||
|
netSupportingWmCheck,
|
||||||
|
0L,
|
||||||
|
1L,
|
||||||
|
false,
|
||||||
|
XA_WINDOW,
|
||||||
|
&actualType,
|
||||||
|
&format,
|
||||||
|
&num,
|
||||||
|
&bytes,
|
||||||
|
&data);
|
||||||
|
if (status != Success || num == 0 ||
|
||||||
|
ewmh_window != ((Window*)data)[0]) {
|
||||||
|
ewmh_window = 0;
|
||||||
|
}
|
||||||
|
if (status == Success && data) {
|
||||||
|
XFree(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ewmh_window != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<Window> getTopLevelWindows()
|
||||||
|
{
|
||||||
|
std::vector<Window> res;
|
||||||
|
|
||||||
|
res.resize(0);
|
||||||
|
|
||||||
|
if (!ewmhIsSupported()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom netClList = XInternAtom(disp(), "_NET_CLIENT_LIST", true);
|
||||||
|
Atom actualType;
|
||||||
|
int format;
|
||||||
|
unsigned long num, bytes;
|
||||||
|
Window* data = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
||||||
|
Window rootWin = RootWindow(disp(), i);
|
||||||
|
|
||||||
|
int status = XGetWindowProperty(
|
||||||
|
disp(),
|
||||||
|
rootWin,
|
||||||
|
netClList,
|
||||||
|
0L,
|
||||||
|
~0L,
|
||||||
|
false,
|
||||||
|
AnyPropertyType,
|
||||||
|
&actualType,
|
||||||
|
&format,
|
||||||
|
&num,
|
||||||
|
&bytes,
|
||||||
|
(uint8_t**)&data);
|
||||||
|
|
||||||
|
if (status != Success) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned long i = 0; i < num; ++i)
|
||||||
|
res.emplace_back(data[i]);
|
||||||
|
|
||||||
|
XFree(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetWindowTitle(size_t i)
|
||||||
|
{
|
||||||
|
Window w = getTopLevelWindows().at(i);
|
||||||
|
std::string windowTitle;
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
int status = XFetchName(disp(), w, &name);
|
||||||
|
if (status >= Success && name != nullptr)
|
||||||
|
{
|
||||||
|
std::string str(name);
|
||||||
|
windowTitle = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(name);
|
||||||
|
|
||||||
|
return windowTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetWindowList(vector<string> &windows)
|
||||||
|
{
|
||||||
|
windows.resize(0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||||
|
if (GetWindowTitle(i) != "")
|
||||||
|
windows.emplace_back(GetWindowTitle(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetCurrentWindowTitle(string &title)
|
||||||
|
{
|
||||||
|
if (!ewmhIsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
|
||||||
|
Atom actualType;
|
||||||
|
int format;
|
||||||
|
unsigned long num, bytes;
|
||||||
|
Window* data = 0;
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
Window rootWin = RootWindow(disp(), 0);
|
||||||
|
|
||||||
|
XGetWindowProperty(
|
||||||
|
disp(),
|
||||||
|
rootWin,
|
||||||
|
active,
|
||||||
|
0L,
|
||||||
|
~0L,
|
||||||
|
false,
|
||||||
|
AnyPropertyType,
|
||||||
|
&actualType,
|
||||||
|
&format,
|
||||||
|
&num,
|
||||||
|
&bytes,
|
||||||
|
(uint8_t**)&data);
|
||||||
|
|
||||||
|
int status = XFetchName(disp(), data[0], &name);
|
||||||
|
|
||||||
|
if (status >= Success && name != nullptr) {
|
||||||
|
std::string str(name);
|
||||||
|
title = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(name);
|
||||||
|
}
|
|
@ -4,10 +4,8 @@
|
||||||
OBS_DECLARE_MODULE()
|
OBS_DECLARE_MODULE()
|
||||||
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
|
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
|
||||||
void InitSceneSwitcher();
|
void InitSceneSwitcher();
|
||||||
void FreeSceneSwitcher();
|
void FreeSceneSwitcher();
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_WIN32) && BUILD_CAPTIONS
|
#if defined(_WIN32) && BUILD_CAPTIONS
|
||||||
void InitCaptions();
|
void InitCaptions();
|
||||||
|
@ -19,23 +17,19 @@ void FreeOutputTimer();
|
||||||
|
|
||||||
bool obs_module_load(void)
|
bool obs_module_load(void)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
|
||||||
InitSceneSwitcher();
|
|
||||||
#endif
|
|
||||||
#if defined(_WIN32) && BUILD_CAPTIONS
|
#if defined(_WIN32) && BUILD_CAPTIONS
|
||||||
InitCaptions();
|
InitCaptions();
|
||||||
#endif
|
#endif
|
||||||
|
InitSceneSwitcher();
|
||||||
InitOutputTimer();
|
InitOutputTimer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void obs_module_unload(void)
|
void obs_module_unload(void)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
|
||||||
FreeSceneSwitcher();
|
|
||||||
#endif
|
|
||||||
#if defined(_WIN32) && BUILD_CAPTIONS
|
#if defined(_WIN32) && BUILD_CAPTIONS
|
||||||
FreeCaptions();
|
FreeCaptions();
|
||||||
#endif
|
#endif
|
||||||
|
FreeSceneSwitcher();
|
||||||
FreeOutputTimer();
|
FreeOutputTimer();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue