X11: How to delay repainting until all events are processed?

前端 未结 2 1881
误落风尘
误落风尘 2020-12-12 01:15

I\'m writing a program that has an X11/Xlib interface, and my event processing loop looks like this:

while (XNextEvent(display, &ev) >= 0) {
    switc         


        
相关标签:
2条回答
  • 2020-12-12 01:37

    FWIW a UI toolkit such as GTK+ does it this way:

    • for each window, maintains a "damage region" (union of all expose events)
    • when the damage region becomes non-empty, adds an "idle handler" which is a function the event loop will run when it doesn't have anything else to do
    • the idle handler will run when the event queue is empty AND the X socket has nothing to read (according to poll() on ConnectionNumber(dpy))
    • the idle handler of course repaints the damage region

    In GTK+, they're changing this over to a more modern 3D-engine oriented way (clean up the damage region on vertical sync) in a future version, but it's worked in the fairly simple way above for many years.

    When translated to raw Xlib, this looks about like n.m.'s answer: repaint when you have a damage region and !XPending(). So feel free to accept that answer I just figured I'd add a little extra info.

    If you wanted things like timers and idles, you could consider something lke libev http://software.schmorp.de/pkg/libev.html it's designed to just drop a couple of source files in your app (it isn't set up to be an external dependency). You would add the display's file descriptor to the event loop.

    For tracking damage regions, people often cut-and-paste the file "miregion.c" which is from the "machine independent" code in the X server. Just google for miregion.c or download the X server sources and look for it. A "region" here is simply a list of rectangles which supports operations such as union and intersect. To add damage, union it with the old region, to repair damage, subtract it, etc.

    0 讨论(0)
  • 2020-12-12 01:40

    Try something like the following (not actually tested):

    while (TRUE) {
      if (XPending(display) || !pendingRedraws) {
        // if an event is pending, fetch it and process it
        // otherwise, we have neither events nor pending redraws, so we can
        // safely block on the event queue
        XNextEvent (display, &ev);
        if (isExposeEvent(&ev)) {
          pendingRedraws = TRUE;
        }
        else {
          processEvent(&ev);
        }
      }
      else {
        // we must have a pending redraw
        redraw();
        pendingRedraws = FALSE;
      }
    }
    

    It could be beneficial to wait for 10 ms or so before doing the redraw. Unfortunately the raw Xlib has no interface for timers. You need a higher-level toolkit for that (all toolkits including Xt have some kind of timer interface), or work directly with the underlying socket of the X11 connection.

    0 讨论(0)
提交回复
热议问题