+struct jwxyz_XFontSet {
+ XFontStruct *font;
+};
+
+
+/* Instead of calling abort(), throw a real exception, so that
+ XScreenSaverView can catch it and display a dialog.
+ */
+void
+jwxyz_abort (const char *fmt, ...)
+{
+ char s[10240];
+ if (!fmt || !*fmt)
+ strcpy (s, "abort");
+ else
+ {
+ va_list args;
+ va_start (args, fmt);
+ vsprintf (s, fmt, args);
+ va_end (args);
+ }
+ [[NSException exceptionWithName: NSInternalInconsistencyException
+ reason: [NSString stringWithCString: s
+ encoding:NSUTF8StringEncoding]
+ userInfo: nil]
+ raise];
+ abort(); // not reached
+}
+
+// 24/32bpp -> 32bpp image conversion.
+// Any of RGBA, BGRA, ABGR, or ARGB can be represented by a rotate of 0/8/16/24
+// bits and an optional byte order swap.
+
+// This type encodes such a conversion.
+typedef unsigned convert_mode_t;
+
+// It's rotate, then swap.
+// A rotation here shifts bytes forward in memory. On x86/ARM, that's a left
+// rotate, and on PowerPC, a rightward rotation.
+static const convert_mode_t CONVERT_MODE_ROTATE_MASK = 0x3;
+static const convert_mode_t CONVERT_MODE_SWAP = 0x4;
+
+
+// Converts an array of pixels ('src') from one format to another, placing the
+// result in 'dest', according to the pixel conversion mode 'mode'.
+static void
+convert_row (uint32_t *dest, const void *src, size_t count,
+ convert_mode_t mode, size_t src_bpp)
+{
+ Assert (src_bpp == 24 || src_bpp == 32, "weird bpp");
+
+ // This works OK iff src == dest or src and dest do not overlap.
+
+ if (!mode) {
+ if (src != dest)
+ memcpy (dest, src, count * 4);
+ return;
+ }
+
+ // This is correct, but not fast.
+ convert_mode_t rot = (mode & CONVERT_MODE_ROTATE_MASK) * 8;
+ convert_mode_t flip = mode & CONVERT_MODE_SWAP;
+
+ src_bpp /= 8;
+
+ uint32_t *dest_end = dest + count;
+ while (dest != dest_end) {
+ uint32_t x;
+
+ if (src_bpp == 4)
+ x = *(const uint32_t *)src;
+ else { // src_bpp == 3
+ const uint8_t *src8 = (const uint8_t *)src;
+ // __LITTLE/BIG_ENDIAN__ are defined by the compiler.
+# if defined __LITTLE_ENDIAN__
+ x = src8[0] | (src8[1] << 8) | (src8[2] << 16) | 0xff000000;
+# elif defined __BIG_ENDIAN__
+ x = (src8[0] << 24) | (src8[1] << 16) | (src8[2] << 8) | 0xff;
+# else
+# error "Can't determine system endianness."
+# endif
+ }
+
+ src = (const uint8_t *)src + src_bpp;
+
+ /* The naive (i.e. ubiquitous) portable implementation of bitwise rotation,
+ for 32-bit integers, is:
+
+ (x << rot) | (x >> (32 - rot))
+
+ This works nearly everywhere. Compilers on x86 wil generally recognize
+ the idiom and convert it to a ROL instruction. But there's a problem
+ here: according to the C specification, bit shifts greater than or equal
+ to the length of the integer are undefined. And if rot = 0:
+ 1. (x << 0) | (x >> (32 - 0))
+ 2. (x << 0) | (x >> 32)
+ 3. (x << 0) | (Undefined!)
+
+ Still, when the compiler converts this to a ROL on x86, everything works
+ as intended. But, there are two additional problems when Clang does
+ compile-time constant expression evaluation with the (x >> 32)
+ expression:
+ 1. Instead of evaluating it to something reasonable (either 0, like a
+ human would intuitively expect, or x, like x86 would with SHR), Clang
+ seems to pull a value out of nowhere, like -1, or some other random
+ number.
+ 2. Clang's warning for this, -Wshift-count-overflow, only works when the
+ shift count is a literal constant, as opposed to an arbitrary
+ expression that is optimized down to a constant.
+ Put together, this means that the assertions in jwxyz_make_display with
+ convert_px break with the above naive rotation, but only for a release
+ build.
+
+ http://blog.regehr.org/archives/1063
+ http://llvm.org/bugs/show_bug.cgi?id=17332
+ As described in those links, there is a solution here: Masking the
+ undefined shift with '& 31' as below makes the experesion well-defined
+ again. And LLVM is set to pick up on this safe version of the idiom and
+ use a rotation instruction on architectures (like x86) that support it,
+ just like it does with the unsafe version.
+
+ Too bad LLVM doesn't want to pick up on that particular optimization
+ here. Oh well. At least this code usually isn't critical w.r.t.
+ performance.
+ */
+
+# if defined __LITTLE_ENDIAN__
+ x = (x << rot) | (x >> ((32 - rot) & 31));
+# elif defined __BIG_ENDIAN__
+ x = (x >> rot) | (x << ((32 - rot) & 31));
+# endif
+
+ if (flip)
+ x = __builtin_bswap32(x); // LLVM/GCC built-in function.
+
+ *dest = x;
+ ++dest;
+ }
+}
+
+
+// Converts a single pixel.
+static uint32_t
+convert_px (uint32_t px, convert_mode_t mode)
+{
+ convert_row (&px, &px, 1, mode, 32);
+ return px;
+}
+
+
+// This returns the inverse conversion mode, such that:
+// pixel
+// == convert_px(convert_px(pixel, mode), convert_mode_invert(mode))
+// == convert_px(convert_px(pixel, convert_mode_invert(mode)), mode)
+static convert_mode_t
+convert_mode_invert (convert_mode_t mode)
+{
+ // swap(0); rot(n) == rot(n); swap(0)
+ // swap(1); rot(n) == rot(-n); swap(1)
+ return mode & CONVERT_MODE_SWAP ? mode : CONVERT_MODE_ROTATE_MASK & -mode;
+}
+
+
+// This combines two conversions into one, such that:
+// convert_px(convert_px(pixel, mode0), mode1)
+// == convert_px(pixel, convert_mode_merge(mode0, mode1))
+static convert_mode_t
+convert_mode_merge (convert_mode_t m0, convert_mode_t m1)
+{
+ // rot(r0); swap(s0); rot(r1); swap(s1)
+ // rot(r0); rot(s0 ? -r1 : r1); swap(s0); swap(s1)
+ // rot(r0 + (s0 ? -r1 : r1)); swap(s0 + s1)
+ return
+ ((m0 + (m0 & CONVERT_MODE_SWAP ? -m1 : m1)) & CONVERT_MODE_ROTATE_MASK) |
+ ((m0 ^ m1) & CONVERT_MODE_SWAP);
+}
+
+
+// This returns a conversion mode that converts an arbitrary 32-bit format
+// specified by bitmap_info to RGBA.
+static convert_mode_t
+convert_mode_to_rgba (CGBitmapInfo bitmap_info)
+{
+ // Former default: kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little
+ // i.e. BGRA
+ // red = 0x00FF0000;
+ // green = 0x0000FF00;
+ // blue = 0x000000FF;
+
+ // RGBA: kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big
+
+ CGImageAlphaInfo alpha_info =
+ (CGImageAlphaInfo)(bitmap_info & kCGBitmapAlphaInfoMask);
+
+ Assert (! (bitmap_info & kCGBitmapFloatComponents),
+ "kCGBitmapFloatComponents unsupported");
+ Assert (alpha_info != kCGImageAlphaOnly, "kCGImageAlphaOnly not supported");
+
+ convert_mode_t rot = alpha_info == kCGImageAlphaFirst ||
+ alpha_info == kCGImageAlphaPremultipliedFirst ||
+ alpha_info == kCGImageAlphaNoneSkipFirst ?
+ 3 : 0;
+
+ CGBitmapInfo byte_order = bitmap_info & kCGBitmapByteOrderMask;
+
+ Assert (byte_order == kCGBitmapByteOrder32Little ||
+ byte_order == kCGBitmapByteOrder32Big,
+ "byte order not supported");
+
+ convert_mode_t swap = byte_order == kCGBitmapByteOrder32Little ?
+ CONVERT_MODE_SWAP : 0;
+ if (swap)
+ rot = CONVERT_MODE_ROTATE_MASK & -rot;
+ return swap | rot;
+}
+
+
+union color_bytes
+{
+ uint32_t pixel;
+ uint8_t bytes[4];
+};
+
+
+static uint32_t
+alloc_color (Display *dpy, uint16_t r, uint16_t g, uint16_t b, uint16_t a)
+{
+ union color_bytes color;
+
+ /* Instead of (int)(c / 256.0), another possibility is
+ (int)(c * 255.0 / 65535.0 + 0.5). This can be calculated using only
+ uint8_t integer_math(uint16_t c) {
+ unsigned c0 = c + 128;
+ return (c0 - (c0 >> 8)) >> 8;
+ }
+ */
+
+ color.bytes[0] = r >> 8;
+ color.bytes[1] = g >> 8;
+ color.bytes[2] = b >> 8;
+ color.bytes[3] = a >> 8;
+
+ return
+ convert_px (color.pixel,
+ convert_mode_invert (convert_mode_to_rgba (dpy->screen->bitmap_info)));
+}
+
+
+static void
+query_color (Display *dpy, unsigned long pixel, uint8_t *rgba)
+{
+ union color_bytes color;
+ color.pixel = convert_px ((uint32_t)pixel,
+ convert_mode_to_rgba (dpy->screen->bitmap_info));
+ for (unsigned i = 0; i != 4; ++i)
+ rgba[i] = color.bytes[i];
+}
+
+
+static void
+query_color_float (Display *dpy, unsigned long pixel, float *rgba)
+{
+ uint8_t rgba8[4];
+ query_color (dpy, pixel, rgba8);
+ for (unsigned i = 0; i != 4; ++i)
+ rgba[i] = rgba8[i] * (1.0f / 255.0f);
+}
+
+
+/* We keep a list of all of the Displays that have been created and not
+ yet freed so that they can have sensible display numbers. If three
+ displays are created (0, 1, 2) and then #1 is closed, then the fourth
+ display will be given the now-unused display number 1. (Everything in
+ here assumes a 1:1 Display/Screen mapping.)
+
+ The size of this array is the most number of live displays at one time.
+ So if it's 20, then we'll blow up if the system has 19 monitors and also
+ has System Preferences open (the small preview window).
+
+ Note that xlockmore-style savers tend to allocate big structures, so
+ setting this to 1000 will waste a few megabytes. Also some of them assume
+ that the number of screens never changes, so dynamically expanding this
+ array won't work.
+ */
+# ifndef USE_IPHONE
+static Display *jwxyz_live_displays[20] = { 0, };
+# endif
+