【问题标题】:Using Xlib via JNA to move a window通过 JNA 使用 Xlib 移动窗口
【发布时间】:2010-03-06 01:47:03
【问题描述】:

我正在使用 JNA 通过发送 Xlib 消息来操作 Linux 上的应用程序窗口,但似乎无法移动窗口。

我最初的实现在 shell 上执行 wmctrl 来移动窗口并且成功地移动了窗口。不幸的是,从 Java 调用 shell 程序会产生大量开销,所以现在我尝试使用 JNA 进行直接 API 调用。我正在使用 JNA 网站上提供的 X11 示例,并且可以成功完成一些技巧,例如枚举窗口 ID 和读取窗口属性,因此我知道 JNA+Xlib 至少部分工作。

首先我尝试使用XMoveWindow() 直接移动窗口,但窗口管理器显然阻止了这些调用。

我遇到了一个线程,提示我需要使用XSendMessage() 发送客户端消息,所以我在下面完成了,但显然XSendMessage() 失败了,因为窗口没有移动并且我得到了一个返回值的0。我猜我遗漏了一些明显的东西,但不能完全弄清楚。有什么建议吗?

请注意,就本示例而言,main 方法具有硬编码的窗口 ID。这是我要移动的窗口的窗口 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;
}

【问题讨论】:

  • 也许窗口管理器在告诉你一些事情。移动用户的窗口有点邪恶,可能需要特殊权限。
  • 感谢您的建议,但我不认为它是邪恶的。还有其他程序,例如 wmctrl,可以在命令行上执行此操作而无需任何特殊权限。我最初的实现实际上是从 Java 调用 wmctrl;但是调用 shell 程序有很大的开销,所以我试图在 JNA 中实现相同的功能。我已经将我的代码与几个示例进行了比较,但它不起作用。我希望有一双新的眼睛能发现我的一个愚蠢的错误。 ;)

标签: java linux jna xlib


【解决方案1】:

这可能是一个迟到的答案,但无论如何......

当您尝试移动一个窗口时,会发生什么情况是该窗口(称为“客户端”)向窗口管理器发送了一个 XConfigureRequest。这是因为窗口管理器告诉 X 服务器他是老板(通过在客户端的父级上设置子结构覆盖标志)。

绕过此问题的唯一方法是在您的客户端上设置覆盖重定向标志,执行移动并禁用覆盖重定向标志(以便一切恢复“正常”)。

gl & hf.

【讨论】:

  • 我还没有机会尝试这个,但是覆盖重定向标志听起来很有希望。我想我现在会接受这个,如果我最终能尝试一下,我会发布我的结果。
【解决方案2】:

你看过 XConfigureWindow 吗?

我还没有真正测试过它,因为我今晚刚刚实现它并且我正在 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;
        }
    }

【讨论】:

  • 感谢您的回答。不,我没有尝试过 XConfigureWindow,因为我认为它不会比 XMoveWindow 更有效,但如果有机会,我会继续尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多