如何使用 JNA (Java) 为活动 window 获取 X11 WM_CLASS?
How do I get X11 WM_CLASS for active window using JNA (Java)?
我使用下面的代码获取Linux中的当前(焦点)window:
X11 x11 = X11.INSTANCE;
X11.Display display = x11.XOpenDisplay(null);
X11.Window window = x11.XDefaultRootWindow(display);
现在我想要 WM_CLASS
属性 这个 window。
在 Setting and Reading the WM_CLASS Property 中有一段说明如何做到这一点:
To read a window's WM_CLASS property, use XGetClassHint().
The XClassHint contains:
typedef struct {
char *res_name;
char *res_class;
} XClassHint;
但是,我们看X11.XWMHints (JNA API)可以发现,没有属性res_class
(也就是WM_CLASS
)
那么,如何获取当前window的WM_CLASS
属性?
您可以使用 getWindowClass()
method of X.Window
class from jnacontrib
package: it reads WC_CLASS
property from provided window and replaces null-terminator characters ([=16=]
) with dots (.
). Javadoc says:
Returns the property value as UTF8 string where every '[=18=]' character is replaced by '.'.
X11 x11 = X11.INSTANCE;
X11.Display display = x11.XOpenDisplay(null);
X11.Window window = x11.XDefaultRootWindow(display);
String wmClass = new X.Window(new X.Display(display), window).getWindowClass();
另一种获取此值的方法是手动读取它(从 contrib 包中复制了一些部分):
static class XClassHint {
public final String resName;
public final String resClass;
public XClassHint(final String name, final String cls) {
this.resName = name;
this.resClass = cls;
}
@Override
public String toString() {
return String.format("%s:%s", this.resName, this.resClass);
}
}
private static XClassHint wmClass(X11 x11, X11.Display display, X11.Window window) throws UnsupportedEncodingException {
final X11.Atom xa_prop_type = X11.XA_STRING;
final X11.Atom xa_prop_name = X11.XA_WM_CLASS;
final int MAX_PROPERTY_VALUE_LEN = 4096;
X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference();
IntByReference ret_format_ref = new IntByReference();
NativeLongByReference ret_nitems_ref = new NativeLongByReference();
NativeLongByReference ret_bytes_after_ref = new NativeLongByReference();
PointerByReference ret_prop_ref = new PointerByReference();
NativeLong long_offset = new NativeLong(0);
NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4);
if (x11.XGetWindowProperty(display, window, xa_prop_name, long_offset, long_length, false,
xa_prop_type, xa_ret_type_ref, ret_format_ref,
ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) {
String prop_name = x11.XGetAtomName(display, xa_prop_name);
throw new RuntimeException("Cannot get " + prop_name + " property.");
}
X11.Atom xa_ret_type = xa_ret_type_ref.getValue();
Pointer ret_prop = ret_prop_ref.getValue();
if (xa_ret_type == null) {
//the specified property does not exist for the specified window
return null;
}
if (xa_prop_type == null ||
!xa_ret_type.toNative().equals(xa_prop_type.toNative())) {
x11.XFree(ret_prop);
String prop_name = x11.XGetAtomName(display, xa_prop_name);
throw new RuntimeException("Invalid type of " + prop_name + " property");
}
int ret_format = ret_format_ref.getValue();
long ret_nitems = ret_nitems_ref.getValue().longValue();
// null terminate the result to make string handling easier
int nbytes;
if (ret_format == 32)
nbytes = Native.LONG_SIZE;
else if (ret_format == 16)
nbytes = Native.LONG_SIZE / 2;
else if (ret_format == 8)
nbytes = 1;
else if (ret_format == 0)
nbytes = 0;
else
throw new RuntimeException("Invalid return format");
int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN);
byte[] ret = ret_prop.getByteArray(0, length);
x11.XFree(ret_prop);
if( ret == null ){
return null;
}
// search for '[=11=]'
int i;
for (i = 0; i < ret.length; i++) {
if (ret[i] == '[=11=]') {
ret[i] = '.';
}
}
String wcSrc = new String(ret, "UTF8");
final String[] parts = wcSrc.split("\.");
return new XClassHint(parts[0], parts[1]);
}
我使用下面的代码获取Linux中的当前(焦点)window:
X11 x11 = X11.INSTANCE;
X11.Display display = x11.XOpenDisplay(null);
X11.Window window = x11.XDefaultRootWindow(display);
现在我想要 WM_CLASS
属性 这个 window。
在 Setting and Reading the WM_CLASS Property 中有一段说明如何做到这一点:
To read a window's WM_CLASS property, use XGetClassHint().
The XClassHint contains:
typedef struct {
char *res_name;
char *res_class;
} XClassHint;
但是,我们看X11.XWMHints (JNA API)可以发现,没有属性res_class
(也就是WM_CLASS
)
那么,如何获取当前window的WM_CLASS
属性?
您可以使用 getWindowClass()
method of X.Window
class from jnacontrib
package: it reads WC_CLASS
property from provided window and replaces null-terminator characters ([=16=]
) with dots (.
). Javadoc says:
Returns the property value as UTF8 string where every '[=18=]' character is replaced by '.'.
X11 x11 = X11.INSTANCE;
X11.Display display = x11.XOpenDisplay(null);
X11.Window window = x11.XDefaultRootWindow(display);
String wmClass = new X.Window(new X.Display(display), window).getWindowClass();
另一种获取此值的方法是手动读取它(从 contrib 包中复制了一些部分):
static class XClassHint {
public final String resName;
public final String resClass;
public XClassHint(final String name, final String cls) {
this.resName = name;
this.resClass = cls;
}
@Override
public String toString() {
return String.format("%s:%s", this.resName, this.resClass);
}
}
private static XClassHint wmClass(X11 x11, X11.Display display, X11.Window window) throws UnsupportedEncodingException {
final X11.Atom xa_prop_type = X11.XA_STRING;
final X11.Atom xa_prop_name = X11.XA_WM_CLASS;
final int MAX_PROPERTY_VALUE_LEN = 4096;
X11.AtomByReference xa_ret_type_ref = new X11.AtomByReference();
IntByReference ret_format_ref = new IntByReference();
NativeLongByReference ret_nitems_ref = new NativeLongByReference();
NativeLongByReference ret_bytes_after_ref = new NativeLongByReference();
PointerByReference ret_prop_ref = new PointerByReference();
NativeLong long_offset = new NativeLong(0);
NativeLong long_length = new NativeLong(MAX_PROPERTY_VALUE_LEN / 4);
if (x11.XGetWindowProperty(display, window, xa_prop_name, long_offset, long_length, false,
xa_prop_type, xa_ret_type_ref, ret_format_ref,
ret_nitems_ref, ret_bytes_after_ref, ret_prop_ref) != X11.Success) {
String prop_name = x11.XGetAtomName(display, xa_prop_name);
throw new RuntimeException("Cannot get " + prop_name + " property.");
}
X11.Atom xa_ret_type = xa_ret_type_ref.getValue();
Pointer ret_prop = ret_prop_ref.getValue();
if (xa_ret_type == null) {
//the specified property does not exist for the specified window
return null;
}
if (xa_prop_type == null ||
!xa_ret_type.toNative().equals(xa_prop_type.toNative())) {
x11.XFree(ret_prop);
String prop_name = x11.XGetAtomName(display, xa_prop_name);
throw new RuntimeException("Invalid type of " + prop_name + " property");
}
int ret_format = ret_format_ref.getValue();
long ret_nitems = ret_nitems_ref.getValue().longValue();
// null terminate the result to make string handling easier
int nbytes;
if (ret_format == 32)
nbytes = Native.LONG_SIZE;
else if (ret_format == 16)
nbytes = Native.LONG_SIZE / 2;
else if (ret_format == 8)
nbytes = 1;
else if (ret_format == 0)
nbytes = 0;
else
throw new RuntimeException("Invalid return format");
int length = Math.min((int) ret_nitems * nbytes, MAX_PROPERTY_VALUE_LEN);
byte[] ret = ret_prop.getByteArray(0, length);
x11.XFree(ret_prop);
if( ret == null ){
return null;
}
// search for '[=11=]'
int i;
for (i = 0; i < ret.length; i++) {
if (ret[i] == '[=11=]') {
ret[i] = '.';
}
}
String wcSrc = new String(ret, "UTF8");
final String[] parts = wcSrc.split("\.");
return new XClassHint(parts[0], parts[1]);
}