1 #include <X11/Xlib.h>
2 #include <X11/Xatom.h>
3 #include <X11/Xutil.h>
4 #undef Bool
5 #undef CursorShape
6 #undef Expose
7 #undef KeyPress
8 #undef KeyRelease
9 #undef FocusIn
10 #undef FocusOut
11 #undef FontChange
12 #undef None
13 #undef Status
14 #undef Unsorted
15 #include <util/platform.h>
16 #include "auto-scene-switcher.hpp"
17
18 using namespace std;
19
20 static Display *xdisplay = 0;
21
disp()22 Display *disp()
23 {
24 if (!xdisplay)
25 xdisplay = XOpenDisplay(NULL);
26
27 return xdisplay;
28 }
29
CleanupSceneSwitcher()30 void CleanupSceneSwitcher()
31 {
32 if (!xdisplay)
33 return;
34
35 XCloseDisplay(xdisplay);
36 xdisplay = 0;
37 }
38
ewmhIsSupported()39 static bool ewmhIsSupported()
40 {
41 Display *display = disp();
42 Atom netSupportingWmCheck =
43 XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
44 Atom actualType;
45 int format = 0;
46 unsigned long num = 0, bytes = 0;
47 unsigned char *data = NULL;
48 Window ewmh_window = 0;
49
50 int status = XGetWindowProperty(display, DefaultRootWindow(display),
51 netSupportingWmCheck, 0L, 1L, false,
52 XA_WINDOW, &actualType, &format, &num,
53 &bytes, &data);
54
55 if (status == Success) {
56 if (num > 0) {
57 ewmh_window = ((Window *)data)[0];
58 }
59 if (data) {
60 XFree(data);
61 data = NULL;
62 }
63 }
64
65 if (ewmh_window) {
66 status = XGetWindowProperty(display, ewmh_window,
67 netSupportingWmCheck, 0L, 1L, false,
68 XA_WINDOW, &actualType, &format,
69 &num, &bytes, &data);
70 if (status != Success || num == 0 ||
71 ewmh_window != ((Window *)data)[0]) {
72 ewmh_window = 0;
73 }
74 if (status == Success && data) {
75 XFree(data);
76 }
77 }
78
79 return ewmh_window != 0;
80 }
81
getTopLevelWindows()82 static std::vector<Window> getTopLevelWindows()
83 {
84 std::vector<Window> res;
85
86 res.resize(0);
87
88 if (!ewmhIsSupported()) {
89 return res;
90 }
91
92 Atom netClList = XInternAtom(disp(), "_NET_CLIENT_LIST", true);
93 Atom actualType;
94 int format;
95 unsigned long num, bytes;
96 Window *data = 0;
97
98 for (int i = 0; i < ScreenCount(disp()); ++i) {
99 Window rootWin = RootWindow(disp(), i);
100
101 int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
102 ~0L, false, AnyPropertyType,
103 &actualType, &format, &num,
104 &bytes, (uint8_t **)&data);
105
106 if (status != Success) {
107 continue;
108 }
109
110 for (unsigned long i = 0; i < num; ++i)
111 res.emplace_back(data[i]);
112
113 XFree(data);
114 }
115
116 return res;
117 }
118
GetWindowTitle(size_t i)119 static std::string GetWindowTitle(size_t i)
120 {
121 Window w = getTopLevelWindows().at(i);
122 std::string windowTitle;
123 char *name;
124
125 int status = XFetchName(disp(), w, &name);
126 if (status >= Success && name != nullptr) {
127 std::string str(name);
128 windowTitle = str;
129 XFree(name);
130 } else {
131 XTextProperty xtp_new_name;
132 if (XGetWMName(disp(), w, &xtp_new_name) != 0 &&
133 xtp_new_name.value != nullptr) {
134 std::string str((const char *)xtp_new_name.value);
135 windowTitle = str;
136 XFree(xtp_new_name.value);
137 }
138 }
139
140 return windowTitle;
141 }
142
GetWindowList(vector<string> & windows)143 void GetWindowList(vector<string> &windows)
144 {
145 windows.resize(0);
146
147 for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
148 if (GetWindowTitle(i) != "")
149 windows.emplace_back(GetWindowTitle(i));
150 }
151 }
152
GetCurrentWindowTitle(string & title)153 void GetCurrentWindowTitle(string &title)
154 {
155 if (!ewmhIsSupported()) {
156 return;
157 }
158
159 Atom active = XInternAtom(disp(), "_NET_ACTIVE_WINDOW", true);
160 Atom actualType;
161 int format;
162 unsigned long num, bytes;
163 Window *data = 0;
164 char *name;
165
166 Window rootWin = RootWindow(disp(), 0);
167
168 XGetWindowProperty(disp(), rootWin, active, 0L, ~0L, false,
169 AnyPropertyType, &actualType, &format, &num, &bytes,
170 (uint8_t **)&data);
171
172 int status = XFetchName(disp(), data[0], &name);
173
174 if (status >= Success && name != nullptr) {
175 std::string str(name);
176 title = str;
177 } else {
178 XTextProperty xtp_new_name;
179 if (XGetWMName(disp(), data[0], &xtp_new_name) != 0 &&
180 xtp_new_name.value != nullptr) {
181 std::string str((const char *)xtp_new_name.value);
182 title = str;
183 XFree(xtp_new_name.value);
184 }
185 }
186
187 XFree(name);
188 }
189