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