--- /dev/null
+.\" -*-nroff-*-
+.TH xrepaint 1 "10 January 2016" "Straylight/Edgeware" "xtoys"
+.SH NAME
+xrepaint \- force repainting of X display, or just one screen
+.SH SYNOPSIS
+.B xrepaint
+.RB [ \-as ]
+.RB [ \-d
+.IR display ]
+.SH DESCRIPTION
+The
+.B xrepaint
+program forces a repaint of the entire X display,
+or maybe just a single screen.
+.PP
+Options are as follows.
+.TP
+.B "\-a, \-\-all"
+Repaint all of the screens on the display.
+This is the default.
+.TP
+.BI "\-d, \-\-display=" display
+Sets the X display to connect to.
+The default comes from the
+.B DISPLAY
+environment variable,
+as usual.
+.TP
+.B "\-s, \-\-screen"
+Repaint only the default screen selected by
+.IR display .
+The default is to repaint all of the screens.
+.SH BUGS
+If a compositing manager is present,
+then
+.B xrepaint
+forces recompositing of the screen,
+but if some client has painted rubbish into its window,
+it won't be forced to repaint it.
+.PP
+The current approach is fundamentally incorrect.
+It doesn't seem possible to know when I've actually succeeded
+in forcing a repaint of the display.
+.PP
+The current behaviour seems to be good enough for the author's purposes.
+.SH AUTHOR
+Mark Wooding <mdw@distorted.org.uk>
--- /dev/null
+/* -*-c-*-
+ *
+ * Redraw the screen in case it's been trashed somehow
+ *
+ * (c) 2016 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Edgeware X tools collection.
+ *
+ * X tools is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * X tools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with X tools; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+/*----- Global variables --------------------------------------------------*/
+
+static Display *dpy;
+
+/*----- Main code ---------------------------------------------------------*/
+
+static void version(FILE *fp)
+ { pquis(fp, "$ (xtoys version " VERSION ")\n"); }
+
+static void usage(FILE *fp)
+ { pquis(fp, "Usage: $ [-as] [-d display]\n"); }
+
+static void help(FILE *fp)
+{
+ version(fp);
+ fputc('\n', fp);
+ usage(stdout);
+ fputs("\n\
+Repaint the X display (or just one screen).\n\
+\n\
+Options:\n\
+\n\
+-h, --help Display this help text\n\
+-u, --usage Display a short usage summary\n\
+-v, --version Display the program's version number\n\
+\n\
+-a, --all Repaint all of the screens on the display\n\
+-d, --display=DISPLAY Choose X display to connect to\n\
+-s, --screen Only repaint the selected screen\n",
+ fp);
+}
+
+static void repaint(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.
+ */
+
+ Window w;
+ XSetWindowAttributes attr;
+ XEvent ev;
+
+ attr.background_pixel = 0;
+ attr.event_mask = StructureNotifyMask | VisibilityChangeMask | ExposureMask | KeyPressMask | ButtonPressMask;
+ attr.override_redirect = True;
+ w = XCreateWindow(dpy, RootWindowOfScreen(sc),
+ 0, 0, WidthOfScreen(sc), HeightOfScreen(sc),
+ 0, CopyFromParent, InputOutput,
+ DefaultVisualOfScreen(sc),
+ CWBackPixel | CWEventMask | CWOverrideRedirect, &attr);
+ XMapWindow(dpy, w);
+ do XNextEvent(dpy, &ev);
+ while (ev.type != Expose && ev.type != KeyPress && ev.type != ButtonPress);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *display = 0;
+ unsigned f = 0;
+ struct timeval tv;
+ int i;
+
+#define f_only 1u
+#define f_bogus 2u
+
+ /* Parse command line options. */
+ ego(argv[0]);
+ for (;;) {
+ static struct option opt[] = {
+ { "help", 0, 0, 'h' },
+ { "usage", 0, 0, 'u' },
+ { "version", 0, 0, 'v' },
+ { "all", 0, 0, 'a' },
+ { "display", OPTF_ARGREQ, 0, 'd' },
+ { "screen", 0, 0, 's' },
+ { 0, 0, 0, 0 }
+ };
+ int i = getopt_long(argc, argv, "huv" "ad:s", opt, 0);
+ if (i < 0) break;
+ switch (i) {
+ case 'h': help(stdout); exit(0); break;
+ case 'u': usage(stdout); exit(0); break;
+ case 'v': version(stdout); exit(0); break;
+ case 'a': f &= ~f_only; break;
+ case 'd': display = optarg; break;
+ case 's': f |= f_only; break;
+ default: f |= f_bogus; break;
+ }
+ }
+ if (optind < argc) f |= f_bogus;
+ if (f & f_bogus) { usage(stderr); exit(EXIT_FAILURE); }
+
+ /* Open the display. */
+ 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));
+ }
+
+ /* Wait for a bit. This is an awful hack. */
+ tv.tv_sec = 0; tv.tv_usec = 50*1000;
+ select(0, 0, 0, 0, &tv);
+
+ /* All done. */
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/