123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- #include <X11/Xlib.h>
- #include <X11/Xatom.h>
- #include <X11/Xutil.h>
- #include <X11/extensions/Xcomposite.h>
- #include <unordered_set>
- #include <pthread.h>
- #include <obs-module.h>
- #include "xcompcap-helper.h"
- namespace XCompcap
- {
- static Display* xdisplay = 0;
- Display *disp()
- {
- if(!xdisplay)
- xdisplay = XOpenDisplay(NULL);
- return xdisplay;
- }
- void cleanupDisplay()
- {
- if(!xdisplay)
- return;
- XCloseDisplay(xdisplay);
- xdisplay = 0;
- }
- static void getAllWindows(Window parent, std::list<Window>& windows)
- {
- UNUSED_PARAMETER(parent);
- UNUSED_PARAMETER(windows);
- }
- std::list<Window> getAllWindows()
- {
- std::list<Window> res;
- for(int i = 0; i < ScreenCount(disp()); ++i)
- getAllWindows(RootWindow(disp(), i), res);
- return res;
- }
- std::list<Window> getTopLevelWindows()
- {
- std::list<Window> 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)
- {
- blog(LOG_WARNING, "Failed getting root window properties");
- continue;
- }
- for(unsigned long i = 0; i < num; ++i)
- {
- res.push_back(data[i]);
- }
- XFree(data);
- }
- return res;
- }
- int getRootWindowScreen(Window root)
- {
- XWindowAttributes attr;
- if(!XGetWindowAttributes(disp(), root, &attr))
- return DefaultScreen(disp());
- return XScreenNumberOfScreen(attr.screen);
- }
- std::string getWindowName(Window win)
- {
- Atom netWmName = XInternAtom(disp(), "_NET_WM_NAME", 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 if(XmbTextPropertyToTextList(disp(), &tp, &list, &n) >= Success && n > 0 && *list)
- {
- res = *list;
- XFreeStringList(list);
- }
- XFree(tp.value);
- return res;
- }
- std::string getWindowCommand(Window win)
- {
- Atom xi = XInternAtom(disp(), "WM_COMMAND", false);
- int n;
- char **list = 0;
- XTextProperty tp;
- std::string res = "error";
- XGetTextProperty(disp(), win, &tp, xi);
- if(!tp.nitems)
- return std::string();
- if(tp.encoding == XA_STRING)
- {
- res = (char*)tp.value;
- }
- else if(XmbTextPropertyToTextList(disp(), &tp, &list, &n) >= Success && n > 0 && *list)
- {
- res = *list;
- XFreeStringList(list);
- }
- XFree(tp.value);
- return res;
- }
- int getWindowPid(Window win)
- {
- UNUSED_PARAMETER(win);
- return 1234; //TODO
- }
- 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 == 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)
- {
- if(trylock)
- islock = mtx && pthread_mutex_trylock(mtx) == 0;
- else
- islock = mtx && pthread_mutex_lock(mtx) == 0;
- }
- PLock::~PLock()
- {
- if(islock)
- {
- pthread_mutex_unlock(m);
- }
- }
- bool PLock::isLocked()
- {
- return islock;
- }
- void PLock::unlock()
- {
- if(islock)
- {
- pthread_mutex_unlock(m);
- islock = false;
- }
- }
- void PLock::lock()
- {
- if(!islock)
- {
- pthread_mutex_lock(m);
- islock = true;
- }
- }
- static bool* curErrorTarget = 0;
- static char curErrorText[200];
- static int xerrorlock_handler(Display* disp, XErrorEvent* err)
- {
- if(curErrorTarget)
- *curErrorTarget = true;
- XGetErrorText(disp, err->error_code, curErrorText, 200);
- return 0;
- }
- XErrorLock::XErrorLock()
- {
- goterr = false;
- islock = false;
- prevhandler = 0;
- lock();
- }
- XErrorLock::~XErrorLock()
- {
- unlock();
- }
- bool XErrorLock::isLocked()
- {
- return islock;
- }
- void XErrorLock::lock()
- {
- if(!islock)
- {
- XLockDisplay(XCompcap::disp());
- XSync(XCompcap::disp(), 0);
- curErrorTarget = &goterr;
- curErrorText[0] = 0;
- prevhandler = XSetErrorHandler(xerrorlock_handler);
- islock = true;
- }
- }
- void XErrorLock::unlock()
- {
- if(islock)
- {
- curErrorTarget = 0;
- XSetErrorHandler(prevhandler);
- prevhandler = 0;
- XUnlockDisplay(XCompcap::disp());
- islock = false;
- }
- }
- bool XErrorLock::gotError()
- {
- if(!islock)
- return false;
- XSync(XCompcap::disp(), 0);
- bool res = goterr;
- goterr = false;
- return res;
- }
- std::string XErrorLock::getErrorText()
- {
- return curErrorText;
- }
- void XErrorLock::resetError()
- {
- if(islock)
- XSync(XCompcap::disp(), 0);
- goterr = false;
- curErrorText[0] = 0;
- }
- ObsGsContextHolder::ObsGsContextHolder()
- {
- gs_entercontext(obs_graphics());
- }
- ObsGsContextHolder::~ObsGsContextHolder()
- {
- gs_leavecontext();
- }
|