2013-05-09 237 views
5

前一段時間,我在C中編寫了一個腳本,它使用Windows API函數EnumWindows,SetWindowPos和SetForegroundWindow按照我通常想要的特定佈局自動安排窗口(按標題)。有沒有Linux的SetWindowPos等價物?

這些函數是否有Linux等價物?我將使用Kubuntu,因此KDE特定和/或Ubuntu特定的解決方案都很好。

+0

您可能想要使用平鋪WM和KDE:http://awesome.naquadah.org/wiki/KDE_and_awesome或http://blog.frozen-zone.org/2010/01/kde4-with-xmonad/ – 2013-05-10 09:03:33

回答

2

是的,你可以使用X Windows協議來做到這一點。這是一個非常低級別的協議,因此需要一些工作。您可以使用xcb_query_tree找到要操作的窗口,然後用xcb_configure_window移動它。 This page給出了一些關於如何去做的細節。有一個使用這些函數庫的basic tutorial,但您可能希望谷歌更好。

這似乎令人望而生畏,但也不算太壞。這裏有一個50行的C程序會將所有的xterms你到10px的右邊:

#include <stdio.h> 
#include <string.h> 
#include <xcb/xcb.h> 

void handle(xcb_connection_t* connection, xcb_window_t window) { 

    xcb_query_tree_reply_t *tree = xcb_query_tree_reply(connection, 
     xcb_query_tree(connection, window), NULL); 
    xcb_window_t *children = xcb_query_tree_children(tree); 

    for (int i = 0; i < xcb_query_tree_children_length(tree); i++) { 

     xcb_get_property_reply_t *class_reply = xcb_get_property_reply(
      connection, 
      xcb_get_property(connection, 0, children[i], XCB_ATOM_WM_CLASS, 
       XCB_ATOM_STRING, 0, 512), NULL); 
     char* class = (char*)xcb_get_property_value(class_reply); 
     class[xcb_get_property_value_length(class_reply)] = '\0'; 

     if (!strcmp(class, "xterm")) { 
      /* Get geometry relative to parent window */ 
      xcb_get_geometry_reply_t* geom = xcb_get_geometry_reply(
       connection, 
       xcb_get_geometry(connection, window), 
       NULL); 

      /* Move 10 pixels right */ 
      uint32_t values[] = {geom->x + 10}; 
      xcb_configure_window(connection, children[i], 
       XCB_CONFIG_WINDOW_X, values); 
     } 

     /* Recurse down window tree */ 
     handle(connection, children[i]); 
    } 
} 

int main() { 
    xcb_connection_t *connection; 
    const xcb_setup_t *setup; 

    connection = xcb_connect(NULL, NULL); 
    setup = xcb_get_setup(connection); 
    xcb_screen_iterator_t screen = xcb_setup_roots_iterator(setup); 
    handle(connection, screen.data->root); 

    return 0; 
} 

沒有錯誤檢查或內存管理,以及它可以做的是相當有限。但是應該直接更新到一個你想要的程序,或者通過添加命令行選項來指定要操作哪個窗口以及對它們執行哪些操作來將其變爲通用幫助程序。

+5

@rubenvb \t 如果您有更好的答案,盡一切辦法發佈,我會upvote您的答案,並刪除這一個。但如果你有更好的答案,我認爲你不會訴諸侮辱。 – andrewdotn 2013-05-09 21:56:11

+1

+1提供了一個現代的XCB示例,遺留代碼繼續使用Xlib是一回事......但新代碼應該真正使用現代方法。或者更好的是,完全不使用X,但這不會有意義,因爲OP是專門針對X的。 – TechZilla 2013-11-04 23:51:34

+0

我同意TechZilla,因爲所有過時的代碼,新程序員最終都是在xlib中完成它們的工作,然後意識到他們現在必須切換到xcb,因爲所有的線程都是這樣。我現在正處於這種情況下,用xcb重做我所有的工作,因爲我會用xlib解決無法解釋的問題。感謝這個例子,它非常有用! – Noitidart 2016-05-01 13:37:20

