+ gcv.foreground = mi->white;
+ gcv.background = mi->black;
+ mi->gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+
+ mi->fullrandom = True;
+
+ mi->pause = get_integer_resource (dpy, "delay", "Usecs");
+
+ mi->cycles = get_integer_resource (dpy, "cycles", "Int");
+ mi->batchcount = get_integer_resource (dpy, "count", "Int");
+ mi->size = get_integer_resource (dpy, "size", "Int");
+
+ mi->threed = get_boolean_resource (dpy, "use3d", "Boolean");
+ mi->threed_delta = get_float_resource (dpy, "delta3d", "Float");
+ mi->threed_right_color = get_pixel_resource (dpy,
+ mi->xgwa.colormap, "right3d", "Color");
+ mi->threed_left_color = get_pixel_resource (dpy,
+ mi->xgwa.colormap, "left3d", "Color");
+ mi->threed_both_color = get_pixel_resource (dpy,
+ mi->xgwa.colormap, "both3d", "Color");
+ mi->threed_none_color = get_pixel_resource (dpy,
+ mi->xgwa.colormap, "none3d", "Color");
+
+ mi->wireframe_p = get_boolean_resource (dpy, "wireframe", "Boolean");
+ mi->root_p = root_p;
+ mi->fps_p = get_boolean_resource (dpy, "doFPS", "DoFPS");
+ mi->recursion_depth = -1; /* see fps.c */
+
+ if (mi->pause < 0)
+ mi->pause = 0;
+ else if (mi->pause > 100000000)
+ mi->pause = 100000000;
+
+ /* If this hack uses fonts (meaning, mentioned "font" in DEFAULTS)
+ then load it. */
+ {
+ char *name = get_string_resource (dpy, "font", "Font");
+ if (name)
+ {
+ XFontStruct *f = XLoadQueryFont (dpy, name);
+ const char *def1 = "-*-helvetica-bold-r-normal-*-180-*";
+ const char *def2 = "fixed";
+ if (!f)
+ {
+ fprintf (stderr, "%s: font %s does not exist, using %s\n",
+ progname, name, def1);
+ f = XLoadQueryFont (dpy, def1);
+ }
+ if (!f)
+ {
+ fprintf (stderr, "%s: font %s does not exist, using %s\n",
+ progname, def1, def2);
+ f = XLoadQueryFont (dpy, def2);
+ }
+ if (f) XSetFont (dpy, mi->gc, f->fid);
+ if (f) XFreeFont (dpy, f);
+ free (name);
+ }
+ }
+
+ xlockmore_read_resources (mi);
+
+ return mi;
+}
+
+
+static void
+xlockmore_do_init (ModeInfo *mi)
+{
+ mi->xlmft->got_init |= 1 << mi->screen_number;
+ XClearWindow (mi->dpy, mi->window);
+ mi->xlmft->hack_init (mi);
+}
+
+
+static Bool
+xlockmore_got_init (ModeInfo *mi)
+{
+ return mi->xlmft->got_init & (1 << mi->screen_number);
+}
+
+
+static void
+xlockmore_abort_erase (ModeInfo *mi)
+{
+ if (mi->eraser) {
+ eraser_free (mi->eraser);
+ mi->eraser = NULL;
+ }
+ mi->needs_clear = False;
+}
+
+
+static void
+xlockmore_check_init (ModeInfo *mi)
+{
+ if (! xlockmore_got_init (mi)) {
+ xlockmore_abort_erase (mi);
+ xlockmore_do_init (mi);
+ }
+}
+
+
+static unsigned long
+xlockmore_draw (Display *dpy, Window window, void *closure)
+{
+ ModeInfo *mi = (ModeInfo *) closure;
+ unsigned long orig_pause = mi->pause;
+ unsigned long this_pause;
+
+ if (mi->needs_clear) {
+ /* OpenGL hacks never get here. */
+ if (!mi->is_drawn) {
+ XClearWindow (dpy, window);
+ } else {
+ mi->eraser = erase_window (dpy, window, mi->eraser);
+ /* Delay calls to xlockmore hooks while the erase animation is running. */
+ if (mi->eraser)
+ return 33333;
+ }
+ mi->needs_clear = False;
+ }
+
+ xlockmore_check_init (mi);
+ if (mi->needs_clear)
+ return 0;
+ mi->xlmft->hack_draw (mi);
+
+ this_pause = mi->pause;
+ mi->pause = orig_pause;
+ return mi->needs_clear ? 0 : this_pause;
+}
+
+
+static void
+xlockmore_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ ModeInfo *mi = (ModeInfo *) closure;
+ if (mi) {
+ /* Ignore spurious resize events, because xlockmore_do_init usually clears
+ the screen, and there's no reason to do that if we don't have to.
+ */
+# ifndef HAVE_MOBILE
+ /* These are not spurious on mobile: they are rotations. */
+ if (mi->xgwa.width == w && mi->xgwa.height == h)
+ return;
+# endif
+ mi->xgwa.width = w;
+ mi->xgwa.height = h;
+
+ /* Finish any erase operations. */
+ if (mi->needs_clear) {
+ xlockmore_abort_erase (mi);
+ XClearWindow (dpy, window);
+ }
+
+ /* If there hasn't been an init yet, init now, but don't call reshape_##.
+ */
+ if (xlockmore_got_init (mi) && mi->xlmft->hack_reshape) {
+ mi->xlmft->hack_reshape (mi, mi->xgwa.width, mi->xgwa.height);
+ } else {
+ mi->is_drawn = False;
+ xlockmore_do_init (mi);
+ }
+ }
+}
+
+static Bool
+xlockmore_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ ModeInfo *mi = (ModeInfo *) closure;
+ if (mi) {
+ if (mi->xlmft->hack_handle_events) {
+ xlockmore_check_init (mi);
+ return mi->xlmft->hack_handle_events (mi, event);
+ }
+
+ if (screenhack_event_helper (mi->dpy, mi->window, event)) {
+ /* If a clear is in progress, don't interrupt or restart it. */
+ if (mi->needs_clear)
+ mi->xlmft->got_init &= ~(1ul << mi->screen_number);
+ else
+ mi->xlmft->hack_init (mi);
+ return True;
+ }
+ }
+ return False;
+}
+
+void
+xlockmore_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
+{
+ ModeInfo *mi = (ModeInfo *) closure;
+ fps_compute (fpst, 0, mi ? mi->recursion_depth : -1);
+ fps_draw (fpst);
+}
+