为什么 cairo 不在循环的第一次迭代中绘制?

Why doesn't cairo draw on first iteration of loop?

我正在开发一个创建透明 X windows 并使用 cairo 在其上绘制的库。在主线程中实现了一个事件循环,而绘图操作在循环中的单独线程中进行。后者看起来像这样

  while (self->_running) {
    PyGILState_Release(gstate);
    usleep(1000); // Sleep 1 ms
    gstate = PyGILState_Ensure();

    if (self->_expiry <= gettime()) {
      draw(self, args_tuple); // All the cairo code is in here
      self->_expiry += interval;
      interval = self->interval;
    }
  }

事件循环定期调用 XNextEvent 以仅捕获 key/button 按下。 window 在新的 UI 线程从主线程启动之前被映射。

当 UI 线程(上面的 self->inteval 值)上的迭代间隔很大(秒级)时,window 在线程的第一次迭代中保持透明循环,它只会从第二次迭代开始被绘制。在 while 循环之前调用 draw 没有帮助,除非在调用 draw 之间有几毫秒的暂停。例如,如果我将 interval = 25 放在 while 循环之前,那么对 draw 的第二次调用会在 most[=36= 中的 window 上绘制] 执行此代码的应用程序的执行次数。

我尝试过的事情:

  • cairo_surface_flushdraw 之后的 XFlush 似乎不起作用
  • 发送 Expose 事件似乎也无济于事。

如何确保我的循环从第一次迭代开始在 window 上绘制?

我缺少的是 XSelectInput 调用中的 ExposureMask 标志。设置此标志后,必须使用以下模式在事件循环中查找 Expose 事件:

  switch (e.type) {
  case Expose:
    if (e.xexpose.count == 0) {
      BaseCanvas__redraw(canvas);
    }
    return;
  }

重绘操作不需要是全套的绘制操作。修改了cairo context,在destination重绘就够了,不超过这个

void
BaseCanvas__redraw(BaseCanvas * self) {
  cairo_save(self->context);
  cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
  cairo_paint(self->context);
  cairo_restore(self->context);
}

在我看来,您正在映射 window,然后立即启动一个尝试绘制到 window 的线程。因此,如果您尝试在 window 管理器实际使 window 可见之前绘制,您的绘图将无处可去。如果 window 经理赢得了比赛,并且 window 实际上在您抽签前变得可见,则该抽奖确实有效。

您自己的回答不是您问题的答案。问题是 "why does it stay transparent in the first iteration?",而你的答案(基本上)是 "Don't use threads, just do all drawing in the main loop"。 (当然,处理 Expose 事件是正确的做法,但这不是问题所问的。)