简体   繁体   English

通过JNA使用Xlib移动窗口

[英]Using Xlib via JNA to move a window

I'm using JNA to manipulate application windows on Linux by sending Xlib messages but can't seem to move a window. 我正在使用JNA通过发送Xlib消息来操纵Linux上的应用程序窗口,但似乎无法移动窗口。

My original implementation executed wmctrl on the shell to move the windows and that successfully moved the windows. 我的原始实现在shell上执行了wmctrl来移动窗口并成功移动了窗口。 Unfortunately, there's a noticeable amount of overhead associated with calling shell programs from Java, so now I'm trying to make direct API calls using JNA. 不幸的是,从Java调用shell程序会产生相当大的开销,所以现在我正在尝试使用JNA进行直接的API调用。 I'm using the X11 example available from the JNA website and can successfully do a few tricks, such as enumerating the window IDs and reading window properties, so I know JNA+Xlib is at least partially working. 我正在使用JNA网站提供的X11示例,并且可以成功地做一些技巧,例如枚举窗口ID和读取窗口属性,所以我知道JNA + Xlib至少部分工作。

First I tried moving the windows directly using XMoveWindow() but the window manager was apparently blocking those calls. 首先,我尝试使用XMoveWindow()直接移动窗口,但窗口管理器显然阻止了这些调用。

I ran across a thread that suggested I needed to send a client message using XSendMessage() , so I've done that below, but apparently XSendMessage() is failing because the window doesn't move and I get a return value of 0 . 我跑过一个线程,建议我需要使用XSendMessage()发送客户端消息,所以我在下面完成了,但显然XSendMessage()失败,因为窗口没有移动,我得到的返回值为0 I'm guessing I omitted something obvious, but can't quite figure it out. 我猜我省略了一些明显的东西,但无法弄明白。 Any suggestions? 有什么建议么?

Note that, for the purposes of this example, the main method has a window ID hard-coded. 注意,出于本示例的目的,main方法具有硬编码的窗口ID。 This is the window ID of the window I'm trying to move (obtained using wmctrl -l on the console). 这是我正在尝试移动的窗口的窗口ID(在控制台上使用wmctrl -l获得)。

import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.examples.unix.X11;
import com.sun.jna.examples.unix.X11.Atom;
import com.sun.jna.examples.unix.X11.AtomByReference;
import com.sun.jna.examples.unix.X11.Display;
import com.sun.jna.examples.unix.X11.Window;
import com.sun.jna.examples.unix.X11.WindowByReference;
import com.sun.jna.examples.unix.X11.XEvent;
import com.sun.jna.examples.unix.X11.XTextProperty;
import com.sun.jna.examples.unix.X11.XWindowAttributes;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.NativeLongByReference;
import com.sun.jna.ptr.PointerByReference;

private static final int FALSE = 0; /** C-style boolean "false" */
private static final int TRUE  = 1; /** C-style boolean "true" */

public static void main(String[] args) {
    setWindowPos(new Window(0x01300007), 100, 100, 600, 400); // update the Window constructor with the appropriate ID given by wmctrl -l
}


public static boolean setWindowPos(Window window, int x, int y, int w, int h) {
    final X11 x11 = X11.INSTANCE;
    Display display = x11.XOpenDisplay(null);

    NativeLong mask = new NativeLong(X11.SubstructureRedirectMask | X11.SubstructureNotifyMask | X11.ResizeRedirectMask);

    XEvent event = new XEvent();

    String msg = "_NET_MOVERESIZE_WINDOW"; //$NON-NLS-1$

    long grflags = 0l; // use the default gravity of the window
    if (x != -1) grflags |= (1 << 8);
    if (y != -1) grflags |= (1 << 9);
    if (w != -1) grflags |= (1 << 10);
    if (h != -1) grflags |= (1 << 11);

    event.xclient.type = X11.ClientMessage;
    event.xclient.serial = new NativeLong(0l);
    event.xclient.send_event = TRUE;
    event.xclient.message_type = x11.XInternAtom(display, msg, false);
    event.xclient.window = window;
    event.xclient.format = 32;
    event.xclient.data.l[0] = new NativeLong(grflags); // gravity flags
    event.xclient.data.l[1] = new NativeLong(x);
    event.xclient.data.l[2] = new NativeLong(y);
    event.xclient.data.l[3] = new NativeLong(w);
    event.xclient.data.l[4] = new NativeLong(h);

    int status = x11.XSendEvent(display, x11.XDefaultRootWindow(display), FALSE, mask, event);
    x11.XFlush(display); // need to XFlush if we're not reading X events

    if (status == 0) { // 0 indicates XSendEvent failed
        logger.error("setWindowPos: XSendEvent failed (" + msg + ")"); //$NON-NLS-1$
        return false;
    }

    return true;
}

This might be a bit of a late answers but anyway... 这可能是一个迟到的答案,但无论如何......

What happens when you try to move a window is that the window (called "the client") sends an XConfigureRequest to the window manager. 当您尝试移动窗口时会发生的情况是窗口(称为“客户端”)将XConfigureRequest发送到窗口管理器。 This happens because the window manager tells the X server that he is boss (by setting the substructure override flag on the client's parent). 发生这种情况是因为窗口管理器告诉X服务器他是老板(通过在客户端的父节点上设置子结构覆盖标志)。

The only way to bypass this is to set the override redirect flag on your client, do the move, and disable the override redirect flag (so that everything goes back to 'normal'). 绕过这个的唯一方法是在客户端上设置覆盖重定向标志,执行移动,并禁用覆盖重定向标志(以便一切都恢复到“正常”)。

gl & hf. gl&hf。

Have you looked at XConfigureWindow? 你看过XConfigureWindow吗?

I haven't actually tested this out yet since I just implemented it tonight and I'm developing on Windows, but it's worth a try.... 我实际上还没有对此进行过测试,因为我今晚刚刚实现它,而且我正在开发Windows,但值得一试....

public static interface X11Ext extends Library
    {
        public static X11Ext INSTANCE = (X11Ext)Native.loadLibrary("X11", X11Ext.class);

        public int XConfigureWindow(X11.Display display, X11.Window window, int value_mask, XWindowChanges changes);

        /**
         * Use value_mask flags:
         * CWX
         * CWY
         * CWWidth
         * CWHeight
         * CWBorderWidth
         * CWSibling
         * CWStackMode
         */
        public class XWindowChanges extends Structure
        {
            public int x;
            public int y;
            public int width;
            public int height;
            public int border_width;
            public X11.Window sibling;
            public int stack_mode;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM