--- /dev/null
+/* xscreensaver, Copyright (c) 1991-2016 Jamie Zawinski <jwz@jwz.org>
+ *
+ * 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.
+ */
+
+/* JWXYZ Is Not Xlib.
+
+ But it's a bunch of function definitions that bear some resemblance to
+ Xlib and that do Cocoa-ish or OpenGL-ish things that bear some resemblance
+ to the things that Xlib might have done.
+
+ This is the version of jwxyz for Android. The version used by MacOS
+ and iOS is in jwxyz.m.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_JWXYZ /* whole file */
+
+#include "jwxyzI.h"
+
+/* There's only one Window for a given jwxyz_Display. */
+#define assert_window(dpy, w) \
+ Assert (w == RootWindow (dpy, 0), "not a window")
+
+int
+XDisplayWidth (Display *dpy, int screen)
+{
+ return jwxyz_frame (XRootWindow (dpy, 0))->width;
+}
+
+int
+XDisplayHeight (Display *dpy, int screen)
+{
+ return jwxyz_frame (XRootWindow (dpy, 0))->height;
+}
+
+
+/* XLFDs use dots per inch, but Xlib uses millimeters. Go figure. */
+static const unsigned dpi = 75;
+
+int
+XDisplayWidthMM (Display *dpy, int screen)
+{
+ const unsigned denom = dpi * 10 / 2;
+ return (254 * XDisplayWidth (dpy, screen) + denom) / (2 * denom);
+}
+
+int
+XDisplayHeightMM (Display *dpy, int screen)
+{
+ const unsigned denom = dpi * 10 / 2;
+ return (254 * XDisplayHeight (dpy, screen) + denom) / (2 * denom);
+}
+
+
+void
+jwxyz_validate_pixel (Display *dpy, unsigned long pixel, unsigned int depth,
+ Bool alpha_allowed_p)
+{
+ Assert (depth == 1 || depth == visual_depth(NULL, NULL),
+ "invalid depth: %d", depth);
+
+ if (depth == 1)
+ Assert ((pixel == 0 || pixel == 1), "bogus mono pixel: 0x%08X", pixel);
+ else if (!alpha_allowed_p)
+ Assert (((pixel & BlackPixel(dpy,0)) == BlackPixel(dpy,0)),
+ "bogus color pixel: 0x%08X", pixel);
+}
+
+
+int
+XDrawPoint (Display *dpy, Drawable d, GC gc, int x, int y)
+{
+ XPoint p;
+ p.x = x;
+ p.y = y;
+ return XDrawPoints (dpy, d, gc, &p, 1, CoordModeOrigin);
+}
+
+
+Bool
+jwxyz_dumb_drawing_mode(Display *dpy, Drawable d, GC gc,
+ int x, int y, unsigned width, unsigned height)
+{
+ XGCValues *gcv = jwxyz_gc_gcv (gc);
+
+ if (gcv->function == GXset || gcv->function == GXclear) {
+ // "set" and "clear" are dumb drawing modes that ignore the source
+ // bits and just draw solid rectangles.
+ unsigned depth = jwxyz_gc_depth (gc);
+ jwxyz_fill_rect (dpy, d, 0, x, y, width, height,
+ (gcv->function == GXset
+ ? (depth == 1 ? 1 : WhitePixel(dpy,0))
+ : (depth == 1 ? 0 : BlackPixel(dpy,0))));
+ return True;
+ }
+
+ return False;
+}
+
+
+int
+XCopyArea (Display *dpy, Drawable src, Drawable dst, GC gc,
+ int src_x, int src_y,
+ unsigned int width, unsigned int height,
+ int dst_x, int dst_y)
+{
+ Assert (gc, "no GC");
+ Assert ((width < 65535), "improbably large width");
+ Assert ((height < 65535), "improbably large height");
+ Assert ((src_x < 65535 && src_x > -65535), "improbably large src_x");
+ Assert ((src_y < 65535 && src_y > -65535), "improbably large src_y");
+ Assert ((dst_x < 65535 && dst_x > -65535), "improbably large dst_x");
+ Assert ((dst_y < 65535 && dst_y > -65535), "improbably large dst_y");
+
+ if (width == 0 || height == 0)
+ return 0;
+
+ if (jwxyz_dumb_drawing_mode (dpy, dst, gc, dst_x, dst_y, width, height))
+ return 0;
+
+ XRectangle src_frame, dst_frame; // Sizes and origins of the two drawables
+ Bool clipped = False; // Whether we did any clipping of the rects.
+
+ src_frame = *jwxyz_frame (src);
+ dst_frame = *jwxyz_frame (dst);
+
+ // Initialize src_rect...
+ //
+ src_x += src_frame.x;
+ src_y += src_frame.y;
+ if (src_y < -65535) Assert(0, "src.origin.y went nuts");
+
+ // Initialize dst_rect...
+ //
+ dst_x += dst_frame.x;
+ dst_y += dst_frame.y;
+ if (dst_y < -65535) Assert(0, "dst.origin.y went nuts");
+
+ // Use signed width and height for this...
+ int width0 = width, height0 = height;
+
+ // Clip rects to frames...
+ //
+
+# define CLIP(THIS,THAT,VAL,SIZE) do { \
+ int off = THIS##_##VAL; \
+ if (off < 0) { \
+ clipped = True; \
+ SIZE##0 += off; \
+ THIS##_##VAL -= off; \
+ THAT##_##VAL -= off; \
+ } \
+ off = (( THIS##_##VAL + SIZE##0) - \
+ (THIS##_frame.VAL + THIS##_frame.SIZE)); \
+ if (off > 0) { \
+ clipped = True; \
+ SIZE##0 -= off; \
+ }} while(0)
+
+ CLIP (dst, src, x, width);
+ CLIP (dst, src, y, height);
+
+ // Not actually the original dst_rect, just the one before it's clipped to
+ // the src_frame.
+ int orig_dst_x = dst_x;
+ int orig_dst_y = dst_y;
+ int orig_width = width0;
+ int orig_height = height0;
+
+ if (width0 <= 0 || height0 <= 0)
+ return 0;
+
+ CLIP (src, dst, x, width);
+ CLIP (src, dst, y, height);
+# undef CLIP
+
+ // Sort-of-special case where no pixels can be grabbed from the source,
+ // and the whole destination is filled with the background color.
+ if (width0 <= 0 || height0 <= 0) {
+ width0 = 0;
+ height0 = 0;
+ } else {
+ jwxyz_copy_area (dpy, src, dst, gc,
+ src_x, src_y, width0, height0, dst_x, dst_y);
+ }
+
+ // If either the src or dst rects did not lie within their drawables, then
+ // we have adjusted both the src and dst rects to account for the clipping;
+ // that means we need to clear to the background, so that clipped bits end
+ // up in the bg color instead of simply not being copied.
+ //
+ // This has to happen after the copy, because if it happens before, the
+ // cleared area will get grabbed if it overlaps with the source rectangle.
+ //
+ if (clipped && dst == XRootWindow (dpy,0)) {
+ int dst_x0 = dst_x;
+ int dst_y0 = dst_y;
+
+ Assert (orig_dst_x >= 0 &&
+ orig_dst_x + orig_width <= dst_frame.width &&
+ orig_dst_y >= 0 &&
+ orig_dst_y + orig_height <= dst_frame.height,
+ "wrong dimensions");
+
+ XRectangle rects[4];
+ XRectangle *rects_end = rects;
+
+ if (orig_dst_y < dst_y0) {
+ rects_end->x = orig_dst_x;
+ rects_end->y = orig_dst_y;
+ rects_end->width = orig_width;
+ rects_end->height = dst_y0 - orig_dst_y;
+ ++rects_end;
+ }
+
+ if (orig_dst_y + orig_height > dst_y0 + height0) {
+ rects_end->x = orig_dst_x;
+ rects_end->y = dst_y0 + height0;
+ rects_end->width = orig_width;
+ rects_end->height = orig_dst_y + orig_height - dst_y0 - height0;
+ ++rects_end;
+ }
+
+ if (orig_dst_x < dst_x0) {
+ rects_end->x = orig_dst_x;
+ rects_end->y = dst_y0;
+ rects_end->width = dst_x0 - orig_dst_x;
+ rects_end->height = height0;
+ ++rects_end;
+ }
+
+ if (dst_x0 + width0 < orig_dst_x + orig_width) {
+ rects_end->x = dst_x0 + width0;
+ rects_end->y = dst_y0;
+ rects_end->width = orig_dst_x + orig_width - dst_x0 - width0;
+ rects_end->height = height0;
+ ++rects_end;
+ }
+
+ XGCValues *gcv = jwxyz_gc_gcv (gc);
+ int old_function = gcv->function;
+ gcv->function = GXcopy;
+ jwxyz_fill_rects (dpy, dst, gc, rects, rects_end - rects,
+ jwxyz_window_background (dpy));
+ gcv->function = old_function;
+ }
+
+ return 0;
+}
+
+
+int
+XCopyPlane (Display *dpy, Drawable src, Drawable dest, GC gc,
+ int src_x, int src_y,
+ unsigned width, int height,
+ int dest_x, int dest_y, unsigned long plane)
+{
+ Assert ((jwxyz_gc_depth (gc) == 1 || plane == 1), "hairy plane mask!");
+
+ // This isn't right: XCopyPlane() is supposed to map 1/0 to fg/bg,
+ // not to white/black.
+ return XCopyArea (dpy, src, dest, gc,
+ src_x, src_y, width, height, dest_x, dest_y);
+}
+
+
+void
+jwxyz_fill_rect (Display *dpy, Drawable d, GC gc,
+ int x, int y, unsigned int width, unsigned int height,
+ unsigned long pixel)
+{
+ XRectangle r = {x, y, width, height};
+ jwxyz_fill_rects (dpy, d, gc, &r, 1, pixel);
+}
+
+int
+XFillRectangle (Display *dpy, Drawable d, GC gc, int x, int y,
+ unsigned int width, unsigned int height)
+{
+ jwxyz_fill_rect (dpy, d, gc, x, y, width, height,
+ jwxyz_gc_gcv (gc)->foreground);
+ return 0;
+}
+
+int
+XDrawRectangle (Display *dpy, Drawable d, GC gc, int x, int y,
+ unsigned int width, unsigned int height)
+{
+ XPoint points[5] = {
+ {x, y},
+ {x, y + height},
+ {x + width, y + height},
+ {x + width, y},
+ {x, y}
+ };
+
+ XDrawLines(dpy, d, gc, points, 5, CoordModeOrigin);
+ return 0;
+}
+
+int
+XFillRectangles (Display *dpy, Drawable d, GC gc, XRectangle *rects, int n)
+{
+ jwxyz_fill_rects (dpy, d, gc, rects, n, jwxyz_gc_gcv (gc)->foreground);
+ return 0;
+}
+
+
+int
+XDrawArc (Display *dpy, Drawable d, GC gc, int x, int y,
+ unsigned int width, unsigned int height, int angle1, int angle2)
+{
+ return jwxyz_draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
+ False);
+}
+
+int
+XFillArc (Display *dpy, Drawable d, GC gc, int x, int y,
+ unsigned int width, unsigned int height, int angle1, int angle2)
+{
+ return jwxyz_draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
+ True);
+}
+
+int
+XDrawArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
+{
+ int i;
+ for (i = 0; i < narcs; i++)
+ jwxyz_draw_arc (dpy, d, gc,
+ arcs[i].x, arcs[i].y,
+ arcs[i].width, arcs[i].height,
+ arcs[i].angle1, arcs[i].angle2,
+ False);
+ return 0;
+}
+
+int
+XFillArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
+{
+ int i;
+ for (i = 0; i < narcs; i++)
+ jwxyz_draw_arc (dpy, d, gc,
+ arcs[i].x, arcs[i].y,
+ arcs[i].width, arcs[i].height,
+ arcs[i].angle1, arcs[i].angle2,
+ True);
+ return 0;
+}
+
+void
+jwxyz_gcv_defaults (Display *dpy, XGCValues *gcv, int depth)
+{
+ memset (gcv, 0, sizeof(*gcv));
+ gcv->function = GXcopy;
+ gcv->foreground = (depth == 1 ? 1 : WhitePixel(dpy,0));
+ gcv->background = (depth == 1 ? 0 : BlackPixel(dpy,0));
+ gcv->line_width = 1;
+ gcv->cap_style = CapButt;
+ gcv->join_style = JoinMiter;
+ gcv->fill_rule = EvenOddRule;
+
+ gcv->alpha_allowed_p = False;
+ gcv->antialias_p = True;
+}
+
+
+int
+XChangeGC (Display *dpy, GC gc, unsigned long mask, XGCValues *from)
+{
+ if (! mask) return 0;
+ Assert (gc && from, "no gc");
+ if (!gc || !from) return 0;
+
+ XGCValues *to = jwxyz_gc_gcv (gc);
+ unsigned depth = jwxyz_gc_depth (gc);
+
+ if (mask & GCFunction) to->function = from->function;
+ if (mask & GCForeground) to->foreground = from->foreground;
+ if (mask & GCBackground) to->background = from->background;
+ if (mask & GCLineWidth) to->line_width = from->line_width;
+ if (mask & GCCapStyle) to->cap_style = from->cap_style;
+ if (mask & GCJoinStyle) to->join_style = from->join_style;
+ if (mask & GCFillRule) to->fill_rule = from->fill_rule;
+ if (mask & GCClipXOrigin) to->clip_x_origin = from->clip_x_origin;
+ if (mask & GCClipYOrigin) to->clip_y_origin = from->clip_y_origin;
+ if (mask & GCSubwindowMode) to->subwindow_mode = from->subwindow_mode;
+
+ if (mask & GCClipMask) XSetClipMask (0, gc, from->clip_mask);
+ if (mask & GCFont) XSetFont (0, gc, from->font);
+
+ if (mask & GCForeground)
+ jwxyz_validate_pixel (dpy, from->foreground, depth, to->alpha_allowed_p);
+ if (mask & GCBackground)
+ jwxyz_validate_pixel (dpy, from->background, depth, to->alpha_allowed_p);
+
+ Assert ((! (mask & (GCLineStyle |
+ GCPlaneMask |
+ GCFillStyle |
+ GCTile |
+ GCStipple |
+ GCTileStipXOrigin |
+ GCTileStipYOrigin |
+ GCGraphicsExposures |
+ GCDashOffset |
+ GCDashList |
+ GCArcMode))),
+ "unimplemented gcvalues mask");
+
+ return 0;
+}
+
+
+Status
+XGetWindowAttributes (Display *dpy, Window w, XWindowAttributes *xgwa)
+{
+ assert_window(dpy, w);
+ memset (xgwa, 0, sizeof(*xgwa));
+ const XRectangle *frame = jwxyz_frame (w);
+ xgwa->x = frame->x;
+ xgwa->y = frame->y;
+ xgwa->width = frame->width;
+ xgwa->height = frame->height;
+ xgwa->depth = visual_depth (NULL, NULL);
+ xgwa->screen = DefaultScreenOfDisplay (dpy);
+ xgwa->visual = XDefaultVisualOfScreen (xgwa->screen);
+ return 0;
+}
+
+Status
+XGetGeometry (Display *dpy, Drawable d, Window *root_ret,
+ int *x_ret, int *y_ret,
+ unsigned int *w_ret, unsigned int *h_ret,
+ unsigned int *bw_ret, unsigned int *d_ret)
+{
+ const XRectangle *frame = jwxyz_frame (d);
+ *x_ret = frame->x;
+ *y_ret = frame->y;
+ *w_ret = frame->width;
+ *h_ret = frame->height;
+ *d_ret = jwxyz_drawable_depth (d);
+ *root_ret = RootWindow (dpy, 0);
+ *bw_ret = 0;
+ return True;
+}
+
+
+Status
+XAllocColor (Display *dpy, Colormap cmap, XColor *color)
+{
+ color->pixel = jwxyz_alloc_color (dpy,
+ color->red,
+ color->green,
+ color->blue,
+ 0xFFFF);
+ return 1;
+}
+
+Status
+XAllocColorCells (Display *dpy, Colormap cmap, Bool contig,
+ unsigned long *pmret, unsigned int npl,
+ unsigned long *pxret, unsigned int npx)
+{
+ return 0;
+}
+
+int
+XStoreColors (Display *dpy, Colormap cmap, XColor *colors, int n)
+{
+ Assert(0, "XStoreColors called");
+ return 0;
+}
+
+int
+XStoreColor (Display *dpy, Colormap cmap, XColor *c)
+{
+ Assert(0, "XStoreColor called");
+ return 0;
+}
+
+int
+XFreeColors (Display *dpy, Colormap cmap, unsigned long *px, int npixels,
+ unsigned long planes)
+{
+ return 0;
+}
+
+Status
+XParseColor (Display *dpy, Colormap cmap, const char *spec, XColor *ret)
+{
+ unsigned char r=0, g=0, b=0;
+ if (*spec == '#' && strlen(spec) == 7) {
+ static unsigned const char hex[] = { // yeah yeah, shoot me.
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
+ 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ const unsigned char *uspec = (const unsigned char *)spec;
+ r = (hex[uspec[1]] << 4) | hex[uspec[2]];
+ g = (hex[uspec[3]] << 4) | hex[uspec[4]];
+ b = (hex[uspec[5]] << 4) | hex[uspec[6]];
+ } else if (!strcasecmp(spec,"black")) {
+ // r = g = b = 0;
+ } else if (!strcasecmp(spec,"white")) {
+ r = g = b = 255;
+ } else if (!strcasecmp(spec,"red")) {
+ r = 255;
+ } else if (!strcasecmp(spec,"green")) {
+ g = 255;
+ } else if (!strcasecmp(spec,"blue")) {
+ b = 255;
+ } else if (!strcasecmp(spec,"cyan")) {
+ g = b = 255;
+ } else if (!strcasecmp(spec,"magenta")) {
+ r = b = 255;
+ } else if (!strcasecmp(spec,"yellow")) {
+ r = g = 255;
+ } else {
+ return 0;
+ }
+
+ ret->red = (r << 8) | r;
+ ret->green = (g << 8) | g;
+ ret->blue = (b << 8) | b;
+ ret->flags = DoRed|DoGreen|DoBlue;
+ return 1;
+}
+
+Status
+XAllocNamedColor (Display *dpy, Colormap cmap, char *name,
+ XColor *screen_ret, XColor *exact_ret)
+{
+ if (! XParseColor (dpy, cmap, name, screen_ret))
+ return False;
+ *exact_ret = *screen_ret;
+ return XAllocColor (dpy, cmap, screen_ret);
+}
+
+int
+XQueryColor (Display *dpy, Colormap cmap, XColor *color)
+{
+ jwxyz_validate_pixel (dpy, color->pixel, visual_depth (NULL, NULL), False);
+ uint8_t rgba[4];
+ jwxyz_query_color (dpy, color->pixel, rgba);
+ color->red = (rgba[0] << 8) | rgba[0];
+ color->green = (rgba[1] << 8) | rgba[1];
+ color->blue = (rgba[2] << 8) | rgba[2];
+ color->flags = DoRed|DoGreen|DoBlue;
+ return 0;
+}
+
+int
+XQueryColors (Display *dpy, Colormap cmap, XColor *c, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ XQueryColor (dpy, cmap, &c[i]);
+ return 0;
+}
+
+
+static unsigned long
+ximage_getpixel_1 (XImage *ximage, int x, int y)
+{
+ return ((ximage->data [y * ximage->bytes_per_line + (x>>3)] >> (x & 7)) & 1);
+}
+
+static int
+ximage_putpixel_1 (XImage *ximage, int x, int y, unsigned long pixel)
+{
+ if (pixel)
+ ximage->data [y * ximage->bytes_per_line + (x>>3)] |= (1 << (x & 7));
+ else
+ ximage->data [y * ximage->bytes_per_line + (x>>3)] &= ~(1 << (x & 7));
+
+ return 0;
+}
+
+static unsigned long
+ximage_getpixel_32 (XImage *ximage, int x, int y)
+{
+ return ((unsigned long)
+ *((uint32_t *) ximage->data +
+ (y * (ximage->bytes_per_line >> 2)) +
+ x));
+}
+
+static int
+ximage_putpixel_32 (XImage *ximage, int x, int y, unsigned long pixel)
+{
+ *((uint32_t *) ximage->data +
+ (y * (ximage->bytes_per_line >> 2)) +
+ x) = (uint32_t) pixel;
+ return 0;
+}
+
+
+Status
+XInitImage (XImage *ximage)
+{
+ if (!ximage->bytes_per_line)
+ ximage->bytes_per_line = (ximage->depth == 1
+ ? (ximage->width + 7) / 8
+ : ximage->width * 4);
+
+ if (ximage->depth == 1) {
+ ximage->f.put_pixel = ximage_putpixel_1;
+ ximage->f.get_pixel = ximage_getpixel_1;
+ } else if (ximage->depth == 32 || ximage->depth == 24) {
+ ximage->f.put_pixel = ximage_putpixel_32;
+ ximage->f.get_pixel = ximage_getpixel_32;
+ } else {
+ Assert (0, "unknown depth");
+ }
+ return 1;
+}
+
+
+XImage *
+XCreateImage (Display *dpy, Visual *visual, unsigned int depth,
+ int format, int offset, char *data,
+ unsigned int width, unsigned int height,
+ int bitmap_pad, int bytes_per_line)
+{
+ XImage *ximage = (XImage *) calloc (1, sizeof(*ximage));
+ ximage->width = width;
+ ximage->height = height;
+ ximage->format = format;
+ ximage->data = data;
+ ximage->bitmap_unit = 8;
+ ximage->byte_order = LSBFirst;
+ ximage->bitmap_bit_order = ximage->byte_order;
+ ximage->bitmap_pad = bitmap_pad;
+ ximage->depth = depth;
+ Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay (dpy));
+ ximage->red_mask = (depth == 1 ? 0 : v->red_mask);
+ ximage->green_mask = (depth == 1 ? 0 : v->green_mask);
+ ximage->blue_mask = (depth == 1 ? 0 : v->blue_mask);
+ ximage->bits_per_pixel = (depth == 1 ? 1 : visual_depth (NULL, NULL));
+ ximage->bytes_per_line = bytes_per_line;
+
+ XInitImage (ximage);
+ return ximage;
+}
+
+XImage *
+XSubImage (XImage *from, int x, int y, unsigned int w, unsigned int h)
+{
+ XImage *to = (XImage *) malloc (sizeof(*to));
+ memcpy (to, from, sizeof(*from));
+ to->width = w;
+ to->height = h;
+ to->bytes_per_line = 0;
+ XInitImage (to);
+
+ to->data = (char *) malloc (h * to->bytes_per_line);
+
+ if (x >= from->width)
+ w = 0;
+ else if (x+w > from->width)
+ w = from->width - x;
+
+ if (y >= from->height)
+ h = 0;
+ else if (y+h > from->height)
+ h = from->height - y;
+
+ int tx, ty;
+ for (ty = 0; ty < h; ty++)
+ for (tx = 0; tx < w; tx++)
+ XPutPixel (to, tx, ty, XGetPixel (from, x+tx, y+ty));
+ return to;
+}
+
+
+XPixmapFormatValues *
+XListPixmapFormats (Display *dpy, int *n_ret)
+{
+ XPixmapFormatValues *ret = calloc (2, sizeof(*ret));
+ ret[0].depth = visual_depth (NULL, NULL);
+ ret[0].bits_per_pixel = 32;
+ ret[0].scanline_pad = 8;
+ ret[1].depth = 1;
+ ret[1].bits_per_pixel = 1;
+ ret[1].scanline_pad = 8;
+ *n_ret = 2;
+ return ret;
+}
+
+
+unsigned long
+XGetPixel (XImage *ximage, int x, int y)
+{
+ return ximage->f.get_pixel (ximage, x, y);
+}
+
+
+int
+XPutPixel (XImage *ximage, int x, int y, unsigned long pixel)
+{
+ return ximage->f.put_pixel (ximage, x, y, pixel);
+}
+
+int
+XDestroyImage (XImage *ximage)
+{
+ if (ximage->data) free (ximage->data);
+ free (ximage);
+ return 0;
+}
+
+
+Pixmap
+XCreatePixmapFromBitmapData (Display *dpy, Drawable drawable,
+ const char *data,
+ unsigned int w, unsigned int h,
+ unsigned long fg, unsigned int bg,
+ unsigned int depth)
+{
+ Pixmap p = XCreatePixmap (dpy, drawable, w, h, depth);
+ XImage *image = XCreateImage (dpy, 0, 1, XYPixmap, 0,
+ (char *) data, w, h, 0, 0);
+ XGCValues gcv;
+ gcv.foreground = fg;
+ gcv.background = bg;
+ GC gc = XCreateGC (dpy, p, GCForeground|GCBackground, &gcv);
+ XPutImage (dpy, p, gc, image, 0, 0, 0, 0, w, h);
+ XFreeGC (dpy, gc);
+ image->data = 0;
+ XDestroyImage (image);
+ return p;
+}
+
+
+char *
+XGetAtomName (Display *dpy, Atom atom)
+{
+ if (atom == XA_FONT)
+ return strdup ("FONT");
+
+ // Note that atoms (that aren't predefined) are just char *.
+ return strdup ((char *) atom);
+}
+
+
+int
+XSetForeground (Display *dpy, GC gc, unsigned long fg)
+{
+ XGCValues *gcv = jwxyz_gc_gcv (gc);
+ jwxyz_validate_pixel (dpy, fg, jwxyz_gc_depth (gc), gcv->alpha_allowed_p);
+ gcv->foreground = fg;
+ return 0;
+}
+
+
+int
+XSetBackground (Display *dpy, GC gc, unsigned long bg)
+{
+ XGCValues *gcv = jwxyz_gc_gcv (gc);
+ jwxyz_validate_pixel (dpy, bg, jwxyz_gc_depth (gc), gcv->alpha_allowed_p);
+ gcv->background = bg;
+ return 0;
+}
+
+int
+jwxyz_XSetAlphaAllowed (Display *dpy, GC gc, Bool allowed)
+{
+ jwxyz_gc_gcv (gc)->alpha_allowed_p = allowed;
+ return 0;
+}
+
+int
+jwxyz_XSetAntiAliasing (Display *dpy, GC gc, Bool antialias_p)
+{
+ jwxyz_gc_gcv (gc)->antialias_p = antialias_p;
+ return 0;
+}
+
+
+int
+XSetLineAttributes (Display *dpy, GC gc, unsigned int line_width,
+ int line_style, int cap_style, int join_style)
+{
+ XGCValues *gcv = jwxyz_gc_gcv (gc);
+ gcv->line_width = line_width;
+ Assert (line_style == LineSolid, "only LineSolid implemented");
+// gc->gcv.line_style = line_style;
+ gcv->cap_style = cap_style;
+ gcv->join_style = join_style;
+ return 0;
+}
+
+int
+XSetGraphicsExposures (Display *dpy, GC gc, Bool which)
+{
+ return 0;
+}
+
+int
+XSetFunction (Display *dpy, GC gc, int which)
+{
+ jwxyz_gc_gcv (gc)->function = which;
+ return 0;
+}
+
+int
+XSetSubwindowMode (Display *dpy, GC gc, int which)
+{
+ jwxyz_gc_gcv (gc)->subwindow_mode = which;
+ return 0;
+}
+
+
+Bool
+XQueryPointer (Display *dpy, Window w, Window *root_ret, Window *child_ret,
+ int *root_x_ret, int *root_y_ret,
+ int *win_x_ret, int *win_y_ret, unsigned int *mask_ret)
+{
+ assert_window (dpy, w);
+
+ XPoint vpos, p;
+ jwxyz_get_pos (w, &vpos, &p);
+
+ if (root_x_ret) *root_x_ret = p.x;
+ if (root_y_ret) *root_y_ret = p.y;
+ if (win_x_ret) *win_x_ret = p.x - vpos.x;
+ if (win_y_ret) *win_y_ret = p.y - vpos.y;
+ if (mask_ret) *mask_ret = 0; // #### poll the keyboard modifiers?
+ if (root_ret) *root_ret = 0;
+ if (child_ret) *child_ret = 0;
+ return True;
+}
+
+Bool
+XTranslateCoordinates (Display *dpy, Window w, Window dest_w,
+ int src_x, int src_y,
+ int *dest_x_ret, int *dest_y_ret,
+ Window *child_ret)
+{
+ assert_window (dpy, w);
+
+ XPoint vpos, p;
+ jwxyz_get_pos (w, &vpos, NULL);
+
+ // point starts out relative to top left of view
+ p.x = src_x;
+ p.y = src_y;
+
+ // get point relative to top left of screen
+ p.x += vpos.x;
+ p.y += vpos.y;
+
+ *dest_x_ret = p.x;
+ *dest_y_ret = p.y;
+ if (child_ret)
+ *child_ret = w;
+ return True;
+}
+
+
+KeySym
+XKeycodeToKeysym (Display *dpy, KeyCode code, int index)
+{
+ return code;
+}
+
+int
+XLookupString (XKeyEvent *e, char *buf, int size, KeySym *k_ret,
+ XComposeStatus *xc)
+{
+ KeySym ks = XKeycodeToKeysym (0, e->keycode, 0);
+ char c = 0;
+ // Do not put non-ASCII KeySyms like XK_Shift_L and XK_Page_Up in the string.
+ if ((unsigned int) ks <= 255)
+ c = (char) ks;
+
+ // Put control characters in the string. Not meta.
+ if (e->state & ControlMask) {
+ if (c >= 'a' && c <= 'z') // Upcase control.
+ c -= 'a'-'A';
+ if (c >= '@' && c <= '_') // Shift to control page.
+ c -= '@';
+ if (c == ' ') // C-SPC is NULL.
+ c = 0;
+ }
+
+ if (k_ret) *k_ret = ks;
+ if (size > 0) buf[0] = c;
+ if (size > 1) buf[1] = 0;
+ return (size > 0 ? 1 : 0);
+}
+
+
+int
+XFlush (Display *dpy)
+{
+ // Just let the event loop take care of this on its own schedule.
+ return 0;
+}
+
+int
+XSync (Display *dpy, Bool flush)
+{
+ return XFlush (dpy);
+}
+
+
+// declared in utils/visual.h
+int
+has_writable_cells (Screen *s, Visual *v)
+{
+ return 0;
+}
+
+int
+visual_depth (Screen *s, Visual *v)
+{
+ return 32;
+}
+
+int
+visual_cells (Screen *s, Visual *v)
+{
+ return (int)(v->red_mask | v->green_mask | v->blue_mask);
+}
+
+int
+visual_class (Screen *s, Visual *v)
+{
+ return TrueColor;
+}
+
+int
+get_bits_per_pixel (Display *dpy, int depth)
+{
+ Assert (depth == 32 || depth == 1, "unexpected depth");
+ return depth;
+}
+
+int
+screen_number (Screen *screen)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int i;
+ for (i = 0; i < ScreenCount (dpy); i++)
+ if (ScreenOfDisplay (dpy, i) == screen)
+ return i;
+ abort ();
+ return 0;
+}
+
+// declared in utils/grabclient.h
+Bool
+use_subwindow_mode_p (Screen *screen, Window window)
+{
+ return False;
+}
+
+#endif /* HAVE_JWXYZ */