1 /* testx11.c, Copyright (c) 2015-2017 Dave Odell <dmo2118@gmail.com>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or
9  * implied warranty.
10  *
11  * This is a test for X11 drawing primitives for the non-X11 ports of
12  * XScreenSaver. It shouldn't normally be installed with the other screenhacks.
13  *
14  * Almost no error checking in here. This is intentional.
15  */
16 
17 #include "screenhack.h"
18 #include "glx/rotator.h"
19 #include "colorbars.h"
20 #include "erase.h"
21 
22 #include "ximage-loader.h"
23 #include "images/gen/logo-180_png.h"
24 
25 #include <assert.h>
26 #include <errno.h>
27 
28 #ifndef HAVE_JWXYZ
29 # define jwxyz_XSetAntiAliasing(dpy, gc, p)
30 #endif
31 
32 #ifndef jwxyz_assert_display
33 # define jwxyz_assert_display(dpy)
34 #endif
35 
36 #define countof(a) (sizeof(a) / sizeof(*(a)))
37 
38 static const char *testx11_defaults [] = {
39   ".background: #a020f0", /* purple */
40   ".foreground: white",
41 #ifdef HAVE_MOBILE
42   "*ignoreRotation: True",
43 #endif
44   0
45 };
46 
47 static XrmOptionDescRec testx11_options [] = {
48   { 0, 0, 0, 0 }
49 };
50 
51 enum
52 {
53   mode_welcome,
54   mode_primitives,
55   mode_images,
56   mode_copy,
57   mode_preserve,
58   mode_erase,
59 
60   mode_count
61 };
62 
63 struct testx11 {
64   Display *dpy;
65   Window win;
66 
67   XWindowAttributes xgwa;
68 
69 # ifndef HAVE_JWXYZ
70   Pixmap backbuffer;
71 # endif
72 
73   unsigned mode;
74 
75   /* Pixels from XAllocPixel. */
76   unsigned long rgb[3], salmon, magenta, gray50, dark_slate_gray1, cyan;
77 
78   unsigned frame;
79 
80   Bool anti_alias_p;
81 
82   /* These X11 objects aren't altered after creation, except for:
83      - copy_gc and thick_line_gc get anti-aliasing toggled.
84      - xor_gc's clip mask (if it's turned on) always covers the entire window.
85    */
86   GC copy_gc, mono_gc, thick_line_gc, xor_gc, graph_gc;
87   Pixmap clip_mask_tile;
88 
89   /* Backdrop stuff, naturally. */
90   GC backdrop_black_gc;
91   Pixmap backdrop_tile, backdrop_scratch;
92   XColor backdrop_colors[64];
93   int backdrop_ncolors;
94 
95   /* The following items may be modified by various test modes. */
96   Pixmap primitives_mini_pix;
97 
98   GC images_point_gc;
99 
100   Pixmap copy_pix64;
101 
102   Pixmap preserve[2];
103 
104   eraser_state *erase;
105 
106   rotator *rot;
107 };
108 
109 
110 static void
abort_no_mem(void)111 abort_no_mem (void)
112 {
113   fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
114   abort();
115 }
116 
117 static void
check_no_mem(void * ptr)118 check_no_mem (void *ptr)
119 {
120   if(!ptr)
121     abort_no_mem();
122 }
123 
124 
125 static unsigned long
alloc_color(struct testx11 * st,unsigned short r,unsigned short g,unsigned short b)126 alloc_color (struct testx11 *st,
127              unsigned short r, unsigned short g, unsigned short b)
128 {
129   XColor color;
130   color.red = r;
131   color.green = g;
132   color.blue = b;
133   color.flags = DoRed | DoGreen | DoBlue;
134   XAllocColor (st->dpy, st->xgwa.colormap, &color);
135   return color.pixel;
136 }
137 
138 static void
create_backbuffer(struct testx11 * st)139 create_backbuffer(struct testx11 *st)
140 {
141 # ifndef HAVE_JWXYZ
142   st->backbuffer = XCreatePixmap (st->dpy, st->win,
143                                   st->xgwa.width, st->xgwa.height,
144                                   st->xgwa.depth);
145 # endif
146 }
147 
148 static Bool
toggle_antialiasing(struct testx11 * st)149 toggle_antialiasing (struct testx11 *st)
150 {
151   st->anti_alias_p ^= True;
152   jwxyz_XSetAntiAliasing (st->dpy, st->copy_gc, st->anti_alias_p);
153   jwxyz_XSetAntiAliasing (st->dpy, st->thick_line_gc, st->anti_alias_p);
154   return True;
155 }
156 
157 
158 static void
primitives_mini_rect(struct testx11 * st,Drawable t,int x,int y)159 primitives_mini_rect(struct testx11 *st, Drawable t, int x, int y)
160 {
161   XFillRectangle(st->dpy, t, st->copy_gc, x, y, 2, 2);
162 }
163 
164 static void
images_copy_test(Display * dpy,Drawable src,Drawable dst,GC gc,int src_y,int dst_x,int dst_y,unsigned long cells)165 images_copy_test (Display *dpy, Drawable src, Drawable dst, GC gc,
166                   int src_y, int dst_x, int dst_y, unsigned long cells)
167 {
168   XCopyArea(dpy, src, dst, gc, 0, src_y, 3, 2, dst_x, dst_y);
169 
170   {
171     XImage *image = XGetImage(dpy, src, 0, src_y, 3, 2, cells, ZPixmap);
172     XPutImage(dpy, dst, gc, image, 0, 0, dst_x, dst_y + 2, 3, 2);
173     XDestroyImage(image);
174   }
175 }
176 
177 static void
images_pattern(struct testx11 * st,Drawable d,unsigned y)178 images_pattern (struct testx11 *st, Drawable d, unsigned y)
179 {
180   unsigned x;
181   for (x = 0; x != 3; ++x) {
182     XSetForeground(st->dpy, st->images_point_gc, st->rgb[x]);
183     XDrawPoint(st->dpy, d, st->images_point_gc, x, y);
184     XSetForeground(st->dpy, st->images_point_gc, st->rgb[2 - x]);
185     XFillRectangle(st->dpy, d, st->images_point_gc, x, y + 1, 1, 1);
186   }
187 
188   images_copy_test (st->dpy, d, d, st->images_point_gc, y, 0, y + 2,
189                     st->rgb[0] | st->rgb[1] | st->rgb[2]);
190 }
191 
192 static const unsigned tile_size = 16;
193 static const unsigned tile_count = 8;
194 
195 static const unsigned preserve_size = 128;
196 
197 static void
make_clip_mask(struct testx11 * st)198 make_clip_mask (struct testx11 *st)
199 {
200   /* Activate this for extra Fun! */
201 # if 0
202   /* This is kind of slow, but that's OK, because this only happens on int
203      or during a resize.
204    */
205   unsigned w = st->xgwa.width, h = st->xgwa.height;
206   unsigned x, y;
207   Pixmap mask = XCreatePixmap (st->dpy, st->clip_mask_tile, w, h, 1);
208 
209   for (y = 0; y < h; y += 8) {
210     for (x = 0; x < w; x += 8) {
211       XCopyArea (st->dpy, st->clip_mask_tile, mask, st->mono_gc,
212                  0, 0, 8, 8, x, y);
213     }
214   }
215 
216   XSetClipMask (st->dpy, st->xor_gc, mask);
217   XFreePixmap (st->dpy, mask);
218 # endif
219 }
220 
221 
222 static void
colorbars(struct testx11 * st)223 colorbars (struct testx11 *st)
224 {
225   Pixmap logo_mask = 0;
226   Pixmap logo = image_data_to_pixmap (st->dpy, st->win,
227                                       logo_180_png, sizeof(logo_180_png),
228                                       0, 0, &logo_mask);
229   draw_colorbars (st->xgwa.screen, st->xgwa.visual, st->win,
230                   st->xgwa.colormap, 0, 0, st->xgwa.width, st->xgwa.height,
231                   logo, logo_mask);
232   XFreePixmap (st->dpy, logo);
233   XFreePixmap (st->dpy, logo_mask);
234 }
235 
236 
237 static void *
testx11_init(Display * dpy,Window win)238 testx11_init (Display *dpy, Window win)
239 {
240   static const char backdrop_pattern[] = {
241     '\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07', /* Zig */
242     '\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01', /* Zag */
243     '\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07', /* etc. */
244     '\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01',
245     '\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07',
246     '\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01',
247     '\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07',
248     '\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01',
249   };
250 
251   static const char clip_bits[] = {
252     '\x33', '\x33', '\xcc', '\xcc', '\x33', '\x33', '\xcc', '\xcc'
253   };
254 
255   struct testx11 *st = (struct testx11 *) malloc (sizeof(*st));
256   XGCValues gcv;
257 
258   check_no_mem (st);
259 
260   st->dpy = dpy;
261   st->win = win;
262 
263   XGetWindowAttributes (dpy, win, &st->xgwa);
264 
265   create_backbuffer (st);
266 
267   st->rgb[0]           = alloc_color (st, 0xffff, 0x0000, 0x0000);
268   st->rgb[1]           = alloc_color (st, 0x0000, 0xffff, 0x0000);
269   st->rgb[2]           = alloc_color (st, 0x0000, 0x0000, 0xffff);
270   st->salmon           = alloc_color (st, 0xffff, 0x7fff, 0x7fff);
271   st->magenta          = alloc_color (st, 0xffff, 0x0000, 0xffff);
272   st->gray50           = alloc_color (st, 0x8000, 0x8000, 0x8000);
273   st->dark_slate_gray1 = alloc_color (st, 0x8000, 0xffff, 0xffff);
274   st->cyan             = alloc_color (st, 0x0000, 0xffff, 0xffff);
275 
276   st->backdrop_tile = XCreatePixmapFromBitmapData (dpy, win,
277                                                    (char *) backdrop_pattern,
278                                                    tile_size, tile_size * 2,
279                                                    1, 0, 1);
280 
281   st->clip_mask_tile = XCreatePixmapFromBitmapData (dpy, win,
282                                                     (char *) clip_bits, 8, 8,
283                                                     1, 0, 1);
284 
285   {
286     unsigned s = tile_size * tile_count;
287     st->backdrop_scratch = XCreatePixmap (dpy, win, s, s, st->xgwa.depth);
288   }
289 
290   st->backdrop_ncolors = countof (st->backdrop_colors);
291   make_color_loop (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
292                    180, 1, 0.5, 210, 1, 0.5, 240, 1, 0.5,
293                    st->backdrop_colors, &st->backdrop_ncolors, True, NULL);
294 
295   st->frame = 0;
296 
297 # ifdef HAVE_ANDROID
298   st->mode = mode_primitives;
299 # else
300   st->mode = mode_welcome;
301 # endif
302 
303   st->anti_alias_p = False;
304 
305   gcv.function = GXcopy;
306   gcv.foreground = st->cyan;
307   gcv.background = st->magenta;
308   gcv.line_width = 0;
309   gcv.cap_style = CapRound;
310   /* TODO: Real X11 uses fixed by default. */
311   gcv.font = XLoadFont (dpy, "fixed");
312   st->copy_gc = XCreateGC (dpy, win,
313                            GCFunction | GCForeground | GCBackground
314                              | GCLineWidth | GCCapStyle | GCFont, &gcv);
315 
316   gcv.foreground = BlackPixelOfScreen (st->xgwa.screen);
317   st->backdrop_black_gc = XCreateGC (dpy, win, GCForeground, &gcv);
318 
319   gcv.foreground = alloc_color (st, 0x8000, 0x4000, 0xffff);
320   gcv.line_width = 8;
321   gcv.cap_style = CapProjecting;
322   st->thick_line_gc = XCreateGC (dpy, win,
323                                  GCForeground | GCLineWidth | GCCapStyle,
324                                  &gcv);
325 
326   gcv.function = GXxor;
327   st->xor_gc = XCreateGC (dpy, win, GCFunction, &gcv);
328 
329   st->images_point_gc = XCreateGC (dpy, win, 0, NULL);
330 
331   st->graph_gc = XCreateGC (dpy, win, 0, &gcv);
332 
333   st->mono_gc = XCreateGC (dpy, st->clip_mask_tile, 0, &gcv);
334 
335   st->copy_pix64 = XCreatePixmap(dpy, win, 64, 64, st->xgwa.depth);
336 
337   st->primitives_mini_pix = XCreatePixmap (dpy, win, 16, 24, st->xgwa.depth);
338 
339   {
340     static const char text[] = "Welcome from testx11_init().";
341     colorbars (st);
342     XDrawString (dpy, win, st->copy_gc, 16, 16, text, countof (text) - 1);
343   }
344 
345   make_clip_mask (st);
346 
347   st->preserve[0] =
348     XCreatePixmap(dpy, win, preserve_size, preserve_size, st->xgwa.depth);
349   st->preserve[1] =
350     XCreatePixmap(dpy, win, preserve_size, preserve_size, st->xgwa.depth);
351 
352   toggle_antialiasing (st);
353 
354   st->erase = NULL;
355 
356   jwxyz_assert_display (dpy);
357 
358   st->rot = make_rotator (2, 2, 2, 2, 0.01, False);
359   return st;
360 }
361 
362 
363 static void
backdrop(struct testx11 * st,Drawable t)364 backdrop (struct testx11 *st, Drawable t)
365 {
366   unsigned w = st->xgwa.width, h = st->xgwa.height;
367   unsigned x, y;
368 
369   for (y = 0; y != tile_count; ++y) {
370     const float s0 = 2 * M_PI / tile_count;
371     float y_fac = sin ((y + st->frame / 16.0) * s0);
372     for (x = 0; x != tile_count; ++x) {
373       int c = ((sin ((x + st->frame / 8.0) * s0) * y_fac) - 1) / 2 *
374               st->backdrop_ncolors / 2;
375       c = (c + st->frame) % st->backdrop_ncolors;
376       XSetBackground (st->dpy, st->backdrop_black_gc,
377                       st->backdrop_colors[c].pixel);
378       XCopyPlane (st->dpy, st->backdrop_tile, st->backdrop_scratch,
379                   st->backdrop_black_gc, 0, st->frame % tile_size,
380                   tile_size, tile_size, x * tile_size, y * tile_size, 1);
381     }
382   }
383 
384   /* XFillRectangle (st->dpy, t, st->backdrop_black_gc, 0, 0, w, h); */
385 
386   for (y = 0; y < h; y += tile_count * tile_size) {
387     for (x = 0; x < w; x += tile_count * tile_size) {
388       XCopyArea (st->dpy, st->backdrop_scratch, t, st->copy_gc, 0, 0,
389                  tile_count * tile_size, tile_count * tile_size, x, y);
390     }
391   }
392 }
393 
394 static const unsigned button_pad = 16;
395 static const unsigned button_size = 64;
396 
397 
398 static void
testx11_graph_rotator(struct testx11 * st)399 testx11_graph_rotator (struct testx11 *st)
400 {
401   double x, y, z;
402 
403   int boxw = st->xgwa.width / 3;
404   int boxh = (st->xgwa.height - (22 * 5)) / 4;
405   int boxx = st->xgwa.width - boxw - 20;
406   int boxy = st->xgwa.height - boxh - 20;
407 
408   /* position */
409 
410   get_position (st->rot, &x, &y, &z, True);
411   if (x < 0 || x >= 1 || y < 0 || y >= 1 || z < 0 || z >= 1) abort();
412 
413 
414   XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
415   XDrawRectangle (st->dpy, st->win, st->graph_gc,
416                   boxx-1, boxy-1, boxw+2, boxh+2);
417 
418   XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
419              boxx+1, boxy, boxw-1, boxh, boxx, boxy);
420 
421   XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
422   XDrawLine (st->dpy, st->win, st->graph_gc,
423              boxx + boxw - 1, boxy,
424              boxx + boxw - 1, boxy + boxh);
425 
426   XSetForeground (st->dpy, st->graph_gc, st->salmon);
427   XDrawPoint (st->dpy, st->win, st->graph_gc,
428               boxx + boxw - 1,
429               boxy + boxh - 1 - (int) (x * (boxh - 1)));
430 
431   XSetForeground (st->dpy, st->graph_gc, st->magenta);
432   XDrawPoint (st->dpy, st->win, st->graph_gc,
433               boxx + boxw - 1,
434               boxy + boxh - 1 - (int) (y * (boxh - 1)));
435 
436   XSetForeground (st->dpy, st->graph_gc, st->gray50);
437   XDrawPoint (st->dpy, st->win, st->graph_gc,
438               boxx + boxw - 1,
439               boxy + boxh - 1 - (int) (z * (boxh - 1)));
440 
441   /* spin */
442 
443   get_rotation (st->rot, &x, &y, &z, True);
444   if (x < 0 || x >= 1 || y < 0 || y >= 1 || z < 0 || z >= 1) abort();
445 
446   /* put 0 in the middle */
447   x += 0.5; if (x > 1) x--;
448   y += 0.5; if (y > 1) y--;
449   z += 0.5; if (z > 1) z--;
450 
451 
452   boxy -= boxh + 20;
453 
454   XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
455   XDrawRectangle (st->dpy, st->win, st->graph_gc,
456                   boxx-1, boxy-1, boxw+2, boxh+2);
457 
458   XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
459              boxx+1, boxy, boxw-1, boxh, boxx, boxy);
460 
461   XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
462   XDrawLine (st->dpy, st->win, st->graph_gc,
463              boxx + boxw - 1, boxy,
464              boxx + boxw - 1, boxy + boxh);
465 
466   XSetForeground (st->dpy, st->graph_gc, st->magenta);
467   XDrawPoint (st->dpy, st->win, st->graph_gc,
468               boxx + boxw - 1,
469               boxy + boxh - 1 - (int) (x * (boxh - 1)));
470 
471 
472   boxy -= boxh + 20;
473 
474   XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
475   XDrawRectangle (st->dpy, st->win, st->graph_gc,
476                   boxx-1, boxy-1, boxw+2, boxh+2);
477 
478   XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
479              boxx+1, boxy, boxw-1, boxh, boxx, boxy);
480 
481   XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
482   XDrawLine (st->dpy, st->win, st->graph_gc,
483              boxx + boxw - 1, boxy,
484              boxx + boxw - 1, boxy + boxh);
485 
486   XSetForeground (st->dpy, st->graph_gc, st->magenta);
487   XDrawPoint (st->dpy, st->win, st->graph_gc,
488               boxx + boxw - 1,
489               boxy + boxh - 1 - (int) (y * (boxh - 1)));
490 
491 
492   boxy -= boxh + 20;
493 
494   XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
495   XDrawRectangle (st->dpy, st->win, st->graph_gc,
496                   boxx-1, boxy-1, boxw+2, boxh+2);
497 
498   XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
499              boxx+1, boxy, boxw-1, boxh, boxx, boxy);
500 
501   XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
502   XDrawLine (st->dpy, st->win, st->graph_gc,
503              boxx + boxw - 1, boxy,
504              boxx + boxw - 1, boxy + boxh);
505 
506   XSetForeground (st->dpy, st->graph_gc, st->magenta);
507   XDrawPoint (st->dpy, st->win, st->graph_gc,
508               boxx + boxw - 1,
509               boxy + boxh - 1 - (int) (z * (boxh - 1)));
510 }
511 
512 
513 /* Draws a blinking box in what should be the upper left corner of the
514    device, as physically oriented. The box is taller than it is wide.
515  */
516 static void
testx11_show_orientation(struct testx11 * st)517 testx11_show_orientation (struct testx11 *st)
518 {
519 #ifdef HAVE_MOBILE
520   int x, y;
521   int w = st->xgwa.width;
522   int h = st->xgwa.height;
523   int ww = 15;
524   int hh = ww*2;
525   static int tick = 0;
526   static int oo = -1;
527   int o = (int) current_device_rotation ();
528 
529   if (o != oo) {
530 //    fprintf (stderr,"ROT %d -> %d\n", oo, o);
531     oo = o;
532   }
533 
534   switch (o) {
535   case    0: case  360: x = 0;    y = 0;    w = ww; h = hh; break;
536   case   90: case -270: x = 0;    y = h-ww; w = hh; h = ww; break;
537   case  -90: case  270: x = w-hh; y = 0;    w = hh; h = ww; break;
538   case  180: case -180: x = w-ww; y = h-hh; w = ww; h = hh; break;
539   default: return;
540   }
541 
542   if (++tick > 20) tick = 0;
543 
544   XSetForeground (st->dpy, st->graph_gc,
545                   (tick > 10
546                    ? WhitePixelOfScreen (st->xgwa.screen)
547                    : BlackPixelOfScreen (st->xgwa.screen)));
548   XFillRectangle (st->dpy, st->win, st->graph_gc,
549                   x, y, w, h);
550 #endif
551 }
552 
553 
554 static unsigned long
testx11_draw(Display * dpy,Window win,void * st_raw)555 testx11_draw (Display *dpy, Window win, void *st_raw)
556 {
557   struct testx11 *st = (struct testx11 *) st_raw;
558   unsigned w = st->xgwa.width, h = st->xgwa.height;
559 # ifdef HAVE_JWXYZ
560   Drawable t = win;
561 # else
562   Drawable t = st->mode == mode_primitives ? st->backbuffer : win;
563 # endif
564   unsigned i;
565 
566   assert (dpy == st->dpy);
567   assert (win == st->win);
568 
569   jwxyz_assert_display (dpy);
570 
571   XSetWindowBackground (dpy, win, st->gray50);
572 
573   switch (st->mode)
574   {
575   case mode_primitives:
576     backdrop (st, t);
577 
578     XDrawPoint (dpy, t, st->thick_line_gc, 0, 0);
579     XDrawPoint (dpy, t, st->thick_line_gc, 0, 1);
580     XDrawPoint (dpy, t, st->thick_line_gc, 1, 0);
581     XDrawPoint (dpy, t, st->thick_line_gc, 1, 1);
582 
583     primitives_mini_rect (st, t, 2, 0);
584     primitives_mini_rect (st, t, 0, 2);
585     primitives_mini_rect (st, t, 4, 2);
586     primitives_mini_rect (st, t, 2, 4);
587 
588     primitives_mini_rect (st, t, 30, -2);
589     primitives_mini_rect (st, t, 32, 0);
590 
591     primitives_mini_rect (st, t, 30, h - 2);
592     primitives_mini_rect (st, t, 32, h);
593 
594     primitives_mini_rect (st, t, -2, 30);
595     primitives_mini_rect (st, t, 0, 32);
596     primitives_mini_rect (st, t, w - 2, 30);
597     primitives_mini_rect (st, t, w, 32);
598 
599     primitives_mini_rect (st, t, w / 2 + 4, h / 2 + 4);
600 
601     XFillArc (dpy, t, st->copy_gc, 16, 16, 256, 256, 45 * 64, -135 * 64);
602     /* XCopyArea(dpy, t, t, st->copy_gc, 48, 48, 128, 128, 64, 64); */
603 
604     /* Center */
605     XDrawPoint (dpy, t, st->copy_gc, w / 2, h / 2);
606 
607     /* Top/bottom */
608     XDrawPoint (dpy, t, st->copy_gc, w / 2, 0);
609     XDrawPoint (dpy, t, st->copy_gc, w / 2, h - 1);
610 
611     XDrawPoint (dpy, t, st->copy_gc, 16, -1);
612     XDrawPoint (dpy, t, st->copy_gc, 17, 0);
613 
614     XDrawPoint (dpy, t, st->copy_gc, 15, h - 2);
615     XDrawPoint (dpy, t, st->copy_gc, 16, h - 1);
616     XDrawPoint (dpy, t, st->copy_gc, 17, h);
617 
618     {
619       XPoint *points = malloc (sizeof(XPoint) * h);
620       XSegment *lines = malloc (sizeof(XSegment) * h);
621       XPoint *points2 = malloc (sizeof(XPoint) * h);
622       for(i = 0; i != h; ++i)
623       {
624         points[i].x = 8 + (i & 1);
625         points[i].y = i;
626 
627         lines[i].x1 = 48 + (i & 1) * 4;
628         lines[i].y1 = i;
629         lines[i].x2 = 50;
630         lines[i].y2 = i;
631 
632         points2[i].x = 24 + (i & 1);
633         points2[i].y = i;
634         /* XFillRectangle(st->dpy, t, st->copy_gc, 24 + (i & 1), i, 1, 1); */
635       }
636 
637       XDrawPoints (dpy, t, st->copy_gc, points, h, CoordModeOrigin);
638       XDrawSegments (dpy, t, st->copy_gc, lines, h);
639       XDrawPoints (dpy, t, st->copy_gc, points2, h, CoordModeOrigin);
640       free (lines);
641       free (points);
642       free (points2);
643     }
644 
645     /* Left/right */
646     XDrawPoint (dpy, t, st->copy_gc, -1, 16);
647     XDrawPoint (dpy, t, st->copy_gc, 0, 17);
648     XDrawPoint (dpy, t, st->copy_gc, w - 1, 16);
649     XDrawPoint (dpy, t, st->copy_gc, w, 17);
650 
651     {
652       XPoint *points = malloc(sizeof(XPoint) * w);
653       XSegment *lines = malloc(sizeof(XSegment) * w);
654       XPoint *points2 = malloc(sizeof(XPoint) * w);
655       for(i = 0; i != w; ++i)
656       {
657         points[i].x = i;
658         points[i].y = 8 + (i & 1);
659         lines[i].x1 = i;
660         lines[i].y1 = 48 + (i & 1) * 4;
661         lines[i].x2 = i;
662         lines[i].y2 = 50;
663 
664         points2[i].x = i;
665         points2[i].y = 24 + (i & 1);
666         /* XFillRectangle(dpy, t, st->copy_gc, i, 24 + (i & 1), 1, 1); */
667       }
668 
669       XDrawPoints (dpy, t, st->copy_gc, points, w, CoordModeOrigin);
670       XDrawSegments (dpy, t, st->copy_gc, lines, w);
671       {
672         /* Thick purple lines */
673         XSegment seg[2] =
674         {
675           {31, 31, 31, 31}, /* TODO: This should not be rotated in Cocoa. */
676           {42, 31, 42, 42}
677         };
678         XDrawSegments (dpy, t, st->thick_line_gc, seg, 2);
679 
680         XDrawLine (dpy, t, st->thick_line_gc, 58, 43, 64, 43);
681         XDrawLine (dpy, t, st->thick_line_gc, 73, 43, 80, 43);
682       }
683 
684       XDrawPoints (dpy, t, st->copy_gc, points2, w, CoordModeOrigin);
685       free (points);
686       free (points2);
687       free (lines);
688     }
689 
690     XDrawLine (dpy, t, st->copy_gc, 54, 11, 72, 22);
691 
692     {
693       XPoint vertices[] = {{5, 5}, {5, 8}, {8, 8}, {8, 5}};
694       XFillPolygon (dpy, t, st->copy_gc, vertices, 4, Convex, CoordModeOrigin);
695     }
696 
697     {
698       XDrawRectangle (dpy, t, st->copy_gc, 11, 11, 11, 11);
699       XFillRectangle (dpy, t, st->copy_gc, 13, 13, 8, 8);
700     }
701 
702     /* Several ~16 pixel boxes in a row. */
703 
704     /* Box 0 */
705     {
706       XDrawRectangle (dpy, t, st->copy_gc, 54, 54, 16, 16);
707       XDrawRectangle (dpy, t, st->copy_gc, 55, 55, 14, 14);
708 
709       XDrawPoint (dpy, t, st->thick_line_gc, 56, 56);
710       XDrawPoint (dpy, t, st->copy_gc, 57, 56);
711     }
712 
713     /* Box 1 */
714     XCopyArea (dpy, t, t, st->copy_gc, 55, 55, 15, 15, 72, 55);
715 
716     /* Box 2 */
717     {
718       XImage *image = XGetImage(st->dpy, t, 55, 55, 15, 15, 0xffffff, ZPixmap);
719       XPutPixel(image, 2, 0, 0x00000000);
720       XPutImage (dpy, t, st->copy_gc, image, 0, 0, 88, 55, 15, 15);
721       XDestroyImage(image);
722     }
723 
724     /* Box 3 */
725 
726     {
727       XCopyArea (dpy, t, st->primitives_mini_pix, st->copy_gc,
728                  104, 55, 16, 16, 0, 0);
729       /* XCopyArea (dpy, t, st->primitives_mini_pix, st->copy_gc,
730                     105, 56, 14, 14, 1, 1);
731          XCopyArea (dpy, t, st->primitives_mini_pix, st->copy_gc,
732                     1, 1, 14, 14, 1, 1);
733        */
734 
735       /* This point gets hidden. */
736       XDrawPoint (dpy, t, st->copy_gc, 104 + 8, 55 + 8);
737 
738       XDrawPoint (dpy, st->primitives_mini_pix, st->copy_gc, 0, 0);
739       XDrawPoint (dpy, st->primitives_mini_pix, st->copy_gc, 1, 0);
740       XDrawPoint (dpy, st->primitives_mini_pix, st->copy_gc, 15, 15);
741       XDrawRectangle (dpy, st->primitives_mini_pix, st->copy_gc,
742                       1, 1, 13, 13);
743       XCopyArea (dpy, st->primitives_mini_pix, t, st->copy_gc,
744                  0, 0, 16, 16, 104, 55);
745     }
746 
747     {
748       XDrawLine (dpy, t, st->copy_gc, 11, 28, 22, 28);
749       XDrawLine (dpy, t, st->copy_gc, 12, 27, 12, 46);
750       XDrawLine (dpy, t, st->copy_gc, 14, 30, 14, 30);
751     }
752 
753     XDrawArc (dpy, t, st->copy_gc, 27, 11, 19, 11, 0, 360 * 64);
754 
755     XDrawRectangle (dpy, t, st->copy_gc, 54, 73, 64, 64);
756     XFillArc (dpy, t, st->copy_gc, 56, 75, 60, 60, 0, 360 * 64);
757     /* XDrawArc (dpy, t, st->thick_line_gc, 56, 75, 60, 60, 0, 360 * 64); */
758 
759     XClearArea (dpy, win, 121, 55, 16, 16, False);
760     break;
761 
762   case mode_images:
763     backdrop (st, t);
764 
765     /* if(w >= 9 && h >= 10) */
766     {
767 #ifdef HAVE_ANDROID
768       /* Draw below the status bar. */
769       const unsigned y = 64;
770 #else
771       const unsigned y = 0;
772 #endif
773 
774       Screen *screen = st->xgwa.screen;
775       Visual *visual = st->xgwa.visual;
776       Pixmap pixmap = XCreatePixmap (dpy, t, 3, 10,
777                                      visual_depth (screen, visual));
778       unsigned long cells = cells = st->rgb[0] | st->rgb[1] | st->rgb[2];
779 
780       {
781         XSetForeground (dpy, st->images_point_gc, st->salmon);
782         XDrawPoint (dpy, t, st->images_point_gc, 0, h - 1);
783         XDrawLine (dpy, t, st->images_point_gc, 0, y - 1, 8, y - 1);
784       }
785 
786       images_pattern (st, t, y);
787       images_pattern (st, pixmap, 0);
788       /* Here's a good spot to verify that the pixmap contains the right colors
789          at the top.
790        */
791       images_copy_test (dpy, t, pixmap, st->copy_gc, y, 0, 6, cells);
792 
793       XCopyArea (dpy, pixmap, t, st->copy_gc, 0, 0, 3, 10, 3, y);
794 
795       {
796         XImage *image = XGetImage (dpy, pixmap, 0, 0, 3, 10, cells, ZPixmap);
797         XPutImage (dpy, t, st->copy_gc, image, 0, 0, 6, y, 3, 10);
798         XDestroyImage (image);
799       }
800 
801       XFreePixmap (dpy, pixmap);
802       XSync (dpy, False);
803     }
804     break;
805 
806   case mode_copy:
807     backdrop (st, win);
808 
809     /* X.org isn't making a whole lot of sense here. */
810 
811     Bool use_copy = (st->frame / 20) & 1;
812 
813     {
814       GC gc = use_copy ? st->copy_gc : st->xor_gc;
815 
816       XSetWindowBackground (dpy, t, st->magenta);
817       XCopyArea (dpy, t, t, gc, -2, -2, 40, 40, 20, 20);
818 
819       if (!use_copy)
820         XCopyArea (st->dpy, t, t, gc, -20, h - 20, 40, 40, 20, h - 60);
821       XCopyArea (dpy, t, t, gc, w - 38, h - 38, 40, 40, w - 60, h - 60);
822       XCopyArea (dpy, t, t, gc, w - 20, -20, 40, 40, w - 60, 20);
823 
824       XSetWindowBackground (dpy, t, st->gray50);
825       XCopyArea (st->dpy, t, t, gc, -20, 64, 40, 40, 20, 64);
826 
827       XSetWindowBackground (dpy, t, st->dark_slate_gray1);
828       XCopyArea (st->dpy, t, t, gc, -20, 112, 40, 40, 20, 112);
829     }
830 
831     if (use_copy)
832     {
833       GC gc = st->copy_gc;
834       XCopyArea (st->dpy, t, st->copy_pix64, gc, 0, h - 64, 64, 64, 0, 0);
835 
836       XSetForeground (st->dpy, st->xor_gc, st->rgb[1]);
837       XSetBackground (st->dpy, st->xor_gc, st->cyan);
838 
839       /* XCopyArea (st->dpy, st->copy_pix64, st->copy_pix64, gc,
840                     32, 32, 64, 64, 0, 0);
841          XCopyArea (st->dpy, st->copy_pix64, t, gc, 0, 0, 64, 64, 4, h - 68);
842        */
843       XCopyArea (st->dpy, st->copy_pix64, t, gc, 32, 32, 128, 64, 0, h - 64);
844     }
845 
846     break;
847 
848   case mode_preserve:
849     backdrop (st, t);
850 
851     if(!(st->frame % 10)) {
852       const unsigned r = 16;
853       unsigned n = st->frame / 10;
854       unsigned m = n >> 1;
855       XFillArc (st->dpy, st->preserve[n & 1],
856                 m & 1 ? st->copy_gc : st->thick_line_gc,
857                 NRAND(preserve_size) - r, NRAND(preserve_size) - r,
858                 r * 2, r * 2, 0, 360 * 64);
859     }
860 
861     XCopyArea (st->dpy, st->preserve[0], t, st->copy_gc, 0, 0,
862                preserve_size, preserve_size, 0, 0);
863     XCopyArea (st->dpy, st->preserve[1], t, st->copy_gc, 0, 0,
864                preserve_size, preserve_size, preserve_size, 0);
865     XCopyArea (st->dpy, st->preserve[1], t, st->copy_gc, 0, 0,
866                preserve_size, preserve_size,
867                w - preserve_size / 2, preserve_size);
868     break;
869 
870   case mode_erase:
871     if (!st->erase)
872       colorbars (st);
873     st->erase = erase_window(st->dpy, st->win, st->erase);
874     break;
875   }
876 
877   /* Mode toggle buttons */
878   for (i = 1; i != mode_count; ++i) {
879     unsigned i0 = i - 1;
880     char str[32];
881     XRectangle button_dims;
882     button_dims.x = i0 * (button_pad + button_size) + button_pad;
883     button_dims.y = h - button_pad - button_size;
884     button_dims.width = button_size;
885     button_dims.height = button_size;
886     if (!st->mode)
887       XFillRectangles (dpy, t, st->backdrop_black_gc, &button_dims, 1);
888     XDrawRectangle (dpy, t, st->copy_gc, button_dims.x, button_dims.y,
889                     button_dims.width, button_dims.height);
890 
891     XDrawString (dpy, t, st->copy_gc,
892                  button_dims.x + button_size / 2 - 3,
893                  h - button_pad - button_size / 2 + 13 / 2,
894                  str, sprintf(str, "%u", i));
895   }
896 
897   if (t != win)
898     XCopyArea (dpy, t, win, st->copy_gc, 0, 0, w, h, 0, 0);
899 
900   testx11_graph_rotator (st);
901   testx11_show_orientation (st);
902 
903   ++st->frame;
904   return 1000000 / 20;
905 }
906 
907 static void
testx11_reshape(Display * dpy,Window window,void * st_raw,unsigned int w,unsigned int h)908 testx11_reshape (Display *dpy, Window window, void *st_raw,
909                  unsigned int w, unsigned int h)
910 {
911   struct testx11 *st = (struct testx11 *)st_raw;
912   st->xgwa.width = w;
913   st->xgwa.height = h;
914 # ifndef HAVE_JWXYZ
915   XFreePixmap (st->dpy, st->backbuffer);
916 # endif
917   create_backbuffer (st);
918   make_clip_mask (st);
919 }
920 
921 static Bool
testx11_event(Display * dpy,Window window,void * st_raw,XEvent * event)922 testx11_event (Display *dpy, Window window, void *st_raw, XEvent *event)
923 {
924   struct testx11 *st = (struct testx11 *) st_raw;
925 
926   Bool handled = False;
927 
928   switch (event->xany.type)
929   {
930   case KeyPress:
931     {
932       KeySym keysym;
933       char c = 0;
934       XLookupString (&event->xkey, &c, 1, &keysym, 0);
935       if (c == ' ')
936         handled = toggle_antialiasing (st);
937 
938       if (c >= '0' && c <= '9' && c < '0' + mode_count) {
939         st->mode = c - '0';
940         handled = True;
941       }
942     }
943     break;
944 
945   case ButtonPress:
946     if (event->xbutton.y >= st->xgwa.height - button_pad * 2 - button_size) {
947       int i = (event->xbutton.x - button_pad / 2) / (button_pad + button_size) + 1;
948       if (i && i < mode_count) {
949         st->mode = i;
950         handled = True;
951       }
952     }
953 
954     if (!handled)
955       handled = toggle_antialiasing (st);
956     break;
957   }
958 
959   return handled;
960 }
961 
962 static void
testx11_free(Display * dpy,Window window,void * st_raw)963 testx11_free (Display *dpy, Window window, void *st_raw)
964 {
965   /* Omitted for the sake of brevity. */
966 }
967 
968 XSCREENSAVER_MODULE_2 ("TestX11", testx11, testx11)
969