简体   繁体   English

如何使用XCB绘制标题栏

[英]How to draw titlebar with XCB

I am working on a simple window manager in c with libxcb and I am trying to decorate a window with a titlebar, icon and min/max/close buttons. 我正在使用libxcb在c中创建一个简单的窗口管理器,我正在尝试使用标题栏,图标和最小/最大/关闭按钮来装饰窗口。

I test my wm in Xephyr. 我在Xephyr测试我的wm。 I can spawn a new xterm window, move it around and resize it. 我可以生成一个新的xterm窗口,移动它并调整它的大小。 But now I would like to decorate the new xterm window (or any other app for that matter), so that it has a titlebar, icon and min/max/close buttons. 但现在我想装饰新的xterm窗口(或任何其他应用程序),以便它有一个标题栏,图标和最小/最大/关闭按钮。

On my Linux machine I've just installed a Gtk theme, and if I launch Firefox for example, the window gets decorated after I set that theme in my settings. 在我的Linux机器上,我刚刚安装了一个Gtk主题,如果我以Firefox为例,那么在我在我的设置中设置该主题后,窗口就会被装饰。 So in that case I think it's Gtk that applies the window decorations. 所以在这种情况下,我认为应用窗户装饰的是Gtk。 How does this work? 这是如何运作的?

I read that the EWMH window property, _NET_WM_WINDOW_TYPE , can be used to determine how to handle decorating your window. 我读到EWMH窗口属性_NET_WM_WINDOW_TYPE可用于确定如何处理窗口的装饰。 So I think I could check if the window type is _NET_WM_WINDOW_TYPE_NORMAL , get the WM_NAME from the app and then manually draw a titlebar on top of it. 所以我想我可以检查窗口类型是否为_NET_WM_WINDOW_TYPE_NORMAL ,从应用程序中获取WM_NAME ,然后在其上面手动绘制标题栏。

Is this how you should draw your window decorations normally? 这是你应该如何正常绘制窗饰? Or can I use Gtk (or something else) for this? 或者我可以使用Gtk(或其他东西)吗?

So in that case I think it's Gtk that applies the window decorations. 所以在这种情况下,我认为应用窗户装饰的是Gtk。 How does this work? 这是如何运作的?

Correct. 正确。 GTK apps tell the window manager not to decorate them by setting the border width to 0. For now my suggestion would be to only implement that: if the window sets a border width of 0, ignore decorations for it. GTK应用程序告诉窗口管理器不要通过将边框宽度设置为0来装饰它们。现在我的建议是仅实现:如果窗口设置边框宽度为0,则忽略它的装饰。 I wouldn't bother with anything else in the beginning. 我一开始不打扰任何其他事情。 In fact you could even ignore this hint for now. 事实上,你现在甚至可以忽略这个提示。

I read that the EWMH window property […] 我读到了EWMH窗口属性[...]

Don't bother with EWMH for now. 现在不要打扰EWMH。 Just decorate all managed windows which don't set the border to 0. Besides, I don't see a good reason for why other window types like dialogs shouldn't be decorated; 只是装饰所有未设置边框的托管窗口。此外,我没有看到为什么不应该装饰其他窗口类型(如对话框)的充分理由; I don't think window managers really use this property to determine that, but I can only say for sure for a couple. 我不认为窗口管理器真的使用这个属性来确定,但我只能肯定地说一对。

Is this how you should draw your window decorations normally? 这是你应该如何正常绘制窗饰? Or can I use Gtk (or something else) for this? 或者我可以使用Gtk(或其他东西)吗?

While you didn't explicitly ask for this, the last sentence in this quote tells me you might not fully understand how decorations work. 虽然你没有明确要求这个,但这句话中的最后一句话告诉我你可能不完全理解装饰是如何工作的。 The most common way, and I strongly recommend you do it like this, is called reparenting . 最常见的方式,我强烈建议你做这样的,被称为重排根

Reparenting means that when you manage a window, you create a new window (which of course you should not manage like a normal client window) called the frame window and then reparent the client window into your frame window. 重新显示意味着当您管理窗口时,您创建一个新窗口(当然您不应该像普通客户端窗口那样管理)称为框架窗口,然后将客户端窗口重新显示到框架窗口中。 So the actual top-level window is the frame window owned by the window manager; 所以实际的顶级窗口是窗口管理器拥有的框架窗口; the client window (the window the user interacts with) is the direct child of it. 客户端窗口(用户与之交互的窗口)是它的直接子节点。

Now you simply make the frame window slightly larger than the client window and position the client window correctly within it. 现在,您只需使框架窗口略大于客户端窗口,并在其中正确定位客户端窗口。 Of course you need to track resizes of the client window and act upon them. 当然,您需要跟踪客户端窗口的大小调整并对其进行操作。

So why did we create this frame window? 那我们为什么要创建这个框架窗口呢? Simple! 简单! Because you can create a pixmap that you use for it and on which you draw your titlebar. 因为您可以创建一个用于它的像素图,并在其上绘制标题栏。 This is better than drawing directly onto the child window because you don't mess with a window you don't actually own. 这比直接绘制到子窗口更好,因为您不会弄乱您实际上没有的窗口。

Drawing can be done with "raw" and simple calls like xcb_poly_fill_rectangle or you can use a more sophisticated approach by, eg, using a library like cairo (which I would recommend). 绘图可以使用“原始”和简单的调用来完成,例如xcb_poly_fill_rectangle或者您可以使用更复杂的方法,例如,使用像cairo这样的库(我建议)。 The i3 window manager, for example, uses a simple abstraction which supports both via compile flag (libi3/draw_util.c). 例如,i3窗口管理器使用一个简单的抽象,它支持via compile flag(libi3 / draw_util.c)。

This reparenting approach is the reason why tools such a xwininfo or xprop have a -frame option. 这种重排根的办法就是为什么工具这样的理由xwininfoxprop-frame选项。 By default, these tools actually ignore the frame window and descend into the client window, pretty much hiding the fact that there is a frame window. 默认情况下,这些工具实际上忽略了框架窗口并下降到客户端窗口,几乎隐藏了存在框架窗口的事实。 Just try xprop and xprop -frame on the same window and you'll see that the frame window has much less information attached to it. 只需在同一个窗口上尝试xpropxprop -frame ,您就会看到框架窗口附加的信息要少得多。

Once you have reparenting and drawing in place you can think more about cases where you don't need / want to decorate a window. 一旦你进行了重新定位和绘图,你可以更多地思考你不需要/想要装饰窗户的情况。 Given that there's quite a bit to keep track of here I think implementing this at first will keep you busy for a while. 鉴于此处有相当多的记录,我认为首先实现这一点会让你忙碌一段时间。 I strongly recommend studying the code of other simple window managers which reparent. 我强烈建议研究其他简单窗口管理器的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM