前段时间我在C中编写了一个脚本,它使用Windows API函数EnumWindows,SetWindowPos和SetForegroundWindow来自动排列我常用的特定布局中的窗口(按标题)。
这些功能是否有Linux等价物?我将使用Kubuntu,因此特定于KDE和/或Ubuntu的解决方案都可以。
答案 0 :(得分:5)
执行此操作的最佳方法是在窗口管理器本身(如果您的支持扩展)或使用旨在支持“寻呼机”的协议和提示(寻呼机=任何窗口组织或导航的非窗口管理器进程)的东西)。
EWMH规范包含一个供寻呼机使用的_NET_MOVERESIZE_WINDOW。 http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2731465
Raw Xlib或Xcb非常粗糙,但有一个名为libwnck的库,专门用于处理你正在讨论的事情。 (我很久以前就编写了原始库,但它一直由其他人维护。)即使你不使用它,也请阅读代码以了解如何处理这些内容。 KDE可能与KDE风格的API相当,我不确定。
不需要使用任何KDE或GNOME或分发特定的东西,因为所需的东西都是在EWMH中拼写出来的。也就是说,对于某些窗口管理器来说,这样做作为扩展可能比编写单独的应用程序更容易。
直接使用旧学校的X电话当然可以工作但是有很多细节要处理,如果你想解决所有的错误和角落案件需要大量的专业知识,在我看来,所以使用WM扩展API或寻呼机库是我的建议。
答案 1 :(得分: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;
}
没有错误检查或内存管理,它可以做的是非常有限的。但是,通过添加命令行选项来指定要对哪些窗口进行操作以及对它们执行哪些操作,应该直接更新到执行所需操作的程序,或将其转换为通用帮助程序。
答案 2 :(得分: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;
}
答案 3 :(得分:0)