I'm working on a library that creates transparent X windows and uses cairo to draw on them. There is an event loop implemented in the main thread, while the drawing operations take place in a separate thread within a loop. The latter looks like this
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;
}
}
The event loop calls XNextEvent periodically to trap key/button presses only. The window is mapped before the new UI thread is started from the main thread.
When the interval between iterations on the UI thread (the self->inteval
value above) is large (order of seconds), the window stays transparent on the first iteration of the loop, and it only gets painted on from the second iteration onward. Calling draw
right before the while
loop doesn't help, unless there is a pause of some milliseconds in between calls to draw
. For example, if I put interval = 25
right before the while
loop, then the second call to draw
paints on the window in most of the executions of the application implementing this code.
Things that I have tried:
cairo_surface_flush
and XFlush
right after draw
don't seem to workExpose
event doesn't seem to help either.How can I make sure that my loop starts painting on the window from the first iteration?
What I'm missing is the ExposureMask
flag in the call to XSelectInput
. With this flag set, one then has to look for Expose
events in the event loop with the following pattern:
switch (e.type) {
case Expose:
if (e.xexpose.count == 0) {
BaseCanvas__redraw(canvas);
}
return;
}
The redraw operation doesn't need to be the full set of draw operations. Having modified the cairo context, it is enough to repaint it on the destination with no more than this
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);
}