chiark / gitweb /
xrepaint.c: Map all of the windows, and then wait for them all.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 24 Apr 2022 11:16:34 +0000 (12:16 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 24 Apr 2022 11:25:07 +0000 (12:25 +0100)
This will be faster on displays with multiple screens.  If anyone still
has one of those.

xrepaint.c

index 5a454a8599fd1c187b319f9856a0aac50efcefda..b957650d69253aa417d49a982e290dc14f1ce59e 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <X11/Xlib.h>
 
+#include <mLib/alloc.h>
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
 #include <mLib/report.h>
@@ -72,18 +73,12 @@ Options:\n\
        fp);
 }
 
-static void repaint(Screen *sc)
+static Window cover_screen(Screen *sc)
 {
-  /* Repaint the screen SC.
-   *
-   * Annoyingly, `XClearWindow' uses `ClipByChildren' semantics, and there's
-   * no way to change that.  The best idea I can come up with is to drop
-   * another window in front and take it away again.
-   */
+  /* Make, map, and return a window completely covering the screen SC. */
 
   Window w;
   XSetWindowAttributes attr;
-  XEvent ev;
 
   attr.background_pixel = 0;
   attr.event_mask = StructureNotifyMask | VisibilityChangeMask | ExposureMask | KeyPressMask | ButtonPressMask;
@@ -94,8 +89,7 @@ static void repaint(Screen *sc)
                    DefaultVisualOfScreen(sc),
                    CWBackPixel | CWEventMask | CWOverrideRedirect, &attr);
   XMapWindow(dpy, w);
-  do XNextEvent(dpy, &ev);
-  while (ev.type != Expose && ev.type != KeyPress && ev.type != ButtonPress);
+  return (w);
 }
 
 int main(int argc, char *argv[])
@@ -103,7 +97,9 @@ int main(int argc, char *argv[])
   const char *display = 0;
   unsigned f = 0;
   struct timeval tv;
-  int i;
+  XEvent ev;
+  Window *win, w;
+  int i, n;
 
 #define f_only 1u
 #define f_bogus 2u
@@ -139,15 +135,35 @@ int main(int argc, char *argv[])
   dpy = XOpenDisplay(display);
   if (!dpy) { die(EXIT_FAILURE, "couldn't open display"); }
 
-  /* Do the repainting thing. */
-  if (f & f_only)
-    repaint(DefaultScreenOfDisplay(dpy));
-  else {
-    for (i = 0; i < ScreenCount(dpy); i++)
-      repaint(ScreenOfDisplay(dpy, i));
+  /* Annoyingly, `XClearWindow' uses `ClipByChildren' semantics, and there's
+   * no way to change that.  The best idea I can come up with is to drop
+   * windows over the top of each screen and take them away again.  The
+   * latter part is easy because they'll disappear when we close the
+   * display.
+   *
+   * Start by making and mapping the windows.
+   */
+  n = f&f_only ? 1 : ScreenCount(dpy);
+  win = xmalloc(n*sizeof(Window));
+  if (f&f_only)
+    win[0] = cover_screen(DefaultScreenOfDisplay(dpy));
+  else for (i = 0; i < n; i++)
+    win[i] = cover_screen(ScreenOfDisplay(dpy, i));
+
+  /* Now we wait until they're all obviously mapped. */
+  while (n) {
+    XNextEvent(dpy, &ev);
+    switch (ev.type) {
+      case Expose: case KeyPress: case ButtonPress:
+       w = ev.xany.window; goto window_visible;
+      window_visible:
+       for (i = 0; i < n; i++)
+         if (w == win[i]) { win[i] = win[--n]; break; }
+       break;
+    }
   }
 
-  /* Wait for a bit.  This is an awful hack. */
+  /* Finally, we must wait for a bit longer.  This is an awful hack. */
   tv.tv_sec = 0; tv.tv_usec = 50*1000;
   select(0, 0, 0, 0, &tv);