5

少し前に、Windows API 関数の EnumWindows、SetWindowPos、および SetForegroundWindow を使用して、私が一般的に望んでいた特定のレイアウトでウィンドウを (タイトルごとに) 自動的に配置するスクリプトを C で作成しました。

これらの機能に相当する Linux はありますか? 私は Kubuntu を使用するので、KDE ​​固有および/または Ubuntu 固有のソリューションで問題ありません。

4

4 に答える 4

5

これを行う最善の方法は、ウィンドウ マネージャー自体 (拡張機能をサポートしている場合)、または「ページャー」をサポートするように設計されたプロトコルとヒント (ページャー = ウィンドウの編成やナビゲーションを行う非ウィンドウ マネージャー プロセス) を使用することです。

EWMH 仕様には、ページャーで使用するために設計された _NET_MOVERESIZE_WINDOW が含まれています。http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2731465

生の Xlib または Xcb はかなりラフですが、あなたが話しているようなことを行うために特別に設計された libwnck というライブラリがあります。(元のライブラリはずっと前に書きましたが、他の人によって永久に維持されています。) 使用していない場合でも、コードを読んで操作方法を確認してください。KDE には KDE スタイルの API と同等のものがあるかもしれませんが、私にはわかりません。

必要なものはすべて EWMH に記載されているため、KDE、GNOME、またはディストリビューション固有のものを使用する必要はありません。とはいえ、特定のウィンドウ マネージャーでは、これを拡張機能として実行する方が、別のアプリを作成するよりも簡単な場合があります。

古い学校の X 呼び出しを直接使用することは確かに機能しますが、私の意見では、すべてのバグとコーナーケースを解決したい場合は、かなりの専門知識を必要とする多くの詳細を処理する必要があるため、WM 拡張 API またはページャーを使用するライブラリは私のアドバイスです。

于 2013-05-10T02:03:02.290 に答える
3

@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;
}
于 2013-05-10T01:16:07.427 に答える
2

はい、X Windows プロトコルを使用してこれを行うことができます。これは非常に低レベルのプロトコルであるため、多少の作業が必要です。を使用xcb_query_treeして操作するウィンドウを見つけ、 で移動できxcb_configure_windowます。このページでは、その方法について詳しく説明します。これらの関数の元となるライブラリの使用に関する基本的なチュートリアルがありますが、Google でより良いライブラリを探したいと思うでしょう。

気が遠くなるかもしれませんが、それほど悪くはありません。すべての xterms を 10px 右に移動する 50 行の C プログラムを次に示します。

#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;
}

エラーチェックやメモリ管理はなく、できることはかなり限られています。ただし、実行するウィンドウと実行する操作を指定するコマンド ライン オプションを追加することで、必要な機能を実行するプログラムに更新したり、汎用のヘルパー プログラムに変換したりするのは簡単です。

于 2013-05-09T20:36:40.280 に答える
0

コードでの解決策を特に探しているのではなく、デスクトップ環境で探しているように見えるので、そのようなデスクトップ環境でウィンドウの配置を処理するウィンドウ マネージャーの 1 つを調べる必要があります。

  1. KDE のKWin のウィンドウ属性

  2. Compiz (GNOME) には、CompizConfig 設定マネージャー アプリケーションに「ウィンドウ ルール」と「ウィンドウの配置」があります。たとえば、ここを参照してください

  3. このページの下部にある GUI ツールにリンクしていますが、Openbox を正しく理解するのはかなり難しいようです。

X を直接使用する場合の問題は、X 自体がデスクトップ環境 (パネル、ショートカットなど) について何も認識しないため、手動で補正する必要があることです。

これをグーグルで検索した後、これを行う簡単な方法を持つのは KDE だけであることに驚きました。

于 2013-05-10T08:58:37.033 に答える