2010-03-06 69 views
1

我使用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; 
} 
+1

也許窗口管理器告訴你一些東西。移動用戶的窗戶有點邪惡,並且可能需要特殊的權限。 – 2010-03-06 02:23:18

+1

感謝您的建議,但我不認爲它被認爲是邪惡的。還有其他程序,如wmctrl,可以在命令行上執行此操作,而無需任何特殊權限。我的原始實現實際上稱爲Java的wmctrl;但是與調用shell程序相關的開銷很大,所以我試圖在JNA中實現相同的功能。我用幾個例子比較了我的代碼,但它不起作用。我希望一個新的眼睛可能會發現我的一個愚蠢的錯誤。 ;) – rob 2010-03-08 17:11:27

回答

3

這可能是一個有點但是無論如何...

當您嘗試移動窗口時,會發生什麼情況是窗口(稱爲「客戶端」)將XConfigureRequest發送到窗口管理器。發生這種情況是因爲窗口管理器通知X服務器他是老闆(通過在客戶端的父級上設置子結構覆蓋標誌)。

要繞過這一點,唯一的方法是在客戶端上設置覆蓋重定向標誌,執行移動操作並禁用覆蓋重定向標誌(以便所有事情都回到「正常」狀態)。

gl & hf。

+0

我還沒有機會嘗試這個,但覆蓋重定向標誌聽起來很有希望。我想現在我會接受這一個,如果我試着去嘗試,最終我會發布我的結果。 – rob 2011-11-21 23:47:29

1

你看過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; 
     } 
    } 
+0

感謝您的回答。不,我沒有嘗試過XConfigureWindow,因爲我認爲它不會比XMoveWindow更有效,但是當我有機會時,我會繼續嘗試它。 – rob 2010-03-15 19:58:00