-/* xscreensaver, Copyright (c) 1992-2014 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2018 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
*/
#include "screenhack.h"
-#include "xpm-pixmap.h"
+#include "ximage-loader.h"
#include "textclient.h"
-
-#ifdef HAVE_COCOA
-# define HAVE_XPM
-#endif
+#include "xft.h"
#define font_height(font) (font->ascent + font->descent)
+typedef struct { Pixmap p, m; } PM;
+
struct state {
Display *dpy;
Window window;
int Width, Height;
GC fg_gc, bg_gc, text_fg_gc, text_bg_gc;
int x, y;
- XFontStruct *font;
+
+ XftFont *xftfont;
+ XftColor xftcolor;
+ XftDraw *xftdraw;
unsigned long interval;
- Pixmap left1, left2, right1, right2;
- Pixmap left_front, right_front, front, down;
+ PM left1, left2, right1, right2, left_front, right_front, front, down;
+ int pix_w, pix_h;
text_data *tc;
int walk_lastdir;
int walk_up;
- Pixmap walk_frame;
+ PM *walk_frame;
int X, Y, talking;
#define IS_MOVING 1
-#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
-# include "images/noseguy/nose-f1.xpm"
-# include "images/noseguy/nose-f2.xpm"
-# include "images/noseguy/nose-f3.xpm"
-# include "images/noseguy/nose-f4.xpm"
-# include "images/noseguy/nose-l1.xpm"
-# include "images/noseguy/nose-l2.xpm"
-# include "images/noseguy/nose-r1.xpm"
-# include "images/noseguy/nose-r2.xpm"
-#else
-# include "images/noseguy/nose-f1.xbm"
-# include "images/noseguy/nose-f2.xbm"
-# include "images/noseguy/nose-f3.xbm"
-# include "images/noseguy/nose-f4.xbm"
-# include "images/noseguy/nose-l1.xbm"
-# include "images/noseguy/nose-l2.xbm"
-# include "images/noseguy/nose-r1.xbm"
-# include "images/noseguy/nose-r2.xbm"
-#endif
+#include "images/gen/nose-f1_png.h"
+#include "images/gen/nose-f2_png.h"
+#include "images/gen/nose-f3_png.h"
+#include "images/gen/nose-f4_png.h"
+#include "images/gen/nose-l1_png.h"
+#include "images/gen/nose-l2_png.h"
+#include "images/gen/nose-r1_png.h"
+#include "images/gen/nose-r2_png.h"
+
+static Pixmap
+double_pixmap (Display *dpy, Visual *visual, int depth, Pixmap pixmap,
+ int pix_w, int pix_h)
+{
+ int x, y;
+ Pixmap p2 = XCreatePixmap(dpy, pixmap, pix_w*2, pix_h*2, depth);
+ XImage *i1 = XGetImage (dpy, pixmap, 0, 0, pix_w, pix_h, ~0L,
+ (depth == 1 ? XYPixmap : ZPixmap));
+ XImage *i2 = XCreateImage (dpy, visual, depth,
+ (depth == 1 ? XYPixmap : ZPixmap), 0, 0,
+ pix_w*2, pix_h*2, 8, 0);
+ XGCValues gcv;
+ GC gc = XCreateGC (dpy, p2, 0, &gcv);
+ i2->data = (char *) calloc(i2->height, i2->bytes_per_line);
+ for (y = 0; y < pix_h; y++)
+ for (x = 0; x < pix_w; x++)
+ {
+ unsigned long p = XGetPixel(i1, x, y);
+ XPutPixel(i2, x*2, y*2, p);
+ XPutPixel(i2, x*2+1, y*2, p);
+ XPutPixel(i2, x*2, y*2+1, p);
+ XPutPixel(i2, x*2+1, y*2+1, p);
+ }
+ free(i1->data); i1->data = 0;
+ XDestroyImage(i1);
+ XPutImage(dpy, p2, gc, i2, 0, 0, 0, 0, i2->width, i2->height);
+ XFreeGC (dpy, gc);
+ free(i2->data); i2->data = 0;
+ XDestroyImage(i2);
+ XFreePixmap(dpy, pixmap);
+ return p2;
+}
+
static void
init_images (struct state *st)
{
- Pixmap *images[8];
-#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
- char **bits[8];
-#else
- unsigned char *bits[8];
-#endif
+ PM *images[8];
+ struct { const unsigned char *png; unsigned long size; } bits[8];
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (st->dpy, st->window, &xgwa);
int i = 0;
images[i++] = &st->left1;
images[i++] = &st->front;
images[i] = &st->down;
-#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
-
+#define DEF(N,S) bits[i].png = N; bits[i].size = S; i++
i = 0;
- bits[i++] = nose_l1_xpm;
- bits[i++] = nose_l2_xpm;
- bits[i++] = nose_r1_xpm;
- bits[i++] = nose_r2_xpm;
- bits[i++] = nose_f2_xpm;
- bits[i++] = nose_f3_xpm;
- bits[i++] = nose_f1_xpm;
- bits[i] = nose_f4_xpm;
+ DEF(nose_l1_png, sizeof(nose_l1_png));
+ DEF(nose_l2_png, sizeof(nose_l2_png));
+ DEF(nose_r1_png, sizeof(nose_r1_png));
+ DEF(nose_r2_png, sizeof(nose_r2_png));
+ DEF(nose_f2_png, sizeof(nose_f2_png));
+ DEF(nose_f3_png, sizeof(nose_f3_png));
+ DEF(nose_f1_png, sizeof(nose_f1_png));
+ DEF(nose_f4_png, sizeof(nose_f4_png));
for (i = 0; i < sizeof (images) / sizeof(*images); i++)
{
- Pixmap pixmap = xpm_data_to_pixmap (st->dpy, st->window, bits[i],
- 0, 0, 0);
+ Pixmap mask = 0;
+ Pixmap pixmap = image_data_to_pixmap (st->dpy, st->window,
+ bits[i].png, bits[i].size,
+ &st->pix_w, &st->pix_h, &mask);
if (!pixmap)
{
fprintf (stderr, "%s: Can't load nose images\n", progname);
exit (1);
}
- *images[i] = pixmap;
+ images[i]->p = pixmap;
+ images[i]->m = mask;
}
-#else
- i = 0;
- bits[i++] = nose_l1_bits;
- bits[i++] = nose_l2_bits;
- bits[i++] = nose_r1_bits;
- bits[i++] = nose_r2_bits;
- bits[i++] = nose_f2_bits;
- bits[i++] = nose_f3_bits;
- bits[i++] = nose_f1_bits;
- bits[i++] = nose_f4_bits;
- for (i = 0; i < sizeof (images) / sizeof(*images); i++)
- if (!(*images[i] =
- XCreatePixmapFromBitmapData(st->dpy, st->window,
- (char *) bits[i], 64, 64, 1, 0, 1)))
- {
- fprintf (stderr, "%s: Can't load nose images\n", progname);
- exit (1);
- }
-#endif
+ if (xgwa.width > 2560) /* Retina display */
+ {
+ for (i = 0; i < sizeof (images) / sizeof(*images); i++)
+ {
+ images[i]->p = double_pixmap (st->dpy, xgwa.visual, xgwa.depth,
+ images[i]->p, st->pix_w, st->pix_h);
+ images[i]->m = double_pixmap (st->dpy, xgwa.visual, 1,
+ images[i]->m, st->pix_w, st->pix_h);
+ }
+ st->pix_w *= 2;
+ st->pix_h *= 2;
+ }
}
#define LEFT 001
st->next_fn = move;
}
-#ifdef HAVE_XPM
-# define COPY(dpy,frame,window,gc,x,y,w,h,x2,y2) \
- XCopyArea (dpy,frame,window,gc,x,y,w,h,x2,y2)
-#else
-# define COPY(dpy,frame,window,gc,x,y,w,h,x2,y2) \
- XCopyPlane(dpy,frame,window,gc,x,y,w,h,x2,y2,1L)
-#endif
+# define COPY(dpy,frame,window,gc,x,y,w,h,x2,y2) do {\
+ int X2 = (x2), Y2 = (y2); \
+ PM *FRAME = (frame); \
+ XFillRectangle(dpy,window,st->bg_gc,X2,Y2,w,h); \
+ XSetClipMask (dpy,gc,FRAME->m); \
+ XSetClipOrigin (dpy,gc,X2,Y2); \
+ XCopyArea (dpy,FRAME->p,window,gc,x,y,w,h,X2,Y2); \
+ XSetClipMask (dpy,gc,None); \
+ } while(0)
static void
walk (struct state *st, int dir)
if (dir & LEFT)
{
incr = X_INCR;
- st->walk_frame = (st->walk_up < 0) ? st->left1 : st->left2;
+ st->walk_frame = (st->walk_up < 0) ? &st->left1 : &st->left2;
}
else
{
incr = -X_INCR;
- st->walk_frame = (st->walk_up < 0) ? st->right1 : st->right2;
+ st->walk_frame = (st->walk_up < 0) ? &st->right1 : &st->right2;
}
if ((st->walk_lastdir == FRONT || st->walk_lastdir == DOWN) && dir & UP)
{
* workaround silly bug that leaves screen dust when guy is
* facing forward or st->down and moves up-left/right.
*/
- COPY(st->dpy, st->walk_frame, st->window, st->fg_gc, 0, 0, 64, 64, st->x, st->y);
+ COPY(st->dpy, st->walk_frame, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, st->x, st->y);
}
/* note that maybe neither UP nor DOWN is set! */
if (dir & UP && st->y > Y_INCR)
st->y -= Y_INCR;
- else if (dir & DOWN && st->y < st->Height - 64)
+ else if (dir & DOWN && st->y < st->Height - st->pix_h)
st->y += Y_INCR;
}
/* Explicit up/st->down movement only (no left/right) */
else if (dir == UP)
- COPY(st->dpy, st->front, st->window, st->fg_gc, 0, 0, 64, 64, st->x, st->y -= Y_INCR);
+ COPY(st->dpy, &st->front, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, st->x, st->y -= Y_INCR);
else if (dir == DOWN)
- COPY(st->dpy, st->down, st->window, st->fg_gc, 0, 0, 64, 64, st->x, st->y += Y_INCR);
- else if (dir == FRONT && st->walk_frame != st->front)
+ COPY(st->dpy, &st->down, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, st->x, st->y += Y_INCR);
+ else if (dir == FRONT && st->walk_frame != &st->front)
{
if (st->walk_up > 0)
st->walk_up = -st->walk_up;
if (st->walk_lastdir & LEFT)
- st->walk_frame = st->left_front;
+ st->walk_frame = &st->left_front;
else if (st->walk_lastdir & RIGHT)
- st->walk_frame = st->right_front;
+ st->walk_frame = &st->right_front;
else
- st->walk_frame = st->front;
- COPY(st->dpy, st->walk_frame, st->window, st->fg_gc, 0, 0, 64, 64, st->x, st->y);
+ st->walk_frame = &st->front;
+ COPY(st->dpy, st->walk_frame, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, st->x, st->y);
}
if (dir & LEFT)
while (--incr >= 0)
{
- COPY(st->dpy, st->walk_frame, st->window, st->fg_gc, 0, 0, 64, 64, --st->x, st->y + st->walk_up);
+ COPY(st->dpy, st->walk_frame, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, --st->x, st->y + st->walk_up);
}
else if (dir & RIGHT)
while (++incr <= 0)
{
- COPY(st->dpy, st->walk_frame, st->window, st->fg_gc, 0, 0, 64, 64, ++st->x, st->y + st->walk_up);
+ COPY(st->dpy, st->walk_frame, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, ++st->x, st->y + st->walk_up);
}
st->walk_lastdir = dir;
}
if (!(p2 = strchr(p, '\n')) || !p2[1])
{
+ XGlyphInfo extents;
+
total = strlen (st->words);
strncpy (args[0], st->words, LINELEN);
args[0][LINELEN - 1] = 0;
- width = XTextWidth(st->font, st->words, total);
+ XftTextExtentsUtf8 (st->dpy, st->xftfont,
+ (FcChar8 *) st->words, total,
+ &extents);
+ width = extents.xOff;
height = 0;
}
else
for (height = 0; p; height++)
{
int w;
+ XGlyphInfo extents;
*p2 = 0;
- if ((w = XTextWidth(st->font, p, p2 - p)) > width)
- width = w;
+
+ XftTextExtentsUtf8 (st->dpy, st->xftfont,
+ (FcChar8 *) p, p2 - p,
+ &extents);
+ w = extents.xOff;
+ if (w > width)
+ width = w;
+
total += p2 - p; /* total chars; count to determine reading
* time */
(void) strncpy(args[height], p, LINELEN);
* new box by 15 pixels on the sides (30 total) top and bottom.
*/
st->s_rect.width = width + 30;
- st->s_rect.height = height * font_height(st->font) + 30;
+ st->s_rect.height = height * font_height(st->xftfont) + 30;
if (st->x - st->s_rect.width - 10 < 5)
st->s_rect.x = 5;
else if ((st->s_rect.x = st->x + 32 - (st->s_rect.width + 15) / 2)
+ st->s_rect.width + 15 > st->Width - 5)
st->s_rect.x = st->Width - 15 - st->s_rect.width;
if (st->y - st->s_rect.height - 10 < 5)
- st->s_rect.y = st->y + 64 + 5;
+ st->s_rect.y = st->y + st->pix_h + 5;
else
st->s_rect.y = st->y - 5 - st->s_rect.height;
st->s_rect.x + 7, st->s_rect.y + 7, st->s_rect.width - 15, st->s_rect.height - 15);
st->X = 15;
- st->Y = 15 + font_height(st->font);
+ st->Y = 15 + font_height(st->xftfont);
/* now print each string in reverse order (start at bottom of box) */
for (Z = 0; Z < height; Z++)
/* If there are continuous new lines, L can be 0 */
if (L && (args[Z][L-1] == '\r' || args[Z][L-1] == '\n'))
args[Z][--L] = 0;
- XDrawString(st->dpy, st->window, st->text_fg_gc, st->s_rect.x + st->X, st->s_rect.y + st->Y,
- args[Z], L);
- st->Y += font_height(st->font);
+ XftDrawStringUtf8 (st->xftdraw, &st->xftcolor, st->xftfont,
+ st->s_rect.x + st->X, st->s_rect.y + st->Y,
+ (FcChar8 *) args[Z], L);
+
+ st->Y += font_height(st->xftfont);
}
st->interval = (total / 15) * 1000;
if (st->interval < 2000) st->interval = 2000;
{
if (random() % 3)
{
- COPY(st->dpy, (random() & 1) ? st->down : st->front, st->window, st->fg_gc,
- 0, 0, 64, 64, st->x, st->y);
+ COPY(st->dpy, (random() & 1) ? &st->down : &st->front, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, st->x, st->y);
return 1000L;
}
if (!(random() % 5))
return 0;
if (random() % 3)
{
- COPY(st->dpy, (random() & 1) ? st->left_front : st->right_front,
- st->window, st->fg_gc, 0, 0, 64, 64, st->x, st->y);
+ COPY(st->dpy, (random() & 1) ? &st->left_front : &st->right_front,
+ st->window, st->fg_gc, 0, 0, st->pix_w, st->pix_h, st->x, st->y);
return 1000L;
}
if (!(random() % 5))
return 0;
- COPY(st->dpy, (random() & 1) ? st->left1 : st->right1, st->window, st->fg_gc,
- 0, 0, 64, 64, st->x, st->y);
+ COPY(st->dpy, (random() & 1) ? &st->left1 : &st->right1, st->window, st->fg_gc,
+ 0, 0, st->pix_w, st->pix_h, st->x, st->y);
return 1000L;
}
"*fpsSolid: true",
"*program: xscreensaver-text",
"*usePty: False",
- ".font: -*-new century schoolbook-*-r-*-*-*-180-*-*-*-*-*-*",
+ ".font: -*-helvetica-medium-r-*-*-*-140-*-*-*-*-*-*",
0
};
init_images(st);
- if (!fontname || !*fontname)
- fprintf (stderr, "%s: no font specified.\n", progname);
- st->font = XLoadQueryFont(st->dpy, fontname);
- if (!st->font) {
- fprintf (stderr, "%s: could not load font %s.\n", progname, fontname);
- exit(1);
- }
+ st->xftfont = XftFontOpenXlfd (st->dpy, screen_number (xgwa.screen),
+ fontname);
+ XftColorAllocName (st->dpy, xgwa.visual, xgwa.colormap,
+ get_string_resource (st->dpy,
+ "textForeground", "Foreground"),
+ &st->xftcolor);
+ st->xftdraw = XftDrawCreate (st->dpy, st->window, xgwa.visual,
+ xgwa.colormap);
+
fg = get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
bg = get_pixel_resource (st->dpy, cmap, "background", "Background");
if (! get_string_resource (st->dpy, "textBackground", "Background"))
text_bg = fg;
- gcvalues.font = st->font->fid;
gcvalues.foreground = fg;
gcvalues.background = bg;
st->fg_gc = XCreateGC (st->dpy, st->window,
- GCForeground|GCBackground|GCFont,
+ GCForeground|GCBackground,
&gcvalues);
gcvalues.foreground = bg;
gcvalues.background = fg;
st->bg_gc = XCreateGC (st->dpy, st->window,
- GCForeground|GCBackground|GCFont,
+ GCForeground|GCBackground,
&gcvalues);
gcvalues.foreground = text_fg;
gcvalues.background = text_bg;
st->text_fg_gc = XCreateGC (st->dpy, st->window,
- GCForeground|GCBackground|GCFont,
+ GCForeground|GCBackground,
&gcvalues);
gcvalues.foreground = text_bg;
gcvalues.background = text_fg;
st->text_bg_gc = XCreateGC (st->dpy, st->window,
- GCForeground|GCBackground|GCFont,
+ GCForeground|GCBackground,
&gcvalues);
st->x = st->Width / 2;
st->y = st->Height / 2;