Почему Каир не рисует на первой итерации цикла? - PullRequest
0 голосов
/ 03 июня 2018

Я работаю над библиотекой, которая создает прозрачные окна X и использует 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, чтобы перехватывать только нажатия клавиш / кнопок.Окно отображается до того, как новый поток пользовательского интерфейса запускается из основного потока.

Когда интервал между итерациями в потоке пользовательского интерфейса (значение self->inteval выше) большой (порядок секунд), окно остаетсяПрозрачный на первой итерации цикла, и он рисуется только со второй итерации.Вызов draw прямо перед циклом while не помогает, если между вызовами draw не происходит пауза в несколько миллисекунд.Например, если я поставлю interval = 25 прямо перед циклом while, то второй вызов draw раскроет окно в большинстве выполнений приложения, реализующего этот код.

То, что я пробовал:

  • cairo_surface_flush и XFlush сразу после draw, похоже, не работает
  • Отправка Expose события не 'Кажется, это тоже не помогает.

Как я могу убедиться, что мой цикл начинает рисовать в окне с первой итерации?

Ответы [ 2 ]

0 голосов
/ 03 июня 2018

Для меня это выглядит так, как будто вы отображаете окно, а затем немедленно запускаете поток, который пытается нарисовать окно.Таким образом, если вы попытаетесь нарисовать до того, как оконный менеджер фактически сделает окно видимым, ваш рисунок ни к чему не приведет.Если оконный менеджер выигрывает гонку, и окно фактически становится видимым до вашего розыгрыша, рисунок действительно работает.

Ваш собственный ответ не является ответом на ваш вопрос.Вопрос в том, почему он остается прозрачным на первой итерации?в то время как ваш ответ (в основном) «Не используйте потоки, просто делайте все рисование в основном цикле».(Конечно, обработка событий Expose - это правильно, но вопрос не в этом.)

0 голосов
/ 03 июня 2018

Мне не хватает только флага ExposureMask при вызове XSelectInput.С этим установленным флагом необходимо искать Expose события в цикле событий со следующим шаблоном:

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

Операция перерисовки не должна быть полным набором операций рисования.Изменив контекст Каира, достаточно перекрасить его в месте назначения, указав не более этого

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);
}
...