如何在真棒wm中仅重绘整个开罗布局的一部分?



注意:我需要这些信息,因为我正在为awesome-wm开发一个替代的小部件库。

简而言之,如何仅为布局重绘开罗绘图的一部分?

在查看了wibox/drawable和wibox/hierarchy.lua中的源代码后.lua据我所知,当一个元素被更新时(假设一个元素的布局发生了变化),重新绘制的方式如下:

  • 首先,重新计算布局,从无效元素开始,直到它的子项等。
  • 其次,基于这些重新布局的元素创建一堆蒙版,当它们重叠时,这些蒙版将被"组合",并在以后用于跳过绘图中没有更改的绘图部分。
  • 然后,在另一个名为hierarchy:draw的函数中,绘图发生,在这里我假设只有更改的小部件被重新绘制,然后,由于之前应用了蒙版,只有这些部分会穿过蒙版并在最终图像上"重新绘制"。

如果这就是重绘发生的方式,那么我也想实现类似的东西。如果没有,我很乐意得到纠正.
我面临的问题是我对开罗的经验不足和困惑。作为答案,我最感激的是一个注释的代码块,其中包含此更新-布局-重绘过程的略读简化版本。

好的,所以...是的。。。首先:你的描述对我来说很好。

我将对您的观点进行一些扩展:

首先,重新计算布局,从无效元素开始,直到它的子项等。

是的。这是通过wibox.hierachy:update完成的。这里重要的部分是这个函数self._dirty_area作为它的参数。这是一个开罗地区,基本上是一个像素对齐矩形的列表(开罗会自动删除重叠)。

其次,基于这些重新布局的元素创建一堆蒙版,当它们重叠时,这些蒙版将被"组合",并在以后用于跳过绘图中没有更改的绘图部分。

是的,好吧。开罗地区的代码在构建区域时已经删除了所有重叠。

你陈述的其余部分似乎是正确的。这里的代码首先检查是否有任何要绘制的内容:

if self._dirty_area:is_empty() then
return
end

以上调用cairo_region_is_empty.

接下来,它将每个矩形添加到当前路径:

for i = 0, self._dirty_area:num_rectangles() - 1 do
local rect = self._dirty_area:get_rectangle(i)
cr:rectangle(rect.x, rect.y, rect.width, rect.height)
end

它清除了_dirty_area,以便从现在开始,所有"需要重新绘制的东西"都在一个新的、最初为空的区域中进行跟踪:

self._dirty_area = cairo.Region.create()

最后,它剪辑到我们刚刚添加的矩形:

cr:clip()

什么是剪辑?让我们问一下文档:

当前剪辑区域

通过有效地遮罩当前剪辑区域之外的图面所做的任何更改来影响所有绘制操作。

基本上:所有绘图只会在(以前的)self._dirty_area内进行。试图在此之外绘制根本没有效果。

接下来,drawable.lua中的代码绘制背景,调用self._widget_hierarchy:draw()进行实际绘制,最后调用self.drawable:refresh()。最后一段代码实际上是使绘图可见的原因(AwesomeWM使用类似于双缓冲的东西)。

另一个重要成分是功能empty_clip.这在wibox.hierarchy:draw()中用于跳过所有绘图,如果它会被完全剪掉:https://github.com/awesomeWM/awesome/blob/6ca2fbb31c5cdf50b946b50f3f814f39a8f1cfbe/lib/wibox/hierarchy.lua#L338

(哦,当然,为了防止小部件在其"指定区域"之外绘制,代码首先将所有绘图剪辑到小部件的区域。只有在之后,它才会检查空剪辑,从而有效地检查小部件是否覆盖了我们的任何"需要重绘"区域。

另一个可能重要的成分:绘图代码使用cr:save()/cr:restore()restore()恢复上一次save()时存在的状态。这包括剪辑区域。这是撤消:clip()的唯一好方法(另一种方法是:reset_clip()但会删除整个剪辑区域,因此不仅不会撤消最后一个:clip(),而是撤消所有剪辑区域)。

最新更新