1 /* xscreensaver, Copyright (c) 1991-2016 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)->rgba_masks[3];
110 XWhitePixelOfScreen(Screen *screen)
112 const unsigned long *masks = DefaultVisualOfScreen (screen)->rgba_masks;
113 return masks[0] | masks[1] | masks[2] | masks[3];
117 XCellsOfScreen(Screen *screen)
119 const unsigned long *masks = DefaultVisualOfScreen (screen)->rgba_masks;
120 return masks[0] | masks[1] | masks[2];
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 const unsigned long *masks =
583 DefaultVisualOfScreen(DefaultScreenOfDisplay(dpy))->rgba_masks;
585 (((color->red << 16) >> (31 - i_log2(masks[0]))) & masks[0]) |
586 (((color->green << 16) >> (31 - i_log2(masks[1]))) & masks[1]) |
587 (((color->blue << 16) >> (31 - i_log2(masks[2]))) & masks[2]) |
593 XAllocColorCells (Display *dpy, Colormap cmap, Bool contig,
594 unsigned long *pmret, unsigned int npl,
595 unsigned long *pxret, unsigned int npx)
601 XStoreColors (Display *dpy, Colormap cmap, XColor *colors, int n)
603 Assert(0, "XStoreColors called");
608 XStoreColor (Display *dpy, Colormap cmap, XColor *c)
610 Assert(0, "XStoreColor called");
615 XFreeColors (Display *dpy, Colormap cmap, unsigned long *px, int npixels,
616 unsigned long planes)
622 XParseColor (Display *dpy, Colormap cmap, const char *spec, XColor *ret)
624 unsigned char r=0, g=0, b=0;
625 if (*spec == '#' && strlen(spec) == 7) {
626 static unsigned const char hex[] = { // yeah yeah, shoot me.
627 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,
628 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,
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,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,
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 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};
635 const unsigned char *uspec = (const unsigned char *)spec;
636 r = (hex[uspec[1]] << 4) | hex[uspec[2]];
637 g = (hex[uspec[3]] << 4) | hex[uspec[4]];
638 b = (hex[uspec[5]] << 4) | hex[uspec[6]];
639 } else if (!strcasecmp(spec,"black")) {
641 } else if (!strcasecmp(spec,"white")) {
643 } else if (!strcasecmp(spec,"red")) {
645 } else if (!strcasecmp(spec,"green")) {
647 } else if (!strcasecmp(spec,"blue")) {
649 } else if (!strcasecmp(spec,"cyan")) {
651 } else if (!strcasecmp(spec,"magenta")) {
653 } else if (!strcasecmp(spec,"yellow")) {
659 ret->red = (r << 8) | r;
660 ret->green = (g << 8) | g;
661 ret->blue = (b << 8) | b;
662 ret->flags = DoRed|DoGreen|DoBlue;
667 XAllocNamedColor (Display *dpy, Colormap cmap, char *name,
668 XColor *screen_ret, XColor *exact_ret)
670 if (! XParseColor (dpy, cmap, name, screen_ret))
672 *exact_ret = *screen_ret;
673 return XAllocColor (dpy, cmap, screen_ret);
677 XQueryColor (Display *dpy, Colormap cmap, XColor *color)
679 jwxyz_validate_pixel (dpy, color->pixel, visual_depth (NULL, NULL), False);
681 JWXYZ_QUERY_COLOR (dpy, color->pixel, 0xffffull, rgba);
682 color->red = rgba[0];
683 color->green = rgba[1];
684 color->blue = rgba[2];
685 color->flags = DoRed|DoGreen|DoBlue;
690 XQueryColors (Display *dpy, Colormap cmap, XColor *c, int n)
693 for (i = 0; i < n; i++)
694 XQueryColor (dpy, cmap, &c[i]);
700 ximage_getpixel_1 (XImage *ximage, int x, int y)
702 return ((ximage->data [y * ximage->bytes_per_line + (x>>3)] >> (x & 7)) & 1);
706 ximage_putpixel_1 (XImage *ximage, int x, int y, unsigned long pixel)
709 ximage->data [y * ximage->bytes_per_line + (x>>3)] |= (1 << (x & 7));
711 ximage->data [y * ximage->bytes_per_line + (x>>3)] &= ~(1 << (x & 7));
717 ximage_getpixel_32 (XImage *ximage, int x, int y)
719 return ((unsigned long)
720 *((uint32_t *) ximage->data +
721 (y * (ximage->bytes_per_line >> 2)) +
726 ximage_putpixel_32 (XImage *ximage, int x, int y, unsigned long pixel)
728 *((uint32_t *) ximage->data +
729 (y * (ximage->bytes_per_line >> 2)) +
730 x) = (uint32_t) pixel;
736 XInitImage (XImage *ximage)
738 if (!ximage->bytes_per_line)
739 ximage->bytes_per_line = (ximage->depth == 1
740 ? (ximage->width + 7) / 8
741 : ximage->width * 4);
743 if (ximage->depth == 1) {
744 ximage->f.put_pixel = ximage_putpixel_1;
745 ximage->f.get_pixel = ximage_getpixel_1;
746 } else if (ximage->depth == 32 || ximage->depth == 24) {
747 ximage->f.put_pixel = ximage_putpixel_32;
748 ximage->f.get_pixel = ximage_getpixel_32;
750 Assert (0, "unknown depth");
757 XCreateImage (Display *dpy, Visual *visual, unsigned int depth,
758 int format, int offset, char *data,
759 unsigned int width, unsigned int height,
760 int bitmap_pad, int bytes_per_line)
762 XImage *ximage = (XImage *) calloc (1, sizeof(*ximage));
763 ximage->width = width;
764 ximage->height = height;
765 ximage->format = format;
767 ximage->bitmap_unit = 8;
768 ximage->byte_order = LSBFirst;
769 ximage->bitmap_bit_order = ximage->byte_order;
770 ximage->bitmap_pad = bitmap_pad;
771 ximage->depth = depth;
772 Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay (dpy));
773 ximage->red_mask = (depth == 1 ? 0 : v->rgba_masks[0]);
774 ximage->green_mask = (depth == 1 ? 0 : v->rgba_masks[1]);
775 ximage->blue_mask = (depth == 1 ? 0 : v->rgba_masks[2]);
776 ximage->bits_per_pixel = (depth == 1 ? 1 : visual_depth (NULL, NULL));
777 ximage->bytes_per_line = bytes_per_line;
784 XSubImage (XImage *from, int x, int y, unsigned int w, unsigned int h)
786 XImage *to = (XImage *) malloc (sizeof(*to));
787 memcpy (to, from, sizeof(*from));
790 to->bytes_per_line = 0;
793 to->data = (char *) malloc (h * to->bytes_per_line);
795 if (x >= from->width)
797 else if (x+w > from->width)
800 if (y >= from->height)
802 else if (y+h > from->height)
803 h = from->height - y;
806 for (ty = 0; ty < h; ty++)
807 for (tx = 0; tx < w; tx++)
808 XPutPixel (to, tx, ty, XGetPixel (from, x+tx, y+ty));
813 XPixmapFormatValues *
814 XListPixmapFormats (Display *dpy, int *n_ret)
816 XPixmapFormatValues *ret = calloc (2, sizeof(*ret));
817 ret[0].depth = visual_depth (NULL, NULL);
818 ret[0].bits_per_pixel = 32;
819 ret[0].scanline_pad = 8;
821 ret[1].bits_per_pixel = 1;
822 ret[1].scanline_pad = 8;
829 XGetPixel (XImage *ximage, int x, int y)
831 return ximage->f.get_pixel (ximage, x, y);
836 XPutPixel (XImage *ximage, int x, int y, unsigned long pixel)
838 return ximage->f.put_pixel (ximage, x, y, pixel);
842 XDestroyImage (XImage *ximage)
844 if (ximage->data) free (ximage->data);
851 XGetImage (Display *dpy, Drawable d, int x, int y,
852 unsigned int width, unsigned int height,
853 unsigned long plane_mask, int format)
855 unsigned depth = jwxyz_drawable_depth (d);
856 XImage *image = XCreateImage (dpy, 0, depth, format, 0, 0, width, height,
858 image->data = (char *) malloc (height * image->bytes_per_line);
860 return XGetSubImage (dpy, d, x, y, width, height, plane_mask, format,
866 XCreatePixmapFromBitmapData (Display *dpy, Drawable drawable,
868 unsigned int w, unsigned int h,
869 unsigned long fg, unsigned long bg,
872 Pixmap p = XCreatePixmap (dpy, drawable, w, h, depth);
873 XImage *image = XCreateImage (dpy, 0, 1, XYPixmap, 0,
874 (char *) data, w, h, 0, 0);
878 GC gc = XCreateGC (dpy, p, GCForeground|GCBackground, &gcv);
879 XPutImage (dpy, p, gc, image, 0, 0, 0, 0, w, h);
882 XDestroyImage (image);
888 XGetAtomName (Display *dpy, Atom atom)
891 return strdup ("FONT");
893 // Note that atoms (that aren't predefined) are just char *.
894 return strdup ((char *) atom);
898 // This is XQueryFont, but for the XFontStruct embedded in 'Font'
901 query_font (Font fid)
903 Assert (fid && fid->native_font, "no native font in fid");
908 Display *dpy = fid->dpy;
909 void *native_font = fid->native_font;
911 XFontStruct *f = &fid->metrics;
912 XCharStruct *min = &f->min_bounds;
913 XCharStruct *max = &f->max_bounds;
916 f->min_char_or_byte2 = first;
917 f->max_char_or_byte2 = last;
918 f->default_char = 'M';
919 f->ascent = fid->ascent;
920 f->descent = fid->descent;
922 min->width = 32767; // set to smaller values in the loop
924 min->descent = 32767;
925 min->lbearing = 32767;
926 min->rbearing = 32767;
928 f->per_char = (XCharStruct *) calloc (last-first+2, sizeof (XCharStruct));
930 for (int i = first; i <= last; i++) {
931 XCharStruct *cs = &f->per_char[i-first];
933 jwxyz_render_text (dpy, native_font, &s, 1, False, False, cs, 0);
935 max->width = MAX (max->width, cs->width);
936 max->ascent = MAX (max->ascent, cs->ascent);
937 max->descent = MAX (max->descent, cs->descent);
938 max->lbearing = MAX (max->lbearing, cs->lbearing);
939 max->rbearing = MAX (max->rbearing, cs->rbearing);
941 min->width = MIN (min->width, cs->width);
942 min->ascent = MIN (min->ascent, cs->ascent);
943 min->descent = MIN (min->descent, cs->descent);
944 min->lbearing = MIN (min->lbearing, cs->lbearing);
945 min->rbearing = MIN (min->rbearing, cs->rbearing);
947 Log (" %3d %c: w=%3d lb=%3d rb=%3d as=%3d ds=%3d "
948 " bb=%5.1f x %5.1f @ %5.1f %5.1f adv=%5.1f %5.1f\n"
949 i, i, cs->width, cs->lbearing, cs->rbearing,
950 cs->ascent, cs->descent,
951 bbox.size.width, bbox.size.height,
952 bbox.origin.x, bbox.origin.y,
953 advancement.width, advancement.height);
959 // Since 'Font' includes the metrics, this just makes a copy of that.
962 XQueryFont (Display *dpy, Font fid)
965 XFontStruct *f = (XFontStruct *) calloc (1, sizeof(*f));
971 f->properties = malloc (sizeof(*f->properties) * f->n_properties);
972 f->properties[0].name = XA_FONT;
973 Assert (sizeof (f->properties[0].card32) >= sizeof (char *),
974 "atoms probably needs a real implementation");
975 // If XInternAtom is ever implemented, use it here.
976 f->properties[0].card32 = (unsigned long)fid->xa_font;
978 // copy XCharStruct array
979 int size = (f->max_char_or_byte2 - f->min_char_or_byte2) + 1;
980 f->per_char = (XCharStruct *) calloc (size + 2, sizeof (XCharStruct));
982 memcpy (f->per_char, fid->metrics.per_char,
983 size * sizeof (XCharStruct));
997 /* On Cocoa and iOS, fonts may be specified as "Georgia Bold 24" instead
998 of XLFD strings; also they can be comma-separated strings with multiple
999 font names. First one that exists wins.
1002 try_native_font (Display *dpy, const char *name, Font fid)
1005 const char *spc = strrchr (name, ' ');
1008 char *token = strdup (name);
1009 char *otoken = token;
1013 while ((name2 = strtok_r (token, ",", &lasts))) {
1016 while (*name2 == ' ' || *name2 == '\t' || *name2 == '\n')
1019 spc = strrchr (name2, ' ');
1023 if (1 != sscanf (spc, " %d ", &dsize))
1027 if (size < 4) continue;
1029 name2[strlen(name2) - strlen(spc)] = 0;
1031 fid->native_font = jwxyz_load_native_font(XRootWindow(dpy,0), 0, 0, name2,
1032 strlen(name2) - strlen(spc),
1033 JWXYZ_FONT_FACE, size, NULL,
1034 &fid->ascent, &fid->descent);
1035 if (fid->native_font) {
1036 fid->xa_font = strdup (name); // Maybe this should be an XLFD?
1040 // po [UIFont familyNames]
1041 // po [UIFont fontNamesForFamilyName:@"Arial"]
1042 Log("No native font: \"%s\" %.0f", name2, size);
1051 xlfd_field_end (const char *s)
1053 const char *s2 = strchr(s, '-');
1061 xlfd_next (const char **s, const char **s2)
1066 Assert (**s2 == '-', "xlfd parse error");
1068 *s2 = xlfd_field_end (*s);
1076 try_xlfd_font (Display *dpy, const char *name, Font fid)
1078 const char *family_name = NULL; /* Not NULL-terminated. */
1079 size_t family_name_size = 0;
1081 // Default mask is for the built-in X11 font aliases.
1082 mask = JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD | JWXYZ_STYLE_ITALIC;
1084 float size = 12; /* In points (1/72 in.) */
1086 const char *s = (name ? name : "");
1088 size_t L = strlen (s);
1089 # define CMP(STR) (L == strlen(STR) && !strncasecmp (s, (STR), L))
1090 # define UNSPEC (L == 0 || (L == 1 && *s == '*'))
1091 if (CMP ("6x10")) size = 8, require |= JWXYZ_STYLE_MONOSPACE;
1092 else if (CMP ("6x10bold")) size = 8, require |= JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD;
1093 else if (CMP ("fixed")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1094 else if (CMP ("9x15")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1095 else if (CMP ("9x15bold")) size = 12, require |= JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD;
1096 else if (CMP ("vga")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1097 else if (CMP ("console")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1098 else if (CMP ("gallant")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1103 // Incorrect fields are ignored.
1107 const char *s2 = xlfd_field_end(s);
1111 L = xlfd_next (&s, &s2); // Family name
1112 // This used to substitute Georgia for Times. Now it doesn't.
1113 if (CMP ("random")) {
1115 } else if (CMP ("fixed")) {
1116 require |= JWXYZ_STYLE_MONOSPACE;
1117 family_name = "Courier";
1118 family_name_size = strlen(family_name);
1119 } else if (!UNSPEC) {
1121 family_name_size = L;
1124 L = xlfd_next (&s, &s2); // Weight name
1125 if (CMP ("bold") || CMP ("demibold"))
1126 require |= JWXYZ_STYLE_BOLD;
1127 else if (CMP ("medium") || CMP ("regular"))
1128 forbid |= JWXYZ_STYLE_BOLD;
1130 L = xlfd_next (&s, &s2); // Slant
1131 if (CMP ("i") || CMP ("o"))
1132 require |= JWXYZ_STYLE_ITALIC;
1134 forbid |= JWXYZ_STYLE_ITALIC;
1136 xlfd_next (&s, &s2); // Set width name (ignore)
1137 xlfd_next (&s, &s2); // Add style name (ignore)
1139 L = xlfd_next (&s, &s2); // Pixel size
1141 uintmax_t pxsize = strtoumax(s, &s3, 10);
1142 if (UNSPEC || s2 != s3)
1143 pxsize = UINTMAX_MAX; // i.e. it's invalid.
1145 L = xlfd_next (&s, &s2); // Point size
1146 uintmax_t ptsize = strtoumax(s, &s3, 10);
1147 if (UNSPEC || s2 != s3)
1148 ptsize = UINTMAX_MAX;
1150 xlfd_next (&s, &s2); // Resolution X (ignore)
1151 xlfd_next (&s, &s2); // Resolution Y (ignore)
1153 L = xlfd_next (&s, &s2); // Spacing
1155 forbid |= JWXYZ_STYLE_MONOSPACE;
1156 else if (CMP ("m") || CMP ("c"))
1157 require |= JWXYZ_STYLE_MONOSPACE;
1159 xlfd_next (&s, &s2); // Average width (ignore)
1161 // -*-courier-bold-r-*-*-14-*-*-*-*-*-*-* 14 px
1162 // -*-courier-bold-r-*-*-*-140-*-*-m-*-*-* 14 pt
1163 // -*-courier-bold-r-*-*-140-* 14 pt, via wildcard
1164 // -*-courier-bold-r-*-140-* 14 pt, not handled
1165 // -*-courier-bold-r-*-*-14-180-*-*-*-*-*-* error
1167 L = xlfd_next (&s, &s2); // Charset registry
1168 if (ptsize != UINTMAX_MAX) {
1169 // It was in the ptsize field, so that's definitely what it is.
1170 size = ptsize / 10.0;
1171 } else if (pxsize != UINTMAX_MAX) {
1173 // If it's a fully qualified XLFD, then this really is the pxsize.
1174 // Otherwise, this is probably point size with a multi-field wildcard.
1179 mask = require | forbid;
1184 if (!family_name && !rand) {
1185 family_name = jwxyz_default_font_family (require);
1186 family_name_size = strlen (family_name);
1189 if (size < 6 || size > 1000)
1192 char *family_name_ptr = NULL;
1193 fid->native_font = jwxyz_load_native_font (XRootWindow(dpy,0),
1195 family_name, family_name_size,
1196 rand ? JWXYZ_FONT_RANDOM : JWXYZ_FONT_FAMILY,
1197 size, &family_name_ptr,
1198 &fid->ascent, &fid->descent);
1200 if (fid->native_font) {
1201 unsigned dpi_d = XDisplayHeightMM (dpy,0) * 10 / 2;
1202 unsigned dpi = (254 * XDisplayHeight (dpy,0) + dpi_d) / (2 * dpi_d);
1203 asprintf(&fid->xa_font, "-*-%s-%s-%c-*-*-%u-%u-%u-%u-%c-0-iso10646-1",
1205 (require & JWXYZ_STYLE_BOLD) ? "bold" : "medium",
1206 (require & JWXYZ_STYLE_ITALIC) ? 'o' : 'r',
1207 (unsigned)(dpi * size / 72.27 + 0.5),
1208 (unsigned)(size * 10 + 0.5), dpi, dpi,
1209 (require & JWXYZ_STYLE_MONOSPACE) ? 'm' : 'p');
1212 free (family_name_ptr);
1217 XLoadFont (Display *dpy, const char *name)
1219 Font fid = (Font) calloc (1, sizeof(*fid));
1223 try_native_font (dpy, name, fid);
1225 if (!fid->native_font && name &&
1226 strchr (name, ' ') &&
1227 !strchr (name, '*')) {
1228 // If name contains a space but no stars, it is a native font spec --
1229 // return NULL so that we know it really didn't exist. Else, it is an
1230 // XLFD font, so keep trying.
1235 if (! fid->native_font)
1236 try_xlfd_font (dpy, name, fid);
1238 if (!fid->native_font) {
1250 XLoadQueryFont (Display *dpy, const char *name)
1252 Font fid = XLoadFont (dpy, name);
1254 return XQueryFont (dpy, fid);
1258 XUnloadFont (Display *dpy, Font fid)
1260 if (--fid->refcount < 0) abort();
1261 if (fid->refcount > 0) return 0;
1263 if (fid->native_font)
1264 jwxyz_release_native_font (fid->dpy, fid->native_font);
1266 if (fid->metrics.per_char)
1267 free (fid->metrics.per_char);
1274 XFreeFontInfo (char **names, XFontStruct *info, int n)
1278 for (i = 0; i < n; i++)
1279 if (names[i]) free (names[i]);
1283 for (i = 0; i < n; i++)
1284 if (info[i].per_char) {
1285 free (info[i].per_char);
1286 free (info[i].properties);
1294 XFreeFont (Display *dpy, XFontStruct *f)
1297 XFreeFontInfo (0, f, 1);
1298 XUnloadFont (dpy, fid);
1304 XSetFont (Display *dpy, GC gc, Font fid)
1306 XGCValues *gcv = VTBL->gc_gcv(gc);
1307 Font font2 = copy_font (fid);
1309 XUnloadFont (dpy, gcv->font);
1316 XCreateFontSet (Display *dpy, char *name,
1317 char ***missing_charset_list_return,
1318 int *missing_charset_count_return,
1319 char **def_string_return)
1321 char *name2 = strdup (name);
1322 char *s = strchr (name, ',');
1325 XFontStruct *f = XLoadQueryFont (dpy, name2);
1328 set = (XFontSet) calloc (1, sizeof(*set));
1332 if (missing_charset_list_return) *missing_charset_list_return = 0;
1333 if (missing_charset_count_return) *missing_charset_count_return = 0;
1334 if (def_string_return) *def_string_return = 0;
1340 XFreeFontSet (Display *dpy, XFontSet set)
1342 XFreeFont (dpy, set->font);
1348 XFreeStringList (char **list)
1352 for (i = 0; list[i]; i++)
1359 XTextExtents (XFontStruct *f, const char *s, int length,
1360 int *dir_ret, int *ascent_ret, int *descent_ret,
1363 // Unfortunately, adding XCharStructs together to get the extents for a
1364 // string doesn't work: Cocoa uses non-integral character advancements, but
1365 // XCharStruct.width is an integer. Plus that doesn't take into account
1366 // kerning pairs, alternate glyphs, and fun stuff like the word "Zapfino" in
1370 Display *dpy = ff->dpy;
1371 jwxyz_render_text (dpy, ff->native_font, s, length, False, False, cs, 0);
1373 *ascent_ret = f->ascent;
1374 *descent_ret = f->descent;
1379 XTextWidth (XFontStruct *f, const char *s, int length)
1381 int ascent, descent, dir;
1383 XTextExtents (f, s, length, &dir, &ascent, &descent, &cs);
1389 XTextExtents16 (XFontStruct *f, const XChar2b *s, int length,
1390 int *dir_ret, int *ascent_ret, int *descent_ret,
1393 // Bool latin1_p = True;
1394 int i, utf8_len = 0;
1395 char *utf8 = XChar2b_to_utf8 (s, &utf8_len); // already sanitized
1397 for (i = 0; i < length; i++)
1398 if (s[i].byte1 > 0) {
1399 // latin1_p = False;
1405 Display *dpy = ff->dpy;
1406 jwxyz_render_text (dpy, ff->native_font, utf8, strlen(utf8),
1407 True, False, cs, 0);
1411 *ascent_ret = f->ascent;
1412 *descent_ret = f->descent;
1418 /* "Returns the distance in pixels in the primary draw direction from
1419 the drawing origin to the origin of the next character to be drawn."
1421 "overall_ink_return is set to the bbox of the string's character ink."
1423 "The overall_ink_return for a nondescending, horizontally drawn Latin
1424 character is conventionally entirely above the baseline; that is,
1425 overall_ink_return.height <= -overall_ink_return.y."
1427 [So this means that y is the top of the ink, and height grows down:
1428 For above-the-baseline characters, y is negative.]
1430 "The overall_ink_return for a nonkerned character is entirely at, and to
1431 the right of, the origin; that is, overall_ink_return.x >= 0."
1433 [So this means that x is the left of the ink, and width grows right.
1434 For left-of-the-origin characters, x is negative.]
1436 "A character consisting of a single pixel at the origin would set
1437 overall_ink_return fields y = 0, x = 0, width = 1, and height = 1."
1440 Xutf8TextExtents (XFontSet set, const char *str, int len,
1441 XRectangle *overall_ink_return,
1442 XRectangle *overall_logical_return)
1445 Font f = set->font->fid;
1447 jwxyz_render_text (f->dpy, f->native_font, str, len, True, False, &cs,
1450 /* "The overall_logical_return is the bounding box that provides minimum
1451 spacing to other graphical features for the string. Other graphical
1452 features, for example, a border surrounding the text, should not
1453 intersect this rectangle."
1455 So I think that means they're the same? Or maybe "ink" is the bounding
1456 box, and "logical" is the advancement? But then why is the return value
1459 if (overall_ink_return)
1460 XCharStruct_to_XmbRectangle (cs, *overall_ink_return);
1461 if (overall_logical_return)
1462 XCharStruct_to_XmbRectangle (cs, *overall_logical_return);
1469 jwxyz_draw_string (Display *dpy, Drawable d, GC gc, int x, int y,
1470 const char *str, size_t len, int utf8_p)
1472 const XGCValues *gcv = VTBL->gc_gcv (gc);
1473 Font ff = gcv->font;
1477 jwxyz_render_text (dpy, jwxyz_native_font (ff), str, len, utf8_p,
1478 gcv->antialias_p, &cs, &data);
1479 int w = cs.rbearing - cs.lbearing;
1480 int h = cs.ascent + cs.descent;
1482 if (w < 0 || h < 0) abort();
1483 if (w == 0 || h == 0) {
1484 if (data) free(data);
1488 XImage *img = XCreateImage (dpy, VTBL->visual (dpy), 32,
1489 ZPixmap, 0, data, w, h, 0, 0);
1491 /* The image of text is a 32-bit image, in white.
1492 Take the green channel for intensity and use that as alpha.
1493 replace RGB with the GC's foreground color.
1494 This expects that XPutImage respects alpha and only writes
1495 the bits that are not masked out.
1498 # define ROTL(x, rot) (((x) << ((rot) & 31)) | ((x) >> (32 - ((rot) & 31))))
1500 const unsigned long *masks =
1501 DefaultVisualOfScreen (DefaultScreenOfDisplay(dpy))->rgba_masks;
1502 unsigned shift = (i_log2 (masks[3]) - i_log2 (masks[1])) & 31;
1503 uint32_t mask = ROTL(masks[1], shift) & masks[3],
1504 color = gcv->foreground & ~masks[3];
1505 uint32_t *s = (uint32_t *)data;
1506 uint32_t *end = s + (w * h);
1509 *s = (ROTL(*s, shift) & mask) | color;
1515 Bool old_alpha = gcv->alpha_allowed_p;
1516 jwxyz_XSetAlphaAllowed (dpy, gc, True);
1517 XPutImage (dpy, d, gc, img, 0, 0,
1521 jwxyz_XSetAlphaAllowed (dpy, gc, old_alpha);
1522 XDestroyImage (img);
1530 XDrawString (Display *dpy, Drawable d, GC gc, int x, int y,
1531 const char *str, int len)
1533 return VTBL->draw_string (dpy, d, gc, x, y, str, len, False);
1538 XDrawString16 (Display *dpy, Drawable d, GC gc, int x, int y,
1539 const XChar2b *str, int len)
1541 XChar2b *b2 = malloc ((len + 1) * sizeof(*b2));
1544 memcpy (b2, str, len * sizeof(*b2));
1545 b2[len].byte1 = b2[len].byte2 = 0;
1546 s2 = XChar2b_to_utf8 (b2, 0);
1548 ret = VTBL->draw_string (dpy, d, gc, x, y, s2, strlen(s2), True);
1555 Xutf8DrawString (Display *dpy, Drawable d, XFontSet set, GC gc,
1556 int x, int y, const char *str, int len)
1558 VTBL->draw_string (dpy, d, gc, x, y, str, len, True);
1563 XDrawImageString (Display *dpy, Drawable d, GC gc, int x, int y,
1564 const char *str, int len)
1566 int ascent, descent, dir;
1568 XTextExtents (&VTBL->gc_gcv (gc)->font->metrics, str, len,
1569 &dir, &ascent, &descent, &cs);
1570 jwxyz_fill_rect (dpy, d, gc,
1571 x + MIN (0, cs.lbearing),
1572 y - MAX (0, ascent),
1574 /* The +1 here is almost certainly wrong, but BSOD
1575 requires it; and only BSOD, fluidballs, juggle
1576 and grabclient call XDrawImageString... */
1577 MAX (MAX (0, cs.rbearing) -
1578 MIN (0, cs.lbearing),
1580 MAX (0, ascent) + MAX (0, descent),
1581 VTBL->gc_gcv(gc)->background);
1582 return XDrawString (dpy, d, gc, x, y, str, len);
1587 jwxyz_native_font (Font f)
1589 return f->native_font;
1594 XSetForeground (Display *dpy, GC gc, unsigned long fg)
1596 XGCValues *gcv = VTBL->gc_gcv (gc);
1597 jwxyz_validate_pixel (dpy, fg, VTBL->gc_depth (gc), gcv->alpha_allowed_p);
1598 gcv->foreground = fg;
1604 XSetBackground (Display *dpy, GC gc, unsigned long bg)
1606 XGCValues *gcv = VTBL->gc_gcv (gc);
1607 jwxyz_validate_pixel (dpy, bg, VTBL->gc_depth (gc), gcv->alpha_allowed_p);
1608 gcv->background = bg;
1613 jwxyz_XSetAlphaAllowed (Display *dpy, GC gc, Bool allowed)
1615 VTBL->gc_gcv (gc)->alpha_allowed_p = allowed;
1620 jwxyz_XSetAntiAliasing (Display *dpy, GC gc, Bool antialias_p)
1622 VTBL->gc_gcv (gc)->antialias_p = antialias_p;
1628 XSetLineAttributes (Display *dpy, GC gc, unsigned int line_width,
1629 int line_style, int cap_style, int join_style)
1631 XGCValues *gcv = VTBL->gc_gcv (gc);
1632 gcv->line_width = line_width;
1633 Assert (line_style == LineSolid, "only LineSolid implemented");
1634 // gc->gcv.line_style = line_style;
1635 gcv->cap_style = cap_style;
1636 gcv->join_style = join_style;
1641 XSetGraphicsExposures (Display *dpy, GC gc, Bool which)
1647 XSetFunction (Display *dpy, GC gc, int which)
1649 VTBL->gc_gcv (gc)->function = which;
1654 XSetSubwindowMode (Display *dpy, GC gc, int which)
1656 VTBL->gc_gcv (gc)->subwindow_mode = which;
1662 XQueryPointer (Display *dpy, Window w, Window *root_ret, Window *child_ret,
1663 int *root_x_ret, int *root_y_ret,
1664 int *win_x_ret, int *win_y_ret, unsigned int *mask_ret)
1666 assert_window (dpy, w);
1669 jwxyz_get_pos (w, &vpos, &p);
1671 if (root_x_ret) *root_x_ret = p.x;
1672 if (root_y_ret) *root_y_ret = p.y;
1673 if (win_x_ret) *win_x_ret = p.x - vpos.x;
1674 if (win_y_ret) *win_y_ret = p.y - vpos.y;
1675 if (mask_ret) *mask_ret = 0; // #### poll the keyboard modifiers?
1676 if (root_ret) *root_ret = 0;
1677 if (child_ret) *child_ret = 0;
1682 XTranslateCoordinates (Display *dpy, Window w, Window dest_w,
1683 int src_x, int src_y,
1684 int *dest_x_ret, int *dest_y_ret,
1687 assert_window (dpy, w);
1690 jwxyz_get_pos (w, &vpos, NULL);
1692 // point starts out relative to top left of view
1696 // get point relative to top left of screen
1709 XKeycodeToKeysym (Display *dpy, KeyCode code, int index)
1715 XLookupString (XKeyEvent *e, char *buf, int size, KeySym *k_ret,
1718 KeySym ks = XKeycodeToKeysym (0, e->keycode, 0);
1720 // Do not put non-ASCII KeySyms like XK_Shift_L and XK_Page_Up in the string.
1721 if ((unsigned int) ks <= 255)
1724 // Put control characters in the string. Not meta.
1725 if (e->state & ControlMask) {
1726 if (c >= 'a' && c <= 'z') // Upcase control.
1728 if (c >= '@' && c <= '_') // Shift to control page.
1730 if (c == ' ') // C-SPC is NULL.
1734 if (k_ret) *k_ret = ks;
1735 if (size > 0) buf[0] = c;
1736 if (size > 1) buf[1] = 0;
1737 return (size > 0 ? 1 : 0);
1742 XFlush (Display *dpy)
1744 // Just let the event loop take care of this on its own schedule.
1749 XSync (Display *dpy, Bool flush)
1751 return XFlush (dpy);
1755 // declared in utils/visual.h
1757 has_writable_cells (Screen *s, Visual *v)
1763 visual_depth (Screen *s, Visual *v)
1769 visual_cells (Screen *s, Visual *v)
1771 return (int)(v->rgba_masks[0] | v->rgba_masks[1] | v->rgba_masks[2]);
1775 visual_class (Screen *s, Visual *v)
1781 visual_rgb_masks (Screen *s, Visual *v, unsigned long *red_mask,
1782 unsigned long *green_mask, unsigned long *blue_mask)
1784 *red_mask = v->rgba_masks[0];
1785 *green_mask = v->rgba_masks[1];
1786 *blue_mask = v->rgba_masks[2];
1790 visual_pixmap_depth (Screen *s, Visual *v)
1796 screen_number (Screen *screen)
1801 // declared in utils/grabclient.h
1803 use_subwindow_mode_p (Screen *screen, Window window)
1808 #endif /* HAVE_JWXYZ */