【问题标题】:How to manipulate application windows on linux with C/C++如何使用 C/C++ 在 linux 上操作应用程序窗口
【发布时间】:2019-01-25 02:20:15
【问题描述】:

如果这是一个愚蠢的问题,我对 C 语言没有太多经验,很抱歉。 我正在编写一个将监视和操作应用程序窗口的应用程序,我需要弄清楚如何执行以下操作:

  • 获取所有应用程序窗口的列表
  • 在调整窗口大小时收到通知
  • 在用户最大化/最小化窗口时收到通知
  • 设置应用程序窗口的大小和位置。

我花了很长时间搜索谷歌,但没有找到任何有用的东西。语言并不重要,因为我可以让这个项目使用 C 或 C++ 甚至 C# 任何帮助,将不胜感激。

【问题讨论】:

标签: c++ c linux user-interface


【解决方案1】:

Linux 上的窗口由 X11 (X Window System https://en.wikipedia.org/wiki/X_Window_System, https://en.wikipedia.org/wiki/X.Org_Server) 和 X Window 管理器如 Enlightenment (https://en.wikipedia.org/wiki/Comparison_of_X_window_managers) 和工具处理以及像 xdotoolXlib ( https://www.lemoda.net/c/xlib-resize/ ...) 这样的库。

X11 是 linux 上的低(est)级应用程序窗口处理

在此 X11 基础上,您通常使用 Qt 或 GTK+ 框架编写包含窗口的程序,在这两个框架中都实现了执行您提到的所有任务的方法 (What should I choose: GTK+ or Qt?)

重要的是已安装的 X Windows 管理器 (https://en.wikipedia.org/wiki/Comparison_of_X_window_managers)。在上层的 Qt 和 GTK+ 框架中,只能使用由底层 X 窗口管理器实现的函数

在 Qt 和 GTK 中调整窗口事件捕获:

可以使用Xlib库中的XQueryTree函数查询所有打开的X窗口的列表

(How to get the list of open windows from xserver)

xwininfo (https://linux.die.net/man/1/xwininfo) 可用于收集有关打开窗口的信息

【讨论】:

  • 一直在研究您的建议(顺便说一句,谢谢) 我已经知道如何使用 xdotool 移动/调整窗口大小,但在实际检测窗口更改时遇到了一些麻烦。我有您链接的示例 gtk 代码,但仅适用于应用程序自己的窗口。我找不到从所有活动应用程序窗口中检测事件的方法。
  • 不在家用手机写这么短的东西。在 GTK 中,任何像调整大小这样的事件都由 信号和事件 以及它们触发的回调函数来处理。多个窗口的示例位于 gamedev.net/forums/topic/427117-gtk-and-multiple-windows 中,有关信号请参见stackoverflow.com/questions/1060039/…中的链接
  • zetcode.com/gui/gtk2/gtkevents 中包含有关 GTK 信号和事件的代码信息
  • 对不起,我不认为是在同一页上。您链接的页面显示了如何处理应用程序打开的多个窗口。但我想听听不是由我的应用程序创建的其他窗口。例如,假设用户移动/调整 chrome 窗口的大小。我想听那个活动。
  • 这仅在使用 xdotool 或类似工具直接从 X 服务器捕获低级 X11 事件时才有可能。 GTK 级别更高,仅限于自己的应用程序
【解决方案2】:

编辑:当我第一次回答这个问题时,我只是在想别的东西。其实你要的很简单。

这是一个潜在的解决方案。

  1. 注册创建/销毁/调整窗口大小事件 (XCB_EVENT_MASK_STRUCTURE_NOTIFY),以便您可以跟上新添加/销毁/调整大小的窗口。根据您的设置,您可能需要添加 XCB_EVENT_MASK_PROPERTY_CHANGE 以便您可以判断是否设置了“最小化”或“最大化”属性。

  2. 查询 _NET_CLIENT_LIST(即通过 xcb_ewmh_get_client_list)或使用 XQueryTree 获取所有(应用程序)窗口。前者会给你一个过滤列表,它可能是“应用程序窗口”的超集。后者会给你每一个窗口,这可能会比你想要的更多。

  3. 发送configure request 调整窗口大小。正如其他人所说,xdotool 可用于发送这些请求。请注意,一般来说,这些请求很可能被 WM 阻止/修改。如果您不拥有该窗口,则除非您的 WM 允许,否则没有好的方法可以解决此问题。如果您确实拥有该窗口,则可以在该窗口上设置override redirect 字段。

下面是一个关于如何监听事件的代码示例(遵守 -lxcb)。请注意,这只是一个示例,您可能希望在 switch 语句中过滤事件(即您不想要所有属性)

void main(){
//create connection using default display
xcb_connection_t* dis = xcb_connect(NULL, NULL);
if(xcb_connection_has_error(dis))
    exit(1);

xcb_screen_t*screen=xcb_setup_roots_iterator(xcb_get_setup(dis)).data;
int root = screen->root;
int mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE;
if(xcb_request_check(dis,xcb_change_window_attributes_checked(dis, root,XCB_CW_EVENT_MASK, &mask)))
    exit(1);//an error occured

while(1){
    xcb_generic_event_t *event;
    event = xcb_wait_for_event(dis);
    switch(event->response_type){
        case XCB_CREATE_NOTIFY:
            printf("New window\n");
            break;
        case XCB_DESTROY_NOTIFY:
            printf("Window deleted\n");
            break;
        case XCB_PROPERTY_NOTIFY:
            printf("Window property change\n");
            break;
        case XCB_CONFIGURE_NOTIFY:
            printf("Window size has changed\n");
            break;
    }
}

}

如果您是 X11 的新手,我个人推荐 xcb 而不是 Xlib,因为它更易于调试,但这只是个人喜好。你可以使用其中一个或两个。还要记住,X11 api 已经被移植到许多语言,比如 python,所以你不会被 C 所困。

查看您的 cmets,是的,DE/WM 会影响您的代码。不确定你的用例或你想走多远,但你可以

  • 切换 WM(有很多选择)
  • 在没有运行 WM 的沙盒中运行
  • 查看您的 WM 是否可以将某些窗口列入白名单以便您可以直接修改它们或查看您的 WM 是否可编写脚本/允许您在运行某些事件时添加挂钩
  • 编写自己的 WM。您可以收到有关您关心的每个事件的通知,但您必须做您想做的所有其他事情,所以这将是很多工作

我承认 X 编程可能有一些学习曲线,但它会变得更好。

【讨论】:

  • XCB 并不是进入 X 编程的简单方法。它暴露了许多被 Xlib API 隐藏的细节。因此更容易看出哪里出了问题。不幸的是,这并不容易理解为什么:)。
  • @rubenvb 当归结为给定行错误的原因时,我可以看到您关于 xcb 并不比 Xlib 更好的观点。可能必须查找错误代码或获取错误字符串,然后以任何一种方式查找错误。
  • 还有一点需要提一下,Xlib 实际上已经被重写为使用xcb,因此很少有应用程序会因为被写入访问而变得更好/更快/更可靠直接xcb。此外,在 xcb 方面花费了大量时间编写每个 API 和文档的错误消息非常有限。根据我的经验,写 xlib 要好得多。遗憾的是,X 可能不会再存在了,因为 RedHat 和 Ubuntu 默认提供 Wayland,而 wlroots 距离像 xlib 那样提供完整的桌面独立 API 还有很长的路要走......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-05
  • 1970-01-01
  • 2015-10-20
  • 1970-01-01
  • 2012-06-26
相关资源
最近更新 更多