+#undef EOF
+typedef enum { EOF=0,
+ LEFT, CENTER, RIGHT,
+ LEFT_FULL, CENTER_FULL, RIGHT_FULL,
+ COLOR, INVERT, MOVETO, MARGINS,
+ CURSOR_BLOCK, CURSOR_LINE, RECT, COPY, PIXMAP, IMG,
+ PAUSE, CHAR_DELAY, LINE_DELAY,
+ LOOP
+} bsod_event_type;
+
+struct bsod_event {
+ bsod_event_type type;
+ void *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
+};
+
+struct bsod_state {
+ Display *dpy;
+ Window window;
+ XWindowAttributes xgwa;
+ XFontStruct *font;
+ unsigned long fg, bg;
+ GC gc;
+ int left_margin, right_margin; /* for text wrapping */
+ int top_margin, bottom_margin; /* for text scrolling */
+ Bool wrap_p;
+ Bool scroll_p;
+
+ Pixmap pixmap; /* Source image used by BSOD_PIXMAP */
+
+ int x, y; /* current text-drawing position */
+ int current_left; /* don't use this */
+
+ int pos; /* position in queue */
+ int queue_size;
+ struct bsod_event *queue;
+
+ unsigned long char_delay; /* delay between printing characters */
+ unsigned long line_delay; /* delay between printing lines */
+
+ Bool macx_eol_kludge;
+
+ void *closure;
+ int (*draw_cb) (struct bsod_state *);
+ void (*free_cb) (struct bsod_state *);
+
+ async_load_state *img_loader;
+};
+
+
+# if !defined(__GNUC__) && !defined(__extension__)
+ /* don't warn about "string length is greater than the length ISO C89
+ compilers are required to support" in these string constants... */
+# define __extension__ /**/
+# endif
+
+
+/* Draw text at the current position; align is LEFT, CENTER, RIGHT, or *_FULL
+ (meaning to clear the whole line margin to margin).
+ */
+#define BSOD_TEXT(bst,align,string) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = (align); \
+ (bst)->queue[(bst)->pos].arg1 = (void *) strdup (__extension__ (string)); \
+ (bst)->queue[(bst)->pos].arg2 = (bst)->queue[(bst)->pos].arg1; \
+ (bst)->queue[(bst)->pos].arg3 = (void *) 0; \
+ (bst)->pos++; \
+ } while (0)
+
+/* Flip the foreground and background colors
+ */
+#define BSOD_INVERT(bst) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = INVERT; \
+ (bst)->pos++; \
+ } while (0)
+
+/* Set the foreground and background colors to the given pixels
+ */
+#define BSOD_COLOR(bst,fg,bg) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = COLOR; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) fg; \
+ (bst)->queue[(bst)->pos].arg2 = (void *) bg; \
+ (bst)->pos++; \
+ } while (0)
+
+/* Set the position of the next text.
+ Note that this is the baseline: lower left corner of next char printed.
+ */
+#define BSOD_MOVETO(bst,x,y) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = MOVETO; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (x)); \
+ (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (y)); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Delay for at least the given number of microseconds.
+ */
+#define BSOD_PAUSE(bst,usec) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = PAUSE; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (usec)); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Set the delay after each character is printed.
+ */
+#define BSOD_CHAR_DELAY(bst,usec) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = CHAR_DELAY; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (usec)); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Set the delay after each newline.
+ */
+#define BSOD_LINE_DELAY(bst,usec) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = LINE_DELAY; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) (usec); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Set the prevailing left/right margins (used when strings have
+ embedded newlines, and when centering or right-justifying text.)
+ */
+#define BSOD_MARGINS(bst,left,right) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = MARGINS; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (left)); \
+ (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (right)); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Draw a blinking cursor; type is CURSOR_BLOCK or CURSOR_LINE.
+ usec is how long 1/2 of a cycle is. count is how many times to blink.
+ (You can pass a gigantic number if this is the last thing in your mode.)
+ */
+#define BSOD_CURSOR(bst,ctype,usec,count) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = (ctype); \
+ (bst)->queue[(bst)->pos].arg1 = (void *) (usec); \
+ (bst)->queue[(bst)->pos].arg2 = (void *) (count); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Draw or fill a rectangle. You can set line-width in the GC.
+ */
+#define BSOD_RECT(bst,fill,x,y,w,h) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = RECT; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (fill)); \
+ (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (x)); \
+ (bst)->queue[(bst)->pos].arg3 = (void *) ((long) (y)); \
+ (bst)->queue[(bst)->pos].arg4 = (void *) ((long) (w)); \
+ (bst)->queue[(bst)->pos].arg5 = (void *) ((long) (h)); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Copy a rect from the window, to the window.
+ */
+#define BSOD_COPY(bst,srcx,srcy,w,h,tox,toy) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = COPY; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (srcx)); \
+ (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (srcy)); \
+ (bst)->queue[(bst)->pos].arg3 = (void *) ((long) (w)); \
+ (bst)->queue[(bst)->pos].arg4 = (void *) ((long) (h)); \
+ (bst)->queue[(bst)->pos].arg5 = (void *) ((long) (tox)); \
+ (bst)->queue[(bst)->pos].arg6 = (void *) ((long) (toy)); \
+ (bst)->pos++; \
+ } while (0)
+
+/* Copy a rect from bst->pixmap to the window.
+ */
+#define BSOD_PIXMAP(bst,srcx,srcy,w,h,tox,toy) do { \
+ BSOD_COPY(bst,srcx,srcy,w,h,tox,toy); \
+ (bst)->queue[(bst)->pos-1].type = PIXMAP; \
+ } while (0)
+
+/* Load a random image (or the desktop) onto the window.
+ */
+#define BSOD_IMG(bst) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = IMG; \
+ (bst)->pos++; \
+ } while (0)
+
+/* Jump around in the state table. You can use this as the last thing
+ in your state table to repeat the last N elements forever.
+ */
+#define BSOD_LOOP(bst,off) do { \
+ ensure_queue (bst); \
+ (bst)->queue[(bst)->pos].type = LOOP; \
+ (bst)->queue[(bst)->pos].arg1 = (void *) (off); \
+ (bst)->pos++; \
+ } while (0)
+
+
+static void
+ensure_queue (struct bsod_state *bst)