/* testx11.c, Copyright (c) 2015-2017 Dave Odell <dmo2118@gmail.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* This is a test for X11 drawing primitives for the non-X11 ports of
* XScreenSaver. It shouldn't normally be installed with the other screenhacks.
*
* Almost no error checking in here. This is intentional.
*/
#include "screenhack.h"
#include "glx/rotator.h"
#include "colorbars.h"
#include "erase.h"
#include "ximage-loader.h"
#include "images/gen/logo-180_png.h"
#include <assert.h>
#include <errno.h>
#ifndef HAVE_JWXYZ
# define jwxyz_XSetAntiAliasing(dpy, gc, p)
#endif
#ifndef jwxyz_assert_display
# define jwxyz_assert_display(dpy)
#endif
static const char *testx11_defaults [] = {
".background: #a020f0", /* purple */
".foreground: white",
#ifdef HAVE_MOBILE
"*ignoreRotation: True",
#endif
0
};
static XrmOptionDescRec testx11_options [] = {
{ 0, 0, 0, 0 }
};
enum
{
mode_welcome,
mode_primitives,
mode_images,
mode_copy,
mode_preserve,
mode_erase,
mode_count
};
struct testx11 {
Display *dpy;
Window win;
XWindowAttributes xgwa;
# ifndef HAVE_JWXYZ
Pixmap backbuffer;
# endif
unsigned mode;
/* Pixels from XAllocPixel. */
unsigned long rgb[3], salmon, magenta, gray50, dark_slate_gray1, cyan;
unsigned frame;
Bool anti_alias_p;
/* These X11 objects aren't altered after creation, except for:
- copy_gc and thick_line_gc get anti-aliasing toggled.
- xor_gc's clip mask (if it's turned on) always covers the entire window.
*/
GC copy_gc, mono_gc, thick_line_gc, xor_gc, graph_gc;
Pixmap clip_mask_tile;
/* Backdrop stuff, naturally. */
GC backdrop_black_gc;
Pixmap backdrop_tile, backdrop_scratch;
XColor backdrop_colors[64];
int backdrop_ncolors;
/* The following items may be modified by various test modes. */
Pixmap primitives_mini_pix;
GC images_point_gc;
Pixmap copy_pix64;
Pixmap preserve[2];
eraser_state *erase;
rotator *rot;
};
static void
abort_no_mem (void)
{
fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
abort();
}
static void
check_no_mem (void *ptr)
{
if(!ptr)
abort_no_mem();
}
static unsigned long
alloc_color (struct testx11 *st,
unsigned short r, unsigned short g, unsigned short b)
{
XColor color;
color.red = r;
color.green = g;
color.blue = b;
color.flags = DoRed | DoGreen | DoBlue;
XAllocColor (st->dpy, st->xgwa.colormap, &color);
return color.pixel;
}
static void
create_backbuffer(struct testx11 *st)
{
# ifndef HAVE_JWXYZ
st->backbuffer = XCreatePixmap (st->dpy, st->win,
st->xgwa.width, st->xgwa.height,
st->xgwa.depth);
# endif
}
static Bool
toggle_antialiasing (struct testx11 *st)
{
st->anti_alias_p ^= True;
jwxyz_XSetAntiAliasing (st->dpy, st->copy_gc, st->anti_alias_p);
jwxyz_XSetAntiAliasing (st->dpy, st->thick_line_gc, st->anti_alias_p);
return True;
}
static void
primitives_mini_rect(struct testx11 *st, Drawable t, int x, int y)
{
XFillRectangle(st->dpy, t, st->copy_gc, x, y, 2, 2);
}
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)
{
XCopyArea(dpy, src, dst, gc, 0, src_y, 3, 2, dst_x, dst_y);
{
XImage *image = XGetImage(dpy, src, 0, src_y, 3, 2, cells, ZPixmap);
XPutImage(dpy, dst, gc, image, 0, 0, dst_x, dst_y + 2, 3, 2);
XDestroyImage(image);
}
}
static void
images_pattern (struct testx11 *st, Drawable d, unsigned y)
{
unsigned x;
for (x = 0; x != 3; ++x) {
XSetForeground(st->dpy, st->images_point_gc, st->rgb[x]);
XDrawPoint(st->dpy, d, st->images_point_gc, x, y);
XSetForeground(st->dpy, st->images_point_gc, st->rgb[2 - x]);
XFillRectangle(st->dpy, d, st->images_point_gc, x, y + 1, 1, 1);
}
images_copy_test (st->dpy, d, d, st->images_point_gc, y, 0, y + 2,
st->rgb[0] | st->rgb[1] | st->rgb[2]);
}
static const unsigned tile_size = 16;
static const unsigned tile_count = 8;
static const unsigned preserve_size = 128;
static void
make_clip_mask (struct testx11 *st)
{
/* Activate this for extra Fun! */
# if 0
/* This is kind of slow, but that's OK, because this only happens on int
or during a resize.
*/
unsigned w = st->xgwa.width, h = st->xgwa.height;
unsigned x, y;
Pixmap mask = XCreatePixmap (st->dpy, st->clip_mask_tile, w, h, 1);
for (y = 0; y < h; y += 8) {
for (x = 0; x < w; x += 8) {
XCopyArea (st->dpy, st->clip_mask_tile, mask, st->mono_gc,
0, 0, 8, 8, x, y);
}
}
XSetClipMask (st->dpy, st->xor_gc, mask);
XFreePixmap (st->dpy, mask);
# endif
}
static void
colorbars (struct testx11 *st)
{
Pixmap logo_mask = 0;
Pixmap logo = image_data_to_pixmap (st->dpy, st->win,
logo_180_png, sizeof(logo_180_png),
0, 0, &logo_mask);
draw_colorbars (st->xgwa.screen, st->xgwa.visual, st->win,
st->xgwa.colormap, 0, 0, st->xgwa.width, st->xgwa.height,
logo, logo_mask);
XFreePixmap (st->dpy, logo);
XFreePixmap (st->dpy, logo_mask);
}
static void *
testx11_init (Display *dpy, Window win)
{
static const char backdrop_pattern[] = {
'\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07', /* Zig */
'\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01', /* Zag */
'\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07', /* etc. */
'\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01',
'\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07',
'\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01',
'\xff', '\x00', '\xfe', '\x01', '\xfc', '\x03', '\xf8', '\x07',
'\xf0', '\x0f', '\xf8', '\x07', '\xfc', '\x03', '\xfe', '\x01',
};
static const char clip_bits[] = {
'\x33', '\x33', '\xcc', '\xcc', '\x33', '\x33', '\xcc', '\xcc'
};
struct testx11 *st = (struct testx11 *) malloc (sizeof(*st));
XGCValues gcv;
check_no_mem (st);
st->dpy = dpy;
st->win = win;
XGetWindowAttributes (dpy, win, &st->xgwa);
create_backbuffer (st);
st->rgb[0] = alloc_color (st, 0xffff, 0x0000, 0x0000);
st->rgb[1] = alloc_color (st, 0x0000, 0xffff, 0x0000);
st->rgb[2] = alloc_color (st, 0x0000, 0x0000, 0xffff);
st->salmon = alloc_color (st, 0xffff, 0x7fff, 0x7fff);
st->magenta = alloc_color (st, 0xffff, 0x0000, 0xffff);
st->gray50 = alloc_color (st, 0x8000, 0x8000, 0x8000);
st->dark_slate_gray1 = alloc_color (st, 0x8000, 0xffff, 0xffff);
st->cyan = alloc_color (st, 0x0000, 0xffff, 0xffff);
st->backdrop_tile = XCreatePixmapFromBitmapData (dpy, win,
(char *) backdrop_pattern,
tile_size, tile_size * 2,
1, 0, 1);
st->clip_mask_tile = XCreatePixmapFromBitmapData (dpy, win,
(char *) clip_bits, 8, 8,
1, 0, 1);
{
unsigned s = tile_size * tile_count;
st->backdrop_scratch = XCreatePixmap (dpy, win, s, s, st->xgwa.depth);
}
st->backdrop_ncolors = countof (st->backdrop_colors);
make_color_loop (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
180, 1, 0.5, 210, 1, 0.5, 240, 1, 0.5,
st->backdrop_colors, &st->backdrop_ncolors, True, NULL);
st->frame = 0;
# ifdef HAVE_ANDROID
st->mode = mode_primitives;
# else
st->mode = mode_welcome;
# endif
st->anti_alias_p = False;
gcv.function = GXcopy;
gcv.foreground = st->cyan;
gcv.background = st->magenta;
gcv.line_width = 0;
gcv.cap_style = CapRound;
/* TODO: Real X11 uses fixed by default. */
gcv.font = XLoadFont (dpy, "fixed");
st->copy_gc = XCreateGC (dpy, win,
GCFunction | GCForeground | GCBackground
| GCLineWidth | GCCapStyle | GCFont, &gcv);
gcv.foreground = BlackPixelOfScreen (st->xgwa.screen);
st->backdrop_black_gc = XCreateGC (dpy, win, GCForeground, &gcv);
gcv.foreground = alloc_color (st, 0x8000, 0x4000, 0xffff);
gcv.line_width = 8;
gcv.cap_style = CapProjecting;
st->thick_line_gc = XCreateGC (dpy, win,
GCForeground | GCLineWidth | GCCapStyle,
&gcv);
gcv.function = GXxor;
st->xor_gc = XCreateGC (dpy, win, GCFunction, &gcv);
st->images_point_gc = XCreateGC (dpy, win, 0, NULL);
st->graph_gc = XCreateGC (dpy, win, 0, &gcv);
st->mono_gc = XCreateGC (dpy, st->clip_mask_tile, 0, &gcv);
st->copy_pix64 = XCreatePixmap(dpy, win, 64, 64, st->xgwa.depth);
st->primitives_mini_pix = XCreatePixmap (dpy, win, 16, 24, st->xgwa.depth);
{
static const char text[] = "Welcome from testx11_init().";
colorbars (st);
XDrawString (dpy, win, st->copy_gc, 16, 16, text, countof (text) - 1);
}
make_clip_mask (st);
st->preserve[0] =
XCreatePixmap(dpy, win, preserve_size, preserve_size, st->xgwa.depth);
st->preserve[1] =
XCreatePixmap(dpy, win, preserve_size, preserve_size, st->xgwa.depth);
toggle_antialiasing (st);
st->erase = NULL;
jwxyz_assert_display (dpy);
st->rot = make_rotator (2, 2, 2, 2, 0.01, False);
return st;
}
static void
backdrop (struct testx11 *st, Drawable t)
{
unsigned w = st->xgwa.width, h = st->xgwa.height;
unsigned x, y;
for (y = 0; y != tile_count; ++y) {
const float s0 = 2 * M_PI / tile_count;
float y_fac = sin ((y + st->frame / 16.0) * s0);
for (x = 0; x != tile_count; ++x) {
int c = ((sin ((x + st->frame / 8.0) * s0) * y_fac) - 1) / 2 *
st->backdrop_ncolors / 2;
c = (c + st->frame) % st->backdrop_ncolors;
XSetBackground (st->dpy, st->backdrop_black_gc,
st->backdrop_colors[c].pixel);
XCopyPlane (st->dpy, st->backdrop_tile, st->backdrop_scratch,
st->backdrop_black_gc, 0, st->frame % tile_size,
tile_size, tile_size, x * tile_size, y * tile_size, 1);
}
}
/* XFillRectangle (st->dpy, t, st->backdrop_black_gc, 0, 0, w, h); */
for (y = 0; y < h; y += tile_count * tile_size) {
for (x = 0; x < w; x += tile_count * tile_size) {
XCopyArea (st->dpy, st->backdrop_scratch, t, st->copy_gc, 0, 0,
tile_count * tile_size, tile_count * tile_size, x, y);
}
}
}
static const unsigned button_pad = 16;
static const unsigned button_size = 64;
static void
testx11_graph_rotator (struct testx11 *st)
{
double x, y, z;
int boxw = st->xgwa.width / 3;
int boxh = (st->xgwa.height - (22 * 5)) / 4;
int boxx = st->xgwa.width - boxw - 20;
int boxy = st->xgwa.height - boxh - 20;
/* position */
get_position (st->rot, &x, &y, &z, True);
if (x < 0 || x >= 1 || y < 0 || y >= 1 || z < 0 || z >= 1) abort();
XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
XDrawRectangle (st->dpy, st->win, st->graph_gc,
boxx-1, boxy-1, boxw+2, boxh+2);
XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
boxx+1, boxy, boxw-1, boxh, boxx, boxy);
XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
XDrawLine (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1, boxy,
boxx + boxw - 1, boxy + boxh);
XSetForeground (st->dpy, st->graph_gc, st->salmon);
XDrawPoint (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1,
boxy + boxh - 1 - (int) (x * (boxh - 1)));
XSetForeground (st->dpy, st->graph_gc, st->magenta);
XDrawPoint (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1,
boxy + boxh - 1 - (int) (y * (boxh - 1)));
XSetForeground (st->dpy, st->graph_gc, st->gray50);
XDrawPoint (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1,
boxy + boxh - 1 - (int) (z * (boxh - 1)));
/* spin */
get_rotation (st->rot, &x, &y, &z, True);
if (x < 0 || x >= 1 || y < 0 || y >= 1 || z < 0 || z >= 1) abort();
/* put 0 in the middle */
x += 0.5; if (x > 1) x--;
y += 0.5; if (y > 1) y--;
z += 0.5; if (z > 1) z--;
boxy -= boxh + 20;
XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
XDrawRectangle (st->dpy, st->win, st->graph_gc,
boxx-1, boxy-1, boxw+2, boxh+2);
XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
boxx+1, boxy, boxw-1, boxh, boxx, boxy);
XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
XDrawLine (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1, boxy,
boxx + boxw - 1, boxy + boxh);
XSetForeground (st->dpy, st->graph_gc, st->magenta);
XDrawPoint (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1,
boxy + boxh - 1 - (int) (x * (boxh - 1)));
boxy -= boxh + 20;
XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
XDrawRectangle (st->dpy, st->win, st->graph_gc,
boxx-1, boxy-1, boxw+2, boxh+2);
XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
boxx+1, boxy, boxw-1, boxh, boxx, boxy);
XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
XDrawLine (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1, boxy,
boxx + boxw - 1, boxy + boxh);
XSetForeground (st->dpy, st->graph_gc, st->magenta);
XDrawPoint (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1,
boxy + boxh - 1 - (int) (y * (boxh - 1)));
boxy -= boxh + 20;
XSetForeground (st->dpy, st->graph_gc, st->dark_slate_gray1);
XDrawRectangle (st->dpy, st->win, st->graph_gc,
boxx-1, boxy-1, boxw+2, boxh+2);
XCopyArea (st->dpy, st->win, st->win, st->graph_gc,
boxx+1, boxy, boxw-1, boxh, boxx, boxy);
XSetForeground (st->dpy, st->graph_gc, BlackPixelOfScreen (st->xgwa.screen));
XDrawLine (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1, boxy,
boxx + boxw - 1, boxy + boxh);
XSetForeground (st->dpy, st->graph_gc, st->magenta);
XDrawPoint (st->dpy, st->win, st->graph_gc,
boxx + boxw - 1,
boxy + boxh - 1 - (int) (z * (boxh - 1)));
}
/* Draws a blinking box in what should be the upper left corner of the
device, as physically oriented. The box is taller than it is wide.
*/
static void
testx11_show_orientation (struct testx11 *st)
{
#ifdef HAVE_MOBILE
int x, y;
int w = st->xgwa.width;
int h = st->xgwa.height;
int ww = 15;
int hh = ww*2;
static int tick = 0;
static int oo = -1;
int o = (int) current_device_rotation ();
if (o != oo) {
// fprintf (stderr,"ROT %d -> %d\n", oo, o);
oo = o;
}
switch (o) {
case 0: case 360: x = 0; y = 0; w = ww; h = hh; break;
case 90: case -270: x = 0; y = h-ww; w = hh; h = ww; break;
case -90: case 270: x = w-hh; y = 0; w = hh; h = ww; break;
case 180: case -180: x = w-ww; y = h-hh; w = ww; h = hh; break;
default: return;
}
if (++tick > 20) tick = 0;
XSetForeground (st->dpy, st->graph_gc,
(tick > 10
? WhitePixelOfScreen (st->xgwa.screen)
: BlackPixelOfScreen (st->xgwa.screen)));
XFillRectangle (st->dpy, st->win, st->graph_gc,
x, y, w, h);
#endif
}
static unsigned long
testx11_draw (Display *dpy, Window win, void *st_raw)
{
struct testx11 *st = (struct testx11 *) st_raw;
unsigned w = st->xgwa.width, h = st->xgwa.height;
# ifdef HAVE_JWXYZ
Drawable t = win;
# else
Drawable t = st->mode == mode_primitives ? st->backbuffer : win;
# endif
unsigned i;
assert (dpy == st->dpy);
assert (win == st->win);
jwxyz_assert_display (dpy);
XSetWindowBackground (dpy, win, st->gray50);
switch (st->mode)
{
case mode_primitives:
backdrop (st, t);
XDrawPoint (dpy, t, st->thick_line_gc, 0, 0);
XDrawPoint (dpy, t, st->thick_line_gc, 0, 1);
XDrawPoint (dpy, t, st->thick_line_gc, 1, 0);
XDrawPoint (dpy, t, st->thick_line_gc, 1, 1);
primitives_mini_rect (st, t, 2, 0);
primitives_mini_rect (st, t, 0, 2);
primitives_mini_rect (st, t, 4, 2);
primitives_mini_rect (st, t, 2, 4);
primitives_mini_rect (st, t, 30, -2);
primitives_mini_rect (st, t, 32, 0);
primitives_mini_rect (st, t, 30, h - 2);
primitives_mini_rect (st, t, 32, h);
primitives_mini_rect (st, t, -2, 30);
primitives_mini_rect (st, t, 0, 32);
primitives_mini_rect (st, t, w - 2, 30);
primitives_mini_rect (st, t, w, 32);
primitives_mini_rect (st, t, w / 2 + 4, h / 2 + 4);
XFillArc (dpy, t, st->copy_gc, 16, 16, 256, 256, 45 * 64, -135 * 64);
/* XCopyArea(dpy, t, t, st->copy_gc, 48, 48, 128, 128, 64, 64); */
/* Center */
XDrawPoint (dpy, t, st->copy_gc, w / 2, h / 2);
/* Top/bottom */
XDrawPoint (dpy, t, st->copy_gc, w / 2, 0);
XDrawPoint (dpy, t, st->copy_gc, w / 2, h - 1);
XDrawPoint (dpy, t, st->copy_gc, 16, -1);
XDrawPoint (dpy, t, st->copy_gc, 17, 0);
XDrawPoint (dpy, t, st->copy_gc, 15, h - 2);
XDrawPoint (dpy, t, st->copy_gc, 16, h - 1);
XDrawPoint (dpy, t, st->copy_gc, 17, h);
{
XPoint *points = malloc (sizeof(XPoint) * h);
XSegment *lines = malloc (sizeof(XSegment) * h);
XPoint *points2 = malloc (sizeof(XPoint) * h);
for(i = 0; i != h; ++i)
{
points[i].x = 8 + (i & 1);
points[i].y = i;
lines[i].x1 = 48 + (i & 1) * 4;
lines[i].y1 = i;
lines[i].x2 = 50;
lines[i].y2 = i;
points2[i].x = 24 + (i & 1);
points2[i].y = i;
/* XFillRectangle(st->dpy, t, st->copy_gc, 24 + (i & 1), i, 1, 1); */
}
XDrawPoints (dpy, t, st->copy_gc, points, h, CoordModeOrigin);
XDrawSegments (dpy, t, st->copy_gc, lines, h);
XDrawPoints (dpy, t, st->copy_gc, points2, h, CoordModeOrigin);
free (lines);
free (points);
free (points2);
}
/* Left/right */
XDrawPoint (dpy, t, st->copy_gc, -1, 16);
XDrawPoint (dpy, t, st->copy_gc, 0, 17);
XDrawPoint (dpy, t, st->copy_gc, w - 1, 16);
XDrawPoint (dpy, t, st->copy_gc, w, 17);
{
XPoint *points = malloc(sizeof(XPoint) * w);
XSegment *lines = malloc(sizeof(XSegment) * w);
XPoint *points2 = malloc(sizeof(XPoint) * w);
for(i = 0; i != w; ++i)
{
points[i].x = i;
points[i].y = 8 + (i & 1);
lines[i].x1 = i;
lines[i].y1 = 48 + (i & 1) * 4;
lines[i].x2 = i;
lines[i].y2 = 50;
points2[i].x = i;
points2[i].y = 24 + (i & 1);
/* XFillRectangle(dpy, t, st->copy_gc, i, 24 + (i & 1), 1, 1); */
}
XDrawPoints (dpy, t, st->copy_gc, points, w, CoordModeOrigin);
XDrawSegments (dpy, t, st->copy_gc, lines, w);
{
/* Thick purple lines */
XSegment seg[2] =
{
{31, 31, 31, 31}, /* TODO: This should not be rotated in Cocoa. */
{42, 31, 42, 42}
};
XDrawSegments (dpy, t, st->thick_line_gc, seg, 2);
XDrawLine (dpy, t, st->thick_line_gc, 58, 43, 64, 43);
XDrawLine (dpy, t, st->thick_line_gc, 73, 43, 80, 43);
}
XDrawPoints (dpy, t, st->copy_gc, points2, w, CoordModeOrigin);
free (points);
free (points2);
free (lines);
}
XDrawLine (dpy, t, st->copy_gc, 54, 11, 72, 22);
{
XPoint vertices[] = {{5, 5}, {5, 8}, {8, 8}, {8, 5}};
XFillPolygon (dpy, t, st->copy_gc, vertices, 4, Convex, CoordModeOrigin);
}
{
XDrawRectangle (dpy, t, st->copy_gc, 11, 11, 11, 11);
XFillRectangle (dpy, t, st->copy_gc, 13, 13, 8, 8);
}
/* Several ~16 pixel boxes in a row. */
/* Box 0 */
{
XDrawRectangle (dpy, t, st->copy_gc, 54, 54, 16, 16);
XDrawRectangle (dpy, t, st->copy_gc, 55, 55, 14, 14);
XDrawPoint (dpy, t, st->thick_line_gc, 56, 56);
XDrawPoint (dpy, t, st->copy_gc, 57, 56);
}
/* Box 1 */
XCopyArea (dpy, t, t, st->copy_gc, 55, 55, 15, 15, 72, 55);
/* Box 2 */
{
XImage *image = XGetImage(st->dpy, t, 55, 55, 15, 15, 0xffffff, ZPixmap);
XPutPixel(image, 2, 0, 0x00000000);
XPutImage (dpy, t, st->copy_gc, image, 0, 0, 88, 55, 15, 15);
XDestroyImage(image);
}
/* Box 3 */
{
XCopyArea (dpy, t, st->primitives_mini_pix, st->copy_gc,
104, 55, 16, 16, 0, 0);
/* XCopyArea (dpy, t, st->primitives_mini_pix, st->copy_gc,
105, 56, 14, 14, 1, 1);
XCopyArea (dpy, t, st->primitives_mini_pix, st->copy_gc,
1, 1, 14, 14, 1, 1);
*/
/* This point gets hidden. */
XDrawPoint (dpy, t, st->copy_gc, 104 + 8, 55 + 8);
XDrawPoint (dpy, st->primitives_mini_pix, st->copy_gc, 0, 0);
XDrawPoint (dpy, st->primitives_mini_pix, st->copy_gc, 1, 0);
XDrawPoint (dpy, st->primitives_mini_pix, st->copy_gc, 15, 15);
XDrawRectangle (dpy, st->primitives_mini_pix, st->copy_gc,
1, 1, 13, 13);
XCopyArea (dpy, st->primitives_mini_pix, t, st->copy_gc,
0, 0, 16, 16, 104, 55);
}
{
XDrawLine (dpy, t, st->copy_gc, 11, 28, 22, 28);
XDrawLine (dpy, t, st->copy_gc, 12, 27, 12, 46);
XDrawLine (dpy, t, st->copy_gc, 14, 30, 14, 30);
}
XDrawArc (dpy, t, st->copy_gc, 27, 11, 19, 11, 0, 360 * 64);
XDrawRectangle (dpy, t, st->copy_gc, 54, 73, 64, 64);
XFillArc (dpy, t, st->copy_gc, 56, 75, 60, 60, 0, 360 * 64);
/* XDrawArc (dpy, t, st->thick_line_gc, 56, 75, 60, 60, 0, 360 * 64); */
XClearArea (dpy, win, 121, 55, 16, 16, False);
break;
case mode_images:
backdrop (st, t);
/* if(w >= 9 && h >= 10) */
{
#ifdef HAVE_ANDROID
/* Draw below the status bar. */
const unsigned y = 64;
#else
const unsigned y = 0;
#endif
Screen *screen = st->xgwa.screen;
Visual *visual = st->xgwa.visual;
Pixmap pixmap = XCreatePixmap (dpy, t, 3, 10,
visual_depth (screen, visual));
unsigned long cells = cells = st->rgb[0] | st->rgb[1] | st->rgb[2];
{
XSetForeground (dpy, st->images_point_gc, st->salmon);
XDrawPoint (dpy, t, st->images_point_gc, 0, h - 1);
XDrawLine (dpy, t, st->images_point_gc, 0, y - 1, 8, y - 1);
}
images_pattern (st, t, y);
images_pattern (st, pixmap, 0);
/* Here's a good spot to verify that the pixmap contains the right colors
at the top.
*/
images_copy_test (dpy, t, pixmap, st->copy_gc, y, 0, 6, cells);
XCopyArea (dpy, pixmap, t, st->copy_gc, 0, 0, 3, 10, 3, y);
{
XImage *image = XGetImage (dpy, pixmap, 0, 0, 3, 10, cells, ZPixmap);
XPutImage (dpy, t, st->copy_gc, image, 0, 0, 6, y, 3, 10);
XDestroyImage (image);
}
XFreePixmap (dpy, pixmap);
XSync (dpy, False);
}
break;
case mode_copy:
backdrop (st, win);
/* X.org isn't making a whole lot of sense here. */
{
Bool use_copy = (st->frame / 20) & 1;
{
GC gc = use_copy ? st->copy_gc : st->xor_gc;
XSetWindowBackground (dpy, t, st->magenta);
XCopyArea (dpy, t, t, gc, -2, -2, 40, 40, 20, 20);
if (!use_copy)
XCopyArea (st->dpy, t, t, gc, -20, h - 20, 40, 40, 20, h - 60);
XCopyArea (dpy, t, t, gc, w - 38, h - 38, 40, 40, w - 60, h - 60);
XCopyArea (dpy, t, t, gc, w - 20, -20, 40, 40, w - 60, 20);
XSetWindowBackground (dpy, t, st->gray50);
XCopyArea (st->dpy, t, t, gc, -20, 64, 40, 40, 20, 64);
XSetWindowBackground (dpy, t, st->dark_slate_gray1);
XCopyArea (st->dpy, t, t, gc, -20, 112, 40, 40, 20, 112);
}
if (use_copy)
{
GC gc = st->copy_gc;
XCopyArea (st->dpy, t, st->copy_pix64, gc, 0, h - 64, 64, 64, 0, 0);
XSetForeground (st->dpy, st->xor_gc, st->rgb[1]);
XSetBackground (st->dpy, st->xor_gc, st->cyan);
/* XCopyArea (st->dpy, st->copy_pix64, st->copy_pix64, gc,
32, 32, 64, 64, 0, 0);
XCopyArea (st->dpy, st->copy_pix64, t, gc, 0, 0, 64, 64, 4, h - 68);
*/
XCopyArea (st->dpy, st->copy_pix64, t, gc, 32, 32, 128, 64, 0, h - 64);
}
}
break;
case mode_preserve:
backdrop (st, t);
if(!(st->frame % 10)) {
const unsigned r = 16;
unsigned n = st->frame / 10;
unsigned m = n >> 1;
XFillArc (st->dpy, st->preserve[n & 1],
m & 1 ? st->copy_gc : st->thick_line_gc,
NRAND(preserve_size) - r, NRAND(preserve_size) - r,
r * 2, r * 2, 0, 360 * 64);
}
XCopyArea (st->dpy, st->preserve[0], t, st->copy_gc, 0, 0,
preserve_size, preserve_size, 0, 0);
XCopyArea (st->dpy, st->preserve[1], t, st->copy_gc, 0, 0,
preserve_size, preserve_size, preserve_size, 0);
XCopyArea (st->dpy, st->preserve[1], t, st->copy_gc, 0, 0,
preserve_size, preserve_size,
w - preserve_size / 2, preserve_size);
break;
case mode_erase:
if (!st->erase)
colorbars (st);
st->erase = erase_window(st->dpy, st->win, st->erase);
break;
}
/* Mode toggle buttons */
for (i = 1; i != mode_count; ++i) {
unsigned i0 = i - 1;
char str[32];
XRectangle button_dims;
button_dims.x = i0 * (button_pad + button_size) + button_pad;
button_dims.y = h - button_pad - button_size;
button_dims.width = button_size;
button_dims.height = button_size;
if (!st->mode)
XFillRectangles (dpy, t, st->backdrop_black_gc, &button_dims, 1);
XDrawRectangle (dpy, t, st->copy_gc, button_dims.x, button_dims.y,
button_dims.width, button_dims.height);
XDrawString (dpy, t, st->copy_gc,
button_dims.x + button_size / 2 - 3,
h - button_pad - button_size / 2 + 13 / 2,
str, sprintf(str, "%u", i));
}
if (t != win)
XCopyArea (dpy, t, win, st->copy_gc, 0, 0, w, h, 0, 0);
testx11_graph_rotator (st);
testx11_show_orientation (st);
++st->frame;
return 1000000 / 20;
}
static void
testx11_reshape (Display *dpy, Window window, void *st_raw,
unsigned int w, unsigned int h)
{
struct testx11 *st = (struct testx11 *)st_raw;
st->xgwa.width = w;
st->xgwa.height = h;
# ifndef HAVE_JWXYZ
XFreePixmap (st->dpy, st->backbuffer);
# endif
create_backbuffer (st);
make_clip_mask (st);
}
static Bool
testx11_event (Display *dpy, Window window, void *st_raw, XEvent *event)
{
struct testx11 *st = (struct testx11 *) st_raw;
Bool handled = False;
switch (event->xany.type)
{
case KeyPress:
{
KeySym keysym;
char c = 0;
XLookupString (&event->xkey, &c, 1, &keysym, 0);
if (c == ' ')
handled = toggle_antialiasing (st);
if (c >= '0' && c <= '9' && c < '0' + mode_count) {
st->mode = c - '0';
handled = True;
}
}
break;
case ButtonPress:
if (event->xbutton.y >= st->xgwa.height - button_pad * 2 - button_size) {
int i = (event->xbutton.x - button_pad / 2) / (button_pad + button_size) + 1;
if (i && i < mode_count) {
st->mode = i;
handled = True;
}
}
if (!handled)
handled = toggle_antialiasing (st);
break;
}
return handled;
}
static void
testx11_free (Display *dpy, Window window, void *st_raw)
{
/* Omitted for the sake of brevity. */
}
XSCREENSAVER_MODULE_2 ("TestX11", testx11, testx11)