/* Magnetic poetry xscreensaver hack. Insert copyright notice. Written by Adam Sampson, largely copy-and-pasted from xjack. */ #include #include "screenhack.h" #define XPADDING 8 #define YPADDING 4 char *progclass = "Magnetic"; char *defaults [] = { ".background: white", ".foreground: black", "Magnetic.font: -*-times-medium-r-*-*-*-180-*-*-*-*-*-*", 0 }; XrmOptionDescRec options [] = { { 0, 0, 0, 0 } }; typedef struct tile { const char *text; int len; short twidth; short x; short y; short w; short h; int being_moved; } tile; GC gc; XWindowAttributes xgwa; XFontStruct *font; int font_ascent, font_descent; tile **tiles; int ntiles; void * evil_malloc (size_t size) { void *m = malloc (size); if (!m) { fprintf (stderr, "out of memory\n"); exit (1); } return m; } void draw_tile (Display *dpy, Window window, int i) { short x = tiles[i]->x, y = tiles[i]->y; short tw = tiles[i]->w - 1, th = tiles[i]->h - 1; XPoint pts[8]; pts[0].x = x; pts[0].y = y + th; pts[1].x = x; pts[1].y = y; pts[2].x = x + tw; pts[2].y = y; pts[3].x = x + tw; pts[3].y = y + th; pts[4].x = x; pts[4].y = y + th; pts[5].x = x + 1; pts[5].y = y + th + 1; pts[6].x = x + tw + 1; pts[6].y = y + th + 1; pts[7].x = x + tw + 1; pts[7].y = y + 1; XDrawLines (dpy, window, gc, pts, 8, CoordModeOrigin); XDrawString (dpy, window, gc, tiles[i]->x + XPADDING, tiles[i]->y + YPADDING + font_ascent + font_descent, tiles[i]->text, tiles[i]->len); } void draw_tiles (Display *dpy, Window window) { int i; XClearWindow (dpy, window); for (i = 0; i < ntiles; i++) { draw_tile (dpy, window, i); } XSync (dpy, False); } int collides (int al, int ar, int bl, int br, int fuzz) { al -= fuzz; ar += fuzz; bl -= fuzz; br += fuzz; return (al >= bl && al <= br) || (ar >= bl && ar <= br) || (al <= bl && ar >= br); } int collide (tile *a, tile *b) { return collides (a->x, a->x + a->w, b->x, b->x + b->w, 0) && collides (a->y, a->y + a->h, b->y, b->y + b->h, 0); } void move_tile_to_gap (int n) { int i, found_collisions; do { tiles[n]->x = random() % (xgwa.width - tiles[n]->w); tiles[n]->y = random() % (xgwa.height - tiles[n]->h); found_collisions = 0; for (i = 0; i < ntiles; i++) { if (i != n && collide (tiles[n], tiles[i])) found_collisions = 1; } } while (found_collisions); } void move_tile (Display *dpy, Window window, int n, short x, short y) { int i; draw_tile (dpy, window, n); tiles[n]->x = x; tiles[n]->y = y; for (i = 0; i < ntiles; i++) { if (i != n && collide (tiles[n], tiles[i])) { draw_tile (dpy, window, i); move_tile_to_gap (i); draw_tile (dpy, window, i); } } draw_tile (dpy, window, n); } void randomise_tiles (Display *dpy, Window window) { int i; XClearWindow (dpy, window); for (i = 0; i < ntiles; i++) move_tile_to_gap (i); draw_tiles (dpy, window); } int random_sign (int range) { if (range == 0) return 0; return (random() % (range * 2)) - range; } void yield (Display *dpy, int time) { usleep (time); screenhack_handle_events (dpy); } void screenhack (Display *dpy, Window window) { XGCValues gcv; char *tile_names = strdup ("they were married in the old churchyard and they promised to be true to each other no matter how hard their lives might be but like meteors that fell through moments parallel they were soon to cross and on different plots of earth they both did fall though their lives had really not been hard at all oh my what a shame no-one's to blame it just happened that way and there's nothing you can say when two people say goodbye" /*" two brothers promised they'd return when the war that they were fighting was over but only one lived to keep his vow and the story I was told said he lived to be quite old before time ran out someone asked if he knew what they'd both fought for but he could not recall he'd ever been to war"*/); char *fontname = get_string_resource ("font", "Font"); char *p; int i; int dir; XCharStruct cs; font = XLoadQueryFont (dpy, fontname); if (!font) { fprintf (stderr, "font \"%s\" not found\n", fontname); exit (1); } XTextExtents (font, "X", 1, &dir, &font_ascent, &font_descent, &cs); XGetWindowAttributes (dpy, window, &xgwa); gcv.function = GXinvert; gcv.line_width = 1; gcv.font = font->fid; gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, xgwa.colormap); gcv.background = get_pixel_resource ("background", "Background", dpy, xgwa.colormap); gc = XCreateGC (dpy, window, (GCFunction | GCLineWidth | GCFont | GCForeground | GCBackground), &gcv); ntiles = 0; for (p = tile_names; *p != '\0'; p++) { if (*p == ' ') { *p = '\0'; ntiles++; } } tiles = evil_malloc (ntiles * sizeof *tiles); p = tile_names; for (i = 0; i < ntiles; i++) { tiles[i] = evil_malloc (sizeof *tiles[i]); tiles[i]->text = p; tiles[i]->len = strlen (p); p += tiles[i]->len + 1; tiles[i]->w = XTextWidth (font, tiles[i]->text, tiles[i]->len) + 2 * XPADDING + 1; tiles[i]->h = font_ascent + 2 * font_descent + 2 * YPADDING + 1; } while (1) { int i, y = 0; for (i = 0; i < ntiles; i++) { int x; if (i == 0) { randomise_tiles (dpy, window); x = 20 + random_sign(20); y = 100 + random_sign(20); } else { x = tiles[i - 1]->x + tiles[i - 1]->w + 4 + random_sign(3); } if (x > (xgwa.width * 3) / 4) { x = 20 + random_sign(20); y += tiles[i]->h + 10; } move_tile (dpy, window, i, x, y + random_sign(3)); yield (dpy, 200000); } yield (dpy, 1000000); } }