+#define MI_IS_DRAWN(MI) ((MI)->is_drawn)
+#define MI_IS_FPS(MI) ((MI)->fps_p)
+#define MI_NCOLORS(MI) ((MI)->npixels)
+#define MI_NAME(MI) (progname)
+
+#define MI_COLORMAP(MI) (MI_WIN_COLORMAP((MI)))
+#define MI_WIDTH(MI) (MI_WIN_WIDTH((MI)))
+#define MI_HEIGHT(MI) (MI_WIN_HEIGHT((MI)))
+#define MI_IS_ICONIC(MI) (MI_WIN_IS_ICONIC((MI)))
+#define MI_IS_WIREFRAME(MI) (MI_WIN_IS_WIREFRAME((MI)))
+#define MI_IS_MONO(MI) (MI_WIN_IS_MONO((MI)))
+#define MI_COUNT(MI) (MI_BATCHCOUNT((MI)))
+#define MI_BLACK_PIXEL(MI) (MI_WIN_BLACK_PIXEL(MI))
+#define MI_WHITE_PIXEL(MI) (MI_WIN_WHITE_PIXEL(MI))
+#define MI_IS_FULLRANDOM(MI) (MI_WIN_IS_FULLRANDOM(MI))
+#define MI_IS_VERBOSE(MI) (MI_WIN_IS_VERBOSE(MI))
+#define MI_IS_INSTALL(MI) (MI_WIN_IS_INSTALL(MI))
+#define MI_IS_DEBUG(MI) (False)
+#define MI_IS_MOUSE(MI) (False)
+
+/* Under xlockmore, MI_CLEARWINDOW runs immediately, and for animated clears
+ it delays execution while the animation runs. This doesn't work on
+ XScreenSaver, which has mandatory double-buffering on macOS/iOS/Android.
+
+ Tricky: As a result, MI_CLEARWINDOW doesn't clear the window until after
+ init_##() or draw_##() finishes.
+ */
+#ifdef USE_GL
+# define MI_CLEARWINDOW(mi) XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi))
+#else
+# define MI_CLEARWINDOW(mi) ((mi)->needs_clear = True)
+#endif
+
+/* MI_INIT and MI_ABORT are XScreenSaver extensions. These exist primarily for
+ the sake of ports to macOS, iOS, and Android, all of which need to restart
+ individual screenhacks repeatedly in the same process. This requires
+ reusing MI_SCREEN() numbers; previously many xlockmore API hacks did not
+ support this the way they were supposed to.
+ */