package net.cakenet.jsaton.nativedef;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import java.awt.*;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class X11WindowManager extends WindowManager {
private static final X11 X = X11.INSTANCE;
private static final X11WindowReference ROOT;
public WindowReference findWindowByPointImpl(Point loc) {
X11.WindowByReference root_return = new X11.WindowByReference();
X11.WindowByReference child_return = new X11.WindowByReference();
IntByReference dummy = new IntByReference();
// Find initial...
X.XQueryPointer(ROOT.display, ROOT.window, root_return, child_return, dummy, dummy, dummy, dummy, dummy);
X11.Window window = child_return.getValue();
// Iterate through children until we reach the most deeply nested...
while (true) {
X.XQueryPointer(ROOT.display, window, root_return, child_return, dummy, dummy, dummy, dummy, dummy);
if (child_return.getValue() == null)
break;
window = child_return.getValue();
}
return new X11WindowReference(ROOT.display, window);
}
public WindowReference getDesktopImpl() {
return ROOT;
}
protected List<WindowReference> getTopLevelWindowsImpl() {
return ROOT.children();
}
static class X11WindowReference extends WindowReference {
private X11.Display display;
private X11.Window window;
public X11WindowReference(X11.Display display, X11.Window window) {
this.display = display;
this.window = window;
}
public int[] capture(int x, int y, int width, int height) {
X11.XImage cap = X.XGetImage(display, window, x, y, width, height, X11.AllPlanes, X11.ZPixmap);
if (cap.bytes_per_line != width * 4)
throw new UnsupportedOperationException("Make sure your bit depth is 24 or 32!");
if (cap.byte_order != 0)
throw new UnsupportedOperationException("Wrong byte order! (let me know, I might fix this)");
int[] pix = cap.data.getIntArray(cap.xoffset, cap.width * cap.height);
X.XFree(cap.getPointer());
return pix;
}
public String getTitle() {
X11.XTextProperty name = new X11.XTextProperty();
X.XGetWMName(display, window, name);
return name.value;
}
public X11WindowReference parent() {
X11.WindowByReference root_return = new X11.WindowByReference();
X11.WindowByReference parent_return = new X11.WindowByReference();
PointerByReference ptr = new PointerByReference();
X.XQueryTree(display, window, root_return, parent_return, ptr, new IntByReference());
if(ptr.getValue() != null && ptr.getValue() != Pointer.NULL)
X.XFree(ptr.getValue());
return new X11WindowReference(display, parent_return.getValue());
}
public List<WindowReference> children() {
X11.WindowByReference root_return = new X11.WindowByReference();
X11.WindowByReference parent_return = new X11.WindowByReference();
PointerByReference ptr = new PointerByReference();
IntByReference numChildren = new IntByReference();
X.XQueryTree(display, window, root_return, parent_return, ptr, numChildren);
if (ptr.getValue() == null || ptr.getValue() == Pointer.NULL)
return null;
List<WindowReference> ret = new ArrayList<>();
Pointer base = ptr.getValue();
int off = 0;
for(int i = 0, count = numChildren.getValue(); i < count; i++) {
X11.WindowByReference wref = new X11.WindowByReference();
wref.setPointer(base.share(off));
off += Pointer.SIZE;
ret.add(new X11WindowReference(display, wref.getValue()));
}
X.XFree(ptr.getValue());
return ret;
}
private Rectangle getReportedBounds() {
X11.WindowByReference root_return = new X11.WindowByReference();
IntByReference x_return = new IntByReference();
IntByReference y_return = new IntByReference();
IntByReference width_return = new IntByReference();
IntByReference height_return = new IntByReference();
IntByReference border_width_return = new IntByReference();
IntByReference depth_return = new IntByReference();
X.XGetGeometry(display, window, root_return, x_return, y_return, width_return, height_return,
border_width_return, depth_return);
return new Rectangle(x_return.getValue(), y_return.getValue(), width_return.getValue(), height_return.getValue());
}
public Rectangle getBounds() {
Rectangle bounds = getReportedBounds();
int x = bounds.x;
int y = bounds.y;
int width = bounds.width;
int height = bounds.height;
if (!parent().equals(ROOT) && !this.equals(ROOT)) {
x = y = 0;
X11WindowReference current = this;
do {
Rectangle relative = current.getReportedBounds();
x += relative.x;
y += relative.y;
current = current.parent();
} while (!current.equals(ROOT));
}
return new Rectangle(x, y, width, height);
}
public boolean equals(Object o) {
return o instanceof X11WindowReference && equals((X11WindowReference) o);
}
public boolean equals(X11WindowReference other) {
return other == this || other.window.equals(this.window);
}
public String toString() {
String title = getTitle();
return window.intValue() + (title != null? String.format(" (%s)", title): "");
}
}
private static final X11.XErrorHandler ERROR_HANDLER = new X11.XErrorHandler() {
public int apply(X11.Display display, X11.XErrorEvent rep) {
PrintStream out = System.out;
out.printf("X Error of failed request: %s\n ", errorMessage(rep.error_code & 0xff));
out.printf("Major opcode of failed request: %d\n ", rep.request_code);
out.printf("Minor opcode of failed request: %d\n ", rep.minor_code);
out.printf("Resource id in failed request: %x\n ", rep.resourceid.longValue());
out.printf("Serial number of failed request: %x\n", rep.serial.longValue());
return 0;
}
};
static {
X.XInitThreads();
X11.Display disp = X.XOpenDisplay(null);
// X.XSynchronize(disp, true); // Uncomment to debug errors synchronously...
ROOT = new X11WindowReference(disp, X.XDefaultRootWindow(disp));
//X.XSetErrorHandler(ERROR_HANDLER);
}
private static String errorMessage(int code) {
byte[] mesg = new byte[100];
X.XGetErrorText(ROOT.display, code, mesg, mesg.length);
String s = new String(mesg);
return s.substring(0, s.indexOf(0));
}
}
interface X11 extends com.sun.jna.platform.unix.X11 {
//<editor-fold desc="constants">
public static final NativeLong AllPlanes = new NativeLong(-1);
//</editor-fold>
public static X11 INSTANCE = (X11) Native.loadLibrary("X11", X11.class);
XImage XGetImage(Display display, Drawable d, int x, int y, int width, int height, NativeLong plane_mask, int format);
int XInitThreads();
int XSynchronize(Display display, boolean state);
static class XImage extends Structure {
public int width;
public int height; /* size of image */
public int xoffset; /* number of pixels offset in X direction */
public int format; /* XYBitmap, XYPixmap, ZPixmap */
public Pointer data; /* pointer to image data */
public int byte_order; /* data byte order, LSBFirst, MSBFirst */
public int bitmap_unit; /* quant. of scanline 8, 16, 32 */
public int bitmap_bit_order; /* LSBFirst, MSBFirst */
public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */
public int depth; /* depth of image */
public int bytes_per_line; /* accelerator to next scanline */
public int bits_per_pixel; /* bits per pixel (ZPixmap) */
public NativeLong red_mask; /* bits in z arrangement */
public NativeLong green_mask;
public NativeLong blue_mask;
public Pointer obdata; /* hook for the object routines to hang on */
//public Structure funcs;
@Override
protected List getFieldOrder() {
return Arrays.asList("width", "height", "xoffset", "format", "data", "byte_order", "bitmap_unit",
"bitmap_bit_order", "bitmap_pad", "depth", "bytes_per_line", "bits_per_pixel",
"red_mask", "green_mask", "blue_mask", "obdata");
}
// struct funcs { /* image manipulation routines */
// XImage * ( * create_image)();
// int( * destroy_image)();
// unsigned long( * get_pixel)();
// int( * put_pixel)();
// XImage * ( * sub_image)();
// int( * add_pixel)();
// } f;
}
}