前一段时间,我用C语言编写了一个脚本,使用Windows API函数EnumWindows,SetWindowPos和SetForegroundWindow按照我通常想要的布局自动排列窗口(按标题)。
有这些function的Linux等价物吗? 我将使用Kubuntu,因此KDE特定和/或Ubuntu特定的解决scheme都可以。
最好的方法是在窗口管理器本身(如果你的支持扩展的话)或者支持“寻呼机”的协议和提示(寻呼机=任何非窗口管理器进程来完成窗口的组织和导航)。
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或者寻呼机图书馆将是我的建议。
是的,你可以使用X Windows协议来做到这一点。 这是一个非常低级的协议,所以需要一些工作。 您可以使用xcb_query_tree
来查找要操作的窗口,然后使用xcb_query_tree
来移动它。 本页提供了一些关于如何做的细节。 有一个关于使用这些函数库的基本教程 ,但您可能希望Google更好。
这似乎令人生畏,但也不算太坏。 这是一个50行的C程序,将所有xterm的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; }
没有错误检查或内存管理,它可以做的是非常有限的。 但是应该直接更新一个你想要的程序,或者把它变成一个通用的帮助程序,通过添加命令行选项来指定要操作哪个窗口以及对它们执行哪些操作。
@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; }
因为看起来你不是专门寻找代码解决方案,而是在桌面环境中寻找解决方案,所以你需要看看在这样的桌面环境中处理窗口放置的窗口管理器之一。
KDE的KWin的窗口属性
Compiz(GNOME)在CompizConfig Settings Manager应用程序中具有“窗口规则”和“放置Windows”。 看这里例如
尽管Openbox链接到本页底部的GUI工具,但看起来Openbox似乎更难以正确使用。
直接使用X的问题在于X本身对桌面环境(面板,快捷方式等)一无所知,您必须手动进行补偿。
谷歌搜索后,我很惊讶KDE是唯一有一个简单的方法来做到这一点。