sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
526
app/xlockmore/modes/marquee.c
Normal file
526
app/xlockmore/modes/marquee.c
Normal file
|
@ -0,0 +1,526 @@
|
|||
/* -*- Mode: C; tab-width: 4 -*- */
|
||||
/* marquee --- types a text-file or a text ribbon */
|
||||
|
||||
#if !defined( lint ) && !defined( SABER )
|
||||
static const char sccsid[] = "@(#)marquee.c 5.00 2000/11/01 xlockmore";
|
||||
|
||||
#endif
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1995 by Tobias Gloth and David Bagley
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and that
|
||||
* both that copyright notice and this permission notice appear in
|
||||
* supporting documentation.
|
||||
*
|
||||
* This file is provided AS IS with no warranties of any kind. The author
|
||||
* shall have no liability with respect to the infringement of copyrights,
|
||||
* trade secrets or any patents by this file or any part thereof. In no
|
||||
* event will the author be liable for any lost revenue or profits or
|
||||
* other special, indirect and consequential damages.
|
||||
*
|
||||
* Revision History:
|
||||
* 01-Nov-2000: Allocation checks
|
||||
* 10-May-1997: Compatible with xscreensaver
|
||||
* 03-Nov-1995: Many changes (hopefully good ones) by David Bagley
|
||||
* 01-Oct-1995: Written by Tobias Gloth
|
||||
*/
|
||||
|
||||
#ifdef STANDALONE
|
||||
#define MODE_marquee
|
||||
#define PROGCLASS "Marquee"
|
||||
#define HACK_INIT init_marquee
|
||||
#define HACK_DRAW draw_marquee
|
||||
#define marquee_opts xlockmore_opts
|
||||
#define DEFAULTS "*delay: 100000 \n" \
|
||||
"*ncolors: 64 \n" \
|
||||
"*font: \n" \
|
||||
"*text: \n" \
|
||||
"*filename: \n" \
|
||||
"*fortunefile: \n" \
|
||||
"*program: \n"
|
||||
#define SMOOTH_COLORS
|
||||
#include "xlockmore.h" /* in xscreensaver distribution */
|
||||
#else /* STANDALONE */
|
||||
#include "xlock.h" /* in xlockmore distribution */
|
||||
#endif /* STANDALONE */
|
||||
#include "iostuff.h"
|
||||
|
||||
#ifdef MODE_marquee
|
||||
|
||||
ModeSpecOpt marquee_opts =
|
||||
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
|
||||
|
||||
#ifdef USE_MODULES
|
||||
ModStruct marquee_description =
|
||||
{"marquee", "init_marquee", "draw_marquee", "release_marquee",
|
||||
"init_marquee", "init_marquee", (char *) NULL, &marquee_opts,
|
||||
100000, 1, 1, 1, 64, 1.0, "",
|
||||
"Shows messages", 0, NULL};
|
||||
|
||||
#endif
|
||||
|
||||
#define font_height(f) ((f==None)?8:f->ascent + f->descent)
|
||||
|
||||
extern XFontStruct *getFont(Display * display);
|
||||
extern char *getWords(int screen, int screens);
|
||||
extern int isRibbon(void);
|
||||
|
||||
typedef struct {
|
||||
int ascent;
|
||||
int height;
|
||||
int win_height;
|
||||
int win_width;
|
||||
int x;
|
||||
int y;
|
||||
int t;
|
||||
int startx;
|
||||
int nonblanks;
|
||||
int color;
|
||||
int time;
|
||||
GC gc;
|
||||
char *words;
|
||||
char modwords[256];
|
||||
} marqueestruct;
|
||||
|
||||
static marqueestruct *marquees = (marqueestruct *) NULL;
|
||||
|
||||
static XFontStruct *mode_font = None;
|
||||
static int char_width[256];
|
||||
|
||||
static int
|
||||
font_width(XFontStruct * font, char ch)
|
||||
{
|
||||
int dummy;
|
||||
XCharStruct xcs;
|
||||
|
||||
(void) XTextExtents(font, &ch, 1, &dummy, &dummy, &dummy, &xcs);
|
||||
return xcs.width;
|
||||
}
|
||||
|
||||
/* returns 1 if c is a printable char, the test should work for most 8 * bit
|
||||
charsets (e.g. latin1), if we would use isprint, we would * depend of
|
||||
locale settings that are probably incorrect. */
|
||||
|
||||
static int
|
||||
is_valid_char(char c)
|
||||
{
|
||||
return (unsigned char) c >= ' ';
|
||||
}
|
||||
|
||||
static int
|
||||
is_char_back_char(char *s)
|
||||
{
|
||||
return is_valid_char(*s) && *(s + 1) == '\b' &&
|
||||
*(s + 2) && is_valid_char(*(s + 2));
|
||||
}
|
||||
|
||||
static int
|
||||
char_back_char_width(char *s)
|
||||
{
|
||||
int w1 = char_width[(int) (unsigned char) *s];
|
||||
int w2 = char_width[(int) (unsigned char) *(s + 2)];
|
||||
|
||||
return w2 < w1 ? w1 : w2;
|
||||
}
|
||||
|
||||
|
||||
/*-
|
||||
* fix strings of the form abc^H^H^H123 to a^H1b^H2c^H3, since we only
|
||||
* handle backspace for char, back, char correctly. We do this without
|
||||
* duplicating the string, but I'm not sure if there are conditions
|
||||
* when the string is actually const. (when it is def_message, no ^Hs
|
||||
* are present, I'm not sure about resource strings)
|
||||
*/
|
||||
|
||||
static char *
|
||||
fixup_back(char *s)
|
||||
{
|
||||
char *p, *p1, *p2;
|
||||
char tmp[1000];
|
||||
char *t;
|
||||
char *w;
|
||||
|
||||
/* first of all, check if we have to do anything */
|
||||
|
||||
if (!*s)
|
||||
return s;
|
||||
|
||||
for (p = s + 1; *p; p++)
|
||||
if (*p == '\b' && *(p + 1) == '\b')
|
||||
break;
|
||||
if (!*p)
|
||||
return s;
|
||||
|
||||
/* now search for runs of the form char*n, back*n, char. */
|
||||
|
||||
for (p = s; *p; p++) {
|
||||
for (p1 = p; *p1 && is_valid_char(*p1); p1++);
|
||||
if (*p1 == '\b') {
|
||||
for (p2 = p1; *p2 && *p2 == '\b'; p2++);
|
||||
|
||||
/* do we have `enough' chars for the backspaces? */
|
||||
|
||||
if (p2 - p1 > 1 && p1 - p >= p2 - p1) {
|
||||
if (p1 - p > p2 - p1) {
|
||||
p = p1 - (p2 - p1);
|
||||
}
|
||||
/* the situation is as follows:
|
||||
p points to the first char,
|
||||
p1 to the first backspace (end first char run),
|
||||
p2 to the first char in the 2nd run
|
||||
|
||||
Question: how to do that without tmp storage?
|
||||
*/
|
||||
(void) strncpy(tmp, p, p1 - p);
|
||||
t = tmp;
|
||||
w = p;
|
||||
while (t - tmp < p1 - p && *p2) {
|
||||
*w++ = *t++;
|
||||
*w++ = '\b';
|
||||
*w++ = *p2++;
|
||||
}
|
||||
p = p2;
|
||||
} else {
|
||||
p = p2;
|
||||
}
|
||||
} else {
|
||||
/* we hit some other control char, just continue at this
|
||||
position */
|
||||
p = p1;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static int
|
||||
text_font_width(char *string)
|
||||
{
|
||||
int n = 0, x = 0, t = 0;
|
||||
|
||||
/* The following does not handle a tab or other weird junk */
|
||||
while (*string != '\0') {
|
||||
if (x > n)
|
||||
n = x;
|
||||
switch (*string) {
|
||||
case '\v':
|
||||
case '\f':
|
||||
case '\n':
|
||||
x = 0;
|
||||
t = 0;
|
||||
break;
|
||||
case '\b':
|
||||
/* we handle only char, ^H, char smartly, if
|
||||
* we have something different, we use the
|
||||
* (probably wrong) assumption that we have
|
||||
* a monospaced font. */
|
||||
if (t) {
|
||||
t--;
|
||||
x -= char_width[(int) (' ')];
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
x += char_width[(int) (' ')] * (8 - (t % 8));
|
||||
t = ((t + 8) / 8) * 8;
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
default:
|
||||
t++;
|
||||
/* handle char, ^H, char */
|
||||
if (is_char_back_char(string)) {
|
||||
x += char_back_char_width(string);
|
||||
string += 2;
|
||||
} else {
|
||||
x += char_width[(int) (unsigned char) *string];
|
||||
}
|
||||
}
|
||||
string++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
text_height(char *string)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
while (*string != '\0') {
|
||||
if ((*string == '\n') || (*string == '\f') || (*string == '\v'))
|
||||
n++;
|
||||
string++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
add_blanks(marqueestruct * mp)
|
||||
{
|
||||
if (mp->t < 251) {
|
||||
mp->modwords[mp->t] = ' ';
|
||||
mp->t++;
|
||||
mp->modwords[mp->t] = ' ';
|
||||
mp->t++;
|
||||
mp->modwords[mp->t] = '\0';
|
||||
(void) strcat(mp->modwords, " ");
|
||||
}
|
||||
mp->x -= 2 * char_width[(int) (' ')];
|
||||
if (mp->x <= -char_width[(int) (unsigned char) mp->modwords[0]]) {
|
||||
mp->x += char_width[(int) (unsigned char) mp->modwords[0]];
|
||||
(void) memcpy(mp->modwords, &(mp->modwords[1]), mp->nonblanks);
|
||||
mp->nonblanks--;
|
||||
}
|
||||
return (mp->nonblanks < 0);
|
||||
}
|
||||
|
||||
static void
|
||||
add_letter(marqueestruct * mp, char letter)
|
||||
{
|
||||
if (mp->t < 252) {
|
||||
mp->modwords[mp->t] = letter;
|
||||
mp->t++;
|
||||
mp->modwords[mp->t] = '\0';
|
||||
(void) strcat(mp->modwords, " ");
|
||||
}
|
||||
mp->x -= char_width[(int) letter];
|
||||
if (mp->x <= -char_width[(int) (unsigned char) mp->modwords[0]]) {
|
||||
mp->x += char_width[(int) (unsigned char) mp->modwords[0]];
|
||||
(void) memcpy(mp->modwords, &(mp->modwords[1]), mp->t);
|
||||
mp->modwords[mp->t] = ' ';
|
||||
mp->t--;
|
||||
} else
|
||||
mp->nonblanks = mp->t;
|
||||
}
|
||||
|
||||
void
|
||||
init_marquee(ModeInfo * mi)
|
||||
{
|
||||
Display *display = MI_DISPLAY(mi);
|
||||
marqueestruct *mp;
|
||||
XGCValues gcv;
|
||||
int i;
|
||||
|
||||
if (marquees == NULL) {
|
||||
if ((marquees = (marqueestruct *) calloc(MI_NUM_SCREENS(mi),
|
||||
sizeof (marqueestruct))) == NULL)
|
||||
return;
|
||||
}
|
||||
mp = &marquees[MI_SCREEN(mi)];
|
||||
|
||||
mp->win_width = MI_WIDTH(mi);
|
||||
mp->win_height = MI_HEIGHT(mi);
|
||||
if (MI_NPIXELS(mi) > 2)
|
||||
mp->color = NRAND(MI_NPIXELS(mi));
|
||||
mp->time = 0;
|
||||
mp->t = 0;
|
||||
mp->nonblanks = 0;
|
||||
mp->x = 0;
|
||||
|
||||
MI_CLEARWINDOW(mi);
|
||||
|
||||
if (mode_font == None)
|
||||
mode_font = getFont(display);
|
||||
if (mp->gc == NULL && mode_font != None) {
|
||||
gcv.font = mode_font->fid;
|
||||
XSetFont(display, MI_GC(mi), mode_font->fid);
|
||||
gcv.graphics_exposures = False;
|
||||
gcv.foreground = MI_WHITE_PIXEL(mi);
|
||||
gcv.background = MI_BLACK_PIXEL(mi);
|
||||
if ((mp->gc = XCreateGC(display, MI_WINDOW(mi),
|
||||
GCForeground | GCBackground | GCGraphicsExposures | GCFont,
|
||||
&gcv)) == None) {
|
||||
return;
|
||||
}
|
||||
mp->ascent = mode_font->ascent;
|
||||
mp->height = font_height(mode_font);
|
||||
for (i = 0; i < 256; i++)
|
||||
if ((i >= (int) mode_font->min_char_or_byte2) &&
|
||||
(i <= (int) mode_font->max_char_or_byte2))
|
||||
char_width[i] = font_width(mode_font, (char) i);
|
||||
else
|
||||
char_width[i] = font_width(mode_font, (char) mode_font->default_char);
|
||||
} else if (mode_font == None) {
|
||||
for (i = 0; i < 256; i++)
|
||||
char_width[i] = 8;
|
||||
}
|
||||
mp->words = fixup_back(getWords(MI_SCREEN(mi), MI_NUM_SCREENS(mi)));
|
||||
mp->y = 0;
|
||||
|
||||
if (isRibbon()) {
|
||||
mp->x = mp->win_width;
|
||||
if (mp->win_height > font_height(mode_font))
|
||||
mp->y += NRAND(mp->win_height - font_height(mode_font));
|
||||
else if (mp->win_height < font_height(mode_font))
|
||||
mp->y -= NRAND(font_height(mode_font) - mp->win_height);
|
||||
} else {
|
||||
int text_ht = text_height(mp->words);
|
||||
int text_font_wid = text_font_width(mp->words);
|
||||
|
||||
if (mp->win_height > text_ht * font_height(mode_font))
|
||||
mp->y = NRAND(mp->win_height - text_ht * font_height(mode_font));
|
||||
if (mp->y < 0)
|
||||
mp->y = 0;
|
||||
mp->x = 0;
|
||||
if (mp->win_width > text_font_wid)
|
||||
mp->x += NRAND(mp->win_width - text_font_wid);
|
||||
/* else if (mp->win_width < text_font_wid)
|
||||
mp->x -= NRAND(text_font_wid - mp->win_width); */
|
||||
mp->startx = mp->x;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
draw_marquee(ModeInfo * mi)
|
||||
{
|
||||
Display *display = MI_DISPLAY(mi);
|
||||
Window window = MI_WINDOW(mi);
|
||||
char *space = (char *) " ";
|
||||
char *ch;
|
||||
marqueestruct *mp = &marquees[MI_SCREEN(mi)];
|
||||
|
||||
if (marquees == NULL)
|
||||
return;
|
||||
mp = &marquees[MI_SCREEN(mi)];
|
||||
if (mp->gc == None && mode_font != None)
|
||||
return;
|
||||
|
||||
MI_IS_DRAWN(mi) = True;
|
||||
ch = mp->words;
|
||||
if (isRibbon()) {
|
||||
ch = mp->words;
|
||||
switch (*ch) {
|
||||
case '\0':
|
||||
if (add_blanks(mp)) {
|
||||
init_marquee(mi);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case '\b':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\f':
|
||||
add_letter(mp, ' ');
|
||||
mp->words++;
|
||||
break;
|
||||
default:
|
||||
add_letter(mp, *ch);
|
||||
mp->words++;
|
||||
}
|
||||
if (MI_NPIXELS(mi) > 2) {
|
||||
XSetForeground(display, mp->gc, MI_PIXEL(mi, mp->color));
|
||||
if (++mp->color == MI_NPIXELS(mi))
|
||||
mp->color = 0;
|
||||
} else
|
||||
XSetForeground(display, mp->gc, MI_WHITE_PIXEL(mi));
|
||||
(void) XDrawImageString(display, MI_WINDOW(mi), mp->gc,
|
||||
mp->x, mp->y + mp->ascent, mp->modwords, mp->t + 2);
|
||||
} else {
|
||||
switch (*ch) {
|
||||
case '\0':
|
||||
if (++mp->time > 16)
|
||||
init_marquee(mi);
|
||||
return;
|
||||
case '\b':
|
||||
if (mp->t) {
|
||||
/* see note in text_font_width */
|
||||
mp->t--;
|
||||
mp->x -= char_width[(int) (' ')];
|
||||
}
|
||||
break;
|
||||
case '\v':
|
||||
case '\f':
|
||||
case '\n':
|
||||
mp->x = mp->startx;
|
||||
mp->t = 0;
|
||||
mp->y += mp->height;
|
||||
if (mp->y + mp->height > mp->win_height) {
|
||||
XCopyArea(display, window, window, mp->gc,
|
||||
0, mp->height, mp->win_width, mp->y - mp->height, 0, 0);
|
||||
XSetForeground(display, mp->gc, MI_BLACK_PIXEL(mi));
|
||||
mp->y -= mp->height;
|
||||
XFillRectangle(display, window, mp->gc,
|
||||
0, mp->y, mp->win_width, mp->height);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
(void) XDrawString(display, window, mp->gc, mp->x, mp->y + mp->ascent,
|
||||
space, 8 - (mp->t % 8));
|
||||
mp->x += char_width[(int) (' ')] * (8 - (mp->t % 8));
|
||||
mp->t = ((mp->t + 8) / 8) * 8;
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
default:
|
||||
if (MI_NPIXELS(mi) > 2) {
|
||||
XSetForeground(display, mp->gc, MI_PIXEL(mi, mp->color));
|
||||
if (++mp->color == MI_NPIXELS(mi))
|
||||
mp->color = 0;
|
||||
} else
|
||||
XSetForeground(display, mp->gc, MI_WHITE_PIXEL(mi));
|
||||
if (is_char_back_char(ch)) {
|
||||
int xmid = mp->x + (char_back_char_width(ch) + 1) / 2;
|
||||
|
||||
(void) XDrawString(display, window, mp->gc,
|
||||
xmid - char_width[(int) (unsigned char) *ch] / 2,
|
||||
mp->y + mp->ascent, ch, 1);
|
||||
(void) XDrawString(display, window, mp->gc,
|
||||
xmid - char_width[(int) (unsigned char) *(ch + 2)] / 2,
|
||||
mp->y + mp->ascent, ch + 2, 1);
|
||||
mp->x += char_back_char_width(ch);
|
||||
mp->words += 2;
|
||||
} else {
|
||||
#ifdef USE_MB
|
||||
int mb = (*ch & 0x80) ? 2 : 1;
|
||||
|
||||
(void) XDrawString(display, window, mp->gc,
|
||||
mp->x, mp->y + mp->ascent, ch, mb);
|
||||
if (mb == 1)
|
||||
mp->x += char_width[(int) (unsigned char) *ch];
|
||||
else {
|
||||
XRectangle rect;
|
||||
|
||||
XmbTextExtents(fontset, ch, 2, NULL, &rect);
|
||||
mp->x += rect.width;
|
||||
}
|
||||
#else
|
||||
(void) XDrawString(display, window, mp->gc,
|
||||
mp->x, mp->y + mp->ascent, ch, 1);
|
||||
mp->x += char_width[(int) (unsigned char) *ch];
|
||||
#endif
|
||||
}
|
||||
mp->t++;
|
||||
}
|
||||
#ifdef USE_MB
|
||||
mp->words += (*mp->words & 0x80) ? 2 : 1;
|
||||
#else
|
||||
mp->words++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
release_marquee(ModeInfo * mi)
|
||||
{
|
||||
if (marquees != NULL) {
|
||||
int screen;
|
||||
|
||||
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
|
||||
marqueestruct *mp = &marquees[screen];
|
||||
|
||||
if (mp->gc != None)
|
||||
XFreeGC(MI_DISPLAY(mi), mp->gc);
|
||||
}
|
||||
free(marquees);
|
||||
marquees = (marqueestruct *) NULL;
|
||||
}
|
||||
if (mode_font != None) {
|
||||
XFreeFont(MI_DISPLAY(mi), mode_font);
|
||||
mode_font = None;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MODE_marquee */
|
Loading…
Add table
Add a link
Reference in a new issue