forked from adamdruppe/arsd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wmutil.d
172 lines (146 loc) · 4.62 KB
/
wmutil.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/++
Cross platform window manager utilities for interacting with other unknown windows on the OS.
Based on [arsd.simpledisplay].
+/
module arsd.wmutil;
public import arsd.simpledisplay;
version(Windows)
import core.sys.windows.windows;
static assert(UsingSimpledisplayX11 || UsingSimpledisplayWindows, "wmutil only works on X11 or Windows");
static if (UsingSimpledisplayX11) {
extern(C) nothrow @nogc {
Atom* XListProperties(Display *display, Window w, int *num_prop_return);
Status XGetTextProperty(Display *display, Window w, XTextProperty *text_prop_return, Atom property);
Status XQueryTree(Display *display, Window w, Window *root_return, Window *parent_return, Window **children_return, uint *nchildren_return);
}
}
/// A foreachable object that iterates window children
struct WindowChildrenIterator {
NativeWindowHandle parent;
version(Windows)
struct EnumParams {
int result;
int delegate(NativeWindowHandle) dg;
Exception ex;
}
version(Windows)
extern(Windows)
nothrow private static int helper(HWND window, LPARAM lparam) {
EnumParams* args = cast(EnumParams*)lparam;
try {
args.result = args.dg(window);
if (args.result)
return 0;
else
return 1;
} catch (Exception e) {
args.ex = e;
return 0;
}
}
///
int opApply(int delegate(NativeWindowHandle) dg) const {
version (Windows) {
EnumParams params;
// the cast is cuz druntime seems to have a wrong definition here, missing the const
EnumChildWindows(cast(void*) parent, &helper, cast(LPARAM)¶ms);
if (params.ex)
throw params.ex;
return params.result;
} else static if (UsingSimpledisplayX11) {
int result;
Window unusedWindow;
Window* children;
uint numChildren;
Status status = XQueryTree(XDisplayConnection.get(), parent, &unusedWindow, &unusedWindow, &children, &numChildren);
if (status == 0 || children is null)
return 0;
scope (exit)
XFree(children);
foreach (window; children[0 .. numChildren]) {
result = dg(window);
if (result)
break;
}
return result;
} else
static assert(0);
}
}
///
WindowChildrenIterator iterateWindows(NativeWindowHandle parent = NativeWindowHandle.init) {
static if (UsingSimpledisplayX11)
if (parent == NativeWindowHandle.init)
parent = RootWindow(XDisplayConnection.get, DefaultScreen(XDisplayConnection.get));
return WindowChildrenIterator(parent);
}
/++
Searches for a window with the specified class name and returns the native window handle to it.
Params:
className = the class name to check the window for, case-insensitive.
+/
NativeWindowHandle findWindowByClass(string className) {
version (Windows)
return findWindowByClass(className.toWStringz);
else static if (UsingSimpledisplayX11) {
import std.algorithm : splitter;
import std.uni : sicmp;
auto classAtom = GetAtom!"WM_CLASS"(XDisplayConnection.get());
Atom returnType;
int returnFormat;
arch_ulong numItems, bytesAfter;
char* strs;
foreach (window; iterateWindows) {
if (0 == XGetWindowProperty(XDisplayConnection.get(), window, classAtom, 0, 64, false, AnyPropertyType, &returnType, &returnFormat, &numItems, &bytesAfter, cast(void**)&strs)) {
scope (exit)
XFree(strs);
if (returnFormat == 8) {
foreach (windowClassName; strs[0 .. numItems].splitter('\0')) {
if (sicmp(windowClassName, className) == 0)
return window;
}
}
}
}
return NativeWindowHandle.init;
}
}
/// ditto
version (Windows)
NativeWindowHandle findWindowByClass(LPCTSTR className) {
return FindWindow(className, null);
}
/++
Get the PID that owns the window.
Params:
window = The window to check who created it
Returns: the PID of the owner who created this window. On windows this will always work and be accurate. On X11 this might return -1 if none is specified and might not actually be the actual owner.
+/
int ownerPID(NativeWindowHandle window) @property {
version (Windows) {
DWORD ret;
GetWindowThreadProcessId(window, &ret);
return cast(int) ret;
} else static if (UsingSimpledisplayX11) {
auto pidAtom = GetAtom!"_NET_WM_PID"(XDisplayConnection.get());
Atom returnType;
int returnFormat;
arch_ulong numItems, bytesAfter;
uint* ints;
if (0 == XGetWindowProperty(XDisplayConnection.get(), window, pidAtom, 0, 1, false, AnyPropertyType, &returnType, &returnFormat, &numItems, &bytesAfter, cast(void**)&ints)) {
scope (exit)
XFree(ints);
if (returnFormat < 64 && numItems > 0) {
return *ints;
}
}
return -1;
}
}
unittest {
import std.stdio;
auto window = findWindowByClass("x-terminal-emulator");
writeln("Terminal: ", window.ownerPID);
foreach (w; iterateWindows)
writeln(w.ownerPID);
}