2017-06-29 19:01:10 +00:00
|
|
|
#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;
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
static Display *xdisplay = 0;
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
Display *disp()
|
|
|
|
{
|
|
|
|
if (!xdisplay)
|
|
|
|
xdisplay = XOpenDisplay(NULL);
|
|
|
|
|
|
|
|
return xdisplay;
|
|
|
|
}
|
|
|
|
|
2020-10-01 20:15:25 +00:00
|
|
|
void CleanupSceneSwitcher()
|
2017-06-29 19:01:10 +00:00
|
|
|
{
|
|
|
|
if (!xdisplay)
|
|
|
|
return;
|
|
|
|
|
|
|
|
XCloseDisplay(xdisplay);
|
|
|
|
xdisplay = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ewmhIsSupported()
|
|
|
|
{
|
|
|
|
Display *display = disp();
|
2019-09-22 21:19:10 +00:00
|
|
|
Atom netSupportingWmCheck =
|
|
|
|
XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
|
2017-06-29 19:01:10 +00:00
|
|
|
Atom actualType;
|
|
|
|
int format = 0;
|
|
|
|
unsigned long num = 0, bytes = 0;
|
|
|
|
unsigned char *data = NULL;
|
|
|
|
Window ewmh_window = 0;
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
int status = XGetWindowProperty(display, DefaultRootWindow(display),
|
|
|
|
netSupportingWmCheck, 0L, 1L, false,
|
|
|
|
XA_WINDOW, &actualType, &format, &num,
|
|
|
|
&bytes, &data);
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
if (status == Success) {
|
|
|
|
if (num > 0) {
|
2019-09-22 21:19:10 +00:00
|
|
|
ewmh_window = ((Window *)data)[0];
|
2017-06-29 19:01:10 +00:00
|
|
|
}
|
|
|
|
if (data) {
|
|
|
|
XFree(data);
|
|
|
|
data = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ewmh_window) {
|
2019-09-22 21:19:10 +00:00
|
|
|
status = XGetWindowProperty(display, ewmh_window,
|
|
|
|
netSupportingWmCheck, 0L, 1L, false,
|
|
|
|
XA_WINDOW, &actualType, &format,
|
|
|
|
&num, &bytes, &data);
|
2017-06-29 19:01:10 +00:00
|
|
|
if (status != Success || num == 0 ||
|
2019-09-22 21:19:10 +00:00
|
|
|
ewmh_window != ((Window *)data)[0]) {
|
2017-06-29 19:01:10 +00:00
|
|
|
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;
|
2019-09-22 21:19:10 +00:00
|
|
|
Window *data = 0;
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
|
|
|
Window rootWin = RootWindow(disp(), i);
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
|
|
|
|
~0L, false, AnyPropertyType,
|
|
|
|
&actualType, &format, &num,
|
|
|
|
&bytes, (uint8_t **)&data);
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
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;
|
2019-09-22 21:19:10 +00:00
|
|
|
char *name;
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
int status = XFetchName(disp(), w, &name);
|
2019-09-22 21:19:10 +00:00
|
|
|
if (status >= Success && name != nullptr) {
|
2017-06-29 19:01:10 +00:00
|
|
|
std::string str(name);
|
|
|
|
windowTitle = str;
|
2019-12-10 19:31:54 +00:00
|
|
|
XFree(name);
|
|
|
|
} else {
|
|
|
|
XTextProperty xtp_new_name;
|
|
|
|
if (XGetWMName(disp(), w, &xtp_new_name) != 0 &&
|
|
|
|
xtp_new_name.value != nullptr) {
|
|
|
|
std::string str((const char *)xtp_new_name.value);
|
|
|
|
windowTitle = str;
|
|
|
|
XFree(xtp_new_name.value);
|
|
|
|
}
|
2017-06-29 19:01:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return windowTitle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GetWindowList(vector<string> &windows)
|
|
|
|
{
|
|
|
|
windows.resize(0);
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
|
2017-06-29 19:01:10 +00:00
|
|
|
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;
|
2019-09-22 21:19:10 +00:00
|
|
|
Window *data = 0;
|
|
|
|
char *name;
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
Window rootWin = RootWindow(disp(), 0);
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
XGetWindowProperty(disp(), rootWin, active, 0L, ~0L, false,
|
|
|
|
AnyPropertyType, &actualType, &format, &num, &bytes,
|
|
|
|
(uint8_t **)&data);
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
int status = XFetchName(disp(), data[0], &name);
|
|
|
|
|
|
|
|
if (status >= Success && name != nullptr) {
|
|
|
|
std::string str(name);
|
|
|
|
title = str;
|
2020-10-01 20:15:25 +00:00
|
|
|
} else {
|
|
|
|
XTextProperty xtp_new_name;
|
|
|
|
if (XGetWMName(disp(), data[0], &xtp_new_name) != 0 &&
|
|
|
|
xtp_new_name.value != nullptr) {
|
|
|
|
std::string str((const char *)xtp_new_name.value);
|
|
|
|
title = str;
|
|
|
|
XFree(xtp_new_name.value);
|
|
|
|
}
|
2017-06-29 19:01:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XFree(name);
|
|
|
|
}
|