New upstream version 24.0.1+dfsg1

This commit is contained in:
Sebastian Ramacher 2019-09-22 23:19:10 +02:00
parent b14f9eae6d
commit 5a730d6ec3
842 changed files with 42245 additions and 33385 deletions

View file

@ -2,7 +2,7 @@ X11SharedMemoryScreenInput="Bildschirmaufnahme (XSHM)"
Screen="Bildschirm"
CaptureCursor="Mauszeiger aufnehmen"
AdvancedSettings="Erweiterte Einstellungen"
XServer="X-Server"
XServer="XServer"
XCCapture="Fensteraufnahme (Xcomposite)"
Window="Fenster"
CropTop="Oben abschneiden (Pixel)"
@ -10,7 +10,7 @@ CropLeft="Links abschneiden (Pixel)"
CropRight="Rechts abschneiden (Pixel)"
CropBottom="Unten abschneiden (Pixel)"
SwapRedBlue="Rot und Blau tauschen"
LockX="X-Server während der Aufnahme sperren"
IncludeXBorder="X-Rahmen anzeigen"
ExcludeAlpha="Alphaloses Texturformat verwenden (Mesa-Problemumgehung)"
LockX="XServer während der Aufnahme sperren"
IncludeXBorder="XRahmen anzeigen"
ExcludeAlpha="Alphaloses Texturformat verwenden (MesaProblemumgehung)"

View file

@ -1,15 +1,16 @@
X11SharedMemoryScreenInput="Captura de pantalla (XSHM)"
Screen="Pantalla"
CaptureCursor="Captura de cursor"
CaptureCursor="Capturar o cursor"
AdvancedSettings="Axustes avanzados"
XServer="X Server"
XServer="Servidor das X"
XCCapture="Captura de xanela (Xcomposite)"
Window="Xanela"
CropTop="Recortar por arriba (píxeles)"
CropLeft="Recortar pola esquerda (píxeles)"
CropRight="Recortar pola dereita (píxeles)"
CropBottom="Recortar por abaixo (píxeles)"
SwapRedBlue="Trocar vermello e azul"
LockX="Bloquear o servidor X durante a captura"
CropTop="Recortar por riba (píxeis)"
CropLeft="Recortar pola esquerda (píxeis)"
CropRight="Recortar pola dereita (píxeis)"
CropBottom="Recortar por baixo (píxeis)"
SwapRedBlue="Intercambiar vermello e azul"
LockX="Bloquear o servidor das X durante a captura"
IncludeXBorder="Incluír o bordo da xanela X"
ExcludeAlpha="Empregar o formato de textura sen alfa (solución Mesa)"

View file

@ -10,7 +10,7 @@ CropLeft="Trunchiază stânga (pixeli)"
CropRight="Trunchiază dreapta (pixeli)"
CropBottom="Trunchiază partea inferioară (pixeli)"
SwapRedBlue="Schimbă roșu cu albastru"
LockX="Blochează serverul X atunci când se capturează"
LockX="Blochează X server când se capturează"
IncludeXBorder="Include marginea cu X"
ExcludeAlpha="Folosește formatul de texturi fără alpha (soluție de evitare pentru Mesa)"

View file

@ -1,6 +1,6 @@
X11SharedMemoryScreenInput="Zajemanje zaslona (XSHM)"
Screen="Zaslon"
CaptureCursor="Zajemaj kazalec"
CaptureCursor="Zajemi kazalec"
AdvancedSettings="Napredne nastavitve"
XServer="X Server"
XCCapture="Zajemanje okna (Xcomposite)"

View file

