a168bda299a258883cd246752459ef9b9cdbdfcc
[xscreensaver] / jwxyz / jwxyz-common.c
1 /* xscreensaver, Copyright (c) 1991-2016 Jamie Zawinski <jwz@jwz.org>
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
12 /* JWXYZ Is Not Xlib.
13
14    But it's a bunch of function definitions that bear some resemblance to
15    Xlib and that do Cocoa-ish or OpenGL-ish things that bear some resemblance
16    to the things that Xlib might have done.
17
18    This is the version of jwxyz for Android.  The version used by MacOS
19    and iOS is in jwxyz.m.
20  */
21
22 #include "config.h"
23
24 #ifdef HAVE_JWXYZ /* whole file */
25
26 #include "jwxyzI.h"
27
28 /* There's only one Window for a given jwxyz_Display. */
29 #define assert_window(dpy, w) \
30   Assert (w == RootWindow (dpy, 0), "not a window")
31
32 int
33 XDisplayWidth (Display *dpy, int screen)
34 {
35   return jwxyz_frame (XRootWindow (dpy, 0))->width;
36 }
37
38 int
39 XDisplayHeight (Display *dpy, int screen)
40 {
41   return jwxyz_frame (XRootWindow (dpy, 0))->height;
42 }
43
44
45 /* XLFDs use dots per inch, but Xlib uses millimeters. Go figure. */
46 static const unsigned dpi = 75;
47
48 int
49 XDisplayWidthMM (Display *dpy, int screen)
50 {
51   const unsigned denom = dpi * 10 / 2;
52   return (254 * XDisplayWidth (dpy, screen) + denom) / (2 * denom);
53 }
54
55 int
56 XDisplayHeightMM (Display *dpy, int screen)
57 {
58   const unsigned denom = dpi * 10 / 2;
59   return (254 * XDisplayHeight (dpy, screen) + denom) / (2 * denom);
60 }
61
62
63 void
64 jwxyz_validate_pixel (Display *dpy, unsigned long pixel, unsigned int depth,
65                       Bool alpha_allowed_p)
66 {
67   Assert (depth == 1 || depth == visual_depth(NULL, NULL),
68           "invalid depth: %d", depth);
69
70   if (depth == 1)
71     Assert ((pixel == 0 || pixel == 1), "bogus mono  pixel: 0x%08X", pixel);
72   else if (!alpha_allowed_p)
73     Assert (((pixel & BlackPixel(dpy,0)) == BlackPixel(dpy,0)),
74             "bogus color pixel: 0x%08X", pixel);
75 }
76
77
78 int
79 XDrawPoint (Display *dpy, Drawable d, GC gc, int x, int y)
80 {
81   XPoint p;
82   p.x = x;
83   p.y = y;
84   return XDrawPoints (dpy, d, gc, &p, 1, CoordModeOrigin);
85 }
86
87
88 Bool
89 jwxyz_dumb_drawing_mode(Display *dpy, Drawable d, GC gc,
90                         int x, int y, unsigned width, unsigned height)
91 {
92   XGCValues *gcv = jwxyz_gc_gcv (gc);
93
94   if (gcv->function == GXset || gcv->function == GXclear) {
95     // "set" and "clear" are dumb drawing modes that ignore the source
96     // bits and just draw solid rectangles.
97     unsigned depth = jwxyz_gc_depth (gc);
98     jwxyz_fill_rect (dpy, d, 0, x, y, width, height,
99                      (gcv->function == GXset
100                       ? (depth == 1 ? 1 : WhitePixel(dpy,0))
101                       : (depth == 1 ? 0 : BlackPixel(dpy,0))));
102     return True;
103   }
104
105   return False;
106 }
107
108
109 int
110 XCopyArea (Display *dpy, Drawable src, Drawable dst, GC gc, 
111            int src_x, int src_y, 
112            unsigned int width, unsigned int height, 
113            int dst_x, int dst_y)
114 {
115   Assert (gc, "no GC");
116   Assert ((width  < 65535), "improbably large width");
117   Assert ((height < 65535), "improbably large height");
118   Assert ((src_x  < 65535 && src_x  > -65535), "improbably large src_x");
119   Assert ((src_y  < 65535 && src_y  > -65535), "improbably large src_y");
120   Assert ((dst_x  < 65535 && dst_x  > -65535), "improbably large dst_x");
121   Assert ((dst_y  < 65535 && dst_y  > -65535), "improbably large dst_y");
122
123   if (width == 0 || height == 0)
124     return 0;
125
126   if (jwxyz_dumb_drawing_mode (dpy, dst, gc, dst_x, dst_y, width, height))
127     return 0;
128
129   XRectangle src_frame, dst_frame; // Sizes and origins of the two drawables
130   Bool clipped = False;            // Whether we did any clipping of the rects.
131
132   src_frame = *jwxyz_frame (src);
133   dst_frame = *jwxyz_frame (dst);
134   
135   // Initialize src_rect...
136   //
137   src_x += src_frame.x;
138   src_y += src_frame.y;
139   if (src_y < -65535) Assert(0, "src.origin.y went nuts");
140
141   // Initialize dst_rect...
142   //
143   dst_x += dst_frame.x;
144   dst_y += dst_frame.y;
145   if (dst_y < -65535) Assert(0, "dst.origin.y went nuts");
146
147   // Use signed width and height for this...
148   int width0 = width, height0 = height;
149
150   // Clip rects to frames...
151   //
152
153 # define CLIP(THIS,THAT,VAL,SIZE) do { \
154   int off = THIS##_##VAL; \
155   if (off < 0) { \
156     clipped = True; \
157     SIZE##0      += off; \
158     THIS##_##VAL -= off; \
159     THAT##_##VAL -= off; \
160   } \
161   off = (( THIS##_##VAL +  SIZE##0) - \
162          (THIS##_frame.VAL + THIS##_frame.SIZE)); \
163   if (off > 0) { \
164     clipped = True; \
165     SIZE##0 -= off; \
166   }} while(0)
167
168   CLIP (dst, src, x, width);
169   CLIP (dst, src, y, height);
170
171   // Not actually the original dst_rect, just the one before it's clipped to
172   // the src_frame.
173   int orig_dst_x = dst_x;
174   int orig_dst_y = dst_y;
175   int orig_width  = width0;
176   int orig_height = height0;
177
178   if (width0 <= 0 || height0 <= 0)
179     return 0;
180
181   CLIP (src, dst, x, width);
182   CLIP (src, dst, y, height);
183 # undef CLIP
184
185   // Sort-of-special case where no pixels can be grabbed from the source,
186   // and the whole destination is filled with the background color.
187   if (width0 <= 0 || height0 <= 0) {
188     width0  = 0;
189     height0 = 0;
190   } else {
191     jwxyz_copy_area (dpy, src, dst, gc,
192                      src_x, src_y, width0, height0, dst_x, dst_y);
193   }
194
195   // If either the src or dst rects did not lie within their drawables, then
196   // we have adjusted both the src and dst rects to account for the clipping;
197   // that means we need to clear to the background, so that clipped bits end
198   // up in the bg color instead of simply not being copied.
199   //
200   // This has to happen after the copy, because if it happens before, the
201   // cleared area will get grabbed if it overlaps with the source rectangle.
202   //
203   if (clipped && dst == XRootWindow (dpy,0)) {
204     int dst_x0 = dst_x;
205     int dst_y0 = dst_y;
206
207     Assert (orig_dst_x >= 0 &&
208             orig_dst_x + orig_width  <= dst_frame.width &&
209             orig_dst_y >= 0 &&
210             orig_dst_y + orig_height <= dst_frame.height,
211             "wrong dimensions");
212
213     XRectangle rects[4];
214     XRectangle *rects_end = rects;
215
216     if (orig_dst_y < dst_y0) {
217       rects_end->x = orig_dst_x;
218       rects_end->y = orig_dst_y;
219       rects_end->width = orig_width;
220       rects_end->height = dst_y0 - orig_dst_y;
221       ++rects_end;
222     }
223
224     if (orig_dst_y + orig_height > dst_y0 + height0) {
225       rects_end->x = orig_dst_x;
226       rects_end->y = dst_y0 + height0;
227       rects_end->width = orig_width;
228       rects_end->height = orig_dst_y + orig_height - dst_y0 - height0;
229       ++rects_end;
230     }
231
232     if (orig_dst_x < dst_x0) {
233       rects_end->x = orig_dst_x;
234       rects_end->y = dst_y0;
235       rects_end->width = dst_x0 - orig_dst_x;
236       rects_end->height = height0;
237       ++rects_end;
238     }
239
240     if (dst_x0 + width0 < orig_dst_x + orig_width) {
241       rects_end->x = dst_x0 + width0;
242       rects_end->y = dst_y0;
243       rects_end->width = orig_dst_x + orig_width - dst_x0 - width0;
244       rects_end->height = height0;
245       ++rects_end;
246     }
247
248     XGCValues *gcv = jwxyz_gc_gcv (gc);
249     int old_function = gcv->function;
250     gcv->function = GXcopy;
251     jwxyz_fill_rects (dpy, dst, gc, rects, rects_end - rects,
252                       jwxyz_window_background (dpy));
253     gcv->function = old_function;
254   }
255
256   return 0;
257 }
258
259
260 int
261 XCopyPlane (Display *dpy, Drawable src, Drawable dest, GC gc,
262             int src_x, int src_y,
263             unsigned width, int height,
264             int dest_x, int dest_y, unsigned long plane)
265 {
266   Assert ((jwxyz_gc_depth (gc) == 1 || plane == 1), "hairy plane mask!");
267   
268   // This isn't right: XCopyPlane() is supposed to map 1/0 to fg/bg,
269   // not to white/black.
270   return XCopyArea (dpy, src, dest, gc,
271                     src_x, src_y, width, height, dest_x, dest_y);
272 }
273
274
275 void
276 jwxyz_fill_rect (Display *dpy, Drawable d, GC gc,
277                  int x, int y, unsigned int width, unsigned int height,
278                  unsigned long pixel)
279 {
280   XRectangle r = {x, y, width, height};
281   jwxyz_fill_rects (dpy, d, gc, &r, 1, pixel);
282 }
283
284 int
285 XFillRectangle (Display *dpy, Drawable d, GC gc, int x, int y, 
286                 unsigned int width, unsigned int height)
287 {
288   jwxyz_fill_rect (dpy, d, gc, x, y, width, height,
289                    jwxyz_gc_gcv (gc)->foreground);
290   return 0;
291 }
292
293 int
294 XDrawRectangle (Display *dpy, Drawable d, GC gc, int x, int y, 
295                 unsigned int width, unsigned int height)
296 {
297   XPoint points[5] = {
298     {x, y},
299     {x, y + height},
300     {x + width, y + height},
301     {x + width, y},
302     {x, y}
303   };
304
305   XDrawLines(dpy, d, gc, points, 5, CoordModeOrigin);
306   return 0;
307 }
308
309 int
310 XFillRectangles (Display *dpy, Drawable d, GC gc, XRectangle *rects, int n)
311 {
312   jwxyz_fill_rects (dpy, d, gc, rects, n, jwxyz_gc_gcv (gc)->foreground);
313   return 0;
314 }
315
316
317 int
318 XDrawArc (Display *dpy, Drawable d, GC gc, int x, int y,
319           unsigned int width, unsigned int height, int angle1, int angle2)
320 {
321   return jwxyz_draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
322                          False);
323 }
324
325 int
326 XFillArc (Display *dpy, Drawable d, GC gc, int x, int y,
327           unsigned int width, unsigned int height, int angle1, int angle2)
328 {
329   return jwxyz_draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
330                          True);
331 }
332
333 int
334 XDrawArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
335 {
336   int i;
337   for (i = 0; i < narcs; i++)
338     jwxyz_draw_arc (dpy, d, gc,
339                     arcs[i].x, arcs[i].y,
340                     arcs[i].width, arcs[i].height,
341                     arcs[i].angle1, arcs[i].angle2,
342                     False);
343   return 0;
344 }
345
346 int
347 XFillArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
348 {
349   int i;
350   for (i = 0; i < narcs; i++)
351     jwxyz_draw_arc (dpy, d, gc,
352                     arcs[i].x, arcs[i].y,
353                     arcs[i].width, arcs[i].height,
354                     arcs[i].angle1, arcs[i].angle2,
355                     True);
356   return 0;
357 }
358
359 void
360 jwxyz_gcv_defaults (Display *dpy, XGCValues *gcv, int depth)
361 {
362   memset (gcv, 0, sizeof(*gcv));
363   gcv->function   = GXcopy;
364   gcv->foreground = (depth == 1 ? 1 : WhitePixel(dpy,0));
365   gcv->background = (depth == 1 ? 0 : BlackPixel(dpy,0));
366   gcv->line_width = 1;
367   gcv->cap_style  = CapButt;
368   gcv->join_style = JoinMiter;
369   gcv->fill_rule  = EvenOddRule;
370
371   gcv->alpha_allowed_p = False;
372   gcv->antialias_p     = True;
373 }
374
375
376 int
377 XChangeGC (Display *dpy, GC gc, unsigned long mask, XGCValues *from)
378 {
379   if (! mask) return 0;
380   Assert (gc && from, "no gc");
381   if (!gc || !from) return 0;
382
383   XGCValues *to = jwxyz_gc_gcv (gc);
384   unsigned depth = jwxyz_gc_depth (gc);
385
386   if (mask & GCFunction)        to->function            = from->function;
387   if (mask & GCForeground)      to->foreground          = from->foreground;
388   if (mask & GCBackground)      to->background          = from->background;
389   if (mask & GCLineWidth)       to->line_width          = from->line_width;
390   if (mask & GCCapStyle)        to->cap_style           = from->cap_style;
391   if (mask & GCJoinStyle)       to->join_style          = from->join_style;
392   if (mask & GCFillRule)        to->fill_rule           = from->fill_rule;
393   if (mask & GCClipXOrigin)     to->clip_x_origin       = from->clip_x_origin;
394   if (mask & GCClipYOrigin)     to->clip_y_origin       = from->clip_y_origin;
395   if (mask & GCSubwindowMode)   to->subwindow_mode      = from->subwindow_mode;
396
397   if (mask & GCClipMask)        XSetClipMask (0, gc, from->clip_mask);
398   if (mask & GCFont)            XSetFont (0, gc, from->font);
399
400   if (mask & GCForeground)
401     jwxyz_validate_pixel (dpy, from->foreground, depth, to->alpha_allowed_p);
402   if (mask & GCBackground)
403     jwxyz_validate_pixel (dpy, from->background, depth, to->alpha_allowed_p);
404
405   Assert ((! (mask & (GCLineStyle |
406                       GCPlaneMask |
407                       GCFillStyle |
408                       GCTile |
409                       GCStipple |
410                       GCTileStipXOrigin |
411                       GCTileStipYOrigin |
412                       GCGraphicsExposures |
413                       GCDashOffset |
414                       GCDashList |
415                       GCArcMode))),
416           "unimplemented gcvalues mask");
417
418   return 0;
419 }
420
421
422 Status
423 XGetWindowAttributes (Display *dpy, Window w, XWindowAttributes *xgwa)
424 {
425   assert_window(dpy, w);
426   memset (xgwa, 0, sizeof(*xgwa));
427   const XRectangle *frame = jwxyz_frame (w);
428   xgwa->x      = frame->x;
429   xgwa->y      = frame->y;
430   xgwa->width  = frame->width;
431   xgwa->height = frame->height;
432   xgwa->depth  = visual_depth (NULL, NULL);
433   xgwa->screen = DefaultScreenOfDisplay (dpy);
434   xgwa->visual = XDefaultVisualOfScreen (xgwa->screen);
435   return 0;
436 }
437
438 Status
439 XGetGeometry (Display *dpy, Drawable d, Window *root_ret,
440               int *x_ret, int *y_ret,
441               unsigned int *w_ret, unsigned int *h_ret,
442               unsigned int *bw_ret, unsigned int *d_ret)
443 {
444   const XRectangle *frame = jwxyz_frame (d);
445   *x_ret    = frame->x;
446   *y_ret    = frame->y;
447   *w_ret    = frame->width;
448   *h_ret    = frame->height;
449   *d_ret    = jwxyz_drawable_depth (d);
450   *root_ret = RootWindow (dpy, 0);
451   *bw_ret   = 0;
452   return True;
453 }
454
455
456 Status
457 XAllocColor (Display *dpy, Colormap cmap, XColor *color)
458 {
459   color->pixel = jwxyz_alloc_color (dpy,
460                                     color->red,
461                                     color->green,
462                                     color->blue,
463                                     0xFFFF);
464   return 1;
465 }
466
467 Status
468 XAllocColorCells (Display *dpy, Colormap cmap, Bool contig,
469                   unsigned long *pmret, unsigned int npl,
470                   unsigned long *pxret, unsigned int npx)
471 {
472   return 0;
473 }
474
475 int
476 XStoreColors (Display *dpy, Colormap cmap, XColor *colors, int n)
477 {
478   Assert(0, "XStoreColors called");
479   return 0;
480 }
481
482 int
483 XStoreColor (Display *dpy, Colormap cmap, XColor *c)
484 {
485   Assert(0, "XStoreColor called");
486   return 0;
487 }
488
489 int
490 XFreeColors (Display *dpy, Colormap cmap, unsigned long *px, int npixels,
491              unsigned long planes)
492 {
493   return 0;
494 }
495
496 Status
497 XParseColor (Display *dpy, Colormap cmap, const char *spec, XColor *ret)
498 {
499   unsigned char r=0, g=0, b=0;
500   if (*spec == '#' && strlen(spec) == 7) {
501     static unsigned const char hex[] = {   // yeah yeah, shoot me.
502       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,
503       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,
504       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,
505       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,
506       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,
507       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,
508       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,
509       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};
510     const unsigned char *uspec = (const unsigned char *)spec;
511     r = (hex[uspec[1]] << 4) | hex[uspec[2]];
512     g = (hex[uspec[3]] << 4) | hex[uspec[4]];
513     b = (hex[uspec[5]] << 4) | hex[uspec[6]];
514   } else if (!strcasecmp(spec,"black")) {
515     //  r = g = b = 0;
516   } else if (!strcasecmp(spec,"white")) {
517     r = g = b = 255;
518   } else if (!strcasecmp(spec,"red")) {
519     r = 255;
520   } else if (!strcasecmp(spec,"green")) {
521     g = 255;
522   } else if (!strcasecmp(spec,"blue")) {
523     b = 255;
524   } else if (!strcasecmp(spec,"cyan")) {
525     g = b = 255;
526   } else if (!strcasecmp(spec,"magenta")) {
527     r = b = 255;
528   } else if (!strcasecmp(spec,"yellow")) {
529     r = g = 255;
530   } else {
531     return 0;
532   }
533
534   ret->red   = (r << 8) | r;
535   ret->green = (g << 8) | g;
536   ret->blue  = (b << 8) | b;
537   ret->flags = DoRed|DoGreen|DoBlue;
538   return 1;
539 }
540
541 Status
542 XAllocNamedColor (Display *dpy, Colormap cmap, char *name,
543                   XColor *screen_ret, XColor *exact_ret)
544 {
545   if (! XParseColor (dpy, cmap, name, screen_ret))
546     return False;
547   *exact_ret = *screen_ret;
548   return XAllocColor (dpy, cmap, screen_ret);
549 }
550
551 int
552 XQueryColor (Display *dpy, Colormap cmap, XColor *color)
553 {
554   jwxyz_validate_pixel (dpy, color->pixel, visual_depth (NULL, NULL), False);
555   uint8_t rgba[4];
556   jwxyz_query_color (dpy, color->pixel, rgba);
557   color->red   = (rgba[0] << 8) | rgba[0];
558   color->green = (rgba[1] << 8) | rgba[1];
559   color->blue  = (rgba[2] << 8) | rgba[2];
560   color->flags = DoRed|DoGreen|DoBlue;
561   return 0;
562 }
563
564 int
565 XQueryColors (Display *dpy, Colormap cmap, XColor *c, int n)
566 {
567   int i;
568   for (i = 0; i < n; i++)
569     XQueryColor (dpy, cmap, &c[i]);
570   return 0;
571 }
572
573
574 static unsigned long
575 ximage_getpixel_1 (XImage *ximage, int x, int y)
576 {
577   return ((ximage->data [y * ximage->bytes_per_line + (x>>3)] >> (x & 7)) & 1);
578 }
579
580 static int
581 ximage_putpixel_1 (XImage *ximage, int x, int y, unsigned long pixel)
582 {
583   if (pixel)
584     ximage->data [y * ximage->bytes_per_line + (x>>3)] |=  (1 << (x & 7));
585   else
586     ximage->data [y * ximage->bytes_per_line + (x>>3)] &= ~(1 << (x & 7));
587
588   return 0;
589 }
590
591 static unsigned long
592 ximage_getpixel_32 (XImage *ximage, int x, int y)
593 {
594   return ((unsigned long)
595           *((uint32_t *) ximage->data +
596             (y * (ximage->bytes_per_line >> 2)) +
597             x));
598 }
599
600 static int
601 ximage_putpixel_32 (XImage *ximage, int x, int y, unsigned long pixel)
602 {
603   *((uint32_t *) ximage->data +
604     (y * (ximage->bytes_per_line >> 2)) +
605     x) = (uint32_t) pixel;
606   return 0;
607 }
608
609
610 Status
611 XInitImage (XImage *ximage)
612 {
613   if (!ximage->bytes_per_line)
614     ximage->bytes_per_line = (ximage->depth == 1
615                               ? (ximage->width + 7) / 8
616                               : ximage->width * 4);
617
618   if (ximage->depth == 1) {
619     ximage->f.put_pixel = ximage_putpixel_1;
620     ximage->f.get_pixel = ximage_getpixel_1;
621   } else if (ximage->depth == 32 || ximage->depth == 24) {
622     ximage->f.put_pixel = ximage_putpixel_32;
623     ximage->f.get_pixel = ximage_getpixel_32;
624   } else {
625     Assert (0, "unknown depth");
626   }
627   return 1;
628 }
629
630
631 XImage *
632 XCreateImage (Display *dpy, Visual *visual, unsigned int depth,
633               int format, int offset, char *data,
634               unsigned int width, unsigned int height,
635               int bitmap_pad, int bytes_per_line)
636 {
637   XImage *ximage = (XImage *) calloc (1, sizeof(*ximage));
638   ximage->width = width;
639   ximage->height = height;
640   ximage->format = format;
641   ximage->data = data;
642   ximage->bitmap_unit = 8;
643   ximage->byte_order = LSBFirst;
644   ximage->bitmap_bit_order = ximage->byte_order;
645   ximage->bitmap_pad = bitmap_pad;
646   ximage->depth = depth;
647   Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay (dpy));
648   ximage->red_mask   = (depth == 1 ? 0 : v->red_mask);
649   ximage->green_mask = (depth == 1 ? 0 : v->green_mask);
650   ximage->blue_mask  = (depth == 1 ? 0 : v->blue_mask);
651   ximage->bits_per_pixel = (depth == 1 ? 1 : visual_depth (NULL, NULL));
652   ximage->bytes_per_line = bytes_per_line;
653
654   XInitImage (ximage);
655   return ximage;
656 }
657
658 XImage *
659 XSubImage (XImage *from, int x, int y, unsigned int w, unsigned int h)
660 {
661   XImage *to = (XImage *) malloc (sizeof(*to));
662   memcpy (to, from, sizeof(*from));
663   to->width = w;
664   to->height = h;
665   to->bytes_per_line = 0;
666   XInitImage (to);
667
668   to->data = (char *) malloc (h * to->bytes_per_line);
669
670   if (x >= from->width)
671     w = 0;
672   else if (x+w > from->width)
673     w = from->width - x;
674
675   if (y >= from->height)
676     h = 0;
677   else if (y+h > from->height)
678     h = from->height - y;
679
680   int tx, ty;
681   for (ty = 0; ty < h; ty++)
682     for (tx = 0; tx < w; tx++)
683       XPutPixel (to, tx, ty, XGetPixel (from, x+tx, y+ty));
684   return to;
685 }
686
687
688 XPixmapFormatValues *
689 XListPixmapFormats (Display *dpy, int *n_ret)
690 {
691   XPixmapFormatValues *ret = calloc (2, sizeof(*ret));
692   ret[0].depth = visual_depth (NULL, NULL);
693   ret[0].bits_per_pixel = 32;
694   ret[0].scanline_pad = 8;
695   ret[1].depth = 1;
696   ret[1].bits_per_pixel = 1;
697   ret[1].scanline_pad = 8;
698   *n_ret = 2;
699   return ret;
700 }
701
702
703 unsigned long
704 XGetPixel (XImage *ximage, int x, int y)
705 {
706   return ximage->f.get_pixel (ximage, x, y);
707 }
708
709
710 int
711 XPutPixel (XImage *ximage, int x, int y, unsigned long pixel)
712 {
713   return ximage->f.put_pixel (ximage, x, y, pixel);
714 }
715
716 int
717 XDestroyImage (XImage *ximage)
718 {
719   if (ximage->data) free (ximage->data);
720   free (ximage);
721   return 0;
722 }
723
724
725 Pixmap
726 XCreatePixmapFromBitmapData (Display *dpy, Drawable drawable,
727                              const char *data,
728                              unsigned int w, unsigned int h,
729                              unsigned long fg, unsigned int bg,
730                              unsigned int depth)
731 {
732   Pixmap p = XCreatePixmap (dpy, drawable, w, h, depth);
733   XImage *image = XCreateImage (dpy, 0, 1, XYPixmap, 0,
734                                 (char *) data, w, h, 0, 0);
735   XGCValues gcv;
736   gcv.foreground = fg;
737   gcv.background = bg;
738   GC gc = XCreateGC (dpy, p, GCForeground|GCBackground, &gcv);
739   XPutImage (dpy, p, gc, image, 0, 0, 0, 0, w, h);
740   XFreeGC (dpy, gc);
741   image->data = 0;
742   XDestroyImage (image);
743   return p;
744 }
745
746
747 char *
748 XGetAtomName (Display *dpy, Atom atom)
749 {
750   if (atom == XA_FONT)
751     return strdup ("FONT");
752
753   // Note that atoms (that aren't predefined) are just char *.
754   return strdup ((char *) atom);
755 }
756
757
758 int
759 XSetForeground (Display *dpy, GC gc, unsigned long fg)
760 {
761   XGCValues *gcv = jwxyz_gc_gcv (gc);
762   jwxyz_validate_pixel (dpy, fg, jwxyz_gc_depth (gc), gcv->alpha_allowed_p);
763   gcv->foreground = fg;
764   return 0;
765 }
766
767
768 int
769 XSetBackground (Display *dpy, GC gc, unsigned long bg)
770 {
771   XGCValues *gcv = jwxyz_gc_gcv (gc);
772   jwxyz_validate_pixel (dpy, bg, jwxyz_gc_depth (gc), gcv->alpha_allowed_p);
773   gcv->background = bg;
774   return 0;
775 }
776
777 int
778 jwxyz_XSetAlphaAllowed (Display *dpy, GC gc, Bool allowed)
779 {
780   jwxyz_gc_gcv (gc)->alpha_allowed_p = allowed;
781   return 0;
782 }
783
784 int
785 jwxyz_XSetAntiAliasing (Display *dpy, GC gc, Bool antialias_p)
786 {
787   jwxyz_gc_gcv (gc)->antialias_p = antialias_p;
788   return 0;
789 }
790
791
792 int
793 XSetLineAttributes (Display *dpy, GC gc, unsigned int line_width,
794                     int line_style, int cap_style, int join_style)
795 {
796   XGCValues *gcv = jwxyz_gc_gcv (gc);
797   gcv->line_width = line_width;
798   Assert (line_style == LineSolid, "only LineSolid implemented");
799 //  gc->gcv.line_style = line_style;
800   gcv->cap_style = cap_style;
801   gcv->join_style = join_style;
802   return 0;
803 }
804
805 int
806 XSetGraphicsExposures (Display *dpy, GC gc, Bool which)
807 {
808   return 0;
809 }
810
811 int
812 XSetFunction (Display *dpy, GC gc, int which)
813 {
814   jwxyz_gc_gcv (gc)->function = which;
815   return 0;
816 }
817
818 int
819 XSetSubwindowMode (Display *dpy, GC gc, int which)
820 {
821   jwxyz_gc_gcv (gc)->subwindow_mode = which;
822   return 0;
823 }
824
825
826 Bool
827 XQueryPointer (Display *dpy, Window w, Window *root_ret, Window *child_ret,
828                int *root_x_ret, int *root_y_ret,
829                int *win_x_ret, int *win_y_ret, unsigned int *mask_ret)
830 {
831   assert_window (dpy, w);
832
833   XPoint vpos, p;
834   jwxyz_get_pos (w, &vpos, &p);
835
836   if (root_x_ret) *root_x_ret = p.x;
837   if (root_y_ret) *root_y_ret = p.y;
838   if (win_x_ret)  *win_x_ret  = p.x - vpos.x;
839   if (win_y_ret)  *win_y_ret  = p.y - vpos.y;
840   if (mask_ret)   *mask_ret   = 0;  // #### poll the keyboard modifiers?
841   if (root_ret)   *root_ret   = 0;
842   if (child_ret)  *child_ret  = 0;
843   return True;
844 }
845
846 Bool
847 XTranslateCoordinates (Display *dpy, Window w, Window dest_w,
848                        int src_x, int src_y,
849                        int *dest_x_ret, int *dest_y_ret,
850                        Window *child_ret)
851 {
852   assert_window (dpy, w);
853
854   XPoint vpos, p;
855   jwxyz_get_pos (w, &vpos, NULL);
856
857   // point starts out relative to top left of view
858   p.x = src_x;
859   p.y = src_y;
860
861   // get point relative to top left of screen
862   p.x += vpos.x;
863   p.y += vpos.y;
864
865   *dest_x_ret = p.x;
866   *dest_y_ret = p.y;
867   if (child_ret)
868     *child_ret = w;
869   return True;
870 }
871
872
873 KeySym
874 XKeycodeToKeysym (Display *dpy, KeyCode code, int index)
875 {
876   return code;
877 }
878
879 int
880 XLookupString (XKeyEvent *e, char *buf, int size, KeySym *k_ret,
881                XComposeStatus *xc)
882 {
883   KeySym ks = XKeycodeToKeysym (0, e->keycode, 0);
884   char c = 0;
885   // Do not put non-ASCII KeySyms like XK_Shift_L and XK_Page_Up in the string.
886   if ((unsigned int) ks <= 255)
887     c = (char) ks;
888
889   // Put control characters in the string.  Not meta.
890   if (e->state & ControlMask) {
891     if (c >= 'a' && c <= 'z')    // Upcase control.
892       c -= 'a'-'A';
893     if (c >= '@' && c <= '_')    // Shift to control page.
894       c -= '@';
895     if (c == ' ')                // C-SPC is NULL.
896       c = 0;
897   }
898
899   if (k_ret) *k_ret = ks;
900   if (size > 0) buf[0] = c;
901   if (size > 1) buf[1] = 0;
902   return (size > 0 ? 1 : 0);
903 }
904
905
906 int
907 XFlush (Display *dpy)
908 {
909   // Just let the event loop take care of this on its own schedule.
910   return 0;
911 }
912
913 int
914 XSync (Display *dpy, Bool flush)
915 {
916   return XFlush (dpy);
917 }
918
919
920 // declared in utils/visual.h
921 int
922 has_writable_cells (Screen *s, Visual *v)
923 {
924   return 0;
925 }
926
927 int
928 visual_depth (Screen *s, Visual *v)
929 {
930   return 32;
931 }
932
933 int
934 visual_cells (Screen *s, Visual *v)
935 {
936   return (int)(v->red_mask | v->green_mask | v->blue_mask);
937 }
938
939 int
940 visual_class (Screen *s, Visual *v)
941 {
942   return TrueColor;
943 }
944
945 int
946 get_bits_per_pixel (Display *dpy, int depth)
947 {
948   Assert (depth == 32 || depth == 1, "unexpected depth");
949   return depth;
950 }
951
952 int
953 screen_number (Screen *screen)
954 {
955   Display *dpy = DisplayOfScreen (screen);
956   int i;
957   for (i = 0; i < ScreenCount (dpy); i++)
958     if (ScreenOfDisplay (dpy, i) == screen)
959       return i;
960   abort ();
961   return 0;
962 }
963
964 // declared in utils/grabclient.h
965 Bool
966 use_subwindow_mode_p (Screen *screen, Window window)
967 {
968   return False;
969 }
970
971 #endif /* HAVE_JWXYZ */