所以在这种情况下,我认为是Gtk应用了窗口装饰。这是怎么做到的呢?
没错。GTK应用程序通过将边框宽度设置为0,告诉窗口管理器不要对其进行装饰。现在我的建议是只实现这一点:如果窗口设置了边框宽度为0,则忽略其装饰。起初我不会费心去做其他事情。实际上,你甚至可以暂时忽略这个提示。
我读到了EWMH窗口属性[...]。
暂时不要关注EWMH。只需为所有未设置边框为0的受管理窗口进行装饰。此外,我不认为像对话框这样的其他窗口类型不应该被装饰;我不认为窗口管理器真正使用这个属性来确定这一点,但我只能确切地说几个。
这是你通常应该绘制窗口装饰的方式吗?还是我可以使用Gtk(或其他东西)来完成?
虽然你没有明确要求这样做,但这个引文中的最后一句话告诉我你可能并没有完全理解装饰的工作原理。
最常见的方法,我强烈建议你这样做,叫做重新父化。
重新父化意味着当你管理一个窗口时,你创建一个新窗口(当然你不应该像正常客户端窗口那样管理它)称为框架窗口,然后将客户端窗口重新父化到你的框架窗口中。所以实际的顶层窗口是由窗口管理器拥有的框架窗口;客户端窗口(用户交互的窗口)是其直接子代。
现在,你只需要使框架窗口比客户端窗口稍微大一点,并在其中正确定位客户端窗口。当然,你需要跟踪客户端窗口的大小调整并对其进行操作。
那么我们为什么要创建这个框架窗口呢?很简单!因为你可以为它创建一个像素图,并在上面绘制你的标题栏。这比直接绘制子窗口好,因为你不会干扰你实际上不拥有的窗口。
绘图可以使用“原始”和简单的调用,如xcb_poly_fill_rectangle,或者你可以使用更复杂的方法,例如使用cairo这样的库(我建议这样做)。例如,i3窗口管理器使用一个简单的抽象层,通过编译标志支持两种方法(libi3/draw_util.c)。
这种重新父化的方法是工具如xwininfo或xprop具有“-frame”选项的原因。默认情况下,这些工具实际上会忽略框架窗口并进入客户端窗口,几乎隐藏了框架窗口的存在事实。只需在同一窗口上尝试xprop和xprop -frame,你就会发现框架窗口附加的信息要少得多。
一旦您已经实现了重新父级和绘图,您可以考虑那些不需要/不想装饰窗口的情况。鉴于这里要跟踪的内容相当多,我认为首先实施这个功能将让您忙碌一段时间。我强烈建议您学习其他简单窗口管理器的代码,其中包括重新父级。