chiark / gitweb /
xrepaint.c: Break an absurdly long line.
[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 =
85     StructureNotifyMask | VisibilityChangeMask | ExposureMask |
86     KeyPressMask | ButtonPressMask;
87   attr.override_redirect = True;
88   w = XCreateWindow(dpy, RootWindowOfScreen(sc),
89                     0, 0, WidthOfScreen(sc), HeightOfScreen(sc),
90                     0, CopyFromParent, InputOutput,
91                     DefaultVisualOfScreen(sc),
92                     CWBackPixel | CWEventMask | CWOverrideRedirect, &attr);
93   XMapWindow(dpy, w);
94   return (w);
95 }
96
97 int main(int argc, char *argv[])
98 {
99   const char *display = 0;
100   unsigned f = 0;
101   struct timeval tv;
102   XEvent ev;
103   Window *win, w;
104   int i, n;
105
106 #define f_only 1u
107 #define f_bogus 2u
108
109   /* Parse command line options. */
110   ego(argv[0]);
111   for (;;) {
112     static struct option opt[] = {
113       { "help",         0,              0,      'h' },
114       { "usage",        0,              0,      'u' },
115       { "version",      0,              0,      'v' },
116       { "all",          0,              0,      'a' },
117       { "display",      OPTF_ARGREQ,    0,      'd' },
118       { "screen",       0,              0,      's' },
119       { 0,              0,              0,      0 }
120     };
121     int i = getopt_long(argc, argv, "huv" "ad:s", opt, 0);
122     if (i < 0) break;
123     switch (i) {
124       case 'h': help(stdout); exit(0); break;
125       case 'u': usage(stdout); exit(0); break;
126       case 'v': version(stdout); exit(0); break;
127       case 'a': f &= ~f_only; break;
128       case 'd': display = optarg; break;
129       case 's': f |= f_only; break;
130       default: f |= f_bogus; break;
131     }
132   }
133   if (optind < argc) f |= f_bogus;
134   if (f & f_bogus) { usage(stderr); exit(EXIT_FAILURE); }
135
136   /* Open the display. */
137   dpy = XOpenDisplay(display);
138   if (!dpy) { die(EXIT_FAILURE, "couldn't open display"); }
139
140   /* Annoyingly, `XClearWindow' uses `ClipByChildren' semantics, and there's
141    * no way to change that.  The best idea I can come up with is to drop
142    * windows over the top of each screen and take them away again.  The
143    * latter part is easy because they'll disappear when we close the
144    * display.
145    *
146    * Start by making and mapping the windows.
147    */
148   n = f&f_only ? 1 : ScreenCount(dpy);
149   win = xmalloc(n*sizeof(Window));
150   if (f&f_only)
151     win[0] = cover_screen(DefaultScreenOfDisplay(dpy));
152   else for (i = 0; i < n; i++)
153     win[i] = cover_screen(ScreenOfDisplay(dpy, i));
154
155   /* Now we wait until they're all obviously mapped. */
156   while (n) {
157     XNextEvent(dpy, &ev);
158     switch (ev.type) {
159       case MapNotify:
160         w = ev.xmap.window; goto window_visible;
161       case VisibilityNotify: case Expose: case KeyPress: case ButtonPress:
162         w = ev.xany.window; goto window_visible;
163       window_visible:
164         for (i = 0; i < n; i++)
165           if (w == win[i]) { win[i] = win[--n]; break; }
166         break;
167     }
168   }
169
170   /* Finally, we must wait for a bit longer.  This is an awful hack. */
171   tv.tv_sec = 0; tv.tv_usec = 50*1000;
172   select(0, 0, 0, 0, &tv);
173
174   /* All done. */
175   XCloseDisplay(dpy);
176   return (0);
177 }
178
179 /*----- That's all, folks -------------------------------------------------*/