2

@andrewdotn在那裏有一個很好的答案,但你可以做這個老派,相當簡單地通過使用XQueryTree從顯示的根窗口開始走樹並使用XFetchName獲取窗口名稱,然後使用XMoveWindow移動它。這裏是一個將列出所有窗口的例子,如果有的話被稱爲'xeyes',它們會移動到左上角。像大多數X程序一樣,它還有更多的功能,這可能應該是調用XGetWindowProperty來獲取_NET_WM_NAME擴展窗口管理器屬性,但該示例可以作爲啓動程序正常工作。與gcc -Wall -g -o demo demo.c -lX11

#include <X11/Xlib.h> 
#include <stdio.h> 
#include <string.h> 

static int 
EnumWindows(Display *display, Window window, int depth) 
{ 
    Window parent, *children; 
    unsigned int count = 0; 
    int r = 1, n = 0; 
    char *name = NULL; 

    XFetchName(display, window, &name); 
    for (n = 0; n < depth; ++n) putchar(' '); 
    printf("%08x %s\n", (int)window, name?name:"(null)"); 
    if (name && strcmp("xeyes", name) == 0) { 
     XMoveWindow(display, window, 5, 5); 
    } 
    if (name) XFree(name); 

    if (XQueryTree(display, window, &window, &parent, &children, &count) == 0) { 
     fprintf(stderr, "error: XQueryTree error\n"); 
     return 0; 
    } 
    for (n = 0; r && n < count; ++n) { 
     r = EnumWindows(display, children[n], depth+1); 
    } 
    XFree(children); 
    return r; 
} 

int 
main(int argc, char *const argv[]) 
{ 
    Display *display = NULL; 

    if ((display = XOpenDisplay(NULL)) == NULL) { 
     fprintf(stderr, "error: cannot connect to X server\n"); 
     return 1; 
    } 

    EnumWindows(display, DefaultRootWindow(display), 0); 
    XCloseDisplay(display); 
    return 0; 
} 
5

編譯要做到這一點無論是在窗口管理器本身(如果你支持擴展)或設計爲支持「尋呼機」的協議和提示(尋呼機=任何非窗口管理器的最佳方式處理窗口組織或導航事物)。

EWMH規範包含一個_NET_MOVERESIZE_WINDOW設計用於尋呼機。 http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2731465

原始Xlib或Xcb非常粗糙,但有一個名爲libwnck的庫,專門用於處理您所談論的事情。 (我很久以前就寫過原始的圖書館,但它一直由其他人維護)。即使你不使用它,閱讀代碼,看看如何做的東西。 KDE可能與KDE風格的API相當,我不確定。

應該沒有必要使用任何KDE或GNOME或特定發行版,因爲所需的東西都在EWMH中闡述。也就是說,對於某些窗口管理者來說,將其作爲擴展可能比編寫單獨的應用程序更容易。

直接使用舊學校的X電話肯定可以工作,但有很多細節可以處理那些需要重要的專業知識,如果你想消除所有的錯誤和角落案例,在我看來,所以使用WM擴展API或傳呼機庫將是我的建議。

0

看起來您並不是專門尋找代碼解決方案,而是在桌面環境中尋找解決方案,您需要查看處理這種桌面環境中窗口放置的窗口管理器之一。

  1. KDE的KWin's Window Attributes

  2. 的Compiz(GNOME)具有 「窗口規則」 和 「地方的Windows」 在CompizConfig設置管理器應用程序。見例如here

  3. 雖然Openbox鏈接到this page底部的GUI工具,但似乎很難找到正確的方法。

直接使用X的問題在於X本身對您的桌面環境(面板,快捷方式等)一無所知,您必須手動進行補償。

谷歌搜索後,我很驚訝KDE是唯一有一個簡單的方法來做到這一點。

相關問題