summaryrefslogtreecommitdiffstats
path: root/hacks/fontglide.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/fontglide.c')
-rw-r--r--hacks/fontglide.c2582
1 files changed, 0 insertions, 2582 deletions
diff --git a/hacks/fontglide.c b/hacks/fontglide.c
deleted file mode 100644
index 3eff604..0000000
--- a/hacks/fontglide.c
+++ /dev/null
@@ -1,2582 +0,0 @@
-/* xscreensaver, Copyright (c) 2003-2017 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * fontglide -- reads text from a subprocess and puts it on the screen using
- * large characters that glide in from the edges, assemble, then disperse.
- * Requires a system with scalable fonts. (X's font handing sucks. A lot.)
- */
-
-/* If you turn on DEBUG, this program also masquerades as a tool for
- debugging font metrics issues, which is probably only if interest
- if you are doing active development on libjwxyz.a itself.
- */
-/* #define DEBUG */
-
-#include "screenhack.h"
-#include "textclient.h"
-#include "utf8wc.h"
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-#include "xdbe.h"
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-
-#include <math.h>
-#include <time.h>
-
-#ifndef HAVE_JWXYZ
-# include <X11/Intrinsic.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-typedef struct {
- char *text;
-
- int x, y; /* Position of origin of first character in word */
-
- /* These have the same meanings as in XCharStruct: */
- int lbearing; /* origin to leftmost pixel */
- int rbearing; /* origin to rightmost pixel */
- int ascent; /* origin to topmost pixel */
- int descent; /* origin to bottommost pixel */
- int width; /* origin to next word's origin */
-
- int nticks, tick;
- int start_x, start_y;
- int target_x, target_y;
- Pixmap pixmap, mask;
-} word;
-
-
-typedef struct {
- int id;
- Bool dark_p;
- Bool move_chars_p;
- int width;
-
- char *font_name;
- GC fg_gc;
- XftFont *xftfont;
- XftColor xftcolor_fg, xftcolor_bg;
-
- int nwords;
- word **words;
-
- enum { IN, PAUSE, OUT } anim_state;
- enum { LEFT, CENTER, RIGHT } alignment;
- int pause_tick;
-
-} sentence;
-
-
-typedef struct {
- Display *dpy;
- Window window;
- XWindowAttributes xgwa;
-
- Pixmap b, ba; /* double-buffer to reduce flicker */
- GC bg_gc;
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- XdbeBackBuffer backb;
- Bool dbeclear_p;
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-
- Bool dbuf; /* Whether we're using double buffering. */
-
- int border_width; /* size of the font outline */
- char *charset; /* registry and encoding for font lookups */
- double speed; /* frame rate multiplier */
- double linger; /* multiplier for how long to leave words on screen */
- Bool trails_p;
- enum { PAGE, SCROLL, CHARS } mode;
-
- char *font_override; /* if -font was specified on the cmd line */
-
- char buf [40]; /* this only needs to be as big as one "word". */
- int buf_tail;
- Bool early_p;
- time_t start_time;
-
- int nsentences;
- sentence **sentences;
- Bool spawn_p; /* whether it is time to create a new sentence */
- int latest_sentence;
- unsigned long frame_delay;
- int id_tick;
- text_data *tc;
-
-# ifdef DEBUG
- Bool debug_p;
- unsigned long debug_metrics_p;
- int debug_metrics_antialiasing_p;
- int debug_scale;
- unsigned entering_unicode_p; /* 0 = No, 1 = Just started, 2 = in progress */
- XFontStruct *metrics_font1;
- XFontStruct *metrics_font2;
- XftFont *metrics_xftfont;
- GC label_gc;
- char *prev_font_name;
- char *next_font_name;
-# endif /* DEBUG */
-
-} state;
-
-
-static void drain_input (state *s);
-
-
-static int
-pick_font_size (state *s)
-{
- double scale = s->xgwa.height / 1024.0; /* shrink for small windows */
- int min, max, r, pixel;
-
- min = scale * 24;
- max = scale * 260;
-
- if (min < 10) min = 10;
- if (max < 30) max = 30;
-
- r = ((max-min)/3)+1;
-
- pixel = min + ((random() % r) + (random() % r) + (random() % r));
-
- if (s->mode == SCROLL) /* scroll mode likes bigger fonts */
- pixel *= 1.5;
-
- return pixel;
-}
-
-
-#ifdef HAVE_JWXYZ
-
-static char *
-append_font_name(Display *dpy, char *dest, const XFontStruct *font)
-{
- int i;
- for (i = 0; i != font->n_properties; ++i) {
- if (font->properties[i].name == XA_FONT) {
- char *suffix = XGetAtomName (dpy, font->properties[i].card32);
- int L = strlen(suffix);
- strcpy(dest, suffix);
- free (suffix);
- return dest + L;
- }
- }
-
- dest[0] = '?';
- dest[1] = 0;
- return dest + 1;
-
-/*
- float s;
- const char *n = jwxyz_nativeFontName (font->fid, &s);
- return dest + sprintf (dest, "%s %.1f", n, s);
- */
-}
-
-#endif
-
-
-/* Finds the set of scalable fonts on the system; picks one;
- and loads that font in a random pixel size.
- Returns False if something went wrong.
- */
-static Bool
-pick_font_1 (state *s, sentence *se)
-{
- Bool ok = False;
- char pattern[1024];
- char pattern2[1024];
-
-# define _DONE_1 /**/
-# define _DONE_2 /**/
-# if defined(HAVE_XFT) && !defined(HAVE_JWXYZ) /* Real Xft under real X11 */
-# undef _DONE_1
-# undef _DONE_2
-# define _DONE_1 DONE_1:
-# define _DONE_2 DONE_2:
- if (s->font_override)
- {
- sprintf (pattern, "%.200s", s->font_override);
- ok = True;
- goto DONE_1;
- }
- else
- {
- unsigned long pixel = pick_font_size (s);
-
- /* https://keithp.com/~keithp/render/Xft.tutorial */
- XftFontSet *fs =
- XftListFonts (s->dpy, DefaultScreen (s->dpy),
- /* Pattern-triples to match, followed by a NULL */
- /* XFT_FAMILY, XftTypeString, "Helvetica", */
- /* XFT_SIZE, XftTypeDouble, 12.0, */
- NULL,
- /* Properties to return, followed by a second NULL */
- XFT_FAMILY,
- XFT_STYLE,
- XFT_SLANT,
- XFT_WEIGHT,
- XFT_SIZE,
- NULL);
- XftPattern *pat;
- char name1[1024], name2[1024], *s1, *s2;
- XftFont *font;
-
- if (!fs) abort();
- if (fs->nfont <= 0)
- {
- fprintf (stderr, "%s: unable to list fonts\n", progname);
- abort();
- }
- pat = fs->fonts[(random() % fs->nfont)];
- if (!pat) abort();
- if (! XftNameUnparse (pat, name1, sizeof(name1)-1))
- {
- /* I've seen this happen but rarely. Bogus font? */
- /* fprintf (stderr, "%s: unable to get font name\n", progname); */
- return False;
- }
-
- /* Convert "Helvetica:style=..." into "Helvetica-48:style=" */
- s1 = strchr (name1, ':');
- s2 = strchr (name1, '-');
- if (!s1) abort();
- if (!s2) s2 = s1;
- memcpy (name2, name1, s2 - name1);
- name2[s2 - name1] = 0;
- sprintf (name2 + strlen(name2), "-%ld:", pixel);
- strcat (name2, s2 + 1);
- font = XftFontOpenName (s->dpy, screen_number (s->xgwa.screen), name2);
-
- if (!font)
- {
- fprintf (stderr, "%s: unable to load Xft font \"%s\"\n",
- progname, name2);
- return False;
- }
-
- /* #### This gets a link error with FcFontSetDestroy missing. */
- /* if (fs) XftFontSetDestroy (fs); */
-
- se->xftfont = font;
- ok = True;
- goto DONE_2;
- }
-
-# elif !defined(HAVE_JWXYZ) /* No Xft but real Xlib */
-
- char **names = 0;
- char **names2 = 0;
- XFontStruct *info = 0;
- int count = 0, count2 = 0;
- int i;
-
- if (se->xftfont)
- {
- XftFontClose (s->dpy, se->xftfont);
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap,
- &se->xftcolor_fg);
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap,
- &se->xftcolor_bg);
-
- free (se->font_name);
- se->xftfont = 0;
- se->font_name = 0;
- }
-
- if (s->font_override)
- sprintf (pattern, "%.200s", s->font_override);
- else
- sprintf (pattern, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
- "*", /* foundry */
- "*", /* family */
- "*", /* weight */
- "*", /* slant */
- "*", /* swidth */
- "*", /* adstyle */
- "0", /* pixel size */
- "0", /* point size */
- "0", /* resolution x */
- "0", /* resolution y */
- "p", /* spacing */
- "0", /* avg width */
- s->charset); /* registry + encoding */
-
-
- names = XListFonts (s->dpy, pattern, 1000, &count);
-
- if (count <= 0)
- {
- if (s->font_override)
- fprintf (stderr, "%s: -font option bogus: %s\n", progname, pattern);
- else
- fprintf (stderr, "%s: no scalable fonts found! (pattern: %s)\n",
- progname, pattern);
- exit (1);
- }
-
- i = random() % count;
-
- names2 = XListFontsWithInfo (s->dpy, names[i], 1000, &count2, &info);
- if (count2 <= 0)
- {
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: pattern %s\n"
- " gave unusable %s\n\n",
- progname, pattern, names[i]);
-# endif /* DEBUG */
- goto FAIL;
- }
-
- {
- XFontStruct *font = &info[0];
- unsigned long value = 0;
- char *foundry=0, *family=0, *weight=0, *slant=0, *setwidth=0, *add_style=0;
- unsigned long pixel=0, point=0, res_x=0, res_y=0;
- char *spacing=0;
- unsigned long avg_width=0;
- char *registry=0, *encoding=0;
- Atom a;
- char *bogus = "\"?\"";
-
-# define STR(ATOM,VAR) \
- bogus = (ATOM); \
- a = XInternAtom (s->dpy, (ATOM), False); \
- if (XGetFontProperty (font, a, &value)) \
- VAR = XGetAtomName (s->dpy, value); \
- else \
- goto FAIL2
-
-# define INT(ATOM,VAR) \
- bogus = (ATOM); \
- a = XInternAtom (s->dpy, (ATOM), False); \
- if (!XGetFontProperty (font, a, &VAR) || \
- VAR > 9999) \
- goto FAIL2
-
- STR ("FOUNDRY", foundry);
- STR ("FAMILY_NAME", family);
- STR ("WEIGHT_NAME", weight);
- STR ("SLANT", slant);
- STR ("SETWIDTH_NAME", setwidth);
- STR ("ADD_STYLE_NAME", add_style);
- INT ("PIXEL_SIZE", pixel);
- INT ("POINT_SIZE", point);
- INT ("RESOLUTION_X", res_x);
- INT ("RESOLUTION_Y", res_y);
- STR ("SPACING", spacing);
- INT ("AVERAGE_WIDTH", avg_width);
- STR ("CHARSET_REGISTRY", registry);
- STR ("CHARSET_ENCODING", encoding);
-
-#undef INT
-#undef STR
-
- pixel = pick_font_size (s);
-
-#if 0
- /* Occasionally change the aspect ratio of the font, by increasing
- either the X or Y resolution (while leaving the other alone.)
-
- #### Looks like this trick doesn't really work that well: the
- metrics of the individual characters are ok, but the
- overall font ascent comes out wrong (unscaled.)
- */
- if (! (random() % 8))
- {
- double n = 2.5 / 3;
- double scale = 1 + (frand(n) + frand(n) + frand(n));
- if (random() % 2)
- res_x *= scale;
- else
- res_y *= scale;
- }
-# endif
-
- sprintf (pattern,
- "-%s-%s-%s-%s-%s-%s-%ld-%s-%ld-%ld-%s-%s-%s-%s",
- foundry, family, weight, slant, setwidth, add_style,
- pixel, "*", /* point, */
- res_x, res_y, spacing,
- "*", /* avg_width */
- registry, encoding);
- ok = True;
-
- FAIL2:
- if (!ok)
- fprintf (stderr, "%s: font has bogus %s property: %s\n",
- progname, bogus, names[i]);
-
- if (foundry) XFree (foundry);
- if (family) XFree (family);
- if (weight) XFree (weight);
- if (slant) XFree (slant);
- if (setwidth) XFree (setwidth);
- if (add_style) XFree (add_style);
- if (spacing) XFree (spacing);
- if (registry) XFree (registry);
- if (encoding) XFree (encoding);
- }
-
- FAIL:
-
- XFreeFontInfo (names2, info, count2);
- XFreeFontNames (names);
-
-# else /* HAVE_JWXYZ -- no Xft on macOS, iOS or Android */
-
- if (s->font_override)
- sprintf (pattern, "%.200s", s->font_override);
- else
- {
- const char *family = "random";
- const char *weight = ((random() % 2) ? "regular" : "bold");
- const char *slant = ((random() % 2) ? "o" : "r");
- int size = 10 * pick_font_size (s);
- sprintf (pattern, "*-%s-%s-%s-*-*-*-%d-*", family, weight, slant, size);
- }
- ok = True;
-# endif /* HAVE_JWXYZ */
-
- _DONE_1
-
- if (! ok) return False;
-
- se->xftfont = XftFontOpenXlfd (s->dpy, screen_number (s->xgwa.screen),
- pattern);
-
- _DONE_2
-
- if (! se->xftfont)
- {
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: unable to load font %s\n",
- progname, pattern);
-#endif
- return False;
- }
-
- strcpy (pattern2, pattern);
-# ifdef HAVE_JWXYZ
- {
- char *out = pattern2 + strlen(pattern2);
- out[0] = ' ';
- out[1] = '(';
- out = append_font_name (s->dpy, out + 2, se->xftfont->xfont);
- out[0] = ')';
- out[1] = 0;
- }
-# endif
-
-# ifdef DEBUG
- if (s->prev_font_name) free (s->prev_font_name);
- s->prev_font_name = s->next_font_name;
- s->next_font_name = strdup (pattern2);
-# endif
-
- /* Sometimes we get fonts with screwed up metrics. For example:
- -b&h-lucida-medium-r-normal-sans-40-289-100-100-p-0-iso8859-1
-
- When using XDrawString, XTextExtents and XTextExtents16, it is rendered
- as a scaled-up bitmap font. The character M has rbearing 70, ascent 68
- and width 78, which is correct for the glyph as rendered.
-
- But when using XftDrawStringUtf8 and XftTextExtentsUtf8, it is rendered
- at the original, smaller, un-scaled size, with rbearing 26, ascent 25
- and... width 77!
-
- So it's taking the *size* from the unscaled font, the *advancement* from
- the scaled-up version, and then *not* actually scaling it up. Awesome.
-
- So, after loading the font, measure the M, and if its advancement is more
- than 20% larger than its rbearing, reject the font.
-
- ------------------------------------------------------------------------
-
- Some observations on this nonsense from Dave Odell:
-
- 1. -*-lucidatypewriter-bold-r-normal-*-*-480-*-*-*-*-iso8859-1 normally
- resolves to /usr/share/fonts/X11/100dpi/lutBS24-ISO8859-1.pcf.gz.
-
- -*-lucidatypewriter-* is from the 'xfonts-100dpi' package in
- Debian/Ubuntu. It's usually (54.46% of systems), but not always,
- installed whenever an X.org server (57.96% of systems) is. It might
- be a good idea for this and xfonts-75dpi to be recommended
- dependencies of XScreenSaver in Debian, but that's neither here nor
- there. https://qa.debian.org/popcon.php?package=xorg
- https://qa.debian.org/popcon.php?package=xfonts-100dpi
-
- 2. It normally resolves to the PCF font... but not always.
-
- Fontconfig has /etc/fonts/conf.d/ (it's /opt/local/etc/fonts/conf.d/
- with MacPorts) containing symlinks to configuration files. And both
- Debian and Ubuntu normally has a 70-no-bitmaps.conf, installed as part
- of the 'fontconfig-config' package. And the 70-no-bitmaps.conf
- symlink... disables bitmap fonts.
-
- Without bitmap fonts, I get DejaVu Sans.
-
- 3. There's another symlink of interest here:
- /etc/fonts/conf.d/10-scale-bitmap-fonts.conf. This adds space to the
- right of glyphs of bitmap fonts when the requested size of the font is
- larger than the actual bitmap font. Ubuntu and MacPorts has this one.
-
- This specifically is causing text to have excessive character spacing.
-
- (jwz asks: WHY WOULD ANYONE EVER WANT THIS BEHAVIOR?)
-
- 4. Notice that I'm only talking about Debian and Ubuntu. Other distros
- will probably have different symlinks in /etc/fonts/conf.d/. So yes,
- this can be an issue on Linux as well as MacOS.
- */
- {
- XGlyphInfo extents;
- int rbearing, width;
- float ratio;
- float min = 0.8;
-
- XftTextExtentsUtf8 (s->dpy, se->xftfont, (FcChar8 *) "M", 1, &extents);
- rbearing = extents.width - extents.x;
- width = extents.xOff;
- ratio = rbearing / (float) width;
-
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: M ratio %.2f (%d %d): %s\n", progname,
- ratio, rbearing, width, pattern2);
-# endif
-
- if (ratio < min && !s->font_override)
- {
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: skipping font with broken metrics: %s\n",
- progname, pattern2);
-# endif
- return False;
- }
- }
-
-
-# ifdef DEBUG
- if (s->debug_p)
- fprintf(stderr, "%s: %s\n", progname, pattern2);
-# endif /* DEBUG */
-
- se->font_name = strdup (pattern);
- return True;
-}
-
-
-/* Finds the set of scalable fonts on the system; picks one;
- and loads that font in a random pixel size.
- */
-static void
-pick_font (state *s, sentence *se)
-{
- int i;
- for (i = 0; i < 50; i++)
- if (pick_font_1 (s, se))
- return;
- fprintf (stderr, "%s: too many font-loading failures: giving up!\n",
- progname);
- exit (1);
-}
-
-
-static char *unread_word_text = 0;
-
-/* Returns a newly-allocated string with one word in it, or NULL if there
- is no complete word available.
- */
-static char *
-get_word_text (state *s)
-{
- const char *start = s->buf;
- const char *end;
- char *result = 0;
- int lfs = 0;
-
- drain_input (s);
-
- /* If we just launched, and haven't had any text yet, and it has been
- more than 2 seconds since we launched, then push out "Loading..."
- as our first text. So if the text source is speedy, just use that.
- But if we'd display a blank screen for a while, give 'em something
- to see.
- */
- if (s->early_p &&
- !*s->buf &&
- !unread_word_text &&
- s->start_time < ((time ((time_t *) 0) - 2)))
- {
- unread_word_text = "Loading...";
- s->early_p = False;
- }
-
- if (unread_word_text)
- {
- result = unread_word_text;
- unread_word_text = 0;
- return strdup (result);
- }
-
- /* Skip over whitespace at the beginning of the buffer,
- and count up how many linebreaks we see while doing so.
- */
- while (*start &&
- (*start == ' ' ||
- *start == '\t' ||
- *start == '\r' ||
- *start == '\n'))
- {
- if (*start == '\n' || (*start == '\r' && start[1] != '\n'))
- lfs++;
- start++;
- }
-
- end = start;
-
- /* If we saw a blank line, then return NULL (treat it as a temporary "eof",
- to trigger a sentence break here.) */
- if (lfs >= 2)
- goto DONE;
-
- /* Skip forward to the end of this word (find next whitespace.) */
- while (*end &&
- (! (*end == ' ' ||
- *end == '\t' ||
- *end == '\r' ||
- *end == '\n')))
- end++;
-
- /* If we have a word, allocate a string for it */
- if (end > start)
- {
- result = malloc ((end - start) + 1);
- strncpy (result, start, (end-start));
- result [end-start] = 0;
- }
-
- DONE:
-
- /* Make room in the buffer by compressing out any bytes we've processed.
- */
- if (end > s->buf)
- {
- int n = end - s->buf;
- memmove (s->buf, end, sizeof(s->buf) - n);
- s->buf_tail -= n;
- }
-
- return result;
-}
-
-
-/* Returns a 1-bit pixmap of the same size as the drawable,
- with a 0 wherever the drawable is black.
- */
-static Pixmap
-make_mask (Screen *screen, Visual *visual, Drawable drawable)
-{
- Display *dpy = DisplayOfScreen (screen);
- unsigned long black = BlackPixelOfScreen (screen);
- Window r;
- int x, y;
- unsigned int w, h, bw, d;
- XImage *out, *in;
- Pixmap mask;
- GC gc;
-
- XGetGeometry (dpy, drawable, &r, &x, &y, &w, &h, &bw, &d);
- in = XGetImage (dpy, drawable, 0, 0, w, h, ~0L, ZPixmap);
- out = XCreateImage (dpy, visual, 1, XYPixmap, 0, 0, w, h, 8, 0);
- out->data = (char *) malloc (h * out->bytes_per_line);
- for (y = 0; y < h; y++)
- for (x = 0; x < w; x++)
- XPutPixel (out, x, y, (black != XGetPixel (in, x, y)));
- mask = XCreatePixmap (dpy, drawable, w, h, 1L);
- gc = XCreateGC (dpy, mask, 0, 0);
- XPutImage (dpy, mask, gc, out, 0, 0, 0, 0, w, h);
- XFreeGC (dpy, gc);
- free (in->data);
- free (out->data);
- in->data = out->data = 0;
- XDestroyImage (in);
- XDestroyImage (out);
- return mask;
-}
-
-
-/* Gets some random text, and creates a "word" object from it.
- */
-static word *
-new_word (state *s, sentence *se, const char *txt, Bool alloc_p)
-{
- word *w;
- XGlyphInfo extents;
- int bw = s->border_width;
-
- if (!txt)
- return 0;
-
- w = (word *) calloc (1, sizeof(*w));
- XftTextExtentsUtf8 (s->dpy, se->xftfont, (FcChar8 *) txt, strlen(txt),
- &extents);
-
- w->lbearing = -extents.x;
- w->rbearing = extents.width - extents.x;
- w->ascent = extents.y;
- w->descent = extents.height - extents.y;
- w->width = extents.xOff;
-
- w->lbearing -= bw;
- w->rbearing += bw;
- w->descent += bw;
- w->ascent += bw;
-
- if (s->mode == SCROLL && !alloc_p) abort();
-
- if (alloc_p)
- {
- int i, j;
- XGCValues gcv;
- GC gc_fg, gc_bg, gc_black;
- XftDraw *xftdraw;
- int width = w->rbearing - w->lbearing;
- int height = w->ascent + w->descent;
-
- if (width <= 0) width = 1;
- if (height <= 0) height = 1;
-
- w->pixmap = XCreatePixmap (s->dpy, s->b, width, height, s->xgwa.depth);
- xftdraw = XftDrawCreate (s->dpy, w->pixmap, s->xgwa.visual,
- s->xgwa.colormap);
-
- gcv.foreground = se->xftcolor_fg.pixel;
- gc_fg = XCreateGC (s->dpy, w->pixmap, GCForeground, &gcv);
-
- gcv.foreground = se->xftcolor_bg.pixel;
- gc_bg = XCreateGC (s->dpy, w->pixmap, GCForeground, &gcv);
-
- gcv.foreground = BlackPixelOfScreen (s->xgwa.screen);
- gc_black = XCreateGC (s->dpy, w->pixmap, GCForeground, &gcv);
-
- XFillRectangle (s->dpy, w->pixmap, gc_black, 0, 0, width, height);
-
-# ifdef DEBUG
- if (s->debug_p)
- {
- /* bounding box (behind the characters) */
- XDrawRectangle (s->dpy, w->pixmap, (se->dark_p ? gc_bg : gc_fg),
- 0, 0, width-1, height-1);
- }
-# endif /* DEBUG */
-
- /* Draw background text for border */
- for (i = -bw; i <= bw; i++)
- for (j = -bw; j <= bw; j++)
- XftDrawStringUtf8 (xftdraw, &se->xftcolor_bg, se->xftfont,
- -w->lbearing + i, w->ascent + j,
- (FcChar8 *) txt, strlen(txt));
-
- /* Draw foreground text */
- XftDrawStringUtf8 (xftdraw, &se->xftcolor_fg, se->xftfont,
- -w->lbearing, w->ascent,
- (FcChar8 *) txt, strlen(txt));
-
-# ifdef DEBUG
- if (s->debug_p)
- {
- if (w->ascent != height)
- {
- /* baseline (on top of the characters) */
- XDrawLine (s->dpy, w->pixmap, (se->dark_p ? gc_bg : gc_fg),
- 0, w->ascent, width-1, w->ascent);
- }
-
- if (w->lbearing < 0)
- {
- /* left edge of charcell */
- XDrawLine (s->dpy, w->pixmap, (se->dark_p ? gc_bg : gc_fg),
- -w->lbearing, 0,
- -w->lbearing, height-1);
- }
-
- if (w->rbearing != w->width)
- {
- /* right edge of charcell */
- XDrawLine (s->dpy, w->pixmap, (se->dark_p ? gc_bg : gc_fg),
- w->width - w->lbearing, 0,
- w->width - w->lbearing, height-1);
- }
- }
-# endif /* DEBUG */
-
- w->mask = make_mask (s->xgwa.screen, s->xgwa.visual, w->pixmap);
-
- XftDrawDestroy (xftdraw);
- XFreeGC (s->dpy, gc_fg);
- XFreeGC (s->dpy, gc_bg);
- XFreeGC (s->dpy, gc_black);
- }
-
- w->text = strdup (txt);
- return w;
-}
-
-
-static void
-free_word (state *s, word *w)
-{
- if (w->text) free (w->text);
- if (w->pixmap) XFreePixmap (s->dpy, w->pixmap);
- if (w->mask) XFreePixmap (s->dpy, w->mask);
- free (w);
-}
-
-
-static sentence *
-new_sentence (state *st, state *s)
-{
- XGCValues gcv;
- sentence *se = (sentence *) calloc (1, sizeof (*se));
- se->fg_gc = XCreateGC (s->dpy, s->b, 0, &gcv);
- se->anim_state = IN;
- se->id = ++st->id_tick;
- return se;
-}
-
-
-static void
-free_sentence (state *s, sentence *se)
-{
- int i;
- for (i = 0; i < se->nwords; i++)
- free_word (s, se->words[i]);
- if (se->words)
- free (se->words);
- if (se->font_name)
- free (se->font_name);
- if (se->fg_gc)
- XFreeGC (s->dpy, se->fg_gc);
-
- if (se->xftfont)
- {
- XftFontClose (s->dpy, se->xftfont);
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap,
- &se->xftcolor_fg);
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap,
- &se->xftcolor_bg);
- }
-
- free (se);
-}
-
-
-/* free the word, and put its text back at the front of the input queue,
- to be read next time. */
-static void
-unread_word (state *s, word *w)
-{
- if (unread_word_text)
- abort();
- unread_word_text = w->text;
- w->text = 0;
- free_word (s, w);
-}
-
-
-/* Divide each of the words in the sentence into one character words,
- without changing the positions of those characters.
- */
-static void
-split_words (state *s, sentence *se)
-{
- word **words2;
- int nwords2 = 0;
- int i, j;
-
- char ***word_chars = (char ***) malloc (se->nwords * sizeof(*word_chars));
- for (i = 0; i < se->nwords; i++)
- {
- int L;
- word *ow = se->words[i];
- word_chars[i] = utf8_split (ow->text, &L);
- nwords2 += L;
- }
-
- words2 = (word **) calloc (nwords2, sizeof(*words2));
-
- for (i = 0, j = 0; i < se->nwords; i++)
- {
- char **chars = word_chars[i];
- word *parent = se->words[i];
- int x = parent->x;
- int y = parent->y;
- int sx = parent->start_x;
- int sy = parent->start_y;
- int tx = parent->target_x;
- int ty = parent->target_y;
- int k;
-
- for (k = 0; chars[k]; k++)
- {
- char *t2 = chars[k];
- word *w2 = new_word (s, se, t2, True);
- words2[j++] = w2;
- free (t2);
-
- w2->x = x;
- w2->y = y;
- w2->start_x = sx;
- w2->start_y = sy;
- w2->target_x = tx;
- w2->target_y = ty;
-
- x += w2->width;
- sx += w2->width;
- tx += w2->width;
- }
-
- /* This is not invariant when kerning is involved! */
- /* if (x != parent->x + parent->width) abort(); */
-
- free (chars); /* but we retain its contents */
- free_word (s, parent);
- }
- if (j != nwords2) abort();
- free (word_chars);
- free (se->words);
-
- se->words = words2;
- se->nwords = nwords2;
-}
-
-
-/* Set the source or destination position of the words to be somewhere
- off screen.
- */
-static void
-scatter_sentence (state *s, sentence *se)
-{
- int i = 0;
- int off = s->border_width * 4 + 2;
-
- int flock_p = ((random() % 4) == 0);
- int mode = (flock_p ? (random() % 12) : 0);
-
- for (i = 0; i < se->nwords; i++)
- {
- word *w = se->words[i];
- int x, y;
- int r = (flock_p ? mode : (random() % 4));
- int left = -(off + w->rbearing);
- int top = -(off + w->descent);
- int right = off - w->lbearing + s->xgwa.width;
- int bottom = off + w->ascent + s->xgwa.height;
-
- switch (r) {
- /* random positions on the edges */
- case 0: x = left; y = random() % s->xgwa.height; break;
- case 1: x = right; y = random() % s->xgwa.height; break;
- case 2: x = random() % s->xgwa.width; y = top; break;
- case 3: x = random() % s->xgwa.width; y = bottom; break;
-
- /* straight towards the edges */
- case 4: x = left; y = w->target_y; break;
- case 5: x = right; y = w->target_y; break;
- case 6: x = w->target_x; y = top; break;
- case 7: x = w->target_x; y = bottom; break;
-
- /* corners */
- case 8: x = left; y = top; break;
- case 9: x = left; y = bottom; break;
- case 10: x = right; y = top; break;
- case 11: x = right; y = bottom; break;
-
- default: abort(); break;
- }
-
- if (se->anim_state == IN)
- {
- w->start_x = x;
- w->start_y = y;
- }
- else
- {
- w->start_x = w->x;
- w->start_y = w->y;
- w->target_x = x;
- w->target_y = y;
- }
-
- w->nticks = ((100 + ((random() % 140) +
- (random() % 140) +
- (random() % 140)))
- / s->speed);
- if (w->nticks < 2)
- w->nticks = 2;
- w->tick = 0;
- }
-}
-
-
-/* Set the source position of the words to be off the right side,
- and the destination to be off the left side.
- */
-static void
-aim_sentence (state *s, sentence *se)
-{
- int i = 0;
- int nticks;
- int yoff = 0;
-
- if (se->nwords <= 0) abort();
-
- /* Have the sentence shift up or down a little bit; not too far, and
- never let it fall off the top or bottom of the screen before its
- last character has reached the left edge.
- */
- for (i = 0; i < 10; i++)
- {
- int ty = random() % (s->xgwa.height - se->words[0]->ascent);
- yoff = ty - se->words[0]->target_y;
- if (yoff < s->xgwa.height/3) /* this one is ok */
- break;
- }
-
- for (i = 0; i < se->nwords; i++)
- {
- word *w = se->words[i];
- w->start_x = w->target_x + s->xgwa.width;
- w->target_x -= se->width;
- w->start_y = w->target_y;
- w->target_y += yoff;
- }
-
- nticks = ((se->words[0]->start_x - se->words[0]->target_x)
- / (s->speed * 7));
- nticks *= (frand(0.9) + frand(0.9) + frand(0.9));
-
- if (nticks < 2)
- nticks = 2;
-
- for (i = 0; i < se->nwords; i++)
- {
- word *w = se->words[i];
- w->nticks = nticks;
- w->tick = 0;
- }
-}
-
-
-/* Randomize the order of the words in the list (since that changes
- which ones are "on top".)
- */
-static void
-shuffle_words (state *s, sentence *se)
-{
- int i;
- for (i = 0; i < se->nwords-1; i++)
- {
- int j = i + (random() % (se->nwords - i));
- word *swap = se->words[i];
- se->words[i] = se->words[j];
- se->words[j] = swap;
- }
-}
-
-
-/* qsort comparitor */
-static int
-cmp_sentences (const void *aa, const void *bb)
-{
- const sentence *a = *(sentence **) aa;
- const sentence *b = *(sentence **) bb;
- return ((a ? a->id : 999999) - (b ? b->id : 999999));
-}
-
-
-/* Sort the sentences by id, so that sentences added later are on top.
- */
-static void
-sort_sentences (state *s)
-{
- qsort (s->sentences, s->nsentences, sizeof(*s->sentences), cmp_sentences);
-}
-
-
-/* Re-pick the colors of the text and border
- */
-static void
-recolor (state *s, sentence *se)
-{
- XRenderColor fg, bg;
-
- fg.red = (random() % 0x5555) + 0xAAAA;
- fg.green = (random() % 0x5555) + 0xAAAA;
- fg.blue = (random() % 0x5555) + 0xAAAA;
- fg.alpha = 0xFFFF;
- bg.red = (random() % 0x5555);
- bg.green = (random() % 0x5555);
- bg.blue = (random() % 0x5555);
- bg.alpha = 0xFFFF;
- se->dark_p = False;
-
- if (random() & 1)
- {
- XRenderColor swap = fg; fg = bg; bg = swap;
- se->dark_p = True;
- }
-
- if (se->xftfont)
- {
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap,
- &se->xftcolor_fg);
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap,
- &se->xftcolor_bg);
- }
-
- XftColorAllocValue (s->dpy, s->xgwa.visual, s->xgwa.colormap, &fg,
- &se->xftcolor_fg);
- XftColorAllocValue (s->dpy, s->xgwa.visual, s->xgwa.colormap, &bg,
- &se->xftcolor_bg);
-}
-
-
-static void
-align_line (state *s, sentence *se, int line_start, int x, int right)
-{
- int off, j;
- switch (se->alignment)
- {
- case LEFT: off = 0; break;
- case CENTER: off = (right - x) / 2; break;
- case RIGHT: off = (right - x); break;
- default: abort(); break;
- }
-
- if (off != 0)
- for (j = line_start; j < se->nwords; j++)
- se->words[j]->target_x += off;
-}
-
-
-/* Fill the sentence with new words: in "page" mode, fills the page
- with text; in "scroll" mode, just makes one long horizontal sentence.
- The sentence might have *no* words in it, if no text is currently
- available.
- */
-static void
-populate_sentence (state *s, sentence *se)
-{
- int i = 0;
- int left, right, top, x, y;
- int space = 0;
- int line_start = 0;
- Bool done = False;
-
- int array_size = 100;
-
- se->move_chars_p = (s->mode == CHARS ? True :
- s->mode == SCROLL ? False :
- (random() % 3) ? False : True);
- se->alignment = (random() % 3);
-
- recolor (s, se);
-
- if (se->words)
- {
- for (i = 0; i < se->nwords; i++)
- free_word (s, se->words[i]);
- free (se->words);
- }
-
- se->words = (word **) calloc (array_size, sizeof(*se->words));
- se->nwords = 0;
-
- switch (s->mode)
- {
- case PAGE:
- case CHARS:
- left = random() % (s->xgwa.width / 3);
- right = s->xgwa.width - (random() % (s->xgwa.width / 3));
- top = random() % (s->xgwa.height * 2 / 3);
- break;
- case SCROLL:
- left = 0;
- right = s->xgwa.width;
- top = random() % s->xgwa.height;
- break;
- default:
- abort();
- break;
- }
-
- x = left;
- y = top;
-
- while (!done)
- {
- char *txt = get_word_text (s);
- word *w;
- if (!txt)
- {
- if (se->nwords == 0)
- return; /* If the stream is empty, bail. */
- else
- break; /* If EOF after some words, end of sentence. */
- }
-
- if (! se->xftfont) /* Got a word: need a font now */
- {
- XGlyphInfo extents;
- pick_font (s, se);
- if (y < se->xftfont->ascent)
- y += se->xftfont->ascent;
-
- /* Measure the space character to figure out how much room to
- leave between words (since we don't actually render that.) */
- XftTextExtentsUtf8 (s->dpy, se->xftfont, (FcChar8 *) " ", 1,
- &extents);
- space = extents.xOff;
- }
-
- w = new_word (s, se, txt, !se->move_chars_p);
- free (txt);
- txt = 0;
-
- /* If we have a few words, let punctuation terminate the sentence:
- stop gathering more words if the last word ends in a period, etc. */
- if (se->nwords >= 4)
- {
- char c = w->text[strlen(w->text)-1];
- if (c == '.' || c == '?' || c == '!')
- done = True;
- }
-
- /* If the sentence is kind of long already, terminate at commas, etc. */
- if (se->nwords >= 12)
- {
- char c = w->text[strlen(w->text)-1];
- if (c == ',' || c == ';' || c == ':' || c == '-' ||
- c == ')' || c == ']' || c == '}')
- done = True;
- }
-
- if (se->nwords >= 25) /* ok that's just about enough out of you */
- done = True;
-
- if ((s->mode == PAGE || s->mode == CHARS) &&
- x + w->rbearing > right) /* wrap line */
- {
- align_line (s, se, line_start, x, right);
- line_start = se->nwords;
-
- x = left;
- y += se->xftfont->ascent + se->xftfont->descent;
-
- /* If we're close to the bottom of the screen, stop, and
- unread the current word. (But not if this is the first
- word, otherwise we might just get stuck on it.)
- */
- if (se->nwords > 0 &&
- y + se->xftfont->ascent + se->xftfont->descent > s->xgwa.height)
- {
- unread_word (s, w);
- w = 0;
- /* done = True; */
- break;
- }
- }
-
- w->target_x = x;
- w->target_y = y;
-
- x += w->width + space;
- se->width = x;
-
- if (se->nwords >= (array_size - 1))
- {
- array_size += 100;
- se->words = (word **)
- realloc (se->words, array_size * sizeof(*se->words));
- if (!se->words)
- {
- fprintf (stderr, "%s: out of memory (%d words)\n",
- progname, array_size);
- exit (1);
- }
- }
-
- se->words[se->nwords++] = w;
- }
-
- se->width -= space;
-
- switch (s->mode)
- {
- case PAGE:
- case CHARS:
- align_line (s, se, line_start, x, right);
- if (se->move_chars_p)
- split_words (s, se);
- scatter_sentence (s, se);
- shuffle_words (s, se);
- break;
- case SCROLL:
- aim_sentence (s, se);
- break;
- default:
- abort();
- break;
- }
-
-# ifdef DEBUG
- if (s->debug_p)
- {
- fprintf (stderr, "%s: sentence %d:", progname, se->id);
- for (i = 0; i < se->nwords; i++)
- fprintf (stderr, " %s", se->words[i]->text);
- fprintf (stderr, "\n");
- }
-# endif /* DEBUG */
-}
-
-
-/* Render a single word object to the screen.
- */
-static void
-draw_word (state *s, sentence *se, word *word)
-{
- int x, y, w, h;
- if (! word->pixmap) return;
-
- x = word->x + word->lbearing;
- y = word->y - word->ascent;
- w = word->rbearing - word->lbearing;
- h = word->ascent + word->descent;
-
- if (x + w < 0 ||
- y + h < 0 ||
- x > s->xgwa.width ||
- y > s->xgwa.height)
- return;
-
- XSetClipMask (s->dpy, se->fg_gc, word->mask);
- XSetClipOrigin (s->dpy, se->fg_gc, x, y);
- XCopyArea (s->dpy, word->pixmap, s->b, se->fg_gc,
- 0, 0, w, h, x, y);
-}
-
-
-/* If there is room for more sentences, add one.
- */
-static void
-more_sentences (state *s)
-{
- int i;
- Bool any = False;
- for (i = 0; i < s->nsentences; i++)
- {
- sentence *se = s->sentences[i];
- if (! se)
- {
- se = new_sentence (s, s);
- populate_sentence (s, se);
- if (se->nwords > 0)
- s->spawn_p = False, any = True;
- else
- {
- free_sentence (s, se);
- se = 0;
- }
- s->sentences[i] = se;
- if (se)
- s->latest_sentence = se->id;
- break;
- }
- }
-
- if (any) sort_sentences (s);
-}
-
-
-/* Render all the words to the screen, and run the animation one step.
- */
-static void
-draw_sentence (state *s, sentence *se)
-{
- int i;
- Bool moved = False;
-
- if (! se) return;
-
- for (i = 0; i < se->nwords; i++)
- {
- word *w = se->words[i];
-
- switch (s->mode)
- {
- case PAGE:
- case CHARS:
- if (se->anim_state != PAUSE &&
- w->tick <= w->nticks)
- {
- int dx = w->target_x - w->start_x;
- int dy = w->target_y - w->start_y;
- double r = sin (w->tick * M_PI / (2 * w->nticks));
- w->x = w->start_x + (dx * r);
- w->y = w->start_y + (dy * r);
-
- w->tick++;
- if (se->anim_state == OUT &&
- (s->mode == PAGE || s->mode == CHARS))
- w->tick++; /* go out faster */
- moved = True;
- }
- break;
- case SCROLL:
- {
- int dx = w->target_x - w->start_x;
- int dy = w->target_y - w->start_y;
- double r = (double) w->tick / w->nticks;
- w->x = w->start_x + (dx * r);
- w->y = w->start_y + (dy * r);
- w->tick++;
- moved = (w->tick <= w->nticks);
-
- /* Launch a new sentence when:
- - the front of this sentence is almost off the left edge;
- - the end of this sentence is almost on screen.
- - or, randomly
- */
- if (se->anim_state != OUT &&
- i == 0 &&
- se->id == s->latest_sentence)
- {
- Bool new_p = (w->x < (s->xgwa.width * 0.4) &&
- w->x + se->width < (s->xgwa.width * 2.1));
- Bool rand_p = (new_p ? 0 : !(random() % 2000));
-
- if (new_p || rand_p)
- {
- se->anim_state = OUT;
- s->spawn_p = True;
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: OUT %d (x2 = %d%s)\n",
- progname, se->id,
- se->words[0]->x + se->width,
- rand_p ? " randomly" : "");
-# endif /* DEBUG */
- }
- }
- }
- break;
- default:
- abort();
- break;
- }
-
- draw_word (s, se, w);
- }
-
- if (moved && se->anim_state == PAUSE)
- abort();
-
- if (! moved)
- {
- switch (se->anim_state)
- {
- case IN:
- se->anim_state = PAUSE;
- se->pause_tick = (se->nwords * 7 * s->linger);
- if (se->move_chars_p)
- se->pause_tick /= 5;
- scatter_sentence (s, se);
- shuffle_words (s, se);
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: PAUSE %d\n", progname, se->id);
-# endif /* DEBUG */
- break;
- case PAUSE:
- if (--se->pause_tick <= 0)
- {
- se->anim_state = OUT;
- s->spawn_p = True;
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: OUT %d\n", progname, se->id);
-# endif /* DEBUG */
- }
- break;
- case OUT:
-# ifdef DEBUG
- if (s->debug_p)
- fprintf (stderr, "%s: DEAD %d\n", progname, se->id);
-# endif /* DEBUG */
- {
- int j;
- for (j = 0; j < s->nsentences; j++)
- if (s->sentences[j] == se)
- s->sentences[j] = 0;
- free_sentence (s, se);
- }
- break;
- default:
- abort();
- break;
- }
- }
-}
-
-
-#ifdef DEBUG /* All of this stuff is for -debug-metrics mode. */
-
-
-static Pixmap
-scale_ximage (Screen *screen, Window window, XImage *img, int scale,
- int margin)
-{
- Display *dpy = DisplayOfScreen (screen);
- int x, y;
- unsigned width = img->width, height = img->height;
- Pixmap p2;
- GC gc;
-
- p2 = XCreatePixmap (dpy, window, width*scale, height*scale, img->depth);
- gc = XCreateGC (dpy, p2, 0, 0);
-
- XSetForeground (dpy, gc, BlackPixelOfScreen (screen));
- XFillRectangle (dpy, p2, gc, 0, 0, width*scale, height*scale);
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- {
- XSetForeground (dpy, gc, XGetPixel (img, x, y));
- XFillRectangle (dpy, p2, gc, x*scale, y*scale, scale, scale);
- }
-
- if (scale > 2)
- {
- XWindowAttributes xgwa;
- XColor c;
- c.red = c.green = c.blue = 0x4444;
- c.flags = DoRed|DoGreen|DoBlue;
- XGetWindowAttributes (dpy, window, &xgwa);
- if (! XAllocColor (dpy, xgwa.colormap, &c)) abort();
- XSetForeground (dpy, gc, c.pixel);
- XDrawRectangle (dpy, p2, gc, 0, 0, width*scale-1, height*scale-1);
- XDrawRectangle (dpy, p2, gc, margin*scale, margin*scale,
- width*scale-1, height*scale-1);
- for (y = 0; y <= height - 2*margin; y++)
- XDrawLine (dpy, p2, gc,
- margin*scale, (y+margin)*scale-1,
- (width-margin)*scale, (y+margin)*scale-1);
- for (x = 0; x <= width - 2*margin; x++)
- XDrawLine (dpy, p2, gc,
- (x+margin)*scale-1, margin*scale,
- (x+margin)*scale-1, (height-margin)*scale);
- XFreeColors (dpy, xgwa.colormap, &c.pixel, 1, 0);
- }
-
- XFreeGC (dpy, gc);
- return p2;
-}
-
-
-static int check_edge (Display *dpy, Drawable p, GC gc,
- unsigned msg_x, unsigned msg_y, const char *msg,
- XImage *img,
- unsigned x, unsigned y, unsigned dim, unsigned end)
-{
- unsigned pt[2];
- pt[0] = x;
- pt[1] = y;
- end += pt[dim];
-
- for (;;)
- {
- if (pt[dim] == end)
- {
- XDrawString (dpy, p, gc, msg_x, msg_y, msg, strlen (msg));
- return 1;
- }
-
- if (XGetPixel(img, pt[0], pt[1]) & 0xffffff)
- break;
-
- ++pt[dim];
- }
-
- return 0;
-}
-
-
-static unsigned long
-fontglide_draw_metrics (state *s)
-{
- unsigned int margin = (s->debug_metrics_antialiasing_p ? 2 : 0);
-
- char txt[2], utxt[3], txt2[80];
- XChar2b *txt3 = 0;
- const char *fn = (s->font_override ? s->font_override : "fixed");
- char fn2[1024];
- XCharStruct c, overall, fake_c;
- int dir, ascent, descent;
- int x, y;
- XGlyphInfo extents;
- XftColor xftcolor;
- XftDraw *xftdraw;
- int sc = s->debug_scale;
- GC gc;
- unsigned long red = 0xFFFF0000; /* so shoot me */
- unsigned long green = 0xFF00FF00;
- unsigned long blue = 0xFF6666FF;
- unsigned long yellow = 0xFFFFFF00;
- unsigned long cyan = 0xFF004040;
- int i, j;
- Drawable dest = s->b ? s->b : s->window;
-
- if (sc < 1) sc = 1;
-
- /* Self-test these macros to make sure they're symmetrical. */
- for (i = 0; i < 1000; i++)
- {
- XGlyphInfo g, g2;
- XRectangle r;
- c.lbearing = (random()%50)-100;
- c.rbearing = (random()%50)-100;
- c.ascent = (random()%50)-100;
- c.descent = (random()%50)-100;
- c.width = (random()%50)-100;
- XCharStruct_to_XGlyphInfo (c, g);
- XGlyphInfo_to_XCharStruct (g, overall);
- if (c.lbearing != overall.lbearing) abort();
- if (c.rbearing != overall.rbearing) abort();
- if (c.ascent != overall.ascent) abort();
- if (c.descent != overall.descent) abort();
- if (c.width != overall.width) abort();
- XCharStruct_to_XGlyphInfo (overall, g2);
- if (g.x != g2.x) abort();
- if (g.y != g2.y) abort();
- if (g.xOff != g2.xOff) abort();
- if (g.yOff != g2.yOff) abort();
- if (g.width != g2.width) abort();
- if (g.height != g2.height) abort();
- XCharStruct_to_XmbRectangle (overall, r);
- XmbRectangle_to_XCharStruct (r, c, c.width);
- if (c.lbearing != overall.lbearing) abort();
- if (c.rbearing != overall.rbearing) abort();
- if (c.ascent != overall.ascent) abort();
- if (c.descent != overall.descent) abort();
- if (c.width != overall.width) abort();
- }
-
- txt[0] = s->debug_metrics_p;
- txt[1] = 0;
-
- /* Convert Unicode code point to UTF-8. */
- utxt[utf8_encode(s->debug_metrics_p, utxt, 4)] = 0;
-
- txt3 = utf8_to_XChar2b (utxt, 0);
-
- if (! s->metrics_font1)
- s->metrics_font1 = XLoadQueryFont (s->dpy, fn);
- if (! s->metrics_font2)
- s->metrics_font2 = XLoadQueryFont (s->dpy, "fixed");
- if (! s->metrics_font1)
- s->metrics_font1 = s->metrics_font2;
-
- gc = XCreateGC (s->dpy, dest, 0, 0);
- XSetFont (s->dpy, gc, s->metrics_font1->fid);
-
-# if defined(HAVE_JWXYZ)
- jwxyz_XSetAntiAliasing (s->dpy, gc, False);
-# endif
-
- if (! s->metrics_xftfont)
- {
- s->metrics_xftfont =
- load_xft_font_retry (s->dpy, screen_number(s->xgwa.screen), fn);
- if (! s->metrics_xftfont)
- {
- const char *fn2 = "fixed";
- s->metrics_xftfont =
- load_xft_font_retry (s->dpy, screen_number(s->xgwa.screen), fn2);
- if (s->metrics_xftfont)
- fn = fn2;
- else
- {
- fprintf (stderr, "%s: XftFontOpen failed on \"%s\" and \"%s\"\n",
- progname, fn, fn2);
- exit (1);
- }
- }
- }
-
- strcpy (fn2, fn);
-# ifdef HAVE_JWXYZ
- append_font_name (s->dpy, fn2, s->metrics_xftfont->xfont);
-# endif
-
- xftdraw = XftDrawCreate (s->dpy, dest, s->xgwa.visual,
- s->xgwa.colormap);
- XftColorAllocName (s->dpy, s->xgwa.visual, s->xgwa.colormap, "white",
- &xftcolor);
- XftTextExtentsUtf8 (s->dpy, s->metrics_xftfont,
- (FcChar8 *) utxt, strlen(utxt),
- &extents);
-
-
- XTextExtents (s->metrics_font1, txt, strlen(txt),
- &dir, &ascent, &descent, &overall);
- c = ((s->debug_metrics_p >= s->metrics_font1->min_char_or_byte2 &&
- s->debug_metrics_p <= s->metrics_font1->max_char_or_byte2)
- ? s->metrics_font1->per_char[s->debug_metrics_p -
- s->metrics_font1->min_char_or_byte2]
- : overall);
-
- XSetForeground (s->dpy, gc, BlackPixelOfScreen (s->xgwa.screen));
- XFillRectangle (s->dpy, dest, gc, 0, 0, s->xgwa.width, s->xgwa.height);
-
- XSetForeground (s->dpy, gc, WhitePixelOfScreen (s->xgwa.screen));
- XSetFont (s->dpy, gc, s->metrics_font2->fid);
- XDrawString (s->dpy, dest, gc,
- s->xgwa.width / 2,
- s->xgwa.height - 5,
- fn2, strlen(fn2));
-
-# ifdef HAVE_JWXYZ
- {
- char *name = jwxyz_unicode_character_name (
- s->dpy, s->metrics_font1->fid, s->debug_metrics_p);
- if (!name || !*name) name = strdup("unknown character name");
- XDrawString (s->dpy, dest, gc,
- 10,
- 10 + 2 * (s->metrics_font2->ascent +
- s->metrics_font2->descent),
- name, strlen(name));
- free (name);
- }
-# endif
-
- /* i 0, j 0: top left, XDrawString, char metrics
- i 1, j 0: bot left, XDrawString, overall metrics, ink escape
- i 0, j 1: top right, XftDrawStringUtf8, utf8 metrics
- i 1, j 1: bot right, XDrawString16, 16 metrics, ink escape
- */
- for (j = 0; j < 2; j++) {
- Bool xft_p = (j != 0);
- int ww = s->xgwa.width / 2 - 20;
- int xoff = (j == 0 ? 0 : ww + 20);
-
- /* XDrawString only does 8-bit characters, so skip it outside Latin-1. */
- if (s->debug_metrics_p >= 256)
- {
- if (!xft_p)
- continue;
- xoff = 0;
- ww = s->xgwa.width;
- }
-
- x = (ww - overall.width) / 2;
-
- for (i = 0; i < 2; i++)
- {
- XCharStruct cc;
- int x1 = xoff + ww * 0.18;
- int x2 = xoff + ww * 0.82;
- int x3 = xoff + ww;
- int pixw, pixh;
- Pixmap p;
-
- y = 80;
- {
- int h = sc * (ascent + descent);
- int min = (ascent + descent) * 4;
- if (h < min) h = min;
- if (i == 1) h *= 3;
- y += h;
- }
-
- memset (&fake_c, 0, sizeof(fake_c));
-
- if (!xft_p && i == 0)
- cc = c;
- else if (!xft_p && i == 1)
- cc = overall;
- else if (xft_p && i == 0)
- {
- /* Measure the glyph in the Xft way */
- XGlyphInfo extents;
- XftTextExtentsUtf8 (s->dpy,
- s->metrics_xftfont,
- (FcChar8 *) utxt, strlen(utxt),
- &extents);
- XGlyphInfo_to_XCharStruct (extents, fake_c);
- cc = fake_c;
- }
- else if (xft_p)
- {
- /* Measure the glyph in the 16-bit way */
- int dir, ascent, descent;
- XTextExtents16 (s->metrics_font1, txt3, 1, &dir, &ascent, &descent,
- &fake_c);
- cc = fake_c;
- }
-
- pixw = margin * 2 + cc.rbearing - cc.lbearing;
- pixh = margin * 2 + cc.ascent + cc.descent;
- p = (pixw > 0 && pixh > 0
- ? XCreatePixmap (s->dpy, dest, pixw, pixh, s->xgwa.depth)
- : 0);
-
- if (p)
- {
- Pixmap p2;
- GC gc2 = XCreateGC (s->dpy, p, 0, 0);
-# ifdef HAVE_JWXYZ
- jwxyz_XSetAntiAliasing (s->dpy, gc2, False);
-# endif
- XSetFont (s->dpy, gc2, s->metrics_font1->fid);
- XSetForeground (s->dpy, gc2, BlackPixelOfScreen (s->xgwa.screen));
- XFillRectangle (s->dpy, p, gc2, 0, 0, pixw, pixh);
- XSetForeground (s->dpy, gc, WhitePixelOfScreen (s->xgwa.screen));
- XSetForeground (s->dpy, gc2, WhitePixelOfScreen (s->xgwa.screen));
-# ifdef HAVE_JWXYZ
- jwxyz_XSetAntiAliasing (s->dpy, gc2,
- s->debug_metrics_antialiasing_p);
-# endif
-
- if (xft_p && i == 0)
- {
- XftDraw *xftdraw2 = XftDrawCreate (s->dpy, p, s->xgwa.visual,
- s->xgwa.colormap);
- XftDrawStringUtf8 (xftdraw2, &xftcolor,
- s->metrics_xftfont,
- -cc.lbearing + margin,
- cc.ascent + margin,
- (FcChar8 *) utxt, strlen(utxt));
- XftDrawDestroy (xftdraw2);
- }
- else if (xft_p)
- XDrawString16 (s->dpy, p, gc2,
- -cc.lbearing + margin,
- cc.ascent + margin,
- txt3, 1);
- else
- XDrawString (s->dpy, p, gc2,
- -cc.lbearing + margin,
- cc.ascent + margin,
- txt, strlen(txt));
-
- {
- unsigned x2, y2;
- XImage *img = XGetImage (s->dpy, p, 0, 0, pixw, pixh,
- ~0L, ZPixmap);
- XImage *img2;
-
- if (i == 1)
- {
- unsigned w = pixw - margin * 2, h = pixh - margin * 2;
-
- if (margin > 0)
- {
- /* Check for ink escape. */
- unsigned long ink = 0;
- for (y2 = 0; y2 != pixh; ++y2)
- for (x2 = 0; x2 != pixw; ++x2)
- {
- /* Sloppy... */
- if (! (x2 >= margin &&
- x2 < pixw - margin &&
- y2 >= margin &&
- y2 < pixh - margin))
- ink |= XGetPixel (img, x2, y2);
- }
-
- if (ink & 0xFFFFFF)
- {
- XSetFont (s->dpy, gc, s->metrics_font2->fid);
- XDrawString (s->dpy, dest, gc,
- xoff + 10, 40,
- "Ink escape!", 11);
- }
- }
-
- /* ...And wasted space. */
- if (w && h)
- {
- if (check_edge (s->dpy, dest, gc, 120, 60, "left",
- img, margin, margin, 1, h) |
- check_edge (s->dpy, dest, gc, 160, 60, "right",
- img, margin + w - 1, margin, 1, h) |
- check_edge (s->dpy, dest, gc, 200, 60, "top",
- img, margin, margin, 0, w) |
- check_edge (s->dpy, dest, gc, 240, 60, "bottom",
- img, margin, margin + h - 1, 0, w))
- {
- XSetFont (s->dpy, gc, s->metrics_font2->fid);
- XDrawString (s->dpy, dest, gc,
- xoff + 10, 60,
- "Wasted space: ", 14);
- }
- }
- }
-
- if (s->debug_metrics_antialiasing_p)
- {
- /* Draw a dark cyan boundary around antialiased glyphs */
- img2 = XCreateImage (s->dpy, s->xgwa.visual, img->depth,
- ZPixmap, 0, NULL,
- img->width, img->height,
- img->bitmap_pad, 0);
- img2->data = malloc (img->bytes_per_line * img->height);
-
- for (y2 = 0; y2 != pixh; ++y2)
- for (x2 = 0; x2 != pixw; ++x2)
- {
- unsigned long px = XGetPixel (img, x2, y2);
- if ((px & 0xffffff) == 0)
- {
- unsigned long neighbors = 0;
- if (x2)
- neighbors |= XGetPixel (img, x2 - 1, y2);
- if (x2 != pixw - 1)
- neighbors |= XGetPixel (img, x2 + 1, y2);
- if (y2)
- neighbors |= XGetPixel (img, x2, y2 - 1);
- if (y2 != pixh - 1)
- neighbors |= XGetPixel (img, x2, y2 + 1);
- XPutPixel (img2, x2, y2,
- (neighbors & 0xffffff
- ? cyan
- : BlackPixelOfScreen (s->xgwa.screen)));
- }
- else
- {
- XPutPixel (img2, x2, y2, px);
- }
- }
- }
- else
- {
- img2 = img;
- img = NULL;
- }
-
- p2 = scale_ximage (s->xgwa.screen, s->window, img2, sc, margin);
- if (img)
- XDestroyImage (img);
- XDestroyImage (img2);
- }
-
- XCopyArea (s->dpy, p2, dest, gc,
- 0, 0, sc*pixw, sc*pixh,
- xoff + x + sc * (cc.lbearing - margin),
- y - sc * (cc.ascent + margin));
- XFreePixmap (s->dpy, p);
- XFreePixmap (s->dpy, p2);
- XFreeGC (s->dpy, gc2);
- }
-
- if (i == 0)
- {
- XSetFont (s->dpy, gc, s->metrics_font1->fid);
- XSetForeground (s->dpy, gc, WhitePixelOfScreen (s->xgwa.screen));
-# ifdef HAVE_JWXYZ
- jwxyz_XSetAntiAliasing (s->dpy, gc, s->debug_metrics_antialiasing_p);
-# endif
- sprintf (txt2, "%s [XX%sXX] [%s%s%s%s]",
- (xft_p ? utxt : txt),
- (xft_p ? utxt : txt),
- (xft_p ? utxt : txt),
- (xft_p ? utxt : txt),
- (xft_p ? utxt : txt),
- (xft_p ? utxt : txt));
-
- if (xft_p)
- XftDrawStringUtf8 (xftdraw, &xftcolor,
- s->metrics_xftfont,
- xoff + x/2 + (sc*cc.rbearing/2) - cc.rbearing/2
- + 40,
- ascent + 10,
- (FcChar8 *) txt2, strlen(txt2));
- else
- XDrawString (s->dpy, dest, gc,
- xoff + x/2 + (sc*cc.rbearing/2) - cc.rbearing/2,
- ascent + 10,
- txt2, strlen(txt2));
-# ifdef HAVE_JWXYZ
- jwxyz_XSetAntiAliasing (s->dpy, gc, False);
-# endif
- XSetFont (s->dpy, gc, s->metrics_font2->fid);
- if (xft_p)
- {
- char *uptr;
- char *tptr = txt2 + sprintf(txt2, "U+%04lX", s->debug_metrics_p);
- *tptr++ = " ?_"[s->entering_unicode_p];
- *tptr++ = ' ';
-
- uptr = utxt;
- while (*uptr)
- {
- tptr += sprintf (tptr, "0%03o ", (unsigned char) *uptr);
- ++uptr;
- }
- *tptr++ = ' ';
- uptr = utxt;
- while (*uptr)
- {
- tptr += sprintf (tptr, "%02x ", (unsigned char) *uptr);
- ++uptr;
- }
- }
- else
- sprintf (txt2, "%c %3ld 0%03lo 0x%02lx%s",
- (char)s->debug_metrics_p, s->debug_metrics_p,
- s->debug_metrics_p, s->debug_metrics_p,
- (txt[0] < s->metrics_font1->min_char_or_byte2
- ? " *" : ""));
- XDrawString (s->dpy, dest, gc,
- xoff + 10, 20,
- txt2, strlen(txt2));
- }
-
-# ifdef HAVE_JWXYZ
- jwxyz_XSetAntiAliasing (s->dpy, gc, True);
-# endif
-
- {
- const char *ss = (j == 0
- ? (i == 0 ? "char" : "overall")
- : (i == 0 ? "utf8" : "16 bit"));
- XSetFont (s->dpy, gc, s->metrics_font2->fid);
-
- XSetForeground (s->dpy, gc, red);
-
- sprintf (txt2, "%s ascent %d", ss, ascent);
- XDrawString (s->dpy, dest, gc,
- xoff + 10,
- y - sc*ascent - 2,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- xoff, y - sc*ascent,
- x3, y - sc*ascent);
-
- sprintf (txt2, "%s descent %d", ss, descent);
- XDrawString (s->dpy, dest, gc,
- xoff + 10,
- y + sc*descent - 2,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- xoff, y + sc*descent,
- x3, y + sc*descent);
- }
-
-
- /* ascent, descent, baseline */
-
- XSetForeground (s->dpy, gc, green);
-
- sprintf (txt2, "ascent %d", cc.ascent);
- if (cc.ascent != 0)
- XDrawString (s->dpy, dest, gc,
- x1, y - sc*cc.ascent - 2,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- x1, y - sc*cc.ascent,
- x2, y - sc*cc.ascent);
-
- sprintf (txt2, "descent %d", cc.descent);
- if (cc.descent != 0)
- XDrawString (s->dpy, dest, gc,
- x1, y + sc*cc.descent - 2,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- x1, y + sc*cc.descent,
- x2, y + sc*cc.descent);
-
- XSetForeground (s->dpy, gc, yellow);
- strcpy (txt2, "baseline");
- XDrawString (s->dpy, dest, gc,
- x1, y - 2,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc, x1, y, x2, y);
-
-
- /* origin, width */
-
- XSetForeground (s->dpy, gc, blue);
-
- strcpy (txt2, "origin");
- XDrawString (s->dpy, dest, gc,
- xoff + x + 2,
- y + sc*descent + 50,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- xoff + x, y - sc*(ascent - 10),
- xoff + x, y + sc*(descent + 10));
-
- sprintf (txt2, "width %d", cc.width);
- XDrawString (s->dpy, dest, gc,
- xoff + x + sc*cc.width + 2,
- y + sc*descent + 60,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- xoff + x + sc*cc.width, y - sc*(ascent - 10),
- xoff + x + sc*cc.width, y + sc*(descent + 10));
-
-
- /* lbearing, rbearing */
-
- XSetForeground (s->dpy, gc, green);
-
- sprintf (txt2, "lbearing %d", cc.lbearing);
- XDrawString (s->dpy, dest, gc,
- xoff + x + sc*cc.lbearing + 2,
- y + sc * descent + 30,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- xoff + x + sc*cc.lbearing, y - sc*ascent,
- xoff + x + sc*cc.lbearing, y + sc*descent + 20);
-
- sprintf (txt2, "rbearing %d", cc.rbearing);
- XDrawString (s->dpy, dest, gc,
- xoff + x + sc*cc.rbearing + 2,
- y + sc * descent + 40,
- txt2, strlen(txt2));
- XDrawLine (s->dpy, dest, gc,
- xoff + x + sc*cc.rbearing, y - sc*ascent,
- xoff + x + sc*cc.rbearing, y + sc*descent + 40);
-
- /* y += sc * (ascent + descent) * 2; */
- }
- }
-
- if (dest != s->window)
- XCopyArea (s->dpy, dest, s->window, s->bg_gc,
- 0, 0, s->xgwa.width, s->xgwa.height, 0, 0);
-
- XFreeGC (s->dpy, gc);
- XftColorFree (s->dpy, s->xgwa.visual, s->xgwa.colormap, &xftcolor);
- XftDrawDestroy (xftdraw);
- free (txt3);
-
- return s->frame_delay;
-}
-
-# endif /* DEBUG */
-
-
-/* Render all the words to the screen, and run the animation one step.
- Clear screen first, swap buffers after.
- */
-static unsigned long
-fontglide_draw (Display *dpy, Window window, void *closure)
-{
- state *s = (state *) closure;
- int i;
-
-# ifdef DEBUG
- if (s->debug_metrics_p)
- return fontglide_draw_metrics (closure);
-# endif /* DEBUG */
-
- if (s->spawn_p)
- more_sentences (s);
-
- if (!s->trails_p)
- XFillRectangle (s->dpy, s->b, s->bg_gc,
- 0, 0, s->xgwa.width, s->xgwa.height);
-
- for (i = 0; i < s->nsentences; i++)
- draw_sentence (s, s->sentences[i]);
-
-# ifdef DEBUG
- if (s->debug_p && (s->prev_font_name || s->next_font_name))
- {
- if (! s->label_gc)
- {
- if (! s->metrics_font2)
- s->metrics_font2 = XLoadQueryFont (s->dpy, "fixed");
- s->label_gc = XCreateGC (dpy, s->b, 0, 0);
- XSetFont (s->dpy, s->label_gc, s->metrics_font2->fid);
- }
- if (s->prev_font_name)
- XDrawString (s->dpy, s->b, s->label_gc,
- 10, 10 + s->metrics_font2->ascent,
- s->prev_font_name, strlen(s->prev_font_name));
- if (s->next_font_name)
- XDrawString (s->dpy, s->b, s->label_gc,
- 10, 10 + s->metrics_font2->ascent * 2,
- s->next_font_name, strlen(s->next_font_name));
- }
-# endif /* DEBUG */
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- if (s->backb)
- {
- XdbeSwapInfo info[1];
- info[0].swap_window = s->window;
- info[0].swap_action = (s->dbeclear_p ? XdbeBackground : XdbeUndefined);
- XdbeSwapBuffers (s->dpy, info, 1);
- }
- else
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
- if (s->dbuf)
- {
- XCopyArea (s->dpy, s->b, s->window, s->bg_gc,
- 0, 0, s->xgwa.width, s->xgwa.height, 0, 0);
- }
-
- return s->frame_delay;
-}
-
-
-
-/* When the subprocess has generated some output, this reads as much as it
- can into s->buf at s->buf_tail.
- */
-static void
-drain_input (state *s)
-{
- while (s->buf_tail < sizeof(s->buf) - 2)
- {
- int c = textclient_getc (s->tc);
- if (c > 0)
- s->buf[s->buf_tail++] = (char) c;
- else
- break;
- }
-}
-
-
-/* Window setup and resource loading */
-
-static void *
-fontglide_init (Display *dpy, Window window)
-{
- XGCValues gcv;
- state *s = (state *) calloc (1, sizeof(*s));
- s->dpy = dpy;
- s->window = window;
- s->frame_delay = get_integer_resource (dpy, "delay", "Integer");
-
- XGetWindowAttributes (s->dpy, s->window, &s->xgwa);
-
- s->font_override = get_string_resource (dpy, "font", "Font");
- if (s->font_override && (!*s->font_override || *s->font_override == '(')) {
- free (s->font_override);
- s->font_override = 0;
- }
-
- s->charset = get_string_resource (dpy, "fontCharset", "FontCharset");
- s->border_width = get_integer_resource (dpy, "fontBorderWidth", "Integer");
- if (s->border_width < 0 || s->border_width > 20)
- s->border_width = 1;
-
- s->speed = get_float_resource (dpy, "speed", "Float");
- if (s->speed <= 0 || s->speed > 200)
- s->speed = 1;
-
- s->linger = get_float_resource (dpy, "linger", "Float");
- if (s->linger <= 0 || s->linger > 200)
- s->linger = 1;
-
- s->trails_p = get_boolean_resource (dpy, "trails", "Trails");
-
-# ifdef DEBUG
- s->debug_p = get_boolean_resource (dpy, "debug", "Debug");
- s->debug_metrics_p = (get_boolean_resource (dpy, "debugMetrics", "Debug")
- ? 199 : 0);
- s->debug_scale = 6;
-
-# ifdef HAVE_JWXYZ
- if (s->debug_metrics_p && !s->font_override)
- s->font_override = "Helvetica Bold 16";
-# endif
-
-# endif /* DEBUG */
-
- s->dbuf = get_boolean_resource (dpy, "doubleBuffer", "Boolean");
-
-# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
- s->dbuf = False;
-# endif
-
-# ifdef DEBUG
- if (s->debug_metrics_p) s->trails_p = False;
-# endif /* DEBUG */
-
- if (s->trails_p) s->dbuf = False; /* don't need it in this case */
-
- {
- char *ss = get_string_resource (dpy, "mode", "Mode");
- if (!ss || !*ss || !strcasecmp (ss, "random"))
- s->mode = ((random() % 2) ? SCROLL : PAGE);
- else if (!strcasecmp (ss, "scroll"))
- s->mode = SCROLL;
- else if (!strcasecmp (ss, "page"))
- s->mode = PAGE;
- else if (!strcasecmp (ss, "chars") || !strcasecmp (ss, "char"))
- s->mode = CHARS;
- else
- {
- fprintf (stderr,
- "%s: `mode' must be `scroll', `page', or `random', not `%s'\n",
- progname, ss);
- }
- if (ss) free (ss);
- }
-
- if (s->dbuf)
- {
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- s->dbeclear_p = get_boolean_resource (dpy, "useDBEClear", "Boolean");
- if (s->dbeclear_p)
- s->b = xdbe_get_backbuffer (dpy, window, XdbeBackground);
- else
- s->b = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
- s->backb = s->b;
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-
- if (!s->b)
- {
- s->ba = XCreatePixmap (s->dpy, s->window,
- s->xgwa.width, s->xgwa.height,
- s->xgwa.depth);
- s->b = s->ba;
- }
- }
- else
- {
- s->b = s->window;
- }
-
- gcv.foreground = get_pixel_resource (s->dpy, s->xgwa.colormap,
- "background", "Background");
- s->bg_gc = XCreateGC (s->dpy, s->b, GCForeground, &gcv);
-
- s->nsentences = 5; /* #### */
- s->sentences = (sentence **) calloc (s->nsentences, sizeof (sentence *));
- s->spawn_p = True;
-
- s->early_p = True;
- s->start_time = time ((time_t *) 0);
- s->tc = textclient_open (dpy);
-
- return s;
-}
-
-
-static Bool
-fontglide_event (Display *dpy, Window window, void *closure, XEvent *event)
-{
-# ifdef DEBUG
- state *s = (state *) closure;
-
- if (! s->debug_metrics_p)
- return False;
- if (event->xany.type == KeyPress)
- {
- static const unsigned long max = 0x110000;
- KeySym keysym;
- char c = 0;
- XLookupString (&event->xkey, &c, 1, &keysym, 0);
-
- if (s->entering_unicode_p > 0)
- {
- unsigned digit;
- unsigned long new_char = 0;
-
- if (c >= 'a' && c <= 'f')
- digit = c + 0xa - 'a';
- else if (c >= 'A' && c <= 'F')
- digit = c + 0xa - 'A';
- else if (c >= '0' && c <= '9')
- digit = c + 0 - '0';
- else
- {
- s->entering_unicode_p = 0;
- return True;
- }
-
- if (s->entering_unicode_p == 1)
- new_char = 0;
- else if (s->entering_unicode_p == 2)
- new_char = s->debug_metrics_p;
-
- new_char = (new_char << 4) | digit;
- if (new_char > 0 && new_char < max)
- {
- s->debug_metrics_p = new_char;
- s->entering_unicode_p = 2;
- }
- else
- s->entering_unicode_p = 0;
- return True;
- }
-
- if (c == '\t')
- s->debug_metrics_antialiasing_p ^= True;
- else if (c == 3 || c == 27)
- exit (0);
- else if (c >= ' ')
- s->debug_metrics_p = (unsigned char) c;
- else if (keysym == XK_Left || keysym == XK_Right)
- {
- s->debug_metrics_p += (keysym == XK_Left ? -1 : 1);
- if (s->debug_metrics_p >= max)
- s->debug_metrics_p = 1;
- else if (s->debug_metrics_p <= 0)
- s->debug_metrics_p = max - 1;
- return True;
- }
- else if (keysym == XK_Prior)
- s->debug_metrics_p = (s->debug_metrics_p + max - 0x80) % max;
- else if (keysym == XK_Next)
- s->debug_metrics_p = (s->debug_metrics_p + 0x80) % max;
- else if (keysym == XK_Up)
- s->debug_scale++;
- else if (keysym == XK_Down)
- s->debug_scale = (s->debug_scale > 1 ? s->debug_scale-1 : 1);
- else if (keysym == XK_F1)
- s->entering_unicode_p = 1;
- else
- return False;
- return True;
- }
-# endif /* DEBUG */
-
- return False;
-}
-
-
-static void
-fontglide_reshape (Display *dpy, Window window, void *closure,
- unsigned int w, unsigned int h)
-{
- state *s = (state *) closure;
- XGetWindowAttributes (s->dpy, s->window, &s->xgwa);
-
- if (s->dbuf && s->ba)
- {
- XFreePixmap (s->dpy, s->ba);
- s->ba = XCreatePixmap (s->dpy, s->window,
- s->xgwa.width, s->xgwa.height,
- s->xgwa.depth);
- XFillRectangle (s->dpy, s->ba, s->bg_gc, 0, 0,
- s->xgwa.width, s->xgwa.height);
- s->b = s->ba;
- }
-}
-
-static void
-fontglide_free (Display *dpy, Window window, void *closure)
-{
- state *s = (state *) closure;
- int i;
-
- textclient_close (s->tc);
-
-/* if (s->b && s->b != s->window) XFreePixmap (dpy, s->b); */
-/* if (s->ba && s->ba != s->b) XFreePixmap (dpy, s->ba); */
- XFreeGC (dpy, s->bg_gc);
- if (s->charset) free (s->charset);
- if (s->font_override) free (s->font_override);
- for (i = 0;i < s->nsentences; i++)
- if (s->sentences[i])
- free_sentence (s, s->sentences[i]);
- free (s->sentences);
-
-#ifdef DEBUG
- if (s->metrics_xftfont)
- XftFontClose (s->dpy, s->metrics_xftfont);
- if (s->metrics_font1)
- XFreeFont (s->dpy, s->metrics_font1);
- if (s->metrics_font2 && s->metrics_font1 != s->metrics_font2)
- XFreeFont (s->dpy, s->metrics_font2);
- if (s->prev_font_name) free (s->prev_font_name);
- if (s->next_font_name) free (s->next_font_name);
- if (s->label_gc) XFreeGC (dpy, s->label_gc);
-#endif
-
- free (s);
-}
-
-
-static const char *fontglide_defaults [] = {
- ".background: #000000",
- ".foreground: #DDDDDD",
- ".borderColor: #555555",
- "*delay: 10000",
- "*program: xscreensaver-text",
- "*usePty: false",
- "*mode: random",
- ".font: (default)",
-
- /* I'm not entirely clear on whether the charset of an XLFD has any
- meaning when Xft is being used. */
- "*fontCharset: iso8859-1",
-/*"*fontCharset: iso10646-1", */
-/*"*fontCharset: *-*",*/
-
- "*fontBorderWidth: 2",
- "*speed: 1.0",
- "*linger: 1.0",
- "*trails: False",
-# ifdef DEBUG
- "*debug: False",
- "*debugMetrics: False",
-# endif /* DEBUG */
- "*doubleBuffer: True",
-# ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- "*useDBE: True",
- "*useDBEClear: True",
-# endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
- 0
-};
-
-static XrmOptionDescRec fontglide_options [] = {
- { "-mode", ".mode", XrmoptionSepArg, 0 },
- { "-scroll", ".mode", XrmoptionNoArg, "scroll" },
- { "-page", ".mode", XrmoptionNoArg, "page" },
- { "-random", ".mode", XrmoptionNoArg, "random" },
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- { "-speed", ".speed", XrmoptionSepArg, 0 },
- { "-linger", ".linger", XrmoptionSepArg, 0 },
- { "-program", ".program", XrmoptionSepArg, 0 },
- { "-font", ".font", XrmoptionSepArg, 0 },
- { "-fn", ".font", XrmoptionSepArg, 0 },
- { "-bw", ".fontBorderWidth", XrmoptionSepArg, 0 },
- { "-trails", ".trails", XrmoptionNoArg, "True" },
- { "-no-trails", ".trails", XrmoptionNoArg, "False" },
- { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
- { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
-# ifdef DEBUG
- { "-debug", ".debug", XrmoptionNoArg, "True" },
- { "-debug-metrics", ".debugMetrics", XrmoptionNoArg, "True" },
-# endif /* DEBUG */
- { 0, 0, 0, 0 }
-};
-
-
-XSCREENSAVER_MODULE ("FontGlide", fontglide)