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 */
36 /* There's only one Window for a given jwxyz_Display. */
37 #define assert_window(dpy, w) \
38 Assert (w == RootWindow (dpy, 0), "not a window")
40 #define VTBL JWXYZ_VTBL(dpy)
45 int refcount; // for deciding when to release the native font
49 // In X11, "Font" is just an ID, and "XFontStruct" contains the metrics.
50 // But we need the metrics on both of them, so they go here.
54 struct jwxyz_XFontSet {
60 Log (const char *fmt, ...)
70 XDisplayWidth (Display *dpy, int screen)
72 return jwxyz_frame (XRootWindow (dpy, 0))->width;
76 XDisplayHeight (Display *dpy, int screen)
78 return jwxyz_frame (XRootWindow (dpy, 0))->height;
82 /* XLFDs use dots per inch, but Xlib uses millimeters. Go figure. */
84 size_mm (Display *dpy, unsigned size)
86 /* ((mm / inch) / (points / inch)) * dots / (dots / points) */
87 return (25.4 / 72) * size / jwxyz_scale (XRootWindow (dpy,0)) + 0.5;
91 XDisplayWidthMM (Display *dpy, int screen)
93 return size_mm (dpy, XDisplayWidth (dpy, screen));
97 XDisplayHeightMM (Display *dpy, int screen)
99 return size_mm (dpy, XDisplayHeight (dpy, screen));
103 XBlackPixelOfScreen(Screen *screen)
105 return DefaultVisualOfScreen (screen)->rgba_masks[3];
109 XWhitePixelOfScreen(Screen *screen)
111 const unsigned long *masks = DefaultVisualOfScreen (screen)->rgba_masks;
112 return masks[0] | masks[1] | masks[2] | masks[3];
116 XCellsOfScreen(Screen *screen)
118 const unsigned long *masks = DefaultVisualOfScreen (screen)->rgba_masks;
119 return masks[0] | masks[1] | masks[2];
123 jwxyz_validate_pixel (Display *dpy, unsigned long pixel, unsigned int depth,
124 Bool alpha_allowed_p)
126 Assert (depth == 1 || depth == visual_depth(NULL, NULL),
127 "invalid depth: %d", depth);
130 Assert ((pixel == 0 || pixel == 1), "bogus mono pixel: 0x%08X", pixel);
131 else if (!alpha_allowed_p)
132 Assert (((pixel & BlackPixel(dpy,0)) == BlackPixel(dpy,0)),
133 "bogus color pixel: 0x%08X", pixel);
138 XDrawPoint (Display *dpy, Drawable d, GC gc, int x, int y)
143 return XDrawPoints (dpy, d, gc, &p, 1, CoordModeOrigin);
148 jwxyz_dumb_drawing_mode(Display *dpy, Drawable d, GC gc,
149 int x, int y, unsigned width, unsigned height)
151 XGCValues *gcv = VTBL->gc_gcv (gc);
153 if (gcv->function == GXset || gcv->function == GXclear) {
154 // "set" and "clear" are dumb drawing modes that ignore the source
155 // bits and just draw solid rectangles.
156 unsigned depth = VTBL->gc_depth (gc);
157 jwxyz_fill_rect (dpy, d, 0, x, y, width, height,
158 (gcv->function == GXset
159 ? (depth == 1 ? 1 : WhitePixel(dpy,0))
160 : (depth == 1 ? 0 : BlackPixel(dpy,0))));
169 XCopyArea (Display *dpy, Drawable src, Drawable dst, GC gc,
170 int src_x, int src_y,
171 unsigned int width, unsigned int height,
172 int dst_x, int dst_y)
174 Assert (gc, "no GC");
175 Assert ((width < 65535), "improbably large width");
176 Assert ((height < 65535), "improbably large height");
177 Assert ((src_x < 65535 && src_x > -65535), "improbably large src_x");
178 Assert ((src_y < 65535 && src_y > -65535), "improbably large src_y");
179 Assert ((dst_x < 65535 && dst_x > -65535), "improbably large dst_x");
180 Assert ((dst_y < 65535 && dst_y > -65535), "improbably large dst_y");
182 if (width == 0 || height == 0)
185 if (jwxyz_dumb_drawing_mode (dpy, dst, gc, dst_x, dst_y, width, height))
188 XRectangle src_frame, dst_frame; // Sizes and origins of the two drawables
189 Bool clipped = False; // Whether we did any clipping of the rects.
191 src_frame = *jwxyz_frame (src);
192 dst_frame = *jwxyz_frame (dst);
194 // Initialize src_rect...
196 src_x += src_frame.x;
197 src_y += src_frame.y;
198 if (src_y < -65535) Assert(0, "src.origin.y went nuts");
200 // Initialize dst_rect...
202 dst_x += dst_frame.x;
203 dst_y += dst_frame.y;
204 if (dst_y < -65535) Assert(0, "dst.origin.y went nuts");
206 // Use signed width and height for this...
207 int width0 = width, height0 = height;
209 // Clip rects to frames...
212 # define CLIP(THIS,THAT,VAL,SIZE) do { \
213 int off = THIS##_##VAL; \
217 THIS##_##VAL -= off; \
218 THAT##_##VAL -= off; \
220 off = (( THIS##_##VAL + SIZE##0) - \
221 (THIS##_frame.VAL + THIS##_frame.SIZE)); \
227 CLIP (dst, src, x, width);
228 CLIP (dst, src, y, height);
230 // Not actually the original dst_rect, just the one before it's clipped to
232 int orig_dst_x = dst_x;
233 int orig_dst_y = dst_y;
234 int orig_width = width0;
235 int orig_height = height0;
237 if (width0 <= 0 || height0 <= 0)
240 CLIP (src, dst, x, width);
241 CLIP (src, dst, y, height);
244 // Sort-of-special case where no pixels can be grabbed from the source,
245 // and the whole destination is filled with the background color.
246 if (width0 <= 0 || height0 <= 0) {
250 VTBL->copy_area (dpy, src, dst, gc,
251 src_x, src_y, width0, height0, dst_x, dst_y);
254 // If either the src or dst rects did not lie within their drawables, then
255 // we have adjusted both the src and dst rects to account for the clipping;
256 // that means we need to clear to the background, so that clipped bits end
257 // up in the bg color instead of simply not being copied.
259 // This has to happen after the copy, because if it happens before, the
260 // cleared area will get grabbed if it overlaps with the source rectangle.
262 if (clipped && dst == XRootWindow (dpy,0)) {
266 Assert (orig_dst_x >= 0 &&
267 orig_dst_x + orig_width <= dst_frame.width &&
269 orig_dst_y + orig_height <= dst_frame.height,
273 XRectangle *rects_end = rects;
275 if (orig_dst_y < dst_y0) {
276 rects_end->x = orig_dst_x;
277 rects_end->y = orig_dst_y;
278 rects_end->width = orig_width;
279 rects_end->height = dst_y0 - orig_dst_y;
283 if (orig_dst_y + orig_height > dst_y0 + height0) {
284 rects_end->x = orig_dst_x;
285 rects_end->y = dst_y0 + height0;
286 rects_end->width = orig_width;
287 rects_end->height = orig_dst_y + orig_height - dst_y0 - height0;
291 if (orig_dst_x < dst_x0) {
292 rects_end->x = orig_dst_x;
293 rects_end->y = dst_y0;
294 rects_end->width = dst_x0 - orig_dst_x;
295 rects_end->height = height0;
299 if (dst_x0 + width0 < orig_dst_x + orig_width) {
300 rects_end->x = dst_x0 + width0;
301 rects_end->y = dst_y0;
302 rects_end->width = orig_dst_x + orig_width - dst_x0 - width0;
303 rects_end->height = height0;
307 XGCValues *gcv = VTBL->gc_gcv (gc);
308 int old_function = gcv->function;
309 gcv->function = GXcopy;
310 VTBL->fill_rects (dpy, dst, gc, rects, rects_end - rects,
311 *VTBL->window_background (dpy));
312 gcv->function = old_function;
320 jwxyz_blit (const void *src_data, ptrdiff_t src_pitch,
321 unsigned src_x, unsigned src_y,
322 void *dst_data, ptrdiff_t dst_pitch,
323 unsigned dst_x, unsigned dst_y,
324 unsigned width, unsigned height)
326 Bool same = src_data == dst_data;
327 src_data = SEEK_XY (src_data, src_pitch, src_x, src_y);
328 dst_data = SEEK_XY (dst_data, dst_pitch, dst_x, dst_y);
330 size_t bytes = width * 4;
332 if (same && dst_y > src_y) {
333 // Copy upwards if the areas might overlap.
334 src_data += src_pitch * (height - 1);
335 dst_data += dst_pitch * (height - 1);
336 src_pitch = -src_pitch;
337 dst_pitch = -dst_pitch;
341 // memcpy is an alias for memmove on macOS.
342 memmove (dst_data, src_data, bytes);
343 src_data += src_pitch;
344 dst_data += dst_pitch;
351 XCopyPlane (Display *dpy, Drawable src, Drawable dest, GC gc,
352 int src_x, int src_y,
353 unsigned width, int height,
354 int dest_x, int dest_y, unsigned long plane)
356 Assert ((VTBL->gc_depth (gc) == 1 || plane == 1), "hairy plane mask!");
358 // This isn't right: XCopyPlane() is supposed to map 1/0 to fg/bg,
359 // not to white/black.
360 return XCopyArea (dpy, src, dest, gc,
361 src_x, src_y, width, height, dest_x, dest_y);
366 XDrawLine (Display *dpy, Drawable d, GC gc, int x1, int y1, int x2, int y2)
373 XDrawSegments (dpy, d, gc, &segment, 1);
379 XSetWindowBackground (Display *dpy, Window w, unsigned long pixel)
381 Assert (w == XRootWindow (dpy,0), "not a window");
382 jwxyz_validate_pixel (dpy, pixel, visual_depth (NULL, NULL), False);
383 *VTBL->window_background (dpy) = pixel;
388 jwxyz_fill_rect (Display *dpy, Drawable d, GC gc,
389 int x, int y, unsigned int width, unsigned int height,
392 XRectangle r = {x, y, width, height};
393 VTBL->fill_rects (dpy, d, gc, &r, 1, pixel);
397 XFillRectangle (Display *dpy, Drawable d, GC gc, int x, int y,
398 unsigned int width, unsigned int height)
400 jwxyz_fill_rect (dpy, d, gc, x, y, width, height,
401 VTBL->gc_gcv (gc)->foreground);
406 XDrawRectangle (Display *dpy, Drawable d, GC gc, int x, int y,
407 unsigned int width, unsigned int height)
412 {x + width, y + height},
417 XDrawLines(dpy, d, gc, points, 5, CoordModeOrigin);
422 XFillRectangles (Display *dpy, Drawable d, GC gc, XRectangle *rects, int n)
424 VTBL->fill_rects (dpy, d, gc, rects, n, VTBL->gc_gcv (gc)->foreground);
430 XClearArea (Display *dpy, Window win, int x, int y, int w, int h, Bool exp)
432 Assert(win == XRootWindow(dpy,0), "XClearArea: not a window");
433 Assert(!exp, "XClearArea: exposures unsupported");
434 jwxyz_fill_rect (dpy, win, 0, x, y, w, h, *VTBL->window_background (dpy));
440 XDrawArc (Display *dpy, Drawable d, GC gc, int x, int y,
441 unsigned int width, unsigned int height, int angle1, int angle2)
443 return VTBL->draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
448 XFillArc (Display *dpy, Drawable d, GC gc, int x, int y,
449 unsigned int width, unsigned int height, int angle1, int angle2)
451 return VTBL->draw_arc (dpy, d, gc, x, y, width, height, angle1, angle2,
456 XDrawArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
459 for (i = 0; i < narcs; i++)
460 VTBL->draw_arc (dpy, d, gc,
461 arcs[i].x, arcs[i].y,
462 arcs[i].width, arcs[i].height,
463 arcs[i].angle1, arcs[i].angle2,
469 XFillArcs (Display *dpy, Drawable d, GC gc, XArc *arcs, int narcs)
472 for (i = 0; i < narcs; i++)
473 VTBL->draw_arc (dpy, d, gc,
474 arcs[i].x, arcs[i].y,
475 arcs[i].width, arcs[i].height,
476 arcs[i].angle1, arcs[i].angle2,
482 jwxyz_gcv_defaults (Display *dpy, XGCValues *gcv, int depth)
484 memset (gcv, 0, sizeof(*gcv));
485 gcv->function = GXcopy;
486 gcv->foreground = (depth == 1 ? 1 : WhitePixel(dpy,0));
487 gcv->background = (depth == 1 ? 0 : BlackPixel(dpy,0));
489 gcv->cap_style = CapButt;
490 gcv->join_style = JoinMiter;
491 gcv->fill_rule = EvenOddRule;
493 gcv->alpha_allowed_p = False;
494 gcv->antialias_p = True;
499 XChangeGC (Display *dpy, GC gc, unsigned long mask, XGCValues *from)
501 if (! mask) return 0;
502 Assert (gc && from, "no gc");
503 if (!gc || !from) return 0;
505 XGCValues *to = VTBL->gc_gcv (gc);
506 unsigned depth = VTBL->gc_depth (gc);
508 if (mask & GCFunction) to->function = from->function;
509 if (mask & GCForeground) to->foreground = from->foreground;
510 if (mask & GCBackground) to->background = from->background;
511 if (mask & GCLineWidth) to->line_width = from->line_width;
512 if (mask & GCCapStyle) to->cap_style = from->cap_style;
513 if (mask & GCJoinStyle) to->join_style = from->join_style;
514 if (mask & GCFillRule) to->fill_rule = from->fill_rule;
515 if (mask & GCClipXOrigin) to->clip_x_origin = from->clip_x_origin;
516 if (mask & GCClipYOrigin) to->clip_y_origin = from->clip_y_origin;
517 if (mask & GCSubwindowMode) to->subwindow_mode = from->subwindow_mode;
519 if (mask & GCClipMask) XSetClipMask (dpy, gc, from->clip_mask);
520 if (mask & GCFont) XSetFont (dpy, gc, from->font);
522 if (mask & GCForeground)
523 jwxyz_validate_pixel (dpy, from->foreground, depth, to->alpha_allowed_p);
524 if (mask & GCBackground)
525 jwxyz_validate_pixel (dpy, from->background, depth, to->alpha_allowed_p);
527 Assert ((! (mask & (GCLineStyle |
534 GCGraphicsExposures |
538 "unimplemented gcvalues mask");
545 XGetWindowAttributes (Display *dpy, Window w, XWindowAttributes *xgwa)
547 assert_window(dpy, w);
548 memset (xgwa, 0, sizeof(*xgwa));
549 const XRectangle *frame = jwxyz_frame (w);
552 xgwa->width = frame->width;
553 xgwa->height = frame->height;
554 xgwa->depth = visual_depth (NULL, NULL);
555 xgwa->screen = DefaultScreenOfDisplay (dpy);
556 xgwa->visual = XDefaultVisualOfScreen (xgwa->screen);
561 XGetGeometry (Display *dpy, Drawable d, Window *root_ret,
562 int *x_ret, int *y_ret,
563 unsigned int *w_ret, unsigned int *h_ret,
564 unsigned int *bw_ret, unsigned int *d_ret)
566 const XRectangle *frame = jwxyz_frame (d);
569 *w_ret = frame->width;
570 *h_ret = frame->height;
571 *d_ret = jwxyz_drawable_depth (d);
572 *root_ret = RootWindow (dpy, 0);
579 XAllocColor (Display *dpy, Colormap cmap, XColor *color)
581 const unsigned long *masks =
582 DefaultVisualOfScreen(DefaultScreenOfDisplay(dpy))->rgba_masks;
584 (((color->red << 16) >> (31 - i_log2(masks[0]))) & masks[0]) |
585 (((color->green << 16) >> (31 - i_log2(masks[1]))) & masks[1]) |
586 (((color->blue << 16) >> (31 - i_log2(masks[2]))) & masks[2]) |
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_32 (XImage *ximage, int x, int y)
718 return ((unsigned long)
719 *((uint32_t *) ximage->data +
720 (y * (ximage->bytes_per_line >> 2)) +
725 ximage_putpixel_32 (XImage *ximage, int x, int y, unsigned long pixel)
727 *((uint32_t *) ximage->data +
728 (y * (ximage->bytes_per_line >> 2)) +
729 x) = (uint32_t) pixel;
735 XInitImage (XImage *ximage)
737 if (!ximage->bytes_per_line)
738 ximage->bytes_per_line = (ximage->depth == 1
739 ? (ximage->width + 7) / 8
740 : ximage->width * 4);
742 if (ximage->depth == 1) {
743 ximage->f.put_pixel = ximage_putpixel_1;
744 ximage->f.get_pixel = ximage_getpixel_1;
745 } else if (ximage->depth == 32 || ximage->depth == 24) {
746 ximage->f.put_pixel = ximage_putpixel_32;
747 ximage->f.get_pixel = ximage_getpixel_32;
749 Assert (0, "unknown depth");
756 XCreateImage (Display *dpy, Visual *visual, unsigned int depth,
757 int format, int offset, char *data,
758 unsigned int width, unsigned int height,
759 int bitmap_pad, int bytes_per_line)
761 XImage *ximage = (XImage *) calloc (1, sizeof(*ximage));
762 ximage->width = width;
763 ximage->height = height;
764 ximage->format = format;
766 ximage->bitmap_unit = 8;
767 ximage->byte_order = LSBFirst;
768 ximage->bitmap_bit_order = ximage->byte_order;
769 ximage->bitmap_pad = bitmap_pad;
770 ximage->depth = depth;
771 Visual *v = DefaultVisualOfScreen (DefaultScreenOfDisplay (dpy));
772 ximage->red_mask = (depth == 1 ? 0 : v->rgba_masks[0]);
773 ximage->green_mask = (depth == 1 ? 0 : v->rgba_masks[1]);
774 ximage->blue_mask = (depth == 1 ? 0 : v->rgba_masks[2]);
775 ximage->bits_per_pixel = (depth == 1 ? 1 : visual_depth (NULL, NULL));
776 ximage->bytes_per_line = bytes_per_line;
783 XSubImage (XImage *from, int x, int y, unsigned int w, unsigned int h)
785 XImage *to = (XImage *) malloc (sizeof(*to));
786 memcpy (to, from, sizeof(*from));
789 to->bytes_per_line = 0;
792 to->data = (char *) malloc (h * to->bytes_per_line);
794 if (x >= from->width)
796 else if (x+w > from->width)
799 if (y >= from->height)
801 else if (y+h > from->height)
802 h = from->height - y;
805 for (ty = 0; ty < h; ty++)
806 for (tx = 0; tx < w; tx++)
807 XPutPixel (to, tx, ty, XGetPixel (from, x+tx, y+ty));
812 XPixmapFormatValues *
813 XListPixmapFormats (Display *dpy, int *n_ret)
815 XPixmapFormatValues *ret = calloc (2, sizeof(*ret));
816 ret[0].depth = visual_depth (NULL, NULL);
817 ret[0].bits_per_pixel = 32;
818 ret[0].scanline_pad = 8;
820 ret[1].bits_per_pixel = 1;
821 ret[1].scanline_pad = 8;
828 XGetPixel (XImage *ximage, int x, int y)
830 return ximage->f.get_pixel (ximage, x, y);
835 XPutPixel (XImage *ximage, int x, int y, unsigned long pixel)
837 return ximage->f.put_pixel (ximage, x, y, pixel);
841 XDestroyImage (XImage *ximage)
843 if (ximage->data) free (ximage->data);
850 XGetImage (Display *dpy, Drawable d, int x, int y,
851 unsigned int width, unsigned int height,
852 unsigned long plane_mask, int format)
854 unsigned depth = jwxyz_drawable_depth (d);
855 XImage *image = XCreateImage (dpy, 0, depth, format, 0, 0, width, height,
857 image->data = (char *) malloc (height * image->bytes_per_line);
859 return XGetSubImage (dpy, d, x, y, width, height, plane_mask, format,
865 XCreatePixmapFromBitmapData (Display *dpy, Drawable drawable,
867 unsigned int w, unsigned int h,
868 unsigned long fg, unsigned long bg,
871 Pixmap p = XCreatePixmap (dpy, drawable, w, h, depth);
872 XImage *image = XCreateImage (dpy, 0, 1, XYPixmap, 0,
873 (char *) data, w, h, 0, 0);
877 GC gc = XCreateGC (dpy, p, GCForeground|GCBackground, &gcv);
878 XPutImage (dpy, p, gc, image, 0, 0, 0, 0, w, h);
881 XDestroyImage (image);
887 XGetAtomName (Display *dpy, Atom atom)
890 return strdup ("FONT");
892 // Note that atoms (that aren't predefined) are just char *.
893 return strdup ((char *) atom);
897 // This is XQueryFont, but for the XFontStruct embedded in 'Font'
900 query_font (Font fid)
902 Assert (fid && fid->native_font, "no native font in fid");
907 Display *dpy = fid->dpy;
908 void *native_font = fid->native_font;
910 XFontStruct *f = &fid->metrics;
911 XCharStruct *min = &f->min_bounds;
912 XCharStruct *max = &f->max_bounds;
915 f->min_char_or_byte2 = first;
916 f->max_char_or_byte2 = last;
917 f->default_char = 'M';
918 f->ascent = fid->ascent;
919 f->descent = fid->descent;
921 min->width = 32767; // set to smaller values in the loop
923 min->descent = 32767;
924 min->lbearing = 32767;
925 min->rbearing = 32767;
927 f->per_char = (XCharStruct *) calloc (last-first+2, sizeof (XCharStruct));
929 for (int i = first; i <= last; i++) {
930 XCharStruct *cs = &f->per_char[i-first];
932 jwxyz_render_text (dpy, native_font, &s, 1, False, False, cs, 0);
934 max->width = MAX (max->width, cs->width);
935 max->ascent = MAX (max->ascent, cs->ascent);
936 max->descent = MAX (max->descent, cs->descent);
937 max->lbearing = MAX (max->lbearing, cs->lbearing);
938 max->rbearing = MAX (max->rbearing, cs->rbearing);
940 min->width = MIN (min->width, cs->width);
941 min->ascent = MIN (min->ascent, cs->ascent);
942 min->descent = MIN (min->descent, cs->descent);
943 min->lbearing = MIN (min->lbearing, cs->lbearing);
944 min->rbearing = MIN (min->rbearing, cs->rbearing);
946 Log (" %3d %c: w=%3d lb=%3d rb=%3d as=%3d ds=%3d "
947 " bb=%5.1f x %5.1f @ %5.1f %5.1f adv=%5.1f %5.1f\n"
948 i, i, cs->width, cs->lbearing, cs->rbearing,
949 cs->ascent, cs->descent,
950 bbox.size.width, bbox.size.height,
951 bbox.origin.x, bbox.origin.y,
952 advancement.width, advancement.height);
958 // Since 'Font' includes the metrics, this just makes a copy of that.
961 XQueryFont (Display *dpy, Font fid)
964 XFontStruct *f = (XFontStruct *) calloc (1, sizeof(*f));
970 f->properties = malloc (sizeof(*f->properties) * f->n_properties);
971 f->properties[0].name = XA_FONT;
972 Assert (sizeof (f->properties[0].card32) >= sizeof (char *),
973 "atoms probably needs a real implementation");
974 // If XInternAtom is ever implemented, use it here.
975 f->properties[0].card32 = (unsigned long)fid->xa_font;
977 // copy XCharStruct array
978 int size = (f->max_char_or_byte2 - f->min_char_or_byte2) + 1;
979 f->per_char = (XCharStruct *) calloc (size + 2, sizeof (XCharStruct));
981 memcpy (f->per_char, fid->metrics.per_char,
982 size * sizeof (XCharStruct));
996 /* On Cocoa and iOS, fonts may be specified as "Georgia Bold 24" instead
997 of XLFD strings; also they can be comma-separated strings with multiple
998 font names. First one that exists wins.
1001 try_native_font (Display *dpy, const char *name, Font fid)
1004 const char *spc = strrchr (name, ' ');
1007 char *token = strdup (name);
1008 char *otoken = token;
1012 while ((name2 = strtok_r (token, ",", &lasts))) {
1015 while (*name2 == ' ' || *name2 == '\t' || *name2 == '\n')
1018 spc = strrchr (name2, ' ');
1022 if (1 != sscanf (spc, " %d ", &dsize))
1026 if (size < 4) continue;
1028 name2[strlen(name2) - strlen(spc)] = 0;
1030 fid->native_font = jwxyz_load_native_font(XRootWindow(dpy,0), 0, 0, name2,
1031 strlen(name2) - strlen(spc),
1032 JWXYZ_FONT_FACE, size, NULL,
1033 &fid->ascent, &fid->descent);
1034 if (fid->native_font) {
1035 fid->xa_font = strdup (name); // Maybe this should be an XLFD?
1038 Log("No native font: \"%s\" %.0f", name2, size);
1047 xlfd_field_end (const char *s)
1049 const char *s2 = strchr(s, '-');
1057 xlfd_next (const char **s, const char **s2)
1062 Assert (**s2 == '-', "xlfd parse error");
1064 *s2 = xlfd_field_end (*s);
1072 try_xlfd_font (Display *dpy, const char *name, Font fid)
1074 const char *family_name = NULL; /* Not NULL-terminated. */
1075 size_t family_name_size = 0;
1077 // Default mask is for the built-in X11 font aliases.
1078 mask = JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD | JWXYZ_STYLE_ITALIC;
1080 float size = 12; /* In points (1/72 in.) */
1082 const char *s = (name ? name : "");
1084 size_t L = strlen (s);
1085 # define CMP(STR) (L == strlen(STR) && !strncasecmp (s, (STR), L))
1086 # define UNSPEC (L == 0 || (L == 1 && *s == '*'))
1087 if (CMP ("6x10")) size = 8, require |= JWXYZ_STYLE_MONOSPACE;
1088 else if (CMP ("6x10bold")) size = 8, require |= JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD;
1089 else if (CMP ("fixed")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1090 else if (CMP ("9x15")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1091 else if (CMP ("9x15bold")) size = 12, require |= JWXYZ_STYLE_MONOSPACE | JWXYZ_STYLE_BOLD;
1092 else if (CMP ("vga")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1093 else if (CMP ("console")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1094 else if (CMP ("gallant")) size = 12, require |= JWXYZ_STYLE_MONOSPACE;
1099 // Incorrect fields are ignored.
1103 const char *s2 = xlfd_field_end(s);
1107 L = xlfd_next (&s, &s2); // Family name
1108 // This used to substitute Georgia for Times. Now it doesn't.
1109 if (CMP ("random")) {
1111 } else if (CMP ("fixed")) {
1112 require |= JWXYZ_STYLE_MONOSPACE;
1113 family_name = "Courier";
1114 family_name_size = strlen(family_name);
1115 } else if (!UNSPEC) {
1117 family_name_size = L;
1120 L = xlfd_next (&s, &s2); // Weight name
1121 if (CMP ("bold") || CMP ("demibold"))
1122 require |= JWXYZ_STYLE_BOLD;
1123 else if (CMP ("medium") || CMP ("regular"))
1124 forbid |= JWXYZ_STYLE_BOLD;
1126 L = xlfd_next (&s, &s2); // Slant
1127 if (CMP ("i") || CMP ("o"))
1128 require |= JWXYZ_STYLE_ITALIC;
1130 forbid |= JWXYZ_STYLE_ITALIC;
1132 xlfd_next (&s, &s2); // Set width name (ignore)
1133 xlfd_next (&s, &s2); // Add style name (ignore)
1135 L = xlfd_next (&s, &s2); // Pixel size
1137 uintmax_t pxsize = strtoumax(s, &s3, 10);
1138 if (UNSPEC || s2 != s3)
1139 pxsize = UINTMAX_MAX; // i.e. it's invalid.
1141 L = xlfd_next (&s, &s2); // Point size
1142 uintmax_t ptsize = strtoumax(s, &s3, 10);
1143 if (UNSPEC || s2 != s3)
1144 ptsize = UINTMAX_MAX;
1146 xlfd_next (&s, &s2); // Resolution X (ignore)
1147 xlfd_next (&s, &s2); // Resolution Y (ignore)
1149 L = xlfd_next (&s, &s2); // Spacing
1151 forbid |= JWXYZ_STYLE_MONOSPACE;
1152 else if (CMP ("m") || CMP ("c"))
1153 require |= JWXYZ_STYLE_MONOSPACE;
1155 xlfd_next (&s, &s2); // Average width (ignore)
1157 // -*-courier-bold-r-*-*-14-*-*-*-*-*-*-* 14 px
1158 // -*-courier-bold-r-*-*-*-140-*-*-m-*-*-* 14 pt
1159 // -*-courier-bold-r-*-*-140-* 14 pt, via wildcard
1160 // -*-courier-bold-r-*-140-* 14 pt, not handled
1161 // -*-courier-bold-r-*-*-14-180-*-*-*-*-*-* error
1163 L = xlfd_next (&s, &s2); // Charset registry
1164 if (ptsize != UINTMAX_MAX) {
1165 // It was in the ptsize field, so that's definitely what it is.
1166 size = ptsize / 10.0;
1167 } else if (pxsize != UINTMAX_MAX) {
1169 // If it's a fully qualified XLFD, then this really is the pxsize.
1170 // Otherwise, this is probably point size with a multi-field wildcard.
1175 mask = require | forbid;
1180 if (!family_name && !rand) {
1181 family_name = jwxyz_default_font_family (require);
1182 family_name_size = strlen (family_name);
1185 if (size < 6 || size > 1000)
1188 char *family_name_ptr = NULL;
1189 fid->native_font = jwxyz_load_native_font (XRootWindow(dpy,0),
1191 family_name, family_name_size,
1192 rand ? JWXYZ_FONT_RANDOM : JWXYZ_FONT_FAMILY,
1193 size, &family_name_ptr,
1194 &fid->ascent, &fid->descent);
1196 if (fid->native_font) {
1197 unsigned dpi_d = XDisplayHeightMM (dpy,0) * 10 / 2;
1198 unsigned dpi = (254 * XDisplayHeight (dpy,0) + dpi_d) / (2 * dpi_d);
1199 asprintf(&fid->xa_font, "-*-%s-%s-%c-*-*-%u-%u-%u-%u-%c-0-iso10646-1",
1201 (require & JWXYZ_STYLE_BOLD) ? "bold" : "medium",
1202 (require & JWXYZ_STYLE_ITALIC) ? 'o' : 'r',
1203 (unsigned)(dpi * size / 72.27 + 0.5),
1204 (unsigned)(size * 10 + 0.5), dpi, dpi,
1205 (require & JWXYZ_STYLE_MONOSPACE) ? 'm' : 'p');
1208 free (family_name_ptr);
1213 XLoadFont (Display *dpy, const char *name)
1215 Font fid = (Font) calloc (1, sizeof(*fid));
1219 try_native_font (dpy, name, fid);
1221 if (!fid->native_font && name &&
1222 strchr (name, ' ') &&
1223 !strchr (name, '*')) {
1224 // If name contains a space but no stars, it is a native font spec --
1225 // return NULL so that we know it really didn't exist. Else, it is an
1226 // XLFD font, so keep trying.
1231 if (! fid->native_font)
1232 try_xlfd_font (dpy, name, fid);
1234 if (!fid->native_font) {
1246 XLoadQueryFont (Display *dpy, const char *name)
1248 Font fid = XLoadFont (dpy, name);
1250 return XQueryFont (dpy, fid);
1254 XUnloadFont (Display *dpy, Font fid)
1256 if (--fid->refcount < 0) abort();
1257 if (fid->refcount > 0) return 0;
1259 if (fid->native_font)
1260 jwxyz_release_native_font (fid->dpy, fid->native_font);
1262 if (fid->metrics.per_char)
1263 free (fid->metrics.per_char);
1270 XFreeFontInfo (char **names, XFontStruct *info, int n)
1274 for (i = 0; i < n; i++)
1275 if (names[i]) free (names[i]);
1279 for (i = 0; i < n; i++)
1280 if (info[i].per_char) {
1281 free (info[i].per_char);
1282 free (info[i].properties);
1290 XFreeFont (Display *dpy, XFontStruct *f)
1293 XFreeFontInfo (0, f, 1);
1294 XUnloadFont (dpy, fid);
1300 XSetFont (Display *dpy, GC gc, Font fid)
1302 XGCValues *gcv = VTBL->gc_gcv(gc);
1303 Font font2 = copy_font (fid);
1305 XUnloadFont (dpy, gcv->font);
1312 XCreateFontSet (Display *dpy, char *name,
1313 char ***missing_charset_list_return,
1314 int *missing_charset_count_return,
1315 char **def_string_return)
1317 char *name2 = strdup (name);
1318 char *s = strchr (name, ',');
1321 XFontStruct *f = XLoadQueryFont (dpy, name2);
1324 set = (XFontSet) calloc (1, sizeof(*set));
1328 if (missing_charset_list_return) *missing_charset_list_return = 0;
1329 if (missing_charset_count_return) *missing_charset_count_return = 0;
1330 if (def_string_return) *def_string_return = 0;
1336 XFreeFontSet (Display *dpy, XFontSet set)
1338 XFreeFont (dpy, set->font);
1344 XFreeStringList (char **list)
1348 for (i = 0; list[i]; i++)
1355 XTextExtents (XFontStruct *f, const char *s, int length,
1356 int *dir_ret, int *ascent_ret, int *descent_ret,
1359 // Unfortunately, adding XCharStructs together to get the extents for a
1360 // string doesn't work: Cocoa uses non-integral character advancements, but
1361 // XCharStruct.width is an integer. Plus that doesn't take into account
1362 // kerning pairs, alternate glyphs, and fun stuff like the word "Zapfino" in
1366 Display *dpy = ff->dpy;
1367 jwxyz_render_text (dpy, ff->native_font, s, length, False, False, cs, 0);
1369 *ascent_ret = f->ascent;
1370 *descent_ret = f->descent;
1375 XTextWidth (XFontStruct *f, const char *s, int length)
1377 int ascent, descent, dir;
1379 XTextExtents (f, s, length, &dir, &ascent, &descent, &cs);
1385 XTextExtents16 (XFontStruct *f, const XChar2b *s, int length,
1386 int *dir_ret, int *ascent_ret, int *descent_ret,
1389 // Bool latin1_p = True;
1390 int i, utf8_len = 0;
1391 char *utf8 = XChar2b_to_utf8 (s, &utf8_len); // already sanitized
1393 for (i = 0; i < length; i++)
1394 if (s[i].byte1 > 0) {
1395 // latin1_p = False;
1401 Display *dpy = ff->dpy;
1402 jwxyz_render_text (dpy, ff->native_font, utf8, strlen(utf8),
1403 True, False, cs, 0);
1407 *ascent_ret = f->ascent;
1408 *descent_ret = f->descent;
1414 /* "Returns the distance in pixels in the primary draw direction from
1415 the drawing origin to the origin of the next character to be drawn."
1417 "overall_ink_return is set to the bbox of the string's character ink."
1419 "The overall_ink_return for a nondescending, horizontally drawn Latin
1420 character is conventionally entirely above the baseline; that is,
1421 overall_ink_return.height <= -overall_ink_return.y."
1423 [So this means that y is the top of the ink, and height grows down:
1424 For above-the-baseline characters, y is negative.]
1426 "The overall_ink_return for a nonkerned character is entirely at, and to
1427 the right of, the origin; that is, overall_ink_return.x >= 0."
1429 [So this means that x is the left of the ink, and width grows right.
1430 For left-of-the-origin characters, x is negative.]
1432 "A character consisting of a single pixel at the origin would set
1433 overall_ink_return fields y = 0, x = 0, width = 1, and height = 1."
1436 Xutf8TextExtents (XFontSet set, const char *str, int len,
1437 XRectangle *overall_ink_return,
1438 XRectangle *overall_logical_return)
1441 Font f = set->font->fid;
1443 jwxyz_render_text (f->dpy, f->native_font, str, len, True, False, &cs,
1446 /* "The overall_logical_return is the bounding box that provides minimum
1447 spacing to other graphical features for the string. Other graphical
1448 features, for example, a border surrounding the text, should not
1449 intersect this rectangle."
1451 So I think that means they're the same? Or maybe "ink" is the bounding
1452 box, and "logical" is the advancement? But then why is the return value
1455 if (overall_ink_return)
1456 XCharStruct_to_XmbRectangle (cs, *overall_ink_return);
1457 if (overall_logical_return)
1458 XCharStruct_to_XmbRectangle (cs, *overall_logical_return);
1465 jwxyz_draw_string (Display *dpy, Drawable d, GC gc, int x, int y,
1466 const char *str, size_t len, int utf8_p)
1468 const XGCValues *gcv = VTBL->gc_gcv (gc);
1469 Font ff = gcv->font;
1473 jwxyz_render_text (dpy, jwxyz_native_font (ff), str, len, utf8_p,
1474 gcv->antialias_p, &cs, &data);
1475 int w = cs.rbearing - cs.lbearing;
1476 int h = cs.ascent + cs.descent;
1478 if (w < 0 || h < 0) abort();
1479 if (w == 0 || h == 0) {
1480 if (data) free(data);
1484 XImage *img = XCreateImage (dpy, VTBL->visual (dpy), 32,
1485 ZPixmap, 0, data, w, h, 0, 0);
1487 /* The image of text is a 32-bit image, in white.
1488 Take the green channel for intensity and use that as alpha.
1489 replace RGB with the GC's foreground color.
1490 This expects that XPutImage respects alpha and only writes
1491 the bits that are not masked out.
1494 # define ROTL(x, rot) (((x) << ((rot) & 31)) | ((x) >> (32 - ((rot) & 31))))
1496 const unsigned long *masks =
1497 DefaultVisualOfScreen (DefaultScreenOfDisplay(dpy))->rgba_masks;
1498 unsigned shift = (i_log2 (masks[3]) - i_log2 (masks[1])) & 31;
1499 uint32_t mask = ROTL(masks[1], shift) & masks[3],
1500 color = gcv->foreground & ~masks[3];
1501 uint32_t *s = (uint32_t *)data;
1502 uint32_t *end = s + (w * h);
1505 *s = (ROTL(*s, shift) & mask) | color;
1511 Bool old_alpha = gcv->alpha_allowed_p;
1512 jwxyz_XSetAlphaAllowed (dpy, gc, True);
1513 XPutImage (dpy, d, gc, img, 0, 0,
1517 jwxyz_XSetAlphaAllowed (dpy, gc, old_alpha);
1518 XDestroyImage (img);
1526 XDrawString (Display *dpy, Drawable d, GC gc, int x, int y,
1527 const char *str, int len)
1529 return VTBL->draw_string (dpy, d, gc, x, y, str, len, False);
1534 XDrawString16 (Display *dpy, Drawable d, GC gc, int x, int y,
1535 const XChar2b *str, int len)
1537 XChar2b *b2 = malloc ((len + 1) * sizeof(*b2));
1540 memcpy (b2, str, len * sizeof(*b2));
1541 b2[len].byte1 = b2[len].byte2 = 0;
1542 s2 = XChar2b_to_utf8 (b2, 0);
1544 ret = VTBL->draw_string (dpy, d, gc, x, y, s2, strlen(s2), True);
1551 Xutf8DrawString (Display *dpy, Drawable d, XFontSet set, GC gc,
1552 int x, int y, const char *str, int len)
1554 VTBL->draw_string (dpy, d, gc, x, y, str, len, True);
1559 XDrawImageString (Display *dpy, Drawable d, GC gc, int x, int y,
1560 const char *str, int len)
1562 int ascent, descent, dir;
1564 XTextExtents (&VTBL->gc_gcv (gc)->font->metrics, str, len,
1565 &dir, &ascent, &descent, &cs);
1566 jwxyz_fill_rect (dpy, d, gc,
1567 x + MIN (0, cs.lbearing),
1568 y - MAX (0, ascent),
1569 MAX (MAX (0, cs.rbearing) -
1570 MIN (0, cs.lbearing),
1572 MAX (0, ascent) + MAX (0, descent),
1573 VTBL->gc_gcv(gc)->background);
1574 return XDrawString (dpy, d, gc, x, y, str, len);
1579 jwxyz_native_font (Font f)
1581 return f->native_font;
1586 XSetForeground (Display *dpy, GC gc, unsigned long fg)
1588 XGCValues *gcv = VTBL->gc_gcv (gc);
1589 jwxyz_validate_pixel (dpy, fg, VTBL->gc_depth (gc), gcv->alpha_allowed_p);
1590 gcv->foreground = fg;
1596 XSetBackground (Display *dpy, GC gc, unsigned long bg)
1598 XGCValues *gcv = VTBL->gc_gcv (gc);
1599 jwxyz_validate_pixel (dpy, bg, VTBL->gc_depth (gc), gcv->alpha_allowed_p);
1600 gcv->background = bg;
1605 jwxyz_XSetAlphaAllowed (Display *dpy, GC gc, Bool allowed)
1607 VTBL->gc_gcv (gc)->alpha_allowed_p = allowed;
1612 jwxyz_XSetAntiAliasing (Display *dpy, GC gc, Bool antialias_p)
1614 VTBL->gc_gcv (gc)->antialias_p = antialias_p;
1620 XSetLineAttributes (Display *dpy, GC gc, unsigned int line_width,
1621 int line_style, int cap_style, int join_style)
1623 XGCValues *gcv = VTBL->gc_gcv (gc);
1624 gcv->line_width = line_width;
1625 Assert (line_style == LineSolid, "only LineSolid implemented");
1626 // gc->gcv.line_style = line_style;
1627 gcv->cap_style = cap_style;
1628 gcv->join_style = join_style;
1633 XSetGraphicsExposures (Display *dpy, GC gc, Bool which)
1639 XSetFunction (Display *dpy, GC gc, int which)
1641 VTBL->gc_gcv (gc)->function = which;
1646 XSetSubwindowMode (Display *dpy, GC gc, int which)
1648 VTBL->gc_gcv (gc)->subwindow_mode = which;
1654 XQueryPointer (Display *dpy, Window w, Window *root_ret, Window *child_ret,
1655 int *root_x_ret, int *root_y_ret,
1656 int *win_x_ret, int *win_y_ret, unsigned int *mask_ret)
1658 assert_window (dpy, w);
1661 jwxyz_get_pos (w, &vpos, &p);
1663 if (root_x_ret) *root_x_ret = p.x;
1664 if (root_y_ret) *root_y_ret = p.y;
1665 if (win_x_ret) *win_x_ret = p.x - vpos.x;
1666 if (win_y_ret) *win_y_ret = p.y - vpos.y;
1667 if (mask_ret) *mask_ret = 0; // #### poll the keyboard modifiers?
1668 if (root_ret) *root_ret = 0;
1669 if (child_ret) *child_ret = 0;
1674 XTranslateCoordinates (Display *dpy, Window w, Window dest_w,
1675 int src_x, int src_y,
1676 int *dest_x_ret, int *dest_y_ret,
1679 assert_window (dpy, w);
1682 jwxyz_get_pos (w, &vpos, NULL);
1684 // point starts out relative to top left of view
1688 // get point relative to top left of screen
1701 XKeycodeToKeysym (Display *dpy, KeyCode code, int index)
1707 XLookupString (XKeyEvent *e, char *buf, int size, KeySym *k_ret,
1710 KeySym ks = XKeycodeToKeysym (0, e->keycode, 0);
1712 // Do not put non-ASCII KeySyms like XK_Shift_L and XK_Page_Up in the string.
1713 if ((unsigned int) ks <= 255)
1716 // Put control characters in the string. Not meta.
1717 if (e->state & ControlMask) {
1718 if (c >= 'a' && c <= 'z') // Upcase control.
1720 if (c >= '@' && c <= '_') // Shift to control page.
1722 if (c == ' ') // C-SPC is NULL.
1726 if (k_ret) *k_ret = ks;
1727 if (size > 0) buf[0] = c;
1728 if (size > 1) buf[1] = 0;
1729 return (size > 0 ? 1 : 0);
1734 XFlush (Display *dpy)
1736 // Just let the event loop take care of this on its own schedule.
1741 XSync (Display *dpy, Bool flush)
1743 return XFlush (dpy);
1747 // declared in utils/visual.h
1749 has_writable_cells (Screen *s, Visual *v)
1755 visual_depth (Screen *s, Visual *v)
1761 visual_cells (Screen *s, Visual *v)
1763 return (int)(v->rgba_masks[0] | v->rgba_masks[1] | v->rgba_masks[2]);
1767 visual_class (Screen *s, Visual *v)
1773 visual_rgb_masks (Screen *s, Visual *v, unsigned long *red_mask,
1774 unsigned long *green_mask, unsigned long *blue_mask)
1776 *red_mask = v->rgba_masks[0];
1777 *green_mask = v->rgba_masks[1];
1778 *blue_mask = v->rgba_masks[2];
1782 visual_pixmap_depth (Screen *s, Visual *v)
1788 screen_number (Screen *screen)
1793 // declared in utils/grabclient.h
1795 use_subwindow_mode_p (Screen *screen, Window window)
1800 #endif /* HAVE_JWXYZ */