我使用JNA通過發送Xlib消息來操縱Linux上的應用程序窗口,但似乎無法移動窗口。通過JNA使用Xlib來移動窗口
我的原始實現在shell上執行wmctrl來移動窗口,併成功地移動了窗口。不幸的是,與從Java調用shell程序相關的開銷相當大,所以現在我試圖使用JNA進行直接的API調用。我正在使用JNA網站上提供的X11示例,並且可以成功執行一些技巧,例如枚舉窗口ID和閱讀窗口屬性,所以我知道JNA + Xlib至少可以部分工作。
首先,我嘗試使用XMoveWindow()
直接移動窗口,但窗口管理器顯然阻止了這些調用。
我跨建議我需要發送郵件使用XSendMessage()
客戶端消息的線程跑了,所以我已經做了,下面,但顯然XSendMessage()
失敗,因爲窗口不動,我得到的0
返回值。我猜我省略了一些顯而易見的東西,但無法弄清楚。有什麼建議麼?
請注意,出於此示例的目的,主方法具有硬編碼的窗口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;
}
也許窗口管理器告訴你一些東西。移動用戶的窗戶有點邪惡,並且可能需要特殊的權限。 – 2010-03-06 02:23:18
感謝您的建議,但我不認爲它被認爲是邪惡的。還有其他程序,如wmctrl,可以在命令行上執行此操作,而無需任何特殊權限。我的原始實現實際上稱爲Java的wmctrl;但是與調用shell程序相關的開銷很大,所以我試圖在JNA中實現相同的功能。我用幾個例子比較了我的代碼,但它不起作用。我希望一個新的眼睛可能會發現我的一個愚蠢的錯誤。 ;) – rob 2010-03-08 17:11:27