X11 JNA Bad Window (invalid Window parameter) 导致 JVM 退出
X11 JNA Bad Window (invalid Window parameter) causes JVM exit
以下使用 JNA 4.2.2 的 JNA 崩溃 - 如果您 运行 在最小化和最大化 windows 时 JVM 退出并跟随它。发生在 Ubuntu 16.04,但更常见于 Redhat 6u2。
X error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 20 (X_GetProperty)
...
我猜 Window ID 在从 XQueryTree 返回时是有效的,但在调用 XGetWMName 之前变得无效。问题是这会导致 JVM 退出,而不仅仅是我可以很好地处理的异常。我该如何避免这个问题?
public class X11WindowFinder {
private X11 x11;
public X11WindowFinder() {
x11 = X11.INSTANCE;
}
public List<Window> find(Pattern title) {
Display display = x11.XOpenDisplay(null);
Window root = x11.XDefaultRootWindow(display);
List<Window> windows = recurse(x11, display, root, title);
x11.XCloseDisplay(display);
return windows;
}
private synchronized List<Window> recurse(X11 x11, Display display, Window root, Pattern pattern) {
List<Window> windows = new ArrayList<>(1);
X11.WindowByReference windowRef = new X11.WindowByReference();
X11.WindowByReference parentRef = new X11.WindowByReference();
PointerByReference childrenRef = new PointerByReference();
IntByReference childCountRef = new IntByReference();
x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef);
if (childrenRef.getValue() == null) {
return Collections.emptyList();
}
long[] ids = {};
if (Native.LONG_SIZE == Long.BYTES) {
ids = childrenRef.getValue().getLongArray(0, childCountRef.getValue());
} else if (Native.LONG_SIZE == Integer.BYTES) {
int[] intIds = childrenRef.getValue().getIntArray(0, childCountRef.getValue());
ids = new long[intIds.length];
for (int i = 0; i < intIds.length; i++) {
ids[i] = intIds[i];
}
}
for (long id : ids) {
Window child = new Window(id);
X11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
String value = name.value;
if (value != null) {
System.out.println(String.format("Found window %s free %s", value, name));
}
if (value != null && pattern.matcher(value).matches()) {
windows.add(child);
}
windows.addAll(recurse(x11, display, child, pattern));
}
return windows;
}
public static void main(String[] args) {
X11WindowFinder finder = new X11WindowFinder();
while (true) {
finder.find(Pattern.compile(".*Firefox.*"));
}
}
}
看起来默认错误处理程序会导致退出,但可以覆盖。例如
x11.XSetErrorHandler(new XErrorHandler() {
@Override
public int apply(Display display, XErrorEvent errorEvent) {
System.err.println("bad fish " + errorEvent);
return 0;
}
});
以下使用 JNA 4.2.2 的 JNA 崩溃 - 如果您 运行 在最小化和最大化 windows 时 JVM 退出并跟随它。发生在 Ubuntu 16.04,但更常见于 Redhat 6u2。
X error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 20 (X_GetProperty)
...
我猜 Window ID 在从 XQueryTree 返回时是有效的,但在调用 XGetWMName 之前变得无效。问题是这会导致 JVM 退出,而不仅仅是我可以很好地处理的异常。我该如何避免这个问题?
public class X11WindowFinder {
private X11 x11;
public X11WindowFinder() {
x11 = X11.INSTANCE;
}
public List<Window> find(Pattern title) {
Display display = x11.XOpenDisplay(null);
Window root = x11.XDefaultRootWindow(display);
List<Window> windows = recurse(x11, display, root, title);
x11.XCloseDisplay(display);
return windows;
}
private synchronized List<Window> recurse(X11 x11, Display display, Window root, Pattern pattern) {
List<Window> windows = new ArrayList<>(1);
X11.WindowByReference windowRef = new X11.WindowByReference();
X11.WindowByReference parentRef = new X11.WindowByReference();
PointerByReference childrenRef = new PointerByReference();
IntByReference childCountRef = new IntByReference();
x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef);
if (childrenRef.getValue() == null) {
return Collections.emptyList();
}
long[] ids = {};
if (Native.LONG_SIZE == Long.BYTES) {
ids = childrenRef.getValue().getLongArray(0, childCountRef.getValue());
} else if (Native.LONG_SIZE == Integer.BYTES) {
int[] intIds = childrenRef.getValue().getIntArray(0, childCountRef.getValue());
ids = new long[intIds.length];
for (int i = 0; i < intIds.length; i++) {
ids[i] = intIds[i];
}
}
for (long id : ids) {
Window child = new Window(id);
X11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
String value = name.value;
if (value != null) {
System.out.println(String.format("Found window %s free %s", value, name));
}
if (value != null && pattern.matcher(value).matches()) {
windows.add(child);
}
windows.addAll(recurse(x11, display, child, pattern));
}
return windows;
}
public static void main(String[] args) {
X11WindowFinder finder = new X11WindowFinder();
while (true) {
finder.find(Pattern.compile(".*Firefox.*"));
}
}
}
看起来默认错误处理程序会导致退出,但可以覆盖。例如
x11.XSetErrorHandler(new XErrorHandler() {
@Override
public int apply(Display display, XErrorEvent errorEvent) {
System.err.println("bad fish " + errorEvent);
return 0;
}
});