如何使用XCB在新应用程序启动时获取事件

4
我正在尝试制作一个非常简单的窗口管理器以进行学习。我使用C和xcb库。我正在尝试在启动新应用程序时触发事件。
目前,我创建了一个根窗口,可以接收鼠标和键盘事件。我还在窗口顶部绘制了一个彩色条形。当我按下回车键时,使用fork和execvp启动xterm。这一切都很好地运行。
当xterm(或我认为的任何应用程序)启动时,它会在条形之上绘制(x = 0,y = 0)。我想将其稍微向下移动(x = 0,y = 16)。我认为我知道如何移动窗口,使用xcb_configure_window。但我不知道如何获取新启动应用程序的事件。
编辑:经过一些尝试,我得出了以下结论: 如果我像这样创建我的父窗口:
xcb_window_t window_root = screen->root;
uint32_t mask = 0;    
uint32_t values[2];
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(connection, window_root, mask, values);
xcb_flush(connection);

当我生成一个新的终端时,我将会通过XCB_CREATE_NOTIFY收到通知。然而,我无法在屏幕上绘制任何东西,因为我没有"订阅" XCB_EVENT_MASK_EXPOSE 事件。如果我将values[0]行更改为以下内容:
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE;

我仍然会收到创建事件,但是当程序启动时不会立即调用暴露事件,因此我的工具栏不会绘制。 但是,只要我启动新的终端,它就会获得一个暴露事件,但我的初始绘图不会发生。

我创建父窗口的旧方法是:

xcb_window_t window = xcb_generate_id(connection);
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t values[2] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY };
xcb_create_window(connection, 0, window, screen->root, 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values);
xcb_map_window(connection, window);

这将绘制一个白色背景并绘制我的彩色条,因为它立即获取了 XCB_EVENT_MASK_EXPOSURE 事件。但它不会收到 XCB_CREATE_NOTIFY 事件。

那么正确的方法是什么,以便同时获取 XCB_CREATE_NOTIFY 事件和 XCB_EVENT_MASK_EXPOSURE 事件?


@JoachimPileborg 感谢您的评论。我尝试使用XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,因为我在其他WM的代码中读到了类似的内容,但是我在我的事件循环中从未收到任何XCB_MAP_REQUEST或XCB_MAP_NOTIFY事件。我更新了我的帖子并提供了更多信息。 - Carlito
我在今年早些时候使用Python和XCB制作了一个非常简单的窗口管理器。除了XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY之外,我还使用了XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECTXCB_EVENT_MASK_STRUCTURE_NOTIFY - Some programmer dude
你只是将它们添加到了父窗口的掩码中吗?我现在正在尝试这样做,但没有结果。也许我需要一种不同的方法来生成一个新的终端?有可能让我看看你的代码吗? - Carlito
我已经为根窗口设置了所有这些。 - Some programmer dude
@JoachimPileborg,我现在使用XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY取得了一些进展,但是我无法获得暴露事件。这可能取决于我如何创建根窗口。我在我的帖子中更新了一些代码。你是如何创建你的根窗口的? - Carlito
1个回答

4

我有些愚蠢,但我已经解决了!

我以为只有在启动新终端后才会收到曝光事件。但在进入事件循环之前,我甚至没有绘制我的栏和背景,我只在XCB_EXPOSE循环中绘制它们。因此,当启动新的终端时,曝光事件将被调用,我的栏和背景出现了。

现在我将绘图函数放在事件循环之前,一切都像应该的那样工作了。我不知道这是否是正确/最佳的方法,但供以后参考,使用以下内容创建您的根屏幕:

xcb_window_t window_root = screen->root;
uint32_t mask = 0;    
uint32_t values[2];
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(connection, window_root, mask, values);
xcb_flush(connection);

你将获得暴露事件,并且新启动的程序将出现在事件中。

你的事件循环是什么样子的,例如用于捕获 EXPOSE 事件? - smac89

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接