Merge pull request #900 from cg2121/linux-scene-switcher

frontend-tools: Add automatic scene switcher for Linux
master
Jim 2017-05-04 05:08:17 -07:00 committed by GitHub
commit 965e2eea9a
3 changed files with 223 additions and 18 deletions

View File

@ -5,16 +5,10 @@ if(APPLE)
include_directories(${COCOA})
endif()
if(WIN32 OR APPLE)
set(frontend-tools_HEADERS
auto-scene-switcher.hpp
)
set(frontend-tools_SOURCES
auto-scene-switcher.cpp
)
set(frontend-tools_UI
forms/auto-scene-switcher.ui
)
if(UNIX)
find_package(X11 REQUIRED)
link_libraries(${X11_LIBRARIES})
include_directories(${X11_INCLUDE_DIR})
endif()
configure_file(
@ -24,16 +18,19 @@ configure_file(
set(frontend-tools_HEADERS
${frontend-tools_HEADERS}
"${CMAKE_BINARY_DIR}/config/frontend-tools-config.h"
auto-scene-switcher.hpp
output-timer.hpp
tool-helpers.hpp
)
set(frontend-tools_SOURCES
${frontend-tools_SOURCES}
auto-scene-switcher.cpp
frontend-tools.c
output-timer.cpp
)
set(frontend-tools_UI
${frontend-tools_UI}
forms/auto-scene-switcher.ui
forms/output-timer.ui
)
@ -64,6 +61,9 @@ elseif(APPLE)
set(frontend-tools_PLATFORM_LIBS
${COCOA})
else()
set(frontend-tools_PLATFORM_SOURCES
auto-scene-switcher-nix.cpp)
endif()
qt5_wrap_ui(frontend-tools_UI_HEADERS

View File

@ -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);
}

View File

@ -4,10 +4,8 @@
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
#if defined(_WIN32) || defined(__APPLE__)
void InitSceneSwitcher();
void FreeSceneSwitcher();
#endif
#if defined(_WIN32) && BUILD_CAPTIONS
void InitCaptions();
@ -19,23 +17,19 @@ void FreeOutputTimer();
bool obs_module_load(void)
{
#if defined(_WIN32) || defined(__APPLE__)
InitSceneSwitcher();
#endif
#if defined(_WIN32) && BUILD_CAPTIONS
InitCaptions();
#endif
InitSceneSwitcher();
InitOutputTimer();
return true;
}
void obs_module_unload(void)
{
#if defined(_WIN32) || defined(__APPLE__)
FreeSceneSwitcher();
#endif
#if defined(_WIN32) && BUILD_CAPTIONS
FreeCaptions();
#endif
FreeSceneSwitcher();
FreeOutputTimer();
}