chiark / gitweb /
08ef3b6de59f103672108061380092722599198e
[xtoys] / xrepaint.c
1 /* -*-c-*-
2  *
3  * Redraw the screen in case it's been trashed somehow
4  *
5  * (c) 2016 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the Edgeware X tools collection.
11  *
12  * X tools is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * X tools is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with X tools; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37 #include <X11/Xlib.h>
38
39 #include <mLib/alloc.h>
40 #include <mLib/mdwopt.h>
41 #include <mLib/quis.h>
42 #include <mLib/report.h>
43
44 /*----- Global variables --------------------------------------------------*/
45
46 static Display *dpy;
47
48 /*----- Main code ---------------------------------------------------------*/
49
50 static void version(FILE *fp)
51   { pquis(fp, "$ (xtoys version " VERSION ")\n"); }
52
53 static void usage(FILE *fp)
54   { pquis(fp, "Usage: $ [-as] [-d display]\n"); }
55
56 static void help(FILE *fp)
57 {
58   version(fp);
59   fputc('\n', fp);
60   usage(stdout);
61   fputs("\n\
62 Repaint the X display (or just one screen).\n\
63 \n\
64 Options:\n\
65 \n\
66 -h, --help              Display this help text\n\
67 -u, --usage             Display a short usage summary\n\
68 -v, --version           Display the program's version number\n\
69 \n\
70 -a, --all               Repaint all of the screens on the display\n\
71 -d, --display=DISPLAY   Choose X display to connect to\n\
72 -s, --screen            Only repaint the selected screen\n",
73         fp);
74 }
75
76 static Window cover_screen(Screen *sc)
77 {
78   /* Make, map, and return a window completely covering the screen SC. */
79
80   Window w;
81   XSetWindowAttributes attr;
82
83   attr.background_pixel = 0;
84   attr.event_mask = StructureNotifyMask | VisibilityChangeMask | ExposureMask | KeyPressMask | ButtonPressMask;
85   attr.override_redirect = True;
86   w = XCreateWindow(dpy, RootWindowOfScreen(sc),
87                     0, 0, WidthOfScreen(sc), HeightOfScreen(sc),
88                     0, CopyFromParent, InputOutput,
89                     DefaultVisualOfScreen(sc),
90                     CWBackPixel | CWEventMask | CWOverrideRedirect, &attr);
91   XMapWindow(dpy, w);
92   return (w);
93 }
94
95 int main(int argc, char *argv[])
96 {
97   const char *display = 0;
98   unsigned f = 0;
99   struct timeval tv;
100   XEvent ev;
101   Window *win, w;
102   int i, n;
103
104 #define f_only 1u
105 #define f_bogus 2u
106
107   /* Parse command line options. */
108   ego(argv[0]);
109   for (;;) {
110     static struct option opt[] = {
111       { "help",         0,              0,      'h' },
112       { "usage",        0,              0,      'u' },
113       { "version",      0,              0,      'v' },
114       { "all",          0,              0,      'a' },
115       { "display",      OPTF_ARGREQ,    0,      'd' },
116       { "screen",       0,              0,      's' },
117       { 0,              0,              0,      0 }
118     };
119     int i = getopt_long(argc, argv, "huv" "ad:s", opt, 0);
120     if (i < 0) break;
121     switch (i) {
122       case 'h': help(stdout); exit(0); break;
123       case 'u': usage(stdout); exit(0); break;
124       case 'v': version(stdout); exit(0); break;
125       case 'a': f &= ~f_only; break;
126       case 'd': display = optarg; break;
127       case 's': f |= f_only; break;
128       default: f |= f_bogus; break;
129     }
130   }
131   if (optind < argc) f |= f_bogus;
132   if (f & f_bogus) { usage(stderr); exit(EXIT_FAILURE); }
133
134   /* Open the display. */
135   dpy = XOpenDisplay(display);
136   if (!dpy) { die(EXIT_FAILURE, "couldn't open display"); }
137
138   /* Annoyingly, `XClearWindow' uses `ClipByChildren' semantics, and there's
139    * no way to change that.  The best idea I can come up with is to drop
140    * windows over the top of each screen and take them away again.  The
141    * latter part is easy because they'll disappear when we close the
142    * display.
143    *
144    * Start by making and mapping the windows.
145    */
146   n = f&f_only ? 1 : ScreenCount(dpy);
147   win = xmalloc(n*sizeof(Window));
148   if (f&f_only)
149     win[0] = cover_screen(DefaultScreenOfDisplay(dpy));
150   else for (i = 0; i < n; i++)
151     win[i] = cover_screen(ScreenOfDisplay(dpy, i));
152
153   /* Now we wait until they're all obviously mapped. */
154   while (n) {
155     XNextEvent(dpy, &ev);
156     switch (ev.type) {
157       case MapNotify:
158         w = ev.xmap.window; goto window_visible;
159       case VisibilityNotify: case Expose: case KeyPress: case ButtonPress:
160         w = ev.xany.window; goto window_visible;
161       window_visible:
162         for (i = 0; i < n; i++)
163           if (w == win[i]) { win[i] = win[--n]; break; }
164         break;
165     }
166   }
167
168   /* Finally, we must wait for a bit longer.  This is an awful hack. */
169   tv.tv_sec = 0; tv.tv_usec = 50*1000;
170   select(0, 0, 0, 0, &tv);
171
172   /* All done. */
173   XCloseDisplay(dpy);
174   return (0);
175 }
176
177 /*----- That's all, folks -------------------------------------------------*/