1 /* xscreensaver, Copyright (c) 1991-2018 Jamie Zawinski <jwz@jwz.org>
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
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.
18 This is the version of jwxyz for Android. The version used by MacOS
19 and iOS is in jwxyz.m.
26 #ifdef HAVE_JWXYZ /* whole file */
37 /* There's only one Window for a given jwxyz_Display. */
38 #define assert_window(dpy, w) \
39 Assert (w == RootWindow (dpy, 0), "not a window")
41 #define VTBL JWXYZ_VTBL(dpy)
46 int refcount; // for deciding when to release the native font
50 // In X11, "Font" is just an ID, and "XFontStruct" contains the metrics.
51 // But we need the metrics on both of them, so they go here.
55 struct jwxyz_XFontSet {
61 Log (const char *fmt, ...)
71 XDisplayWidth (Display *dpy, int screen)
73 return jwxyz_frame (XRootWindow (dpy, 0))->width;
77 XDisplayHeight (Display *dpy, int screen)
79 return jwxyz_frame (XRootWindow (dpy, 0))->height;
83 /* XLFDs use dots per inch, but Xlib uses millimeters. Go figure. */
85 size_mm (Display *dpy, unsigned size)
87 /* ((mm / inch) / (points / inch)) * dots / (dots / points) */
88 return (25.4 / 72) * size / jwxyz_scale (XRootWindow (dpy,0)) + 0.5;
92 XDisplayWidthMM (Display *dpy, int screen)
94 return size_mm (dpy, XDisplayWidth (dpy, screen));
98 XDisplayHeightMM (Display *dpy, int screen)
100 return size_mm (dpy, XDisplayHeight (dpy, screen));
104 XBlackPixelOfScreen(Screen *screen)
106 return DefaultVisualOfScreen (screen)->alpha_mask;
110 XWhitePixelOfScreen(Screen *screen)
112 Visual *v = DefaultVisualOfScreen (screen);
113 return (v->red_mask | v->green_mask |v->blue_mask | v->alpha_mask);
117 XCellsOfScreen(Screen *screen)
119 Visual *v = DefaultVisualOfScreen (screen);
120 return (v->red_mask | v->green_mask |v->blue_mask);
124 jwxyz_validate_pixel (Display *dpy, unsigned long pixel, unsigned int depth,
125 Bool alpha_allowed_p)
127 Assert (depth == 1 || depth == visual_depth(NULL, NULL),
128 "invalid depth: %d", depth);
131 Assert ((pixel == 0 || pixel == 1), "bogus mono pixel: 0x%08X", pixel);
132 else if (!alpha_allowed_p)
133 Assert (((pixel & BlackPixel(dpy,0)) == BlackPixel(dpy,0)),
134 "bogus color pixel: 0x%08X", pixel);
139 XDrawPoint (Display *dpy, Drawable d, GC gc, int x, int y)
144 return XDrawPoints (dpy, d, gc, &p, 1, CoordModeOrigin);
149 jwxyz_dumb_drawing_mode(Display *dpy, Drawable d, GC gc,
150 int x, int y, unsigned width, unsigned height)
152 XGCValues *gcv = VTBL->gc_gcv (gc);
154 if (gcv->function == GXset || gcv->function == GXclear) {
155 // "set" and "clear" are dumb drawing modes that ignore the source
156 // bits and just draw solid rectangles.
157 unsigned depth = VTBL->gc_depth (gc);
158 jwxyz_fill_rect (dpy, d, 0, x, y, width, height,
159 (gcv->function == GXset
160 ? (depth == 1 ? 1 : WhitePixel(dpy,0))
161 : (depth == 1 ? 0 : BlackPixel(dpy,0))));
170 XCopyArea (Display *dpy, Drawable src, Drawable dst, GC gc,
171 int src_x, int src_y,
172 unsigned int width, unsigned int height,
173 int dst_x, int dst_y)
175 Assert (gc, "no GC");
176 Assert ((width < 65535), "improbably large width");
177 Assert ((height < 65535), "improbably large height");
178 Assert ((src_x < 65535 && src_x > -65535), "improbably large src_x");
179 Assert ((src_y < 65535 && src_y > -65535), "improbably large src_y");
180 Assert ((dst_x < 65535 && dst_x > -65535), "improbably large dst_x");
181 Assert ((dst_y < 65535 && dst_y > -65535), "improbably large dst_y");
183 if (width == 0 || height == 0)
186 if (jwxyz_dumb_drawing_mode (dpy, dst, gc, dst_x, dst_y, width, height))
189 XRectangle src_frame, dst_frame; // Sizes and origins of the two drawables
190 Bool clipped = False; // Whether we did any clipping of the rects.
192 src_frame = *jwxyz_frame (src);
193 dst_frame = *jwxyz_frame (dst);
195 // Initialize src_rect...
197 src_x += src_frame.x;
198 src_y += src_frame.y;
199 if (src_y < -65535) Assert(0, "src.origin.y went nuts");
201 // Initialize dst_rect...
203 dst_x += dst_frame.x;
204 dst_y += dst_frame.y;
205 if (dst_y < -65535) Assert(0, "dst.origin.y went nuts");
207 // Use signed width and height for this...
208 int width0 = width, height0 = height;
210 // Clip rects to frames...
213 # define CLIP(THIS,THAT,VAL,SIZE) do { \
214 int off = THIS##_##VAL; \
218 THIS##_##VAL -= off; \
219 THAT##_##VAL -= off; \
221 off = (( THIS##_##VAL + SIZE##0) - \
222 (THIS##_frame.VAL + THIS##_frame.SIZE)); \
228 CLIP (dst, src, x, width);
229 CLIP (dst, src, y, height);
231 // Not actually the original dst_rect, just the one before it's clipped to
233 int orig_dst_x = dst_x;
234 int orig_dst_y = dst_y;
235 int orig_width = width0;
236 int orig_height = height0;
238 if (width0 <= 0 || height0 <= 0)
241 CLIP (src, dst, x, width);
242 CLIP (src, dst, y, height);
245 // Sort-of-special case where no pixels can be grabbed from the source,
246 // and the whole destination is filled with the background color.
247 if (width0 <= 0 || height0 <= 0) {
251 VTBL->copy_area (dpy, src, dst, gc,
252 src_x, src_y, width0, height0, dst_x, dst_y);
255 // If either the src or dst rects did not lie within their drawables, then
256 // we have adjusted both the src and dst rects to account for the clipping;
257 // that means we need to clear to the background, so that clipped bits end
258 // up in the bg color instead of simply not being copied.
260 // This has to happen after the copy, because if it happens before, the
261 // cleared area will get grabbed if it overlaps with the source rectangle.
263 if (clipped && dst == XRootWindow (dpy,0)) {
267 Assert (orig_dst_x >= 0 &&
268 orig_dst_x + orig_width <= dst_frame.width &&
270 orig_dst_y + orig_height <= dst_frame.height,
274 XRectangle *rects_end = rects;
276 if (orig_dst_y < dst_y0) {
277 rects_end->x = orig_dst_x;
278 rects_end->y = orig_dst_y;
279 rects_end->width = orig_width;
280 rects_end->height = dst_y0 - orig_dst_y;
284 if (orig_dst_y + orig_height > dst_y0 + height0) {
285 rects_end->x = orig_dst_x;
286 rects_end->y = dst_y0 + height0;
287 rects_end->width = orig_width;
288 rects_end->height = orig_dst_y + orig_height - dst_y0 - height0;
292 if (orig_dst_x < dst_x0) {
293 rects_end->x = orig_dst_x;
294 rects_end->y = dst_y0;
295 rects_end->width = dst_x0 - orig_dst_x;
296 rects_end->height = height0;
300 if (dst_x0 + width0 < orig_dst_x + orig_width) {
301 rects_end->x = dst_x0 + width0;
302 rects_end->y = dst_y0;
303 rects_end->width = orig_dst_x + orig_width - dst_x0 - width0;
304 rects_end->height = height0;
308 XGCValues *gcv = VTBL->gc_gcv (gc);
309 int old_function = gcv->function;
310 gcv->function = GXcopy;
311 VTBL->fill_rects (dpy, dst, gc, rects, rects_end - rects,
312 *VTBL->window_background (dpy));
313 gcv->function = old_function;
321 jwxyz_blit (const void *src_data, ptrdiff_t src_pitch,
322 unsigned src_x, unsigned src_y,
323 void *dst_data, ptrdiff_t dst_pitch,
324 unsigned dst_x, unsigned dst_y,
325 unsigned width, unsigned height)
327 Bool same = src_data == dst_data;
328 src_data = SEEK_XY (src_data, src_pitch, src_x, src_y);
329 dst_data = SEEK_XY (dst_data, dst_pitch, dst_x, dst_y);
331 size_t bytes = width * 4;
333 if (same && dst_y > src_y) {
334 // Copy upwards if the areas might overlap.
335 src_data += src_pitch * (height - 1);
336 dst_data += dst_pitch * (height - 1);
337 src_pitch = -src_pitch;
338 dst_pitch = -dst_pitch;
342 // memcpy is an alias for memmove on macOS.
343 memmove (dst_data, src_data, bytes);
344 src_data += src_pitch;
345 dst_data += dst_pitch;
352 XCopyPlane (Display *dpy, Drawable src, Drawable dest, GC gc,
353 int src_x, int src_y,
354 unsigned width, int height,
355 int dest_x, int dest_y, unsigned long plane)
357 Assert ((VTBL->gc_depth (gc) == 1 || plane == 1), "hairy plane mask!");
359 // This isn't right: XCopyPlane() is supposed to map 1/0 to fg/bg,
360 // not to white/black.
361 return XCopyArea (dpy, src, dest, gc,
362 src_x, src_y, width, height, dest_x, dest_y);
367 XDrawLine (Display *dpy, Drawable d, GC gc, int x1, int y1, int x2, int y2)
374 XDrawSegments (dpy, d, gc, &segment, 1);
380 XSetWindowBackground (Display *dpy, Window w, unsigned long pixel)
382 Assert (w == XRootWindow (dpy,0), "not a window");
383 jwxyz_validate_pixel (dpy, pixel, visual_depth (NULL, NULL), False);
384 *VTBL->window_background (dpy) = pixel;
389 jwxyz_fill_rect (Display *dpy, Drawable d, GC gc,
390 int x, int y, unsigned int width, unsigned int height,
393 XRectangle r = {x, y, width, height};
394 VTBL->fill_rects (dpy, d, gc, &r, 1, pixel);
398 XFillRectangle (Display *dpy, Drawable d, GC gc, int x, int y,
399 unsigned int width, unsigned int height)
401 jwxyz_fill_rect (dpy, d, gc, x, y, width, height,
402 VTBL->gc_gcv (gc)->foreground);
407 XDrawRectangle (Display *dpy, Drawable d, GC gc, int x, int y,
408 unsigned int width, unsigned int height)
413 {x + width, y + height},
418 XDrawLines(dpy, d, gc, points, 5, CoordModeOrigin);
423 XFillRectangles (Display *dpy, Drawable d, GC gc, XRectangle *rects, int n)
425 VTBL->fill_rects (dpy, d, gc, rects, n, VTBL->gc_gcv (gc)->foreground);
431 XClearArea (Display *dpy, Window win, int x, int y, int w, int h, Bool exp)
433 Assert(win == XRootWindow(dpy,0), "XClearArea: not a window");
434 Assert(!exp, "XClearArea: exposures unsupported");
435 jwxyz_fill_rect (dpy, win, 0, x, y, w, h, *VTBL->window_background (dpy));
441 XDrawArc (Display *dpy, Drawable d, GC gc, int x, int y,
442 unsigned int width, unsigned int height, int angle1, int angle2)
444 return VTBL->draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
449 XFillArc (Display *dpy, Drawable d, GC gc, int x, int y,
450 unsigned int width, unsigned int height, int angle1, int angle2)
452 return VTBL->draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
457 XDrawArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
460 for (i = 0; i < narcs; i++)
461 VTBL->draw_arc (dpy, d, gc,
462 arcs[i].x, arcs[i].y,
463 arcs[i].width, arcs[i].height,
464 arcs[i].angle1, arcs[i].angle2,
470 XFillArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
473 for (i = 0; i < narcs; i++)
474 VTBL->draw_arc (dpy, d, gc,
475 arcs[i].x, arcs[i].y,
476 arcs[i].width, arcs[i].height,
477 arcs[i].angle1, arcs[i].angle2,
483 jwxyz_gcv_defaults (Display *dpy, XGCValues *gcv, int depth)
485 memset (gcv, 0, sizeof(*gcv));
486 gcv->function = GXcopy;
487 gcv->foreground = (depth == 1 ? 1 : WhitePixel(dpy,0));
488 gcv->background = (depth == 1 ? 0 : BlackPixel(dpy,0));
490 gcv->cap_style = CapButt;
491 gcv->join_style = JoinMiter;
492 gcv->fill_rule = EvenOddRule;
494 gcv->alpha_allowed_p = False;
495 gcv->antialias_p = True;
500 XChangeGC (Display *dpy, GC gc, unsigned long mask, XGCValues *from)
502 if (! mask) return 0;
503 Assert (gc && from, "no gc");
504 if (!gc || !from) return 0;
506 XGCValues *to = VTBL->gc_gcv (gc);
507 unsigned depth = VTBL->gc_depth (gc);
509 if (mask & GCFunction) to->function = from->function;
510 if (mask & GCForeground) to->foreground = from->foreground;
511 if (mask & GCBackground) to->background = from->background;
512 if (mask & GCLineWidth) to->line_width = from->line_width;
513 if (mask & GCCapStyle) to->cap_style = from->cap_style;
514 if (mask & GCJoinStyle) to->join_style = from->join_style;
515 if (mask & GCFillRule) to->fill_rule = from->fill_rule;
516 if (mask & GCClipXOrigin) to->clip_x_origin = from->clip_x_origin;
517 if (mask & GCClipYOrigin) to->clip_y_origin = from->clip_y_origin;
518 if (mask & GCSubwindowMode) to->subwindow_mode = from->subwindow_mode;
520 if (mask & GCClipMask) XSetClipMask (dpy, gc, from->clip_mask);
521 if (mask & GCFont) XSetFont (dpy, gc, from->font);
523 if (mask & GCForeground)
524 jwxyz_validate_pixel (dpy, from->foreground, depth, to->alpha_allowed_p);
525 if (mask & GCBackground)
526 jwxyz_validate_pixel (dpy, from->background, depth, to->alpha_allowed_p);
528 Assert ((! (mask & (GCLineStyle |
535 GCGraphicsExposures |
539 "unimplemented gcvalues mask");
546 XGetWindowAttributes (Display *dpy, Window w, XWindowAttributes *xgwa)
548 assert_window(dpy, w);
549 memset (xgwa, 0, sizeof(*xgwa));
550 const XRectangle *frame = jwxyz_frame (w);
553 xgwa->width = frame->width;
554 xgwa->height = frame->height;
555 xgwa->depth = visual_depth (NULL, NULL);
556 xgwa->screen = DefaultScreenOfDisplay (dpy);
557 xgwa->visual = XDefaultVisualOfScreen (xgwa->screen);
562 XGetGeometry (Display *dpy, Drawable d, Window *root_ret,
563 int *x_ret, int *y_ret,
564 unsigned int *w_ret, unsigned int *h_ret,
565 unsigned int *bw_ret, unsigned int *d_ret)
567 const XRectangle *frame = jwxyz_frame (d);
570 *w_ret = frame->width;
571 *h_ret = frame->height;
572 *d_ret = jwxyz_drawable_depth (d);
573 *root_ret = RootWindow (dpy, 0);
580 XAllocColor (Display *dpy, Colormap cmap, XColor *color)
582 Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay (dpy));
584 (((color->red << 16) >> (31 - i_log2(v->red_mask))) & v->red_mask) |
585 (((color->green << 16) >> (31 - i_log2(v->green_mask))) & v->green_mask) |
586 (((color->blue << 16) >> (31 - i_log2(v->blue_mask))) & v->blue_mask) |
592 XAllocColorCells (Display *dpy, Colormap cmap, Bool contig,
593 unsigned long *pmret, unsigned int npl,
594 unsigned long *pxret, unsigned int npx)
600 XStoreColors (Display *dpy, Colormap cmap, XColor *colors, int n)
602 Assert(0, "XStoreColors called");
607 XStoreColor (Display *dpy, Colormap cmap, XColor *c)
609 Assert(0, "XStoreColor called");
614 XFreeColors (Display *dpy, Colormap cmap, unsigned long *px, int npixels,
615 unsigned long planes)
621 XParseColor (Display *dpy, Colormap cmap, const char *spec, XColor *ret)
623 unsigned char r=0, g=0, b=0;
624 if (*spec == '#' && strlen(spec) == 7) {
625 static unsigned const char hex[] = { // yeah yeah, shoot me.
626 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,
627 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,
628 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,
629 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,
630 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,
631 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,
632 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,
633 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};
634 const unsigned char *uspec = (const unsigned char *)spec;
635 r = (hex[uspec[1]] << 4) | hex[uspec[2]];
636 g = (hex[uspec[3]] << 4) | hex[uspec[4]];
637 b = (hex[uspec[5]] << 4) | hex[uspec[6]];
638 } else if (!strcasecmp(spec,"black")) {
640 } else if (!strcasecmp(spec,"white")) {
642 } else if (!strcasecmp(spec,"red")) {
644 } else if (!strcasecmp(spec,"green")) {
646 } else if (!strcasecmp(spec,"blue")) {
648 } else if (!strcasecmp(spec,"cyan")) {
650 } else if (!strcasecmp(spec,"magenta")) {
652 } else if (!strcasecmp(spec,"yellow")) {
658 ret->red = (r << 8) | r;
659 ret->green = (g << 8) | g;
660 ret->blue = (b << 8) | b;
661 ret->flags = DoRed|DoGreen|DoBlue;
666 XAllocNamedColor (Display *dpy, Colormap cmap, char *name,
667 XColor *screen_ret, XColor *exact_ret)
669 if (! XParseColor (dpy, cmap, name, screen_ret))
671 *exact_ret = *screen_ret;
672 return XAllocColor (dpy, cmap, screen_ret);
676 XQueryColor (Display *dpy, Colormap cmap, XColor *color)
678 jwxyz_validate_pixel (dpy, color->pixel, visual_depth (NULL, NULL), False);
680 JWXYZ_QUERY_COLOR (dpy, color->pixel, 0xffffull, rgba);
681 color->red = rgba[0];
682 color->green = rgba[1];
683 color->blue = rgba[2];
684 color->flags = DoRed|DoGreen|DoBlue;
689 XQueryColors (Display *dpy, Colormap cmap, XColor *c, int n)
692 for (i = 0; i < n; i++)
693 XQueryColor (dpy, cmap, &c[i]);
699 ximage_getpixel_1 (XImage *ximage, int x, int y)
701 return ((ximage->data [y * ximage->bytes_per_line + (x>>3)] >> (x & 7)) & 1);
705 ximage_putpixel_1 (XImage *ximage, int x, int y, unsigned long pixel)
708 ximage->data [y * ximage->bytes_per_line + (x>>3)] |= (1 << (x & 7));
710 ximage->data [y * ximage->bytes_per_line + (x>>3)] &= ~(1 << (x & 7));
716 ximage_getpixel_8 (XImage *ximage, int x, int y)
718 return ((unsigned long)
719 *((uint8_t *) ximage->data +
720 (y * ximage->bytes_per_line) +
725 ximage_putpixel_8 (XImage *ximage, int x, int y, unsigned long pixel)
727 *((uint8_t *) ximage->data +
728 (y * ximage->bytes_per_line) +
729 x) = (uint8_t) pixel;
735 ximage_getpixel_32 (XImage *ximage, int x, int y)
737 return ((unsigned long)
738 *((uint32_t *) ximage->data +
739 (y * (ximage->bytes_per_line >> 2)) +
744 ximage_putpixel_32 (XImage *ximage, int x, int y, unsigned long pixel)
746 *((uint32_t *) ximage->data +
747 (y * (ximage->bytes_per_line >> 2)) +
748 x) = (uint32_t) pixel;
754 XInitImage (XImage *ximage)
756 if (!ximage->bytes_per_line)
757 ximage->bytes_per_line = (ximage->depth == 1 ? (ximage->width + 7) / 8 :
758 ximage->depth == 8 ? ximage->width :
761 if (ximage->depth == 1) {
762 ximage->f.put_pixel = ximage_putpixel_1;
763 ximage->f.get_pixel = ximage_getpixel_1;
764 } else if (ximage->depth == 32 || ximage->depth == 24) {
765 ximage->f.put_pixel = ximage_putpixel_32;
766 ximage->f.get_pixel = ximage_getpixel_32;
767 } else if (ximage->depth == 8) {
768 ximage->f.put_pixel = ximage_putpixel_8;
769 ximage->f.get_pixel = ximage_getpixel_8;
771 Assert (0, "unknown depth");
778 XCreateImage (Display *dpy, Visual *visual, unsigned int depth,
779 int format, int offset, char *data,
780 unsigned int width, unsigned int height,
781 int bitmap_pad, int bytes_per_line)
783 XImage *ximage = (XImage *) calloc (1, sizeof(*ximage));
784 ximage->width = width;
785 ximage->height = height;
786 ximage->format = format;
788 ximage->bitmap_unit = 8;
789 ximage->byte_order = LSBFirst;
790 ximage->bitmap_bit_order = ximage->byte_order;
791 ximage->bitmap_pad = bitmap_pad;
792 ximage->depth = depth;
793 Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay (dpy));
794 ximage->red_mask = (depth == 1 ? 0 : v->red_mask);
795 ximage->green_mask = (depth == 1 ? 0 : v->green_mask);
796 ximage->blue_mask = (depth == 1 ? 0 : v->blue_mask);
797 ximage->bits_per_pixel = (depth == 1 ? 1 : visual_depth (NULL, NULL));
798 ximage->bytes_per_line = bytes_per_line;
805 XSubImage (XImage *from, int x, int y, unsigned int w, unsigned int h)
807 XImage *to = (XImage *) malloc (sizeof(*to));
808 memcpy (to, from, sizeof(*from));
811 to->bytes_per_line = 0;
814 to->data = (char *) malloc (h * to->bytes_per_line);
816 if (x >= from->width)
818 else if (x+w > from->width)
821 if (y >= from->height)
823 else if (y+h > from->height)
824 h = from->height - y;
827 for (ty = 0; ty < h; ty++)
828 for (tx = 0; tx < w; tx++)
829 XPutPixel (to, tx, ty, XGetPixel (from, x+tx, y+ty));
834 XPixmapFormatValues *
835 XListPixmapFormats (Display *dpy, int *n_ret)
837 XPixmapFormatValues *ret = calloc (2, sizeof(*ret));
838 ret[0].depth = visual_depth (NULL, NULL);
839 ret[0].bits_per_pixel = 32;
840 ret[0].scanline_pad = 8;
842 ret[1].bits_per_pixel = 1;
843 ret[1].scanline_pad = 8;
850 XGetPixel (XImage *ximage, int x, int y)
852 return ximage->f.get_pixel (ximage, x, y);
857 XPutPixel (XImage *ximage, int x, int y, unsigned long pixel)
859 return ximage->f.put_pixel (ximage, x, y, pixel);
863 XDestroyImage (XImage *ximage)
865 if (ximage->data) free (ximage->data);
872 XGetImage (Display *dpy, Drawable d, int x, int y,
873 unsigned int width, unsigned int height,
874 unsigned long plane_mask, int format)
876 unsigned depth = jwxyz_drawable_depth (d);
877 XImage *image = XCreateImage (dpy, 0, depth, format, 0, 0, width, height,
879 image->data = (char *) malloc (height * image->bytes_per_line);
881 return XGetSubImage (dpy, d, x, y, width, height, plane_mask, format,
887 XCreatePixmapFromBitmapData (Display *dpy, Drawable drawable,
889 unsigned int w, unsigned int h,
890 unsigned long fg, unsigned long bg,
893 Pixmap p = XCreatePixmap (dpy, drawable, w, h, depth);
894 XImage *image = XCreateImage (dpy, 0, 1, XYPixmap, 0,
895 (char *) data, w, h, 0, 0);
899 GC gc = XCreateGC (dpy, p, GCForeground|GCBackground, &gcv);
900 XPutImage (dpy, p, gc, image, 0, 0, 0, 0, w, h);
903 XDestroyImage (image);
909 XGetAtomName (Display *dpy, Atom atom)
912 return strdup ("FONT");
914 // Note that atoms (that aren't predefined) are just char *.
915 return strdup ((char *) atom);
919 // This is XQueryFont, but for the XFontStruct embedded in 'Font'
922 query_font (Font fid)
924 Assert (fid && fid->native_font, "no native font in fid");
929 Display *dpy = fid->dpy;
930 void *native_font = fid->native_font;
932 XFontStruct *f = &fid->metrics;
933 XCharStruct *min = &f->min_bounds;
934 XCharStruct *max = &f->max_bounds;
937 f->min_char_or_byte2 = first;
938 f->max_char_or_byte2 = last;
939 f->default_char = 'M';
940 f->ascent = fid->ascent;
941 f->descent = fid->descent;
943 min->width = 32767; // set to smaller values in the loop
945 min->descent = 32767;
946 min->lbearing = 32767;
947 min->rbearing = 32767;
949 f->per_char = (XCharStruct *) calloc (last-first+2, sizeof (XCharStruct));
951 for (int i = first; i <= last; i++) {
952 XCharStruct *cs = &f->per_char[i-first];
954 jwxyz_render_text (dpy, native_font, &s, 1, False, False, cs, 0);
956 max->width = MAX (max->width, cs->width);
957 max->ascent = MAX (max->ascent, cs->ascent);
958 max->descent = MAX (max->descent, cs->descent);
959 max->lbearing = MAX (max->lbearing, cs->lbearing);
960 max->rbearing = MAX (max->rbearing, cs->rbearing);
962 min->width = MIN (min->width, cs->width);
963 min->ascent = MIN (min->ascent, cs->ascent);
964 min->descent = MIN (min->descent, cs->descent);
965 min->lbearing = MIN (min->lbearing, cs->lbearing);
966 min->rbearing = MIN (min->rbearing, cs->rbearing);
968 Log (" %3d %c: w=%3d lb=%3d rb=%3d as=%3d ds=%3d "
969 " bb=%5.1f x %5.1f @ %5.1f %5.1f adv=%5.1f %5.1f\n"
970 i, i, cs->width, cs->lbearing, cs->rbearing,
971 cs->ascent, cs->descent,
972 bbox.size.width, bbox.size.height,
973 bbox.origin.x, bbox.origin.y,
974 advancement.width, advancement.height);
980 // Since 'Font' includes the metrics, this just makes a copy of that.
983 XQueryFont (Display *dpy, Font fid)
986 XFontStruct *f = (XFontStruct *) calloc (1, sizeof(*f));
992 f->properties = malloc (sizeof(*f->properties) * f->n_properties);
993 f->properties[0].name = XA_FONT;
994 Assert (sizeof (f->properties[0].card32) >= sizeof (char *),
995 "atoms probably needs a real implementation");
996 // If XInternAtom is ever implemented, use it here.
997 f->properties[0].card32 = (unsigned long)fid->xa_font;
999 // copy XCharStruct array
1000 int size = (f->max_char_or_byte2 - f->min_char_or_byte2) + 1;
1001 f->per_char = (XCharStruct *) calloc (size + 2, sizeof (XCharStruct));
1003 memcpy (f->per_char, fid->metrics.per_char,
1004 size * sizeof (XCharStruct));
1011 copy_font (Font fid)
1018 /* On Cocoa and iOS, fonts may be specified as "Georgia Bold 24" instead
1019 of XLFD strings; also they can be comma-separated strings with multiple
1020 font names. First one that exists wins.
1023 try_native_font (Display *dpy, const char *name, Font fid)
1026 const char *spc = strrchr (name, ' ');
1029 char *token = strdup (name);
1030 char *otoken = token;
1034 while ((name2 = strtok_r (token, ",", &lasts))) {
1037 while (*name2 == ' ' || *name2 == '\t' || *name2 == '\n')
1040 spc = strrchr (name2, ' ');
1044 if (1 != sscanf (spc, " %d ", &dsize))
1048 if (size < 4) continue;
1050 name2[strlen(name2) - strlen(spc)] = 0;
1052 fid->native_font = jwxyz_load_native_font(XRootWindow(dpy,0), 0, 0, name2,
1053 strlen(name2) - strlen(spc),
1054 JWXYZ_FONT_FACE, size, NULL,
1055 &fid->ascent, &fid->descent);
1056 if (fid->native_font) {
1057 fid->xa_font = strdup (name); // Maybe this should be an XLFD?
1061 // po [UIFont familyNames]
1062 // po [UIFont fontNamesForFamilyName:@"Arial"]
1063 Log("No native font: \"%s\" %.0f", name2, size);
1072 xlfd_field_end (const char *s)
1074 const char *s2 = strchr(s, '-');
1082 xlfd_next (const char **s, const char **s2)
1087 Assert (**s2 == '-', "xlfd parse error");
1089 *s2 = xlfd_field_end (*s);
1097 try_xlfd_font (Display *dpy, const char *name, Font fid)
1099 const char *family_name = NULL; /* Not NULL-terminated. */
1100 size_t family_name_size = 0;
1102 // Default mask is for the built-in X11 font aliases.
1103 mask = JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD | JWXYZ_STYLE_ITALIC;
1105 float size = 12; /* In points (1/72 in.) */
1107 const char *s = (name ? name : "");
1109 size_t L = strlen (s);
1110 # define CMP(STR) (L == strlen(STR) && !strncasecmp (s, (STR), L))
1111 # define UNSPEC (L == 0 || (L == 1 && *s == '*'))
1112 if (CMP ("6x10")) size = 8, require |= JWXYZ_STYLE_MONOSPACE;
1113 else if (CMP ("6x10bold")) size = 8, require |= JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD;
1114 else if (CMP ("fixed")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1115 else if (CMP ("9x15")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1116 else if (CMP ("9x15bold")) size = 12, require |= JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD;
1117 else if (CMP ("vga")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1118 else if (CMP ("console")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1119 else if (CMP ("gallant")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1124 // Incorrect fields are ignored.
1128 const char *s2 = xlfd_field_end(s);
1132 L = xlfd_next (&s, &s2); // Family name
1133 // This used to substitute Georgia for Times. Now it doesn't.
1134 if (CMP ("random")) {
1136 } else if (CMP ("fixed")) {
1137 require |= JWXYZ_STYLE_MONOSPACE;
1138 family_name = "Courier";
1139 family_name_size = strlen(family_name);
1140 } else if (!UNSPEC) {
1142 family_name_size = L;
1145 L = xlfd_next (&s, &s2); // Weight name
1146 if (CMP ("bold") || CMP ("demibold"))
1147 require |= JWXYZ_STYLE_BOLD;
1148 else if (CMP ("medium") || CMP ("regular"))
1149 forbid |= JWXYZ_STYLE_BOLD;
1151 L = xlfd_next (&s, &s2); // Slant
1152 if (CMP ("i") || CMP ("o"))
1153 require |= JWXYZ_STYLE_ITALIC;
1155 forbid |= JWXYZ_STYLE_ITALIC;
1157 xlfd_next (&s, &s2); // Set width name (ignore)
1158 xlfd_next (&s, &s2); // Add style name (ignore)
1160 L = xlfd_next (&s, &s2); // Pixel size
1162 uintmax_t pxsize = strtoumax(s, &s3, 10);
1163 if (UNSPEC || s2 != s3)
1164 pxsize = UINTMAX_MAX; // i.e. it's invalid.
1166 L = xlfd_next (&s, &s2); // Point size
1167 uintmax_t ptsize = strtoumax(s, &s3, 10);
1168 if (UNSPEC || s2 != s3)
1169 ptsize = UINTMAX_MAX;
1171 xlfd_next (&s, &s2); // Resolution X (ignore)
1172 xlfd_next (&s, &s2); // Resolution Y (ignore)
1174 L = xlfd_next (&s, &s2); // Spacing
1176 forbid |= JWXYZ_STYLE_MONOSPACE;
1177 else if (CMP ("m") || CMP ("c"))
1178 require |= JWXYZ_STYLE_MONOSPACE;
1180 xlfd_next (&s, &s2); // Average width (ignore)
1182 // -*-courier-bold-r-*-*-14-*-*-*-*-*-*-* 14 px
1183 // -*-courier-bold-r-*-*-*-140-*-*-m-*-*-* 14 pt
1184 // -*-courier-bold-r-*-*-140-* 14 pt, via wildcard
1185 // -*-courier-bold-r-*-140-* 14 pt, not handled
1186 // -*-courier-bold-r-*-*-14-180-*-*-*-*-*-* error
1188 L = xlfd_next (&s, &s2); // Charset registry
1189 if (ptsize != UINTMAX_MAX) {
1190 // It was in the ptsize field, so that's definitely what it is.
1191 size = ptsize / 10.0;
1192 } else if (pxsize != UINTMAX_MAX) {
1194 // If it's a fully qualified XLFD, then this really is the pxsize.
1195 // Otherwise, this is probably point size with a multi-field wildcard.
1200 mask = require | forbid;
1205 if (!family_name && !rand) {
1206 family_name = jwxyz_default_font_family (require);
1207 family_name_size = strlen (family_name);
1210 if (size < 6 || size > 1000)
1213 char *family_name_ptr = NULL;
1214 fid->native_font = jwxyz_load_native_font (XRootWindow(dpy,0),
1216 family_name, family_name_size,
1217 rand ? JWXYZ_FONT_RANDOM : JWXYZ_FONT_FAMILY,
1218 size, &family_name_ptr,
1219 &fid->ascent, &fid->descent);
1221 if (fid->native_font) {
1222 unsigned dpi_d = XDisplayHeightMM (dpy,0) * 10 / 2;
1223 unsigned dpi = (254 * XDisplayHeight (dpy,0) + dpi_d) / (2 * dpi_d);
1224 asprintf(&fid->xa_font, "-*-%s-%s-%c-*-*-%u-%u-%u-%u-%c-0-iso10646-1",
1226 (require & JWXYZ_STYLE_BOLD) ? "bold" : "medium",
1227 (require & JWXYZ_STYLE_ITALIC) ? 'o' : 'r',
1228 (unsigned)(dpi * size / 72.27 + 0.5),
1229 (unsigned)(size * 10 + 0.5), dpi, dpi,
1230 (require & JWXYZ_STYLE_MONOSPACE) ? 'm' : 'p');
1233 free (family_name_ptr);
1238 XLoadFont (Display *dpy, const char *name)
1240 Font fid = (Font) calloc (1, sizeof(*fid));
1244 try_native_font (dpy, name, fid);
1246 if (!fid->native_font && name &&
1247 strchr (name, ' ') &&
1248 !strchr (name, '*')) {
1249 // If name contains a space but no stars, it is a native font spec --
1250 // return NULL so that we know it really didn't exist. Else, it is an
1251 // XLFD font, so keep trying.
1256 if (! fid->native_font)
1257 try_xlfd_font (dpy, name, fid);
1259 if (!fid->native_font) {
1271 XLoadQueryFont (Display *dpy, const char *name)
1273 Font fid = XLoadFont (dpy, name);
1275 return XQueryFont (dpy, fid);
1279 XUnloadFont (Display *dpy, Font fid)
1281 if (--fid->refcount < 0) abort();
1282 if (fid->refcount > 0) return 0;
1284 if (fid->native_font)
1285 jwxyz_release_native_font (fid->dpy, fid->native_font);
1287 if (fid->metrics.per_char)
1288 free (fid->metrics.per_char);
1295 XFreeFontInfo (char **names, XFontStruct *info, int n)
1299 for (i = 0; i < n; i++)
1300 if (names[i]) free (names[i]);
1304 for (i = 0; i < n; i++)
1305 if (info[i].per_char) {
1306 free (info[i].per_char);
1307 free (info[i].properties);
1315 XFreeFont (Display *dpy, XFontStruct *f)
1318 XFreeFontInfo (0, f, 1);
1319 XUnloadFont (dpy, fid);
1325 XSetFont (Display *dpy, GC gc, Font fid)
1327 XGCValues *gcv = VTBL->gc_gcv(gc);
1328 Font font2 = copy_font (fid);
1330 XUnloadFont (dpy, gcv->font);
1337 XCreateFontSet (Display *dpy, char *name,
1338 char ***missing_charset_list_return,
1339 int *missing_charset_count_return,
1340 char **def_string_return)
1342 char *name2 = strdup (name);
1343 char *s = strchr (name, ',');
1346 XFontStruct *f = XLoadQueryFont (dpy, name2);
1349 set = (XFontSet) calloc (1, sizeof(*set));
1353 if (missing_charset_list_return) *missing_charset_list_return = 0;
1354 if (missing_charset_count_return) *missing_charset_count_return = 0;
1355 if (def_string_return) *def_string_return = 0;
1361 XFreeFontSet (Display *dpy, XFontSet set)
1363 XFreeFont (dpy, set->font);
1369 XFreeStringList (char **list)
1373 for (i = 0; list[i]; i++)
1380 XTextExtents (XFontStruct *f, const char *s, int length,
1381 int *dir_ret, int *ascent_ret, int *descent_ret,
1384 // Unfortunately, adding XCharStructs together to get the extents for a
1385 // string doesn't work: Cocoa uses non-integral character advancements, but
1386 // XCharStruct.width is an integer. Plus that doesn't take into account
1387 // kerning pairs, alternate glyphs, and fun stuff like the word "Zapfino" in
1391 Display *dpy = ff->dpy;
1392 jwxyz_render_text (dpy, ff->native_font, s, length, False, False, cs, 0);
1394 *ascent_ret = f->ascent;
1395 *descent_ret = f->descent;
1400 XTextWidth (XFontStruct *f, const char *s, int length)
1402 int ascent, descent, dir;
1404 XTextExtents (f, s, length, &dir, &ascent, &descent, &cs);
1410 XTextExtents16 (XFontStruct *f, const XChar2b *s, int length,
1411 int *dir_ret, int *ascent_ret, int *descent_ret,
1414 // Bool latin1_p = True;
1415 int i, utf8_len = 0;
1416 char *utf8 = XChar2b_to_utf8 (s, &utf8_len); // already sanitized
1418 for (i = 0; i < length; i++)
1419 if (s[i].byte1 > 0) {
1420 // latin1_p = False;
1426 Display *dpy = ff->dpy;
1427 jwxyz_render_text (dpy, ff->native_font, utf8, strlen(utf8),
1428 True, False, cs, 0);
1432 *ascent_ret = f->ascent;
1433 *descent_ret = f->descent;
1439 /* "Returns the distance in pixels in the primary draw direction from
1440 the drawing origin to the origin of the next character to be drawn."
1442 "overall_ink_return is set to the bbox of the string's character ink."
1444 "The overall_ink_return for a nondescending, horizontally drawn Latin
1445 character is conventionally entirely above the baseline; that is,
1446 overall_ink_return.height <= -overall_ink_return.y."
1448 [So this means that y is the top of the ink, and height grows down:
1449 For above-the-baseline characters, y is negative.]
1451 "The overall_ink_return for a nonkerned character is entirely at, and to
1452 the right of, the origin; that is, overall_ink_return.x >= 0."
1454 [So this means that x is the left of the ink, and width grows right.
1455 For left-of-the-origin characters, x is negative.]
1457 "A character consisting of a single pixel at the origin would set
1458 overall_ink_return fields y = 0, x = 0, width = 1, and height = 1."
1461 Xutf8TextExtents (XFontSet set, const char *str, int len,
1462 XRectangle *overall_ink_return,
1463 XRectangle *overall_logical_return)
1466 Font f = set->font->fid;
1468 jwxyz_render_text (f->dpy, f->native_font, str, len, True, False, &cs,
1471 /* "The overall_logical_return is the bounding box that provides minimum
1472 spacing to other graphical features for the string. Other graphical
1473 features, for example, a border surrounding the text, should not
1474 intersect this rectangle."
1476 So I think that means they're the same? Or maybe "ink" is the bounding
1477 box, and "logical" is the advancement? But then why is the return value
1480 if (overall_ink_return)
1481 XCharStruct_to_XmbRectangle (cs, *overall_ink_return);
1482 if (overall_logical_return)
1483 XCharStruct_to_XmbRectangle (cs, *overall_logical_return);
1490 jwxyz_draw_string (Display *dpy, Drawable d, GC gc, int x, int y,
1491 const char *str, size_t len, int utf8_p)
1493 const XGCValues *gcv = VTBL->gc_gcv (gc);
1494 Font ff = gcv->font;
1498 jwxyz_render_text (dpy, jwxyz_native_font (ff), str, len, utf8_p,
1499 gcv->antialias_p, &cs, &data);
1500 int w = cs.rbearing - cs.lbearing;
1501 int h = cs.ascent + cs.descent;
1503 if (w < 0 || h < 0) abort();
1504 if (w == 0 || h == 0) {
1505 if (data) free(data);
1509 XImage *img = XCreateImage (dpy, VTBL->visual (dpy), 32,
1510 ZPixmap, 0, data, w, h, 0, 0);
1512 /* The image of text is a 32-bit image, in white.
1513 Take the green channel for intensity and use that as alpha.
1514 replace RGB with the GC's foreground color.
1515 This expects that XPutImage respects alpha and only writes
1516 the bits that are not masked out.
1519 # define ROTL(x, rot) (((x) << ((rot) & 31)) | ((x) >> (32 - ((rot) & 31))))
1521 Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay(dpy));
1522 unsigned shift = (i_log2 (v->alpha_mask) - i_log2 (v->green_mask)) & 31;
1523 uint32_t mask = ROTL(v->green_mask, shift) & v->alpha_mask,
1524 color = gcv->foreground & ~v->alpha_mask;
1525 uint32_t *s = (uint32_t *)data;
1526 uint32_t *end = s + (w * h);
1529 *s = (ROTL(*s, shift) & mask) | color;
1535 Bool old_alpha = gcv->alpha_allowed_p;
1536 jwxyz_XSetAlphaAllowed (dpy, gc, True);
1537 XPutImage (dpy, d, gc, img, 0, 0,
1541 jwxyz_XSetAlphaAllowed (dpy, gc, old_alpha);
1542 XDestroyImage (img);
1550 XDrawString (Display *dpy, Drawable d, GC gc, int x, int y,
1551 const char *str, int len)
1553 return VTBL->draw_string (dpy, d, gc, x, y, str, len, False);
1558 XDrawString16 (Display *dpy, Drawable d, GC gc, int x, int y,
1559 const XChar2b *str, int len)
1561 XChar2b *b2 = malloc ((len + 1) * sizeof(*b2));
1564 memcpy (b2, str, len * sizeof(*b2));
1565 b2[len].byte1 = b2[len].byte2 = 0;
1566 s2 = XChar2b_to_utf8 (b2, 0);
1568 ret = VTBL->draw_string (dpy, d, gc, x, y, s2, strlen(s2), True);
1575 Xutf8DrawString (Display *dpy, Drawable d, XFontSet set, GC gc,
1576 int x, int y, const char *str, int len)
1578 VTBL->draw_string (dpy, d, gc, x, y, str, len, True);
1583 XDrawImageString (Display *dpy, Drawable d, GC gc, int x, int y,
1584 const char *str, int len)
1586 int ascent, descent, dir;
1588 XTextExtents (&VTBL->gc_gcv (gc)->font->metrics, str, len,
1589 &dir, &ascent, &descent, &cs);
1590 jwxyz_fill_rect (dpy, d, gc,
1591 x + MIN (0, cs.lbearing),
1592 y - MAX (0, ascent),
1594 /* The +1 here is almost certainly wrong, but BSOD
1595 requires it; and only BSOD, fluidballs, juggle
1596 and grabclient call XDrawImageString... */
1597 MAX (MAX (0, cs.rbearing) -
1598 MIN (0, cs.lbearing),
1600 MAX (0, ascent) + MAX (0, descent),
1601 VTBL->gc_gcv(gc)->background);
1602 return XDrawString (dpy, d, gc, x, y, str, len);
1607 jwxyz_native_font (Font f)
1609 return f->native_font;
1614 XSetForeground (Display *dpy, GC gc, unsigned long fg)
1616 XGCValues *gcv = VTBL->gc_gcv (gc);
1617 jwxyz_validate_pixel (dpy, fg, VTBL->gc_depth (gc), gcv->alpha_allowed_p);
1618 gcv->foreground = fg;
1624 XSetBackground (Display *dpy, GC gc, unsigned long bg)
1626 XGCValues *gcv = VTBL->gc_gcv (gc);
1627 jwxyz_validate_pixel (dpy, bg, VTBL->gc_depth (gc), gcv->alpha_allowed_p);
1628 gcv->background = bg;
1633 jwxyz_XSetAlphaAllowed (Display *dpy, GC gc, Bool allowed)
1635 VTBL->gc_gcv (gc)->alpha_allowed_p = allowed;
1640 jwxyz_XSetAntiAliasing (Display *dpy, GC gc, Bool antialias_p)
1642 VTBL->gc_gcv (gc)->antialias_p = antialias_p;
1648 XSetLineAttributes (Display *dpy, GC gc, unsigned int line_width,
1649 int line_style, int cap_style, int join_style)
1651 XGCValues *gcv = VTBL->gc_gcv (gc);
1652 gcv->line_width = line_width;
1653 Assert (line_style == LineSolid, "only LineSolid implemented");
1654 // gc->gcv.line_style = line_style;
1655 gcv->cap_style = cap_style;
1656 gcv->join_style = join_style;
1661 XSetGraphicsExposures (Display *dpy, GC gc, Bool which)
1667 XSetFunction (Display *dpy, GC gc, int which)
1669 VTBL->gc_gcv (gc)->function = which;
1674 XSetSubwindowMode (Display *dpy, GC gc, int which)
1676 VTBL->gc_gcv (gc)->subwindow_mode = which;
1682 XQueryPointer (Display *dpy, Window w, Window *root_ret, Window *child_ret,
1683 int *root_x_ret, int *root_y_ret,
1684 int *win_x_ret, int *win_y_ret, unsigned int *mask_ret)
1686 assert_window (dpy, w);
1689 jwxyz_get_pos (w, &vpos, &p);
1691 if (root_x_ret) *root_x_ret = p.x;
1692 if (root_y_ret) *root_y_ret = p.y;
1693 if (win_x_ret) *win_x_ret = p.x - vpos.x;
1694 if (win_y_ret) *win_y_ret = p.y - vpos.y;
1695 if (mask_ret) *mask_ret = 0; // #### poll the keyboard modifiers?
1696 if (root_ret) *root_ret = 0;
1697 if (child_ret) *child_ret = 0;
1702 XTranslateCoordinates (Display *dpy, Window w, Window dest_w,
1703 int src_x, int src_y,
1704 int *dest_x_ret, int *dest_y_ret,
1707 assert_window (dpy, w);
1710 jwxyz_get_pos (w, &vpos, NULL);
1712 // point starts out relative to top left of view
1716 // get point relative to top left of screen
1729 XKeycodeToKeysym (Display *dpy, KeyCode code, int index)
1735 XLookupString (XKeyEvent *e, char *buf, int size, KeySym *k_ret,
1738 KeySym ks = XKeycodeToKeysym (0, e->keycode, 0);
1740 // Do not put non-ASCII KeySyms like XK_Shift_L and XK_Page_Up in the string.
1741 if ((unsigned int) ks <= 255)
1744 // Put control characters in the string. Not meta.
1745 if (e->state & ControlMask) {
1746 if (c >= 'a' && c <= 'z') // Upcase control.
1748 if (c >= '@' && c <= '_') // Shift to control page.
1750 if (c == ' ') // C-SPC is NULL.
1754 if (k_ret) *k_ret = ks;
1755 if (size > 0) buf[0] = c;
1756 if (size > 1) buf[1] = 0;
1757 return (size > 0 ? 1 : 0);
1762 XFlush (Display *dpy)
1764 // Just let the event loop take care of this on its own schedule.
1769 XSync (Display *dpy, Bool flush)
1771 return XFlush (dpy);
1775 // declared in utils/visual.h
1777 has_writable_cells (Screen *s, Visual *v)
1783 visual_depth (Screen *s, Visual *v)
1789 visual_cells (Screen *s, Visual *v)
1791 return (int)(v->red_mask | v->green_mask | v->blue_mask);
1795 visual_class (Screen *s, Visual *v)
1801 visual_rgb_masks (Screen *s, Visual *v, unsigned long *red_mask,
1802 unsigned long *green_mask, unsigned long *blue_mask)
1804 *red_mask = v->red_mask;
1805 *green_mask = v->green_mask;
1806 *blue_mask = v->blue_mask;
1810 visual_pixmap_depth (Screen *s, Visual *v)
1816 screen_number (Screen *screen)
1821 // declared in utils/grabclient.h
1823 use_subwindow_mode_p (Screen *screen, Window window)
1828 #endif /* HAVE_JWXYZ */