[英]How to redraw only portions of an entire cairo layout in awesome-wm?
注意:我需要这些信息,因为我正在为 awesome-wm 开发一个替代小部件库。
简而言之,如何仅重绘 cairo 绘图的一部分以进行布局?
在查看 wibox/drawable.lua 和 wibox/hierarchy.lua 中的源代码后,据我了解,当元素更新时(假设元素的布局发生变化),重绘方式如下:
hierarchy:draw
的 function 中,绘制发生了,在这里我假设只有被更改的小部件被重绘,然后,由于先前应用了掩码,只有这些部分将 go 通过掩码并成为“重绘”在最终图像上。 如果这就是重绘发生的方式,那么我也想实现类似的东西。 如果没有,我很乐意得到纠正。
我面临的问题是我对开罗的缺乏经验和困惑。 作为答案,我最欣赏的是一个注释代码块,其中包含此更新-布局-重绘过程的简化版本。
好的,所以......是的......首先:你的描述对我来说很好。
我将扩展您的观点:
首先,从无效元素到其子孙等重新计算布局。
是的。 这是通过wibox.hierachy:update
完成的。 这里重要的部分是这个 function 将self._dirty_area
作为它的参数。 这是一个cairo 区域,基本上是像素对齐的矩形列表(cairo 会自动删除重叠)。
其次,基于这些重新布局的元素创建了一堆蒙版,当它们重叠时将被“组合”,然后用于跳过未更改的绘图部分。
是的,嗯。 开罗地区的代码在构建该地区时已经删除了所有重叠。
您声明的 rest 似乎是正确的。 这里的代码首先检查是否有任何东西可以绘制:
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 使用类似双缓冲的东西)。
另一个重要的成分是 function empty_clip
。 这在wibox.hierarchy:draw()
中使用以跳过所有绘图,如果它会被完全剪掉: https://github.com/awesomeWM/awesome/blob/6ca2fbb31c5cdf50b946b50f3f814f39a8f1lucafbe/#338。
(哦,好吧,当然为了防止小部件在其“分配区域”之外绘制,代码首先将所有绘图剪辑到小部件的区域。只有在此之后它才检查空剪辑,从而有效地检查小部件是否覆盖任何我们的“需要重新绘制”区域。)
另一个可能重要的成分:绘图代码使用cr:save()
/ cr:restore()
。 restore()
恢复上次save()
时存在的 state。 这包括剪辑区域。 这是撤消:clip()
的唯一好方法(另一种方法是:reset_clip()
但会删除整个剪辑区域,因此不仅撤消最后一个:clip()
,而且撤消所有这些)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.