@ -11,291 +11,259 @@
#include "xcompcap-helper.hpp"
namespace XCompcap
namespace XCompcap {
static Display *xdisplay = 0;
Display *disp()
{
static Display* xdisplay = 0;
if (!xdisplay)
xdisplay = XOpenDisplay(NULL);
Display *disp()
{
if (!xdisplay)
xdisplay = XOpenDisplay(NULL);
return xdisplay;
}
return xdisplay;
}
void cleanupDisplay()
{
if (!xdisplay)
return;
void cleanupDisplay()
{
if (!xdisplay)
return;
XCloseDisplay(xdisplay);
xdisplay = 0;
}
XCloseDisplay(xdisplay);
xdisplay = 0;
}
static void getAllWindows(Window parent, std::list<Window> &windows)
{
UNUSED_PARAMETER(parent);
UNUSED_PARAMETER(windows);
}
static void getAllWindows(Window parent, std::list<Window>& windows)
{
UNUSED_PARAMETER(parent);
UNUSED_PARAMETER(windows);
}
std::list<Window> getAllWindows()
{
std::list<Window> res;
std::list<Window> getAllWindows()
{
std::list<Window> res;
for (int i = 0; i < ScreenCount(disp()); ++i)
getAllWindows(RootWindow(disp(), i), res);
for (int i = 0; i < ScreenCount(disp()); ++i)
getAllWindows(RootWindow(disp(), i), res);
return res;
}
return res;
}
// Specification for checking for ewmh support at
// http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#idm140200472693600
// Specification for checking for ewmh support at
// http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#idm140200472693600
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;
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);
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 (status == Success) {
if (num > 0) {
ewmh_window = ((Window *)data)[0];
}
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);
}
if (data) {
XFree(data);
data = NULL;
}
return ewmh_window != 0;
}
std::list<Window> getTopLevelWindows()
{
std::list<Window> res;
if (!ewmhIsSupported()) {
blog(LOG_WARNING, "Unable to query window list "
"because window manager "
"does not support extended "
"window manager Hints");
return res;
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;
}
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) {
blog(LOG_WARNING, "Failed getting root "
"window properties");
continue;
}
for (unsigned long i = 0; i < num; ++i)
res.push_back(data[i]);
if (status == Success && data) {
XFree(data);
}
}
return ewmh_window != 0;
}
std::list<Window> getTopLevelWindows()
{
std::list<Window> res;
if (!ewmhIsSupported()) {
blog(LOG_WARNING, "Unable to query window list "
"because window manager "
"does not support extended "
"window manager Hints");
return res;
}
int getRootWindowScreen(Window root)
{
XWindowAttributes attr;
Atom netClList = XInternAtom(disp(), "_NET_CLIENT_LIST", true);
Atom actualType;
int format;
unsigned long num, bytes;
Window *data = 0;
if (!XGetWindowAttributes(disp(), root, &attr))
return DefaultScreen(disp());
for (int i = 0; i < ScreenCount(disp()); ++i) {
Window rootWin = RootWindow(disp(), i);
return XScreenNumberOfScreen(attr.screen);
}
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
~0L, false, AnyPropertyType,
&actualType, &format, &num,
&bytes, (uint8_t **)&data);
std::string getWindowAtom(Window win, const char *atom)
{
Atom netWmName = XInternAtom(disp(), atom, false);
int n;
char **list = 0;
XTextProperty tp;
std::string res = "unknown";
XGetTextProperty(disp(), win, &tp, netWmName);
if (!tp.nitems)
XGetWMName(disp(), win, &tp);
if (!tp.nitems)
return "error";
if (tp.encoding == XA_STRING) {
res = (char*)tp.value;
} else {
int ret = XmbTextPropertyToTextList(disp(), &tp, &list,
&n);
if (ret >= Success && n > 0 && *list) {
res = *list;
XFreeStringList(list);
}
if (status != Success) {
blog(LOG_WARNING, "Failed getting root "
"window properties");
continue;
}
char *conv = nullptr;
if (os_mbs_to_utf8_ptr(res.c_str(), 0, &conv))
res = conv;
bfree(conv);
for (unsigned long i = 0; i < num; ++i)
res.push_back(data[i]);
XFree(tp.value);
return res;
XFree(data);
}
std::string getWindowCommand(Window win)
{
Atom xi = XInternAtom(disp(), "WM_COMMAND", false);
int n;
char **list = 0;
XTextProperty tp;
std::string res = "error";
return res;
}
XGetTextProperty(disp(), win, &tp, xi);
int getRootWindowScreen(Window root)
{
XWindowAttributes attr;
if (!tp.nitems)
return std::string();
if (!XGetWindowAttributes(disp(), root, &attr))
return DefaultScreen(disp());
if (tp.encoding == XA_STRING) {
res = (char*)tp.value;
} else {
int ret = XmbTextPropertyToTextList(disp(), &tp, &list,
&n);
if (ret >= Success && n > 0 && *list) {
res = *list;
XFreeStringList(list);
}
return XScreenNumberOfScreen(attr.screen);
}
std::string getWindowAtom(Window win, const char *atom)
{
Atom netWmName = XInternAtom(disp(), atom, false);
int n;
char **list = 0;
XTextProperty tp;
std::string res = "unknown";
XGetTextProperty(disp(), win, &tp, netWmName);
if (!tp.nitems)
XGetWMName(disp(), win, &tp);
if (!tp.nitems)
return "error";
if (tp.encoding == XA_STRING) {
res = (char *)tp.value;
} else {
int ret = XmbTextPropertyToTextList(disp(), &tp, &list, &n);
if (ret >= Success && n > 0 && *list) {
res = *list;
XFreeStringList(list);
}
XFree(tp.value);
return res;
}
int getWindowPid(Window win)
{
UNUSED_PARAMETER(win);
return 1234; //TODO
}
char *conv = nullptr;
if (os_mbs_to_utf8_ptr(res.c_str(), 0, &conv))
res = conv;
bfree(conv);
static std::unordered_set<Window> changedWindows;
static pthread_mutex_t changeLock = PTHREAD_MUTEX_INITIALIZER;
void processEvents()
{
PLock lock(&changeLock);
XFree(tp.value);
XLockDisplay(disp());
return res;
}
while (XEventsQueued(disp(), QueuedAfterReading) > 0) {
XEvent ev;
std::string getWindowCommand(Window win)
{
Atom xi = XInternAtom(disp(), "WM_COMMAND", false);
int n;
char **list = 0;
XTextProperty tp;
std::string res = "error";
XNextEvent(disp(), &ev);
XGetTextProperty(disp(), win, &tp, xi);
if (ev.type == ConfigureNotify)
changedWindows.insert(ev.xconfigure.event);
if (!tp.nitems)
return std::string();
if (ev.type == MapNotify)
changedWindows.insert(ev.xmap.event);
if (ev.type == Expose)
changedWindows.insert(ev.xexpose.window);
if (ev.type == VisibilityNotify)
changedWindows.insert(ev.xvisibility.window);
if (ev.type == DestroyNotify)
changedWindows.insert(ev.xdestroywindow.event);
if (tp.encoding == XA_STRING) {
res = (char *)tp.value;
} else {
int ret = XmbTextPropertyToTextList(disp(), &tp, &list, &n);
if (ret >= Success && n > 0 && *list) {
res = *list;
XFreeStringList(list);
}
XUnlockDisplay(disp());
}
bool windowWasReconfigured(Window win)
{
PLock lock(&changeLock);
XFree(tp.value);
auto it = changedWindows.find(win);
return res;
}
if (it != changedWindows.end()) {
changedWindows.erase(it);
return true;
}
int getWindowPid(Window win)
{
UNUSED_PARAMETER(win);
return 1234; //TODO
}
return false;
static std::unordered_set<Window> changedWindows;
static pthread_mutex_t changeLock = PTHREAD_MUTEX_INITIALIZER;
void processEvents()
{
PLock lock(&changeLock);
XLockDisplay(disp());
while (XEventsQueued(disp(), QueuedAfterReading) > 0) {
XEvent ev;
XNextEvent(disp(), &ev);
if (ev.type == ConfigureNotify)
changedWindows.insert(ev.xconfigure.event);
if (ev.type == MapNotify)
changedWindows.insert(ev.xmap.event);
if (ev.type == Expose)
changedWindows.insert(ev.xexpose.window);
if (ev.type == VisibilityNotify)
changedWindows.insert(ev.xvisibility.window);
if (ev.type == DestroyNotify)
changedWindows.insert(ev.xdestroywindow.event);
}
XUnlockDisplay(disp());
}
bool windowWasReconfigured(Window win)
{
PLock lock(&changeLock);
auto it = changedWindows.find(win);
if (it != changedWindows.end()) {
changedWindows.erase(it);
return true;
}
return false;
}
}
PLock::PLock(pthread_mutex_t* mtx, bool trylock)
:m(mtx)
PLock::PLock(pthread_mutex_t *mtx, bool trylock) : m(mtx)
{
if (trylock)
islock = mtx && pthread_mutex_trylock(mtx) == 0;
@ -331,11 +299,9 @@ void PLock::lock()
}
}
static bool* curErrorTarget = 0;
static bool *curErrorTarget = 0;
static char curErrorText[200];
static int xerrorlock_handler(Display* disp, XErrorEvent* err)
static int xerrorlock_handler(Display *disp, XErrorEvent *err)
{
if (curErrorTarget)
@ -451,7 +417,6 @@ void XDisplayLock::unlock()
}
}
ObsGsContextHolder::ObsGsContextHolder()
{
obs_enter_graphics();

View file

@ -5,17 +5,15 @@
#define blog(level, msg, ...) blog(level, "xcompcap: " msg, ##__VA_ARGS__)
class PLock
{
class PLock {
pthread_mutex_t *m;
bool islock;
public:
PLock(const PLock&) = delete;
PLock& operator=(const PLock&) = delete;
public:
PLock(const PLock &) = delete;
PLock &operator=(const PLock &) = delete;
PLock(pthread_mutex_t* mtx, bool trylock = false);
PLock(pthread_mutex_t *mtx, bool trylock = false);
~PLock();
@ -25,15 +23,14 @@ class PLock
void lock();
};
class XErrorLock
{
class XErrorLock {
bool islock;
bool goterr;
XErrorHandler prevhandler;
public:
XErrorLock(const XErrorLock&) = delete;
XErrorLock& operator=(const XErrorLock&) = delete;
public:
XErrorLock(const XErrorLock &) = delete;
XErrorLock &operator=(const XErrorLock &) = delete;
XErrorLock();
~XErrorLock();
@ -48,13 +45,12 @@ class XErrorLock
void resetError();
};
class XDisplayLock
{
class XDisplayLock {
bool islock;
public:
XDisplayLock(const XDisplayLock&) = delete;
XDisplayLock& operator=(const XDisplayLock&) = delete;
public:
XDisplayLock(const XDisplayLock &) = delete;
XDisplayLock &operator=(const XDisplayLock &) = delete;
XDisplayLock();
~XDisplayLock();
@ -65,39 +61,37 @@ class XDisplayLock
void lock();
};
class ObsGsContextHolder
{
public:
ObsGsContextHolder(const ObsGsContextHolder&) = delete;
ObsGsContextHolder& operator=(const ObsGsContextHolder&) = delete;
class ObsGsContextHolder {
public:
ObsGsContextHolder(const ObsGsContextHolder &) = delete;
ObsGsContextHolder &operator=(const ObsGsContextHolder &) = delete;
ObsGsContextHolder();
~ObsGsContextHolder();
};
namespace XCompcap
namespace XCompcap {
Display *disp();
void cleanupDisplay();
std::string getWindowCommand(Window win);
int getRootWindowScreen(Window root);
std::string getWindowAtom(Window win, const char *atom);
int getWindowPid(Window win);
bool ewmhIsSupported();
std::list<Window> getTopLevelWindows();
std::list<Window> getAllWindows();
inline std::string getWindowName(Window win)
{
Display* disp();
void cleanupDisplay();
std::string getWindowCommand(Window win);
int getRootWindowScreen(Window root);
std::string getWindowAtom(Window win, const char *atom);
int getWindowPid(Window win);
bool ewmhIsSupported();
std::list<Window> getTopLevelWindows();
std::list<Window> getAllWindows();
inline std::string getWindowName(Window win)
{
return getWindowAtom(win, "_NET_WM_NAME");
}
inline std::string getWindowClass(Window win)
{
return getWindowAtom(win, "WM_CLASS");
}
void processEvents();
bool windowWasReconfigured(Window win);
return getWindowAtom(win, "_NET_WM_NAME");
}
inline std::string getWindowClass(Window win)
{
return getWindowAtom(win, "WM_CLASS");
}
void processEvents();
bool windowWasReconfigured(Window win);
}

View file

@ -35,7 +35,7 @@ bool XCompcapMain::init()
if (major == 0 && minor < 2) {
blog(LOG_ERROR, "Xcomposite extension is too old: %d.%d < 0.2",
major, minor);
major, minor);
return false;
}
@ -51,43 +51,41 @@ obs_properties_t *XCompcapMain::properties()
{
obs_properties_t *props = obs_properties_create();
obs_property_t *wins = obs_properties_add_list(props, "capture_window",
obs_module_text("Window"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
obs_property_t *wins = obs_properties_add_list(
props, "capture_window", obs_module_text("Window"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
for (Window win: XCompcap::getTopLevelWindows()) {
for (Window win : XCompcap::getTopLevelWindows()) {
std::string wname = XCompcap::getWindowName(win);
std::string cls = XCompcap::getWindowClass(win);
std::string winid = std::to_string((long long)win);
std::string desc =
(winid + WIN_STRING_DIV + wname +
WIN_STRING_DIV + cls);
(winid + WIN_STRING_DIV + wname + WIN_STRING_DIV + cls);
obs_property_list_add_string(wins, wname.c_str(),
desc.c_str());
obs_property_list_add_string(wins, wname.c_str(), desc.c_str());
}
obs_properties_add_int(props, "cut_top", obs_module_text("CropTop"),
0, 4096, 1);
obs_properties_add_int(props, "cut_top", obs_module_text("CropTop"), 0,
4096, 1);
obs_properties_add_int(props, "cut_left", obs_module_text("CropLeft"),
0, 4096, 1);
0, 4096, 1);
obs_properties_add_int(props, "cut_right", obs_module_text("CropRight"),
0, 4096, 1);
0, 4096, 1);
obs_properties_add_int(props, "cut_bot", obs_module_text("CropBottom"),
0, 4096, 1);
0, 4096, 1);
obs_properties_add_bool(props, "swap_redblue",
obs_module_text("SwapRedBlue"));
obs_module_text("SwapRedBlue"));
obs_properties_add_bool(props, "lock_x", obs_module_text("LockX"));
obs_properties_add_bool(props, "show_cursor",
obs_module_text("CaptureCursor"));
obs_module_text("CaptureCursor"));
obs_properties_add_bool(props, "include_border",
obs_module_text("IncludeXBorder"));
obs_module_text("IncludeXBorder"));
obs_properties_add_bool(props, "exclude_alpha",
obs_module_text("ExcludeAlpha"));
obs_module_text("ExcludeAlpha"));
return props;
}
@ -108,20 +106,24 @@ void XCompcapMain::defaults(obs_data_t *settings)
#define FIND_WINDOW_INTERVAL 2.0
struct XCompcapMain_private
{
struct XCompcapMain_private {
XCompcapMain_private()
:win(0)
,cut_top(0), cur_cut_top(0)
,cut_left(0), cur_cut_left(0)
,cut_right(0), cur_cut_right(0)
,cut_bot(0), cur_cut_bot(0)
,inverted(false)
,width(0),height(0)
,pixmap(0)
,glxpixmap(0)
,tex(0)
,gltex(0)
: win(0),
cut_top(0),
cur_cut_top(0),
cut_left(0),
cur_cut_left(0),
cut_right(0),
cur_cut_right(0),
cut_bot(0),
cur_cut_bot(0),
inverted(false),
width(0),
height(0),
pixmap(0),
glxpixmap(0),
tex(0),
gltex(0)
{
pthread_mutexattr_init(&lockattr);
pthread_mutexattr_settype(&lockattr, PTHREAD_MUTEX_RECURSIVE);
@ -169,7 +171,6 @@ struct XCompcapMain_private
xcursor_t *cursor = nullptr;
};
XCompcapMain::XCompcapMain(obs_data_t *settings, obs_source_t *source)
{
p = new XCompcapMain_private;
@ -231,7 +232,7 @@ static Window getWindowFromString(std::string wstr)
std::string wcls = wstr.substr(lastMark + markSize);
Window matchedNameWin = wid;
for (Window cwin: XCompcap::getTopLevelWindows()) {
for (Window cwin : XCompcap::getTopLevelWindows()) {
std::string cwinname = XCompcap::getWindowName(cwin);
std::string ccls = XCompcap::getWindowClass(cwin);
@ -249,38 +250,103 @@ static Window getWindowFromString(std::string wstr)
static void xcc_cleanup(XCompcapMain_private *p)
{
PLock lock(&p->lock);
XDisplayLock xlock;
XErrorLock xlock;
if (p->gltex) {
GLuint gltex = *(GLuint*)gs_texture_get_obj(p->gltex);
GLuint gltex = *(GLuint *)gs_texture_get_obj(p->gltex);
glBindTexture(GL_TEXTURE_2D, gltex);
glXReleaseTexImageEXT(xdisp, p->glxpixmap, GLX_FRONT_LEFT_EXT);
if (p->glxpixmap) {
glXReleaseTexImageEXT(xdisp, p->glxpixmap,
GLX_FRONT_LEFT_EXT);
if (xlock.gotError()) {
blog(LOG_ERROR,
"cleanup glXReleaseTexImageEXT failed: %s",
xlock.getErrorText().c_str());
xlock.resetError();
}
glXDestroyPixmap(xdisp, p->glxpixmap);
if (xlock.gotError()) {
blog(LOG_ERROR,
"cleanup glXDestroyPixmap failed: %s",
xlock.getErrorText().c_str());
xlock.resetError();
}
p->glxpixmap = 0;
}
gs_texture_destroy(p->gltex);
p->gltex = 0;
}
if (p->glxpixmap) {
glXDestroyPixmap(xdisp, p->glxpixmap);
p->glxpixmap = 0;
}
if (p->pixmap) {
XFreePixmap(xdisp, p->pixmap);
if (xlock.gotError()) {
blog(LOG_ERROR, "cleanup glXDestroyPixmap failed: %s",
xlock.getErrorText().c_str());
xlock.resetError();
}
p->pixmap = 0;
}
if (p->win) {
XCompositeUnredirectWindow(xdisp, p->win,
CompositeRedirectAutomatic);
CompositeRedirectAutomatic);
XSelectInput(xdisp, p->win, 0);
p->win = 0;
}
if (p->tex) {
gs_texture_destroy(p->tex);
p->tex = 0;
}
}
static gs_color_format gs_format_from_tex()
{
GLint iformat = 0;
// consider GL_ARB_internalformat_query
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT,
&iformat);
// These formats are known to be wrong on Intel platforms. We intentionally
// use swapped internal formats here to preserve historic behavior which
// swapped colors accidentally and because D3D11 would not support a
// GS_RGBX format
switch (iformat) {
case GL_RGB:
return GS_BGRX;
case GL_RGBA:
return GS_RGBA;
default:
return GS_RGBA;
}
}
// from libobs-opengl/gl-subsystem.h because we need to handle GLX modifying textures outside libobs.
struct fb_info;
struct gs_texture {
gs_device_t *device;
enum gs_texture_type type;
enum gs_color_format format;
GLenum gl_format;
GLenum gl_target;
GLenum gl_internal_format;
GLenum gl_type;
GLuint texture;
uint32_t levels;
bool is_dynamic;
bool is_render_target;
bool is_dummy;
bool gen_mipmaps;
gs_samplerstate_t *cur_sampler;
struct fbo_info *fbo;
};
// End shitty hack.
void XCompcapMain::updateSettings(obs_data_t *settings)
{
PLock lock(&p->lock);
XErrorLock xlock;
ObsGsContextHolder obsctx;
blog(LOG_DEBUG, "Settings updating");
@ -290,8 +356,8 @@ void XCompcapMain::updateSettings(obs_data_t *settings)
xcc_cleanup(p);
if (settings) {
const char *windowName = obs_data_get_string(settings,
"capture_window");
const char *windowName =
obs_data_get_string(settings, "capture_window");
p->windowName = windowName;
p->win = getWindowFromString(windowName);
@ -303,30 +369,28 @@ void XCompcapMain::updateSettings(obs_data_t *settings)
p->lockX = obs_data_get_bool(settings, "lock_x");
p->swapRedBlue = obs_data_get_bool(settings, "swap_redblue");
p->show_cursor = obs_data_get_bool(settings, "show_cursor");
p->include_border = obs_data_get_bool(settings, "include_border");
p->include_border =
obs_data_get_bool(settings, "include_border");
p->exclude_alpha = obs_data_get_bool(settings, "exclude_alpha");
p->draw_opaque = false;
} else {
p->win = prevWin;
}
xlock.resetError();
XErrorLock xlock;
if (p->win)
XCompositeRedirectWindow(xdisp, p->win,
CompositeRedirectAutomatic);
CompositeRedirectAutomatic);
if (xlock.gotError()) {
blog(LOG_ERROR, "XCompositeRedirectWindow failed: %s",
xlock.getErrorText().c_str());
xlock.getErrorText().c_str());
return;
}
if (p->win)
XSelectInput(xdisp, p->win,
StructureNotifyMask
| ExposureMask
| VisibilityChangeMask);
StructureNotifyMask | ExposureMask |
VisibilityChangeMask);
XSync(xdisp, 0);
XWindowAttributes attr;
@ -342,75 +406,26 @@ void XCompcapMain::updateSettings(obs_data_t *settings)
int x, y;
XTranslateCoordinates(xdisp, p->win, attr.root, 0, 0, &x, &y,
&child);
&child);
xcursor_offset(p->cursor, x, y);
}
gs_color_format cf = GS_RGBA;
if (p->exclude_alpha) {
cf = GS_BGRX;
}
bool has_alpha = true;
const int attrs[] =
{
GLX_BIND_TO_TEXTURE_RGBA_EXT, GL_TRUE,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
GLX_ALPHA_SIZE, 8,
GLX_DOUBLEBUFFER, GL_FALSE,
None
};
const int config_attrs[] = {GLX_BIND_TO_TEXTURE_RGBA_EXT,
GL_TRUE,
GLX_DRAWABLE_TYPE,
GLX_PIXMAP_BIT,
GLX_BIND_TO_TEXTURE_TARGETS_EXT,
GLX_TEXTURE_2D_BIT_EXT,
GLX_DOUBLEBUFFER,
GL_FALSE,
None};
int nelem = 0;
GLXFBConfig *configs = glXGetFBConfigs(xdisp,
XCompcap::getRootWindowScreen(attr.root),
&nelem);
GLXFBConfig *configs = glXChooseFBConfig(
xdisp, XCompcap::getRootWindowScreen(attr.root), config_attrs,
&nelem);
if (nelem <= 0) {
blog(LOG_ERROR, "no fb configs available");
p->win = 0;
p->height = 0;
p->width = 0;
return;
}
GLXFBConfig config;
for (int i = 0; i < nelem; i++) {
config = configs[i];
XVisualInfo *visual = glXGetVisualFromFBConfig(xdisp, config);
if (!visual)
continue;
if (attr.visual->visualid != visual->visualid) {
XFree(visual);
continue;
}
XFree(visual);
int value;
glXGetFBConfigAttrib(xdisp, config, GLX_ALPHA_SIZE, &value);
if (value != 8)
has_alpha = false;
break;
}
XFree(configs);
configs = glXChooseFBConfig(xdisp,
XCompcap::getRootWindowScreen(attr.root),
attrs, &nelem);
if (nelem <= 0) {
blog(LOG_ERROR, "no matching fb config found");
p->win = 0;
p->height = 0;
p->width = 0;
return;
}
bool found = false;
GLXFBConfig config;
for (int i = 0; i < nelem; i++) {
config = configs[i];
XVisualInfo *visual = glXGetVisualFromFBConfig(xdisp, config);
@ -425,10 +440,16 @@ void XCompcapMain::updateSettings(obs_data_t *settings)
found = true;
break;
}
if (!found)
config = configs[0];
if (!found) {
blog(LOG_ERROR, "no matching fb config found");
p->win = 0;
p->height = 0;
p->width = 0;
XFree(configs);
return;
}
if (cf == GS_BGRX || !has_alpha) {
if (p->exclude_alpha || attr.depth != 32) {
p->draw_opaque = true;
}
@ -462,93 +483,83 @@ void XCompcapMain::updateSettings(obs_data_t *settings)
p->cur_cut_right = 0;
}
if (p->tex)
gs_texture_destroy(p->tex);
uint8_t *texData = new uint8_t[width() * height() * 4];
memset(texData, 0, width() * height() * 4);
const uint8_t* texDataArr[] = { texData, 0 };
p->tex = gs_texture_create(width(), height(), cf, 1,
texDataArr, 0);
delete[] texData;
if (p->swapRedBlue) {
GLuint tex = *(GLuint*)gs_texture_get_obj(p->tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glBindTexture(GL_TEXTURE_2D, 0);
}
// Precautionary since we dont error check every GLX call above.
xlock.resetError();
p->pixmap = XCompositeNameWindowPixmap(xdisp, p->win);
if (xlock.gotError()) {
blog(LOG_ERROR, "XCompositeNameWindowPixmap failed: %s",
xlock.getErrorText().c_str());
xlock.getErrorText().c_str());
p->pixmap = 0;
XFree(configs);
return;
}
const int attribs_alpha[] =
{
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
None
};
const int attribs_no_alpha[] =
{
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
None
};
const int *attribs = cf == GS_RGBA ? attribs_alpha : attribs_no_alpha;
p->glxpixmap = glXCreatePixmap(xdisp, config, p->pixmap, attribs);
// Should be consistent format with config we are using. Since we searched on RGBA lets use RGBA here.
const int pixmap_attrs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT,
GLX_TEXTURE_FORMAT_RGBA_EXT, None};
p->glxpixmap = glXCreatePixmap(xdisp, config, p->pixmap, pixmap_attrs);
if (xlock.gotError()) {
blog(LOG_ERROR, "glXCreatePixmap failed: %s",
xlock.getErrorText().c_str());
xlock.getErrorText().c_str());
XFreePixmap(xdisp, p->pixmap);
XFree(configs);
p->pixmap = 0;
p->glxpixmap = 0;
return;
}
XFree(configs);
p->gltex = gs_texture_create(p->width, p->height, cf, 1, 0,
GS_GL_DUMMYTEX);
GLuint gltex = *(GLuint*)gs_texture_get_obj(p->gltex);
// Build an OBS texture to bind the pixmap to.
p->gltex = gs_texture_create(p->width, p->height, GS_RGBA, 1, 0,
GS_GL_DUMMYTEX);
GLuint gltex = *(GLuint *)gs_texture_get_obj(p->gltex);
glBindTexture(GL_TEXTURE_2D, gltex);
glXBindTexImageEXT(xdisp, p->glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
if (xlock.gotError()) {
blog(LOG_ERROR, "glXBindTexImageEXT failed: %s",
xlock.getErrorText().c_str());
XFreePixmap(xdisp, p->pixmap);
XFree(configs);
p->pixmap = 0;
p->glxpixmap = 0;
return;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glxBindTexImageEXT might modify the textures format.
gs_color_format format = gs_format_from_tex();
glBindTexture(GL_TEXTURE_2D, 0);
// sync OBS texture format based on any glxBindTexImageEXT changes
p->gltex->format = format;
// Create a pure OBS texture to use for rendering. Using the same
// format so we can copy instead of drawing from the source gltex.
if (p->tex)
gs_texture_destroy(p->tex);
p->tex = gs_texture_create(width(), height(), format, 1, 0,
GS_GL_DUMMYTEX);
if (p->swapRedBlue) {
GLuint tex = *(GLuint *)gs_texture_get_obj(p->tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glBindTexture(GL_TEXTURE_2D, 0);
}
if (!p->windowName.empty()) {
blog(LOG_INFO, "[window-capture: '%s'] update settings:\n"
"\ttitle: %s\n"
"\tclass: %s\n"
"\tHas alpha: %s\n"
"\tFound proper GLXFBConfig: %s\n",
obs_source_get_name(p->source),
XCompcap::getWindowName(p->win).c_str(),
XCompcap::getWindowClass(p->win).c_str(),
has_alpha ? "yes" : "no",
found ? "yes" : "no");
blog(LOG_DEBUG, "\n"
"\tid: %s",
std::to_string((long long)p->win).c_str());
blog(LOG_INFO,
"[window-capture: '%s'] update settings:\n"
"\ttitle: %s\n"
"\tclass: %s\n"
"\tBit depth: %i\n"
"\tFound proper GLXFBConfig (in %i): %s\n",
obs_source_get_name(p->source),
XCompcap::getWindowName(p->win).c_str(),
XCompcap::getWindowClass(p->win).c_str(), attr.depth,
nelem, found ? "yes" : "no");
}
}
@ -596,33 +607,28 @@ void XCompcapMain::tick(float seconds)
obs_enter_graphics();
if (p->lockX) {
// XDisplayLock is still live so we should already be locked.
XLockDisplay(xdisp);
XSync(xdisp, 0);
}
if (p->include_border) {
gs_copy_texture_region(
p->tex, 0, 0,
p->gltex,
p->cur_cut_left,
p->cur_cut_top,
width(), height());
gs_copy_texture_region(p->tex, 0, 0, p->gltex, p->cur_cut_left,
p->cur_cut_top, width(), height());
} else {
gs_copy_texture_region(
p->tex, 0, 0,
p->gltex,
p->cur_cut_left + p->border,
p->cur_cut_top + p->border,
width(), height());
gs_copy_texture_region(p->tex, 0, 0, p->gltex,
p->cur_cut_left + p->border,
p->cur_cut_top + p->border, width(),
height());
}
if (p->cursor && p->show_cursor) {
xcursor_tick(p->cursor);
p->cursor_outside =
p->cursor->x < p->cur_cut_left ||
p->cursor->y < p->cur_cut_top ||
p->cursor->x > int(p->width - p->cur_cut_right) ||
p->cursor->x < p->cur_cut_left ||
p->cursor->y < p->cur_cut_top ||
p->cursor->x > int(p->width - p->cur_cut_right) ||
p->cursor->y > int(p->height - p->cur_cut_bot);
}

View file

@ -2,9 +2,8 @@
struct XCompcapMain_private;
class XCompcapMain
{
public:
class XCompcapMain {
public:
static bool init();
static void deinit();
@ -22,6 +21,6 @@ class XCompcapMain
uint32_t width();
uint32_t height();
private:
private:
XCompcapMain_private *p;
};

View file

@ -2,38 +2,38 @@
#include "xcompcap-main.hpp"
static void* xcompcap_create(obs_data_t *settings, obs_source_t *source)
static void *xcompcap_create(obs_data_t *settings, obs_source_t *source)
{
return new XCompcapMain(settings, source);
}
static void xcompcap_destroy(void *data)
{
XCompcapMain* cc = (XCompcapMain*)data;
XCompcapMain *cc = (XCompcapMain *)data;
delete cc;
}
static void xcompcap_video_tick(void* data, float seconds)
static void xcompcap_video_tick(void *data, float seconds)
{
XCompcapMain* cc = (XCompcapMain*)data;
XCompcapMain *cc = (XCompcapMain *)data;
cc->tick(seconds);
}
static void xcompcap_video_render(void* data, gs_effect_t *effect)
static void xcompcap_video_render(void *data, gs_effect_t *effect)
{
XCompcapMain* cc = (XCompcapMain*)data;
XCompcapMain *cc = (XCompcapMain *)data;
cc->render(effect);
}
static uint32_t xcompcap_getwidth(void* data)
static uint32_t xcompcap_getwidth(void *data)
{
XCompcapMain* cc = (XCompcapMain*)data;
XCompcapMain *cc = (XCompcapMain *)data;
return cc->width();
}
static uint32_t xcompcap_getheight(void* data)
static uint32_t xcompcap_getheight(void *data)
{
XCompcapMain* cc = (XCompcapMain*)data;
XCompcapMain *cc = (XCompcapMain *)data;
return cc->height();
}
@ -51,11 +51,11 @@ void xcompcap_defaults(obs_data_t *settings)
void xcompcap_update(void *data, obs_data_t *settings)
{
XCompcapMain* cc = (XCompcapMain*)data;
XCompcapMain *cc = (XCompcapMain *)data;
cc->updateSettings(settings);
}
static const char* xcompcap_getname(void*)
static const char *xcompcap_getname(void *)
{
return obs_module_text("XCCapture");
}
@ -69,20 +69,19 @@ extern "C" void xcomposite_load(void)
memset(&sinfo, 0, sizeof(obs_source_info));
sinfo.id = "xcomposite_input";
sinfo.output_flags = OBS_SOURCE_VIDEO |
OBS_SOURCE_CUSTOM_DRAW |
OBS_SOURCE_DO_NOT_DUPLICATE;
sinfo.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW |
OBS_SOURCE_DO_NOT_DUPLICATE;
sinfo.get_name = xcompcap_getname;
sinfo.create = xcompcap_create;
sinfo.destroy = xcompcap_destroy;
sinfo.get_name = xcompcap_getname;
sinfo.create = xcompcap_create;
sinfo.destroy = xcompcap_destroy;
sinfo.get_properties = xcompcap_props;
sinfo.get_defaults = xcompcap_defaults;
sinfo.update = xcompcap_update;
sinfo.video_tick = xcompcap_video_tick;
sinfo.video_render = xcompcap_video_render;
sinfo.get_width = xcompcap_getwidth;
sinfo.get_height = xcompcap_getheight;
sinfo.get_defaults = xcompcap_defaults;
sinfo.update = xcompcap_update;
sinfo.video_tick = xcompcap_video_tick;
sinfo.video_render = xcompcap_video_render;
sinfo.get_width = xcompcap_getwidth;
sinfo.get_height = xcompcap_getheight;
obs_register_source(&sinfo);
}

View file

@ -26,26 +26,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* size or by creating a new texture if the size is different
*/
static void xcb_xcursor_create(xcb_xcursor_t *data,
xcb_xfixes_get_cursor_image_reply_t *xc)
xcb_xfixes_get_cursor_image_reply_t *xc)
{
uint32_t *pixels = xcb_xfixes_get_cursor_image_cursor_image(xc);
if (!pixels)
return;
if (data->tex && data->last_height == xc->width &&
data->last_width == xc->height) {
gs_texture_set_image(data->tex, (const uint8_t *) pixels,
xc->width * sizeof(uint32_t), false);
data->last_width == xc->height) {
gs_texture_set_image(data->tex, (const uint8_t *)pixels,
xc->width * sizeof(uint32_t), false);
} else {
if (data->tex)
gs_texture_destroy(data->tex);
data->tex = gs_texture_create(xc->width, xc->height,
GS_BGRA, 1, (const uint8_t **) &pixels, GS_DYNAMIC);
data->tex = gs_texture_create(xc->width, xc->height, GS_BGRA, 1,
(const uint8_t **)&pixels,
GS_DYNAMIC);
}
data->last_serial = xc->cursor_serial;
data->last_width = xc->width;
data->last_width = xc->width;
data->last_height = xc->height;
}
@ -58,8 +59,8 @@ xcb_xcursor_t *xcb_xcursor_init(xcb_connection_t *xcb)
xcb_xfixes_query_version_cookie_t xfix_c;
xfix_c = xcb_xfixes_query_version_unchecked(xcb,
XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
xfix_c = xcb_xfixes_query_version_unchecked(
xcb, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
free(xcb_xfixes_query_version_reply(xcb, xfix_c, NULL));
return data;
@ -73,7 +74,7 @@ void xcb_xcursor_destroy(xcb_xcursor_t *data)
}
void xcb_xcursor_update(xcb_xcursor_t *data,
xcb_xfixes_get_cursor_image_reply_t *xc)
xcb_xfixes_get_cursor_image_reply_t *xc)
{
if (!data || !xc)
return;
@ -81,8 +82,8 @@ void xcb_xcursor_update(xcb_xcursor_t *data,
if (!data->tex || data->last_serial != xc->cursor_serial)
xcb_xcursor_create(data, xc);
data->x = xc->x - data->x_org;
data->y = xc->y - data->y_org;
data->x = xc->x - data->x_org;
data->y = xc->y - data->y_org;
data->x_render = data->x - xc->xhot;
data->y_render = data->y - xc->yhot;
}
@ -92,7 +93,7 @@ void xcb_xcursor_render(xcb_xcursor_t *data)
if (!data->tex)
return;
gs_effect_t *effect = gs_get_effect();
gs_effect_t *effect = gs_get_effect();
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
gs_effect_set_texture(image, data->tex);
@ -109,9 +110,8 @@ void xcb_xcursor_render(xcb_xcursor_t *data)
gs_blend_state_pop();
}
void xcb_xcursor_offset(xcb_xcursor_t* data, const int x_org, const int y_org)
void xcb_xcursor_offset(xcb_xcursor_t *data, const int x_org, const int y_org)
{
data->x_org = x_org;
data->y_org = y_org;
}

View file

@ -30,12 +30,12 @@ typedef struct {
unsigned int last_height;
gs_texture_t *tex;
int x;
int y;
int x_org;
int y_org;
float x_render;
float y_render;
int x;
int y;
int x_org;
int y_org;
float x_render;
float y_render;
} xcb_xcursor_t;
/**
@ -60,7 +60,7 @@ void xcb_xcursor_destroy(xcb_xcursor_t *data);
*
*/
void xcb_xcursor_update(xcb_xcursor_t *data,
xcb_xfixes_get_cursor_image_reply_t *xc);
xcb_xfixes_get_cursor_image_reply_t *xc);
/**
* Draw the cursor

View file

@ -28,12 +28,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* Theres a lot of talk about this in other implementation and they tend to
* be really complicated, but this naive approach seems to work fine ...
*/
static uint32_t *xcursor_pixels(XFixesCursorImage *xc) {
static uint32_t *xcursor_pixels(XFixesCursorImage *xc)
{
uint_fast32_t size = xc->width * xc->height;
uint32_t *pixels = bmalloc(size * sizeof(uint32_t));
for (uint_fast32_t i = 0; i < size; ++i)
pixels[i] = (uint32_t) xc->pixels[i];
pixels[i] = (uint32_t)xc->pixels[i];
return pixels;
}
@ -42,22 +43,23 @@ static uint32_t *xcursor_pixels(XFixesCursorImage *xc) {
* Create the cursor texture, either by updating if the new cursor has the same
* size or by creating a new texture if the size is different
*/
static void xcursor_create(xcursor_t *data, XFixesCursorImage *xc) {
static void xcursor_create(xcursor_t *data, XFixesCursorImage *xc)
{
uint32_t *pixels = xcursor_pixels(xc);
if (!pixels)
return;
if (data->tex
&& data->last_height == xc->width
&& data->last_width == xc->height) {
gs_texture_set_image(data->tex, (const uint8_t *) pixels,
xc->width * sizeof(uint32_t), False);
if (data->tex && data->last_height == xc->width &&
data->last_width == xc->height) {
gs_texture_set_image(data->tex, (const uint8_t *)pixels,
xc->width * sizeof(uint32_t), False);
} else {
if (data->tex)
gs_texture_destroy(data->tex);
data->tex = gs_texture_create(xc->width, xc->height,
GS_BGRA, 1, (const uint8_t **) &pixels, GS_DYNAMIC);
data->tex = gs_texture_create(xc->width, xc->height, GS_BGRA, 1,
(const uint8_t **)&pixels,
GS_DYNAMIC);
}
bfree(pixels);
@ -67,7 +69,8 @@ static void xcursor_create(xcursor_t *data, XFixesCursorImage *xc) {
data->last_height = xc->height;
}
xcursor_t *xcursor_init(Display *dpy) {
xcursor_t *xcursor_init(Display *dpy)
{
xcursor_t *data = bzalloc(sizeof(xcursor_t));
data->dpy = dpy;
@ -76,13 +79,15 @@ xcursor_t *xcursor_init(Display *dpy) {
return data;
}
void xcursor_destroy(xcursor_t *data) {
void xcursor_destroy(xcursor_t *data)
{
if (data->tex)
gs_texture_destroy(data->tex);
bfree(data);
}
void xcursor_tick(xcursor_t *data) {
void xcursor_tick(xcursor_t *data)
{
XFixesCursorImage *xc = XFixesGetCursorImage(data->dpy);
if (!xc)
return;
@ -98,11 +103,12 @@ void xcursor_tick(xcursor_t *data) {
XFree(xc);
}
void xcursor_render(xcursor_t *data) {
void xcursor_render(xcursor_t *data)
{
if (!data->tex)
return;
gs_effect_t *effect = gs_get_effect();
gs_effect_t *effect = gs_get_effect();
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
gs_effect_set_texture(image, data->tex);
@ -119,9 +125,8 @@ void xcursor_render(xcursor_t *data) {
gs_blend_state_pop();
}
void xcursor_offset(xcursor_t* data, int_fast32_t x_org, int_fast32_t y_org)
void xcursor_offset(xcursor_t *data, int_fast32_t x_org, int_fast32_t y_org)
{
data->x_org = x_org;
data->y_org = y_org;
}

View file

@ -30,7 +30,7 @@ bool xinerama_is_active(xcb_connection_t *xcb)
bool active = true;
xcb_xinerama_is_active_cookie_t xnr_c;
xcb_xinerama_is_active_reply_t *xnr_r;
xcb_xinerama_is_active_reply_t *xnr_r;
xnr_c = xcb_xinerama_is_active_unchecked(xcb);
xnr_r = xcb_xinerama_is_active_reply(xcb, xnr_c, NULL);
@ -48,7 +48,7 @@ int xinerama_screen_count(xcb_connection_t *xcb)
int screens = 0;
xcb_xinerama_query_screens_cookie_t scr_c;
xcb_xinerama_query_screens_reply_t *scr_r;
xcb_xinerama_query_screens_reply_t *scr_r;
scr_c = xcb_xinerama_query_screens_unchecked(xcb);
scr_r = xcb_xinerama_query_screens_reply(xcb, scr_c, NULL);
@ -60,15 +60,15 @@ int xinerama_screen_count(xcb_connection_t *xcb)
}
int xinerama_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
int_fast32_t *x, int_fast32_t *y,
int_fast32_t *w, int_fast32_t *h)
int_fast32_t *x, int_fast32_t *y, int_fast32_t *w,
int_fast32_t *h)
{
if (!xcb)
goto fail;
bool success = false;
xcb_xinerama_query_screens_cookie_t scr_c;
xcb_xinerama_query_screens_reply_t *scr_r;
xcb_xinerama_query_screens_reply_t *scr_r;
xcb_xinerama_screen_info_iterator_t iter;
scr_c = xcb_xinerama_query_screens_unchecked(xcb);
@ -113,7 +113,7 @@ int randr_screen_count(xcb_connection_t *xcb)
screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
xcb_randr_get_screen_resources_cookie_t res_c;
xcb_randr_get_screen_resources_reply_t* res_r;
xcb_randr_get_screen_resources_reply_t *res_r;
res_c = xcb_randr_get_screen_resources(xcb, screen->root);
res_r = xcb_randr_get_screen_resources_reply(xcb, res_c, 0);
@ -124,15 +124,14 @@ int randr_screen_count(xcb_connection_t *xcb)
}
int randr_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
int_fast32_t *x, int_fast32_t *y,
int_fast32_t *w, int_fast32_t *h,
xcb_screen_t **rscreen)
int_fast32_t *x, int_fast32_t *y, int_fast32_t *w,
int_fast32_t *h, xcb_screen_t **rscreen)
{
xcb_screen_t *xscreen;
xscreen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
xcb_randr_get_screen_resources_cookie_t res_c;
xcb_randr_get_screen_resources_reply_t* res_r;
xcb_randr_get_screen_resources_reply_t *res_r;
res_c = xcb_randr_get_screen_resources(xcb, xscreen->root);
res_r = xcb_randr_get_screen_resources_reply(xcb, res_c, 0);
@ -168,8 +167,8 @@ fail:
return -1;
}
int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
int_fast32_t *w, int_fast32_t *h)
int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen, int_fast32_t *w,
int_fast32_t *h)
{
if (!xcb)
goto fail;
@ -194,14 +193,14 @@ fail:
return -1;
}
xcb_shm_t* xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h)
xcb_shm_t *xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h)
{
if (!xcb)
return NULL;
xcb_shm_t *shm = bzalloc(sizeof(xcb_shm_t));
shm->xcb = xcb;
shm->seg = xcb_generate_id(shm->xcb);
shm->xcb = xcb;
shm->seg = xcb_generate_id(shm->xcb);
shm->shmid = shmget(IPC_PRIVATE, w * h * 4, IPC_CREAT | 0777);
if (shm->shmid == -1)
@ -224,7 +223,7 @@ void xshm_xcb_detach(xcb_shm_t *shm)
xcb_shm_detach(shm->xcb, shm->seg);
if ((char *) shm->data != (char *) -1)
if ((char *)shm->data != (char *)-1)
shmdt(shm->data);
if (shm->shmid != -1)

View file

@ -27,9 +27,9 @@ extern "C" {
typedef struct {
xcb_connection_t *xcb;
xcb_shm_seg_t seg;
int shmid;
uint8_t *data;
xcb_shm_seg_t seg;
int shmid;
uint8_t *data;
} xcb_shm_t;
/**
@ -61,8 +61,8 @@ int xinerama_screen_count(xcb_connection_t *xcb);
* @return < 0 on error
*/
int xinerama_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
int_fast32_t *x, int_fast32_t *y,
int_fast32_t *w, int_fast32_t *h);
int_fast32_t *x, int_fast32_t *y, int_fast32_t *w,
int_fast32_t *h);
/**
* Check for Randr extension
@ -93,9 +93,8 @@ int randr_screen_count(xcb_connection_t *xcb);
* @return < 0 on error
*/
int randr_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
int_fast32_t *x, int_fast32_t *y,
int_fast32_t *w, int_fast32_t *h,
xcb_screen_t **rscreen);
int_fast32_t *x, int_fast32_t *y, int_fast32_t *w,
int_fast32_t *h, xcb_screen_t **rscreen);
/**
* Get screen geometry for a X11 screen
@ -109,8 +108,8 @@ int randr_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
*
* @return < 0 on error
*/
int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
int_fast32_t *w, int_fast32_t *h);
int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen, int_fast32_t *w,
int_fast32_t *h);
/**
* Attach a shared memory segment to the X-Server

View file

@ -33,26 +33,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define blog(level, msg, ...) blog(level, "xshm-input: " msg, ##__VA_ARGS__)
struct xshm_data {
obs_source_t *source;
obs_source_t *source;
xcb_connection_t *xcb;
xcb_screen_t *xcb_screen;
xcb_shm_t *xshm;
xcb_xcursor_t *cursor;
xcb_screen_t *xcb_screen;
xcb_shm_t *xshm;
xcb_xcursor_t *cursor;
char *server;
uint_fast32_t screen_id;
int_fast32_t x_org;
int_fast32_t y_org;
int_fast32_t width;
int_fast32_t height;
char *server;
uint_fast32_t screen_id;
int_fast32_t x_org;
int_fast32_t y_org;
int_fast32_t width;
int_fast32_t height;
gs_texture_t *texture;
gs_texture_t *texture;
bool show_cursor;
bool use_xinerama;
bool use_randr;
bool advanced;
bool show_cursor;
bool use_xinerama;
bool use_randr;
bool advanced;
};
/**
@ -66,8 +66,8 @@ static inline void xshm_resize_texture(struct xshm_data *data)
{
if (data->texture)
gs_texture_destroy(data->texture);
data->texture = gs_texture_create(data->width, data->height,
GS_BGRA, 1, NULL, GS_DYNAMIC);
data->texture = gs_texture_create(data->width, data->height, GS_BGRA, 1,
NULL, GS_DYNAMIC);
}
/**
@ -102,26 +102,23 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data)
int_fast32_t old_height = data->height;
if (data->use_randr) {
if (randr_screen_geo(data->xcb, data->screen_id,
&data->x_org, &data->y_org,
&data->width, &data->height,
&data->xcb_screen) < 0) {
if (randr_screen_geo(data->xcb, data->screen_id, &data->x_org,
&data->y_org, &data->width, &data->height,
&data->xcb_screen) < 0) {
return -1;
}
}
else if (data->use_xinerama) {
} else if (data->use_xinerama) {
if (xinerama_screen_geo(data->xcb, data->screen_id,
&data->x_org, &data->y_org,
&data->width, &data->height) < 0) {
&data->x_org, &data->y_org,
&data->width, &data->height) < 0) {
return -1;
}
data->xcb_screen = xcb_get_screen(data->xcb, 0);
}
else {
} else {
data->x_org = 0;
data->y_org = 0;
if (x11_screen_geo(data->xcb, data->screen_id,
&data->width, &data->height) < 0) {
if (x11_screen_geo(data->xcb, data->screen_id, &data->width,
&data->height) < 0) {
return -1;
}
data->xcb_screen = xcb_get_screen(data->xcb, data->screen_id);
@ -132,9 +129,10 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data)
return -1;
}
blog(LOG_INFO, "Geometry %"PRIdFAST32"x%"PRIdFAST32
" @ %"PRIdFAST32",%"PRIdFAST32,
data->width, data->height, data->x_org, data->y_org);
blog(LOG_INFO,
"Geometry %" PRIdFAST32 "x%" PRIdFAST32 " @ %" PRIdFAST32
",%" PRIdFAST32,
data->width, data->height, data->x_org, data->y_org);
if (old_width == data->width && old_height == data->height)
return 0;
@ -145,7 +143,7 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data)
/**
* Returns the name of the plugin
*/
static const char* xshm_getname(void *unused)
static const char *xshm_getname(void *unused)
{
UNUSED_PARAMETER(unused);
return obs_module_text("X11SharedMemoryScreenInput");
@ -190,8 +188,8 @@ static void xshm_capture_stop(struct xshm_data *data)
*/
static void xshm_capture_start(struct xshm_data *data)
{
const char *server = (data->advanced && *data->server)
? data->server : NULL;
const char *server = (data->advanced && *data->server) ? data->server
: NULL;
data->xcb = xcb_connect(server, NULL);
if (!data->xcb || xcb_connection_has_error(data->xcb)) {
@ -239,10 +237,10 @@ static void xshm_update(void *vptr, obs_data_t *settings)
xshm_capture_stop(data);
data->screen_id = obs_data_get_int(settings, "screen");
data->screen_id = obs_data_get_int(settings, "screen");
data->show_cursor = obs_data_get_bool(settings, "show_cursor");
data->advanced = obs_data_get_bool(settings, "advanced");
data->server = bstrdup(obs_data_get_string(settings, "server"));
data->advanced = obs_data_get_bool(settings, "advanced");
data->server = bstrdup(obs_data_get_string(settings, "server"));
xshm_capture_start(data);
}
@ -260,11 +258,11 @@ static void xshm_defaults(obs_data_t *defaults)
/**
* Toggle visibility of advanced settings
*/
static bool xshm_toggle_advanced(obs_properties_t *props,
obs_property_t *p, obs_data_t *settings)
static bool xshm_toggle_advanced(obs_properties_t *props, obs_property_t *p,
obs_data_t *settings)
{
UNUSED_PARAMETER(p);
const bool visible = obs_data_get_bool(settings, "advanced");
const bool visible = obs_data_get_bool(settings, "advanced");
obs_property_t *server = obs_properties_get(props, "server");
obs_property_set_visible(server, visible);
@ -278,14 +276,14 @@ static bool xshm_toggle_advanced(obs_properties_t *props,
/**
* The x server was changed
*/
static bool xshm_server_changed(obs_properties_t *props,
obs_property_t *p, obs_data_t *settings)
static bool xshm_server_changed(obs_properties_t *props, obs_property_t *p,
obs_data_t *settings)
{
UNUSED_PARAMETER(p);
bool advanced = obs_data_get_bool(settings, "advanced");
bool advanced = obs_data_get_bool(settings, "advanced");
int_fast32_t old_screen = obs_data_get_int(settings, "screen");
const char *server = obs_data_get_string(settings, "server");
const char *server = obs_data_get_string(settings, "server");
obs_property_t *screens = obs_properties_get(props, "screen");
/* we want a real NULL here in case there is no string here */
@ -303,11 +301,11 @@ static bool xshm_server_changed(obs_properties_t *props,
dstr_init(&screen_info);
bool randr = randr_is_active(xcb);
bool xinerama = xinerama_is_active(xcb);
int_fast32_t count = (randr) ?
randr_screen_count(xcb) :
(xinerama) ?
xinerama_screen_count(xcb) :
xcb_setup_roots_length(xcb_get_setup(xcb));
int_fast32_t count =
(randr) ? randr_screen_count(xcb)
: (xinerama)
? xinerama_screen_count(xcb)
: xcb_setup_roots_length(xcb_get_setup(xcb));
for (int_fast32_t i = 0; i < count; ++i) {
int_fast32_t x, y, w, h;
@ -320,21 +318,22 @@ static bool xshm_server_changed(obs_properties_t *props,
else
x11_screen_geo(xcb, i, &w, &h);
dstr_printf(&screen_info, "Screen %"PRIuFAST32" (%"PRIuFAST32
"x%"PRIuFAST32" @ %"PRIuFAST32
",%"PRIuFAST32")", i, w, h, x, y);
dstr_printf(&screen_info,
"Screen %" PRIuFAST32 " (%" PRIuFAST32
"x%" PRIuFAST32 " @ %" PRIuFAST32 ",%" PRIuFAST32
")",
i, w, h, x, y);
obs_property_list_add_int(screens, screen_info.array, i);
}
/* handle missing screen */
if (old_screen + 1 > count) {
dstr_printf(&screen_info, "Screen %"PRIuFAST32" (not found)",
old_screen);
size_t index = obs_property_list_add_int(screens,
screen_info.array, old_screen);
dstr_printf(&screen_info, "Screen %" PRIuFAST32 " (not found)",
old_screen);
size_t index = obs_property_list_add_int(
screens, screen_info.array, old_screen);
obs_property_list_item_disable(screens, index, true);
}
dstr_free(&screen_info);
@ -355,13 +354,13 @@ static obs_properties_t *xshm_properties(void *vptr)
obs_properties_t *props = obs_properties_create();
obs_properties_add_list(props, "screen", obs_module_text("Screen"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_properties_add_bool(props, "show_cursor",
obs_module_text("CaptureCursor"));
obs_property_t *advanced = obs_properties_add_bool(props, "advanced",
obs_module_text("AdvancedSettings"));
obs_property_t *server = obs_properties_add_text(props, "server",
obs_module_text("XServer"), OBS_TEXT_DEFAULT);
obs_module_text("CaptureCursor"));
obs_property_t *advanced = obs_properties_add_bool(
props, "advanced", obs_module_text("AdvancedSettings"));
obs_property_t *server = obs_properties_add_text(
props, "server", obs_module_text("XServer"), OBS_TEXT_DEFAULT);
obs_property_set_modified_callback(advanced, xshm_toggle_advanced);
obs_property_set_modified_callback(server, xshm_server_changed);
@ -415,14 +414,16 @@ static void xshm_video_tick(void *vptr, float seconds)
if (!obs_source_showing(data->source))
return;
xcb_shm_get_image_cookie_t img_c;
xcb_shm_get_image_reply_t *img_r;
xcb_shm_get_image_cookie_t img_c;
xcb_shm_get_image_reply_t *img_r;
xcb_xfixes_get_cursor_image_cookie_t cur_c;
xcb_xfixes_get_cursor_image_reply_t *cur_r;
xcb_xfixes_get_cursor_image_reply_t *cur_r;
img_c = xcb_shm_get_image_unchecked(data->xcb, data->xcb_screen->root,
data->x_org, data->y_org, data->width, data->height,
~0, XCB_IMAGE_FORMAT_Z_PIXMAP, data->xshm->seg, 0);
data->x_org, data->y_org,
data->width, data->height, ~0,
XCB_IMAGE_FORMAT_Z_PIXMAP,
data->xshm->seg, 0);
cur_c = xcb_xfixes_get_cursor_image_unchecked(data->xcb);
img_r = xcb_shm_get_image_reply(data->xcb, img_c, NULL);
@ -433,8 +434,8 @@ static void xshm_video_tick(void *vptr, float seconds)
obs_enter_graphics();
gs_texture_set_image(data->texture, (void *) data->xshm->data,
data->width * 4, false);
gs_texture_set_image(data->texture, (void *)data->xshm->data,
data->width * 4, false);
xcb_xcursor_update(data->cursor, cur_r);
obs_leave_graphics();
@ -491,19 +492,18 @@ static uint32_t xshm_getheight(void *vptr)
}
struct obs_source_info xshm_input = {
.id = "xshm_input",
.type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_VIDEO |
OBS_SOURCE_CUSTOM_DRAW |
OBS_SOURCE_DO_NOT_DUPLICATE,
.get_name = xshm_getname,
.create = xshm_create,
.destroy = xshm_destroy,
.update = xshm_update,
.get_defaults = xshm_defaults,
.id = "xshm_input",
.type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW |
OBS_SOURCE_DO_NOT_DUPLICATE,
.get_name = xshm_getname,
.create = xshm_create,
.destroy = xshm_destroy,
.update = xshm_update,
.get_defaults = xshm_defaults,
.get_properties = xshm_properties,
.video_tick = xshm_video_tick,
.video_render = xshm_video_render,
.get_width = xshm_getwidth,
.get_height = xshm_getheight
.video_tick = xshm_video_tick,
.video_render = xshm_video_render,
.get_width = xshm_getwidth,
.get_height = xshm_getheight,